diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/controller/GraphsController.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/controller/GraphsController.java index ffa0730c5a..9c014b30ab 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/controller/GraphsController.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/controller/GraphsController.java @@ -7,9 +7,9 @@ import com.provectus.kafka.ui.model.GraphDescriptionsDTO; import com.provectus.kafka.ui.model.GraphParameterDTO; import com.provectus.kafka.ui.model.PrometheusApiQueryResponseDTO; import com.provectus.kafka.ui.model.rbac.AccessContext; +import com.provectus.kafka.ui.service.graphs.GraphDescription; import com.provectus.kafka.ui.service.graphs.GraphsService; import com.provectus.kafka.ui.service.audit.AuditService; -import com.provectus.kafka.ui.service.graphs.GraphsStorage; import com.provectus.kafka.ui.service.rbac.AccessControlService; import java.time.Duration; import java.time.OffsetDateTime; @@ -65,11 +65,7 @@ public class GraphsController extends AbstractController implements GraphsApi { @Override public Mono> getGraphsList(String clusterName, ServerWebExchange exchange) { - var graphs = graphsService.getAllGraphs(); - var cluster = getCluster(clusterName); - if (cluster.getPrometheusStorageClient() == null) { - graphs = Stream.empty(); - } + var graphs = graphsService.getGraphs(getCluster(clusterName)); return Mono.just( ResponseEntity.ok( new GraphDescriptionsDTO().graphs(graphs.map(this::map).toList()) @@ -77,7 +73,7 @@ public class GraphsController extends AbstractController implements GraphsApi { ); } - private GraphDescriptionDTO map(GraphsStorage.GraphDescription graph) { + private GraphDescriptionDTO map(GraphDescription graph) { return new GraphDescriptionDTO(graph.id()) .defaultPeriod(Optional.ofNullable(graph.defaultInterval()).map(Duration::toString).orElse(null)) .type(graph.isRange() ? GraphDescriptionDTO.TypeEnum.RANGE : GraphDescriptionDTO.TypeEnum.INSTANT) diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/graphs/GraphDescription.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/graphs/GraphDescription.java new file mode 100644 index 0000000000..21555ea7eb --- /dev/null +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/graphs/GraphDescription.java @@ -0,0 +1,17 @@ +package com.provectus.kafka.ui.service.graphs; + +import java.time.Duration; +import java.util.Set; +import javax.annotation.Nullable; +import lombok.Builder; + +@Builder +public record GraphDescription(String id, + @Nullable Duration defaultInterval, //null for instant queries, set for range + String prometheusQuery, + Set params) { + + public boolean isRange() { + return defaultInterval != null; + } +} diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/graphs/GraphsStorage.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/graphs/GraphDescriptions.java similarity index 82% rename from kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/graphs/GraphsStorage.java rename to kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/graphs/GraphDescriptions.java index 206ef4be3f..57458a9a19 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/graphs/GraphsStorage.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/graphs/GraphDescriptions.java @@ -10,38 +10,26 @@ import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; -import javax.annotation.Nullable; -import lombok.Builder; import org.springframework.stereotype.Component; @Component -public class GraphsStorage { +class GraphDescriptions { private static final Duration DEFAULT_RANGE_DURATION = Duration.ofDays(7); - @Builder - public record GraphDescription(String id, - @Nullable Duration defaultInterval, - String prometheusQuery, - Set params) { - public boolean isRange() { - return defaultInterval != null; - } - } - private final Map graphsById; - GraphsStorage() { + GraphDescriptions() { validateGraphDescr(PREDEFINED_GRAPHS); this.graphsById = PREDEFINED_GRAPHS.stream() .collect(Collectors.toMap(GraphDescription::id, d -> d)); } - Optional getDescription(String id) { + Optional getById(String id) { return Optional.ofNullable(graphsById.get(id)); } - Stream getAll() { + Stream all() { return graphsById.values().stream(); } diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/graphs/GraphsService.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/graphs/GraphsService.java index 811b888716..e7dc7457e3 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/graphs/GraphsService.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/graphs/GraphsService.java @@ -4,7 +4,6 @@ import com.google.common.base.Preconditions; import com.provectus.kafka.ui.exception.NotFoundException; import com.provectus.kafka.ui.exception.ValidationException; import com.provectus.kafka.ui.model.KafkaCluster; -import com.provectus.kafka.ui.service.graphs.GraphsStorage.GraphDescription; import com.provectus.kafka.ui.service.metrics.prometheus.PromQueryTemplate; import java.time.Duration; import java.time.Instant; @@ -24,7 +23,7 @@ public class GraphsService { private static final int TARGET_MATRIX_DATA_POINTS = 200; - private final GraphsStorage graphsStorage; + private final GraphDescriptions graphDescriptions; public Mono getGraphData(KafkaCluster cluster, String id, @@ -32,16 +31,16 @@ public class GraphsService { @Nullable Instant to, @Nullable Map params) { - var graph = graphsStorage.getDescription(id) + var graph = graphDescriptions.getById(id) .orElseThrow(() -> new NotFoundException("No graph found with id = " + id)); var promClient = cluster.getPrometheusStorageClient(); if (promClient == null) { throw new ValidationException("Prometheus not configured for cluster"); } + String preparedQuery = prepareQuery(graph, cluster.getName(), params); return cluster.getPrometheusStorageClient() .mono(client -> { - String preparedQuery = prepareQuery(graph, cluster.getName(), params); if (graph.isRange()) { return queryRange(client, preparedQuery, graph.defaultInterval(), from, to); } @@ -75,8 +74,7 @@ public class GraphsService { if (intervalInSecs <= TARGET_MATRIX_DATA_POINTS) { return intervalInSecs + "s"; } - int step = ((int) (((double) intervalInSecs) / 200)); - System.out.println("Chosen step size " + step); //TODo + int step = ((int) (((double) intervalInSecs) / TARGET_MATRIX_DATA_POINTS)); return step + "s"; } @@ -84,12 +82,15 @@ public class GraphsService { return c.query(preparedQuery, null, null); } - public static String prepareQuery(GraphDescription d, String clusterName, @Nullable Map params) { + private String prepareQuery(GraphDescription d, String clusterName, @Nullable Map params) { return new PromQueryTemplate(d).getQuery(clusterName, Optional.ofNullable(params).orElse(Map.of())); } - public Stream getAllGraphs() { - return graphsStorage.getAll(); + public Stream getGraphs(KafkaCluster cluster) { + if (cluster.getPrometheusStorageClient() == null) { + return Stream.empty(); + } + return graphDescriptions.all(); } } diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/metrics/prometheus/PromQueryLangGrammar.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/metrics/prometheus/PromQueryLangGrammar.java index 13885f2efe..ad62b3ccef 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/metrics/prometheus/PromQueryLangGrammar.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/metrics/prometheus/PromQueryLangGrammar.java @@ -1,12 +1,10 @@ package com.provectus.kafka.ui.service.metrics.prometheus; -import com.provectus.kafka.ui.exception.ValidationException; import java.util.Optional; -import org.antlr.v4.runtime.BaseErrorListener; +import org.antlr.v4.runtime.BailErrorStrategy; import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonTokenStream; -import org.antlr.v4.runtime.RecognitionException; -import org.antlr.v4.runtime.Recognizer; +import org.antlr.v4.runtime.misc.ParseCancellationException; import promql.PromQLLexer; import promql.PromQLParser; @@ -17,27 +15,23 @@ class PromQueryLangGrammar { try { parseExpression(query); return Optional.empty(); - } catch (ValidationException v) { - return Optional.of(v.getMessage()); + } catch (ParseCancellationException e) { + //TODO: add more descriptive msg + return Optional.of("Syntax error"); } } static PromQLParser.ExpressionContext parseExpression(String query) { - return parse(query).expression(); + return createParser(query).expression(); } - private static PromQLParser parse(String str) throws ValidationException { + private static PromQLParser createParser(String str) { PromQLLexer lexer = new PromQLLexer(CharStreams.fromString(str)); - lexer.addErrorListener(new BaseErrorListener() { - @Override - public void syntaxError(Recognizer recognizer, Object offendingSymbol, - int line, int charPositionInLine, - String msg, RecognitionException e) { - throw new ValidationException("Invalid syntax: " + msg); - } - }); CommonTokenStream tokenStream = new CommonTokenStream(lexer); - return new PromQLParser(tokenStream); + var parser = new PromQLParser(tokenStream); + parser.removeErrorListeners(); + parser.setErrorHandler(new BailErrorStrategy()); + return parser; } } diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/metrics/prometheus/PromQueryTemplate.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/metrics/prometheus/PromQueryTemplate.java index 4225d759ae..141b7e9455 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/metrics/prometheus/PromQueryTemplate.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/metrics/prometheus/PromQueryTemplate.java @@ -2,7 +2,7 @@ package com.provectus.kafka.ui.service.metrics.prometheus; import com.google.common.collect.Sets; import com.provectus.kafka.ui.exception.ValidationException; -import com.provectus.kafka.ui.service.graphs.GraphsStorage; +import com.provectus.kafka.ui.service.graphs.GraphDescription; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -14,7 +14,7 @@ public class PromQueryTemplate { private final String queryTemplate; private final Set paramsNames; - public PromQueryTemplate(GraphsStorage.GraphDescription d) { + public PromQueryTemplate(GraphDescription d) { this(d.prometheusQuery(), d.params()); } @@ -35,8 +35,9 @@ public class PromQueryTemplate { public Optional validateSyntax() { Map fakeReplacements = new HashMap<>(); - paramsNames.forEach(paramName -> fakeReplacements.put(paramName, "1")); fakeReplacements.put("cluster", "1"); + paramsNames.forEach(paramName -> fakeReplacements.put(paramName, "1")); + String prepared = replaceParams(fakeReplacements); return PromQueryLangGrammar.validateExpression(prepared); }