From 075b08ce74868ed097b1ab76f06ee778ed8d5329 Mon Sep 17 00:00:00 2001 From: Wan Kai Date: Tue, 28 Nov 2023 07:40:13 +0800 Subject: [PATCH] Support `increase/rate` function in the `MQE` query language. (#11591) --- docs/en/api/metrics-query-expression.md | 40 +++++++ docs/en/changes/changes.md | 1 + .../skywalking/mqe/rt/grammar/MQELexer.g4 | 2 + .../skywalking/mqe/rt/grammar/MQEParser.g4 | 6 +- .../skywalking/mqe/rt/MQEVisitorBase.java | 35 ++++++ .../skywalking/mqe/rt/operation/TrendOp.java | 106 ++++++++++++++++++ .../apache/skywalking/mqe/rt/TrendOpTest.java | 72 ++++++++++++ .../server/core/alarm/provider/AlarmRule.java | 3 + .../core/alarm/provider/RunningRule.java | 17 ++- .../expr/rt/AlarmMQEVerifyVisitor.java | 25 +++++ .../provider/expr/rt/AlarmMQEVisitor.java | 35 +++++- .../core/alarm/provider/AlarmRuleTest.java | 3 + .../core/alarm/provider/RunningRuleTest.java | 11 +- .../promql/handler/PromQLApiHandler.java | 2 +- .../rt/exception/ParseErrorListener.java | 2 +- .../oap/query/graphql/mqe/rt/MQEVisitor.java | 73 ++++++++++-- .../resolver/MetricsExpressionQuery.java | 2 +- test/e2e-v2/cases/alarm/alarm-settings.yml | 4 +- test/e2e-v2/cases/alarm/es/e2e.yaml | 2 +- .../cases/alarm/es/es-sharding/e2e.yaml | 2 +- .../expected/silence-after-graphql-warn.yml | 4 +- .../alarm/expected/silence-after-webhook.yml | 4 +- .../expected/silence-before-graphql-warn.yml | 2 +- .../alarm/expected/silence-before-webhook.yml | 2 +- test/e2e-v2/cases/alarm/h2/e2e.yaml | 2 +- test/e2e-v2/cases/alarm/mysql/e2e.yaml | 2 +- test/e2e-v2/cases/alarm/postgres/e2e.yaml | 2 +- test/e2e-v2/cases/mqe/expected/trend-OP.yml | 31 +++++ test/e2e-v2/cases/mqe/mqe-cases.yaml | 6 + 29 files changed, 457 insertions(+), 41 deletions(-) create mode 100644 oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/TrendOp.java create mode 100644 oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/TrendOpTest.java create mode 100644 test/e2e-v2/cases/mqe/expected/trend-OP.yml diff --git a/docs/en/api/metrics-query-expression.md b/docs/en/api/metrics-query-expression.md index 6c5798c3fa62..2ca901e2eb31 100644 --- a/docs/en/api/metrics-query-expression.md +++ b/docs/en/api/metrics-query-expression.md @@ -296,6 +296,46 @@ view_as_seq(not_existing, service_cpm) #### Result Type The result type is determined by the type of selected not-null metric expression. +## Trend Operation +Trend Operation takes an expression and performs a trend calculation on its results. + +Expression: +```text +(Metrics Expression, time_range) +``` + +`time_range` is the positive int of the calculated range. The unit will automatically align with to the query [Step](../../../oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/enumeration/Step.java), +for example, if the query Step is `MINUTE`, the unit of `time_range` is `minute`. + + +| Operator | Definition | ExpressionResultType | +|----------|---------------------------------------------------------------------------------------|-------------------------------| +| increase | returns the increase in the time range in the time series | TIME_SERIES_VALUES | +| rate | returns the per-second average rate of increase in the time range in the time series | TIME_SERIES_VALUES | + +For example: +If we want to query the increase value of the `service_cpm` metric in 2 minute(assume the query Step is MINUTE), +we can use the following expression: + +```text +increase(service_cpm, 2) +``` + +If the query duration is 3 minutes, from (T1 to T3) and the metric has values in time series: +```text +V(T1-2), V(T1-1), V(T1), V(T2), V(T3) +``` +then the expression result is: +```text +V(T1)-V(T1-2), V(T2)-V(T1-1), V(T3)-V(T1) +``` + +**Note**: +* If the calculated metric value is empty, the result will be empty. Assume in the T3 point, the increase value = V(T3)-V(T1), If the metric V(T3) or V(T1) is empty, the result value in T3 will be empty. + +### Result Type +TIME_SERIES_VALUES. + ## Expression Query Example ### Labeled Value Metrics ```text diff --git a/docs/en/changes/changes.md b/docs/en/changes/changes.md index b033310a1986..97f0ebc485bd 100644 --- a/docs/en/changes/changes.md +++ b/docs/en/changes/changes.md @@ -48,6 +48,7 @@ * Replace Metrics v2 protocol with MQE in UI templates and E2E Test. * Fix incorrect apisix metrics otel rules. * Support `Scratch The OAP Config Dump`. +* Support `increase/rate` function in the `MQE` query language. * Group service endpoints into `_abandoned` when endpoints have high cardinality. diff --git a/oap-server/mqe-grammar/src/main/antlr4/org/apache/skywalking/mqe/rt/grammar/MQELexer.g4 b/oap-server/mqe-grammar/src/main/antlr4/org/apache/skywalking/mqe/rt/grammar/MQELexer.g4 index b7a870a6bc12..69687a8702c9 100644 --- a/oap-server/mqe-grammar/src/main/antlr4/org/apache/skywalking/mqe/rt/grammar/MQELexer.g4 +++ b/oap-server/mqe-grammar/src/main/antlr4/org/apache/skywalking/mqe/rt/grammar/MQELexer.g4 @@ -59,6 +59,8 @@ ABS: 'abs'; CEIL: 'ceil'; FLOOR: 'floor'; ROUND: 'round'; +INCREASE: 'increase'; +RATE: 'rate'; // TopN TOP_N: 'top_n'; diff --git a/oap-server/mqe-grammar/src/main/antlr4/org/apache/skywalking/mqe/rt/grammar/MQEParser.g4 b/oap-server/mqe-grammar/src/main/antlr4/org/apache/skywalking/mqe/rt/grammar/MQEParser.g4 index 0c2d9a931775..e67414422daa 100644 --- a/oap-server/mqe-grammar/src/main/antlr4/org/apache/skywalking/mqe/rt/grammar/MQEParser.g4 +++ b/oap-server/mqe-grammar/src/main/antlr4/org/apache/skywalking/mqe/rt/grammar/MQEParser.g4 @@ -31,8 +31,9 @@ expression | aggregation L_PAREN expression R_PAREN # aggregationOp | mathematical_operator0 L_PAREN expression R_PAREN #mathematicalOperator0OP | mathematical_operator1 L_PAREN expression COMMA parameter R_PAREN #mathematicalOperator1OP + | trend L_PAREN metric COMMA INTEGER R_PAREN #trendOP | logical_operator L_PAREN expressionList R_PAREN #logicalOperatorOP - | topN L_PAREN metric COMMA parameter COMMA order R_PAREN #topNOP + | topN L_PAREN metric COMMA INTEGER COMMA order R_PAREN #topNOP | relabels L_PAREN expression COMMA label R_PAREN #relablesOP | aggregateLabels L_PAREN expression COMMA aggregateLabelsFunc R_PAREN #aggregateLabelsOp ; @@ -69,6 +70,9 @@ mathematical_operator0: mathematical_operator1: ROUND; +trend: + INCREASE | RATE; + topN: TOP_N; logical_operator: diff --git a/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/MQEVisitorBase.java b/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/MQEVisitorBase.java index 2f272dc6c015..235abb30c88b 100644 --- a/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/MQEVisitorBase.java +++ b/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/MQEVisitorBase.java @@ -30,17 +30,24 @@ import org.apache.skywalking.mqe.rt.operation.CompareOp; import org.apache.skywalking.mqe.rt.operation.LogicalFunctionOp; import org.apache.skywalking.mqe.rt.operation.MathematicalFunctionOp; +import org.apache.skywalking.mqe.rt.operation.TrendOp; import org.apache.skywalking.mqe.rt.type.ExpressionResult; import org.apache.skywalking.mqe.rt.exception.IllegalExpressionException; import org.apache.skywalking.mqe.rt.type.ExpressionResultType; import org.apache.skywalking.mqe.rt.type.MQEValue; import org.apache.skywalking.mqe.rt.type.MQEValues; import org.apache.skywalking.oap.server.core.Const; +import org.apache.skywalking.oap.server.core.query.enumeration.Step; import org.apache.skywalking.oap.server.library.util.StringUtil; @Slf4j public abstract class MQEVisitorBase extends MQEParserBaseVisitor { public final static String GENERAL_LABEL_NAME = "_"; + public final Step queryStep; + + protected MQEVisitorBase(final Step queryStep) { + this.queryStep = queryStep; + } @Override public ExpressionResult visitParensOp(MQEParser.ParensOpContext ctx) { @@ -250,6 +257,34 @@ public ExpressionResult visitCompareOp(MQEParser.CompareOpContext ctx) { } } + @Override + public ExpressionResult visitTrendOP(MQEParser.TrendOPContext ctx) { + int opType = ctx.trend().getStart().getType(); + int trendRange = Integer.parseInt(ctx.INTEGER().getText()); + if (trendRange < 1) { + ExpressionResult result = new ExpressionResult(); + result.setType(ExpressionResultType.UNKNOWN); + result.setError("The trend range must be greater than 0."); + return result; + } + ExpressionResult expResult = visit(ctx.metric()); + if (StringUtil.isNotEmpty(expResult.getError())) { + return expResult; + } + if (expResult.getType() != ExpressionResultType.TIME_SERIES_VALUES) { + expResult.setError("The result of expression [" + ctx.metric().getText() + "] is not a time series result."); + return expResult; + } + try { + return TrendOp.doTrendOp(expResult, opType, trendRange, queryStep); + } catch (IllegalExpressionException e) { + ExpressionResult result = new ExpressionResult(); + result.setType(ExpressionResultType.UNKNOWN); + result.setError(e.getMessage()); + return result; + } + } + @Override public abstract ExpressionResult visitMetric(MQEParser.MetricContext ctx); } diff --git a/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/TrendOp.java b/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/TrendOp.java new file mode 100644 index 000000000000..60c0887be363 --- /dev/null +++ b/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/TrendOp.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.mqe.rt.operation; + +import java.util.ArrayList; +import java.util.List; +import org.apache.skywalking.mqe.rt.exception.IllegalExpressionException; +import org.apache.skywalking.mqe.rt.grammar.MQEParser; +import org.apache.skywalking.mqe.rt.type.ExpressionResult; +import org.apache.skywalking.mqe.rt.type.MQEValue; +import org.apache.skywalking.oap.server.core.query.enumeration.Step; + +public class TrendOp { + public static ExpressionResult doTrendOp(ExpressionResult expResult, + int opType, + int trendRange, + Step step) throws IllegalExpressionException { + switch (opType) { + case MQEParser.INCREASE: + return TrendOp.calculateIncrease(expResult, trendRange); + case MQEParser.RATE: + return TrendOp.calculateRate(expResult, trendRange, step); + } + + throw new IllegalExpressionException("Unsupported function."); + } + + private static ExpressionResult calculateIncrease(ExpressionResult expResult, int trendRange) { + expResult.getResults().forEach(resultValues -> { + List mqeValues = resultValues.getValues(); + List newMqeValues = new ArrayList<>(); + for (int i = trendRange; i < mqeValues.size(); i++) { + MQEValue mqeValue = mqeValues.get(i); + //if the current value is empty, then the trend value is empty + if (mqeValue.isEmptyValue()) { + newMqeValues.add(mqeValue); + continue; + } + MQEValue newMqeValue = new MQEValue(); + newMqeValue.setId(mqeValue.getId()); + + //if the previous value is empty, then the trend value is empty + if (mqeValues.get(i - trendRange).isEmptyValue()) { + newMqeValue.setEmptyValue(true); + newMqeValues.add(newMqeValue); + continue; + } + + newMqeValue.setEmptyValue(mqeValue.isEmptyValue()); + newMqeValue.setId(mqeValue.getId()); + newMqeValue.setTraceID(mqeValue.getTraceID()); + double newValue = mqeValue.getDoubleValue() - mqeValues.get(i - trendRange).getDoubleValue(); + newMqeValue.setDoubleValue(newValue); + newMqeValues.add(newMqeValue); + } + resultValues.setValues(newMqeValues); + }); + return expResult; + } + + private static ExpressionResult calculateRate(ExpressionResult expResult, int trendRange, Step step) { + ExpressionResult result = calculateIncrease(expResult, trendRange); + long rangeSeconds; + switch (step) { + case SECOND: + rangeSeconds = trendRange; + break; + case MINUTE: + rangeSeconds = trendRange * 60; + break; + case HOUR: + rangeSeconds = trendRange * 3600; + break; + case DAY: + rangeSeconds = trendRange * 86400; + break; + default: + throw new IllegalArgumentException("Unsupported step: " + step); + } + result.getResults().forEach(resultValues -> { + resultValues.getValues().forEach(mqeValue -> { + if (!mqeValue.isEmptyValue()) { + double newValue = mqeValue.getDoubleValue() / rangeSeconds; + mqeValue.setDoubleValue(newValue); + } + }); + }); + return result; + } +} diff --git a/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/TrendOpTest.java b/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/TrendOpTest.java new file mode 100644 index 000000000000..3c5514123837 --- /dev/null +++ b/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/TrendOpTest.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.mqe.rt; + +import org.apache.skywalking.mqe.rt.grammar.MQEParser; +import org.apache.skywalking.mqe.rt.operation.TrendOp; +import org.apache.skywalking.mqe.rt.type.ExpressionResult; +import org.apache.skywalking.mqe.rt.type.ExpressionResultType; +import org.apache.skywalking.oap.server.core.query.enumeration.Step; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class TrendOpTest { + private final MockData mockData = new MockData(); + + @Test + public void increaseNoLabeledTest() throws Exception { + ExpressionResult increase = TrendOp.doTrendOp( + mockData.newSeriesNoLabeledResult(100, 280), MQEParser.INCREASE, 1, Step.MINUTE); + assertEquals(ExpressionResultType.TIME_SERIES_VALUES, increase.getType()); + assertEquals("300", increase.getResults().get(0).getValues().get(0).getId()); + assertEquals(180, increase.getResults().get(0).getValues().get(0).getDoubleValue()); + } + + @Test + public void increaseLabeledTest() throws Exception { + ExpressionResult increase = TrendOp.doTrendOp( + mockData.newSeriesLabeledResult(100, 280, 100, 220), MQEParser.INCREASE, 1, Step.MINUTE); + assertEquals(ExpressionResultType.TIME_SERIES_VALUES, increase.getType()); + assertEquals("300", increase.getResults().get(0).getValues().get(0).getId()); + assertEquals(180, increase.getResults().get(0).getValues().get(0).getDoubleValue()); + assertEquals("300", increase.getResults().get(1).getValues().get(0).getId()); + assertEquals(120, increase.getResults().get(1).getValues().get(0).getDoubleValue()); + } + + @Test + public void rateNoLabeledTest() throws Exception { + ExpressionResult rate = TrendOp.doTrendOp( + mockData.newSeriesNoLabeledResult(100, 280), MQEParser.RATE, 1, Step.MINUTE); + assertEquals(ExpressionResultType.TIME_SERIES_VALUES, rate.getType()); + assertEquals("300", rate.getResults().get(0).getValues().get(0).getId()); + assertEquals(3, rate.getResults().get(0).getValues().get(0).getDoubleValue()); + } + + @Test + public void rateLabeledTest() throws Exception { + ExpressionResult rate = TrendOp.doTrendOp( + mockData.newSeriesLabeledResult(100, 280, 100, 220), MQEParser.RATE, 1, Step.MINUTE); + assertEquals(ExpressionResultType.TIME_SERIES_VALUES, rate.getType()); + assertEquals("300", rate.getResults().get(0).getValues().get(0).getId()); + assertEquals(3, rate.getResults().get(0).getValues().get(0).getDoubleValue()); + assertEquals("300", rate.getResults().get(1).getValues().get(0).getId()); + assertEquals(2, rate.getResults().get(1).getValues().get(0).getDoubleValue()); + } +} diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmRule.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmRule.java index 76c6e6cc1abe..e5238719b7a3 100644 --- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmRule.java +++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmRule.java @@ -58,6 +58,7 @@ public class AlarmRule { private String message; private Map tags; private Set hooks; + private int maxTrendRange; /** * Init includeMetrics and verify the expression. @@ -67,6 +68,7 @@ public void setExpression(final String expression) throws IllegalExpressionExcep MQELexer lexer = new MQELexer(CharStreams.fromString(expression)); lexer.addErrorListener(new ParseErrorListener()); MQEParser parser = new MQEParser(new CommonTokenStream(lexer)); + parser.addErrorListener(new ParseErrorListener()); ParseTree tree; try { tree = parser.expression(); @@ -88,6 +90,7 @@ public void setExpression(final String expression) throws IllegalExpressionExcep verifyIncludeMetrics(visitor.getIncludeMetrics(), expression); this.expression = expression; this.includeMetrics = visitor.getIncludeMetrics(); + this.maxTrendRange = visitor.getMaxTrendRange(); } private void verifyIncludeMetrics(Set includeMetrics, String expression) throws IllegalExpressionException { diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/RunningRule.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/RunningRule.java index 961473bb0d15..a42e73f5604a 100644 --- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/RunningRule.java +++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/RunningRule.java @@ -82,6 +82,8 @@ public class RunningRule { private final Set hooks; private final Set includeMetrics; private final ParseTree exprTree; + // The additional period is used to calculate the trend. + private final int additionalPeriod; public RunningRule(AlarmRule alarmRule) { expression = alarmRule.getExpression(); @@ -108,6 +110,7 @@ public RunningRule(AlarmRule alarmRule) { MQEParser parser = new MQEParser(new CommonTokenStream(lexer)); parser.addErrorListener(new ParseErrorListener()); this.exprTree = parser.expression(); + this.additionalPeriod = alarmRule.getMaxTrendRange(); } /** @@ -134,7 +137,7 @@ public void in(MetaInAlarm meta, Metrics metrics) { AlarmEntity entity = new AlarmEntity( meta.getScope(), meta.getScopeId(), meta.getName(), meta.getId0(), meta.getId1()); - Window window = windows.computeIfAbsent(entity, ignored -> new Window(period)); + Window window = windows.computeIfAbsent(entity, ignored -> new Window(this.period, this.additionalPeriod)); window.add(meta.getMetricsName(), metrics); } @@ -234,13 +237,15 @@ public List check() { */ public class Window { private LocalDateTime endTime; - private final int period; + private final int additionalPeriod; + private final int size; private int silenceCountdown; private LinkedList> values; private ReentrantLock lock = new ReentrantLock(); - public Window(int period) { - this.period = period; + public Window(int period, int additionalPeriod) { + this.additionalPeriod = additionalPeriod; + this.size = period + additionalPeriod; // -1 means silence countdown is not running. silenceCountdown = -1; init(); @@ -342,7 +347,7 @@ public Optional checkAlarm() { private boolean isMatch() { int isMatch = 0; - AlarmMQEVisitor visitor = new AlarmMQEVisitor(this.values, this.endTime); + AlarmMQEVisitor visitor = new AlarmMQEVisitor(this.values, this.endTime, this.additionalPeriod); ExpressionResult parseResult = visitor.visit(exprTree); if (StringUtil.isNotBlank(parseResult.getError())) { log.error("expression:" + expression + " error: " + parseResult.getError()); @@ -403,7 +408,7 @@ public boolean isExpired() { private void init() { values = new LinkedList<>(); - for (int i = 0; i < period; i++) { + for (int i = 0; i < size; i++) { values.add(null); } } diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/expr/rt/AlarmMQEVerifyVisitor.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/expr/rt/AlarmMQEVerifyVisitor.java index c6c556f9c87e..cc0b861339a1 100644 --- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/expr/rt/AlarmMQEVerifyVisitor.java +++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/expr/rt/AlarmMQEVerifyVisitor.java @@ -35,6 +35,7 @@ import org.apache.skywalking.mqe.rt.type.MQEValues; import org.apache.skywalking.mqe.rt.type.Metadata; import org.apache.skywalking.oap.server.core.Const; +import org.apache.skywalking.oap.server.core.query.enumeration.Step; import org.apache.skywalking.oap.server.core.query.type.KeyValue; import org.apache.skywalking.oap.server.core.storage.annotation.Column; import org.apache.skywalking.oap.server.core.storage.annotation.ValueColumnMetadata; @@ -48,6 +49,11 @@ @Slf4j public class AlarmMQEVerifyVisitor extends MQEVisitorBase { private final Set includeMetrics = new HashSet<>(); + private int maxTrendRange = 0; + + public AlarmMQEVerifyVisitor() { + super(Step.MINUTE); + } @Override public ExpressionResult visitMetric(MQEParser.MetricContext ctx) { @@ -113,4 +119,23 @@ public ExpressionResult visitMetric(MQEParser.MetricContext ctx) { return result; } } + + @Override + public ExpressionResult visitTrendOP(MQEParser.TrendOPContext ctx) { + int trendRange = Integer.parseInt(ctx.INTEGER().getText()); + if (trendRange < 1) { + ExpressionResult result = new ExpressionResult(); + result.setType(ExpressionResultType.UNKNOWN); + result.setError("The trend range must be greater than 0."); + return result; + } + setMaxTrendRange(trendRange); + return super.visitTrendOP(ctx); + } + + private void setMaxTrendRange(int trendRange) { + if (trendRange > maxTrendRange) { + maxTrendRange = trendRange; + } + } } diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/expr/rt/AlarmMQEVisitor.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/expr/rt/AlarmMQEVisitor.java index 98a32d791bcc..712ff70e9a32 100644 --- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/expr/rt/AlarmMQEVisitor.java +++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/expr/rt/AlarmMQEVisitor.java @@ -44,6 +44,7 @@ import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics; import org.apache.skywalking.mqe.rt.MQEVisitorBase; import org.apache.skywalking.oap.server.core.analysis.metrics.MultiIntValuesHolder; +import org.apache.skywalking.oap.server.core.query.enumeration.Step; import org.apache.skywalking.oap.server.core.query.type.KeyValue; import org.apache.skywalking.oap.server.core.storage.annotation.Column; import org.apache.skywalking.oap.server.core.storage.annotation.ValueColumnMetadata; @@ -59,15 +60,19 @@ public class AlarmMQEVisitor extends MQEVisitorBase { private final int windowSize; private final LocalDateTime endTime; private final ArrayList windowTimes; + private final int maxTrendRange; public AlarmMQEVisitor(final LinkedList> metricsValues, - final LocalDateTime endTime) { + final LocalDateTime endTime, + final int maxTrendRange) { + super(Step.MINUTE); this.metricsValues = metricsValues; this.commonValuesMap = new HashMap<>(); this.labeledValuesMap = new HashMap<>(); this.endTime = endTime; this.windowSize = metricsValues.size(); this.windowTimes = initWindowTimes(); + this.maxTrendRange = maxTrendRange; this.initMetricsValues(); } @@ -114,12 +119,38 @@ public ExpressionResult visitMetric(MQEParser.MetricContext ctx) { result.setError("Unsupported value type: " + dataType); return result; } - + if (!(ctx.parent instanceof MQEParser.TrendOPContext)) { + //Trim the redundant data + result.getResults().forEach(resultValues -> { + List mqeValues = resultValues.getValues(); + if (maxTrendRange > 0 && mqeValues.size() > maxTrendRange) { + resultValues.setValues(mqeValues.subList(maxTrendRange, mqeValues.size())); + } + }); + } result.setResults(mqeValuesList); result.setType(ExpressionResultType.TIME_SERIES_VALUES); return result; } + @Override + public ExpressionResult visitTrendOP(MQEParser.TrendOPContext ctx) { + ExpressionResult result = super.visitTrendOP(ctx); + int trendRange = Integer.parseInt(ctx.INTEGER().getText()); + //super.visitTrendOP only trim self trend range, trim more here due to all metrics window size is the same + int trimIndex = maxTrendRange - trendRange; + if (trimIndex > 0) { + //Trim the redundant data + result.getResults().forEach(resultValues -> { + List mqeValues = resultValues.getValues(); + if (mqeValues.size() > trimIndex) { + resultValues.setValues(mqeValues.subList(trimIndex, mqeValues.size())); + } + }); + } + return result; + } + private ArrayList initWindowTimes() { ArrayList windowTimes = new ArrayList<>(); for (int i = this.windowSize - 1; i >= 0; i--) { diff --git a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmRuleTest.java b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmRuleTest.java index 64e353587ac1..5cf7cbcf18d9 100644 --- a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmRuleTest.java +++ b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmRuleTest.java @@ -113,5 +113,8 @@ public void testExpressionVerify() throws IllegalExpressionException { rule.setExpression("sum(service_percent > endpoint_percent) >= 1"); }).getMessage().contains("The metrics in expression: sum(service_percent > endpoint_percent) >= 1 must have the same scope level, but got:")); + //trend expression + rule.setExpression("sum((increase(service_percent,5) + increase(service_percent,2)) > 0) >= 1"); + Assertions.assertEquals(5, rule.getMaxTrendRange()); } } diff --git a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/RunningRuleTest.java b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/RunningRuleTest.java index 60d2932fbabd..a0f66fc04130 100644 --- a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/RunningRuleTest.java +++ b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/RunningRuleTest.java @@ -71,10 +71,11 @@ public void setup() { @Test public void testInitAndStart() throws IllegalExpressionException { AlarmRule alarmRule = new AlarmRule(); - alarmRule.setAlarmRuleName("endpoint_percent_rule"); - alarmRule.setExpression("sum(endpoint_percent < 75) >= 3"); + alarmRule.setAlarmRuleName("mix_rule"); + alarmRule.setExpression("sum((increase(endpoint_cpm,5) + increase(endpoint_percent,2)) > 0) >= 1"); alarmRule.getIncludeMetrics().add("endpoint_percent"); - alarmRule.setPeriod(15); + alarmRule.getIncludeMetrics().add("endpoint_cpm"); + alarmRule.setPeriod(10); alarmRule.setTags(new HashMap() {{ put("key", "value"); }}); @@ -90,11 +91,11 @@ public void testInitAndStart() throws IllegalExpressionException { RunningRule.Window window = windows.get(getAlarmEntity(123)); LocalDateTime endTime = Whitebox.getInternalState(window, "endTime"); - int period = Whitebox.getInternalState(window, "period"); + int additionalPeriod = Whitebox.getInternalState(window, "additionalPeriod"); LinkedList metricsBuffer = Whitebox.getInternalState(window, "values"); Assertions.assertTrue(targetTime.equals(endTime.toDateTime())); - Assertions.assertEquals(15, period); + Assertions.assertEquals(5, additionalPeriod); Assertions.assertEquals(15, metricsBuffer.size()); } diff --git a/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/handler/PromQLApiHandler.java b/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/handler/PromQLApiHandler.java index e3195eb31e40..519f142e00ac 100644 --- a/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/handler/PromQLApiHandler.java +++ b/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/handler/PromQLApiHandler.java @@ -29,7 +29,7 @@ import com.linecorp.armeria.server.annotation.Param; import com.linecorp.armeria.server.annotation.Path; import com.linecorp.armeria.server.annotation.Post; -import graphql.org.antlr.v4.runtime.misc.ParseCancellationException; +import org.antlr.v4.runtime.misc.ParseCancellationException; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; diff --git a/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/rt/exception/ParseErrorListener.java b/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/rt/exception/ParseErrorListener.java index e54481c45876..769cb0735dad 100644 --- a/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/rt/exception/ParseErrorListener.java +++ b/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/rt/exception/ParseErrorListener.java @@ -18,7 +18,7 @@ package org.apache.skywalking.oap.query.promql.rt.exception; -import graphql.org.antlr.v4.runtime.misc.ParseCancellationException; +import org.antlr.v4.runtime.misc.ParseCancellationException; import org.antlr.v4.runtime.BaseErrorListener; import org.antlr.v4.runtime.RecognitionException; import org.antlr.v4.runtime.Recognizer; diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/mqe/rt/MQEVisitor.java b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/mqe/rt/MQEVisitor.java index 9f112429f62e..9b36208bc36f 100644 --- a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/mqe/rt/MQEVisitor.java +++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/mqe/rt/MQEVisitor.java @@ -52,6 +52,7 @@ import org.apache.skywalking.mqe.rt.MQEVisitorBase; import org.apache.skywalking.mqe.rt.type.ExpressionResult; import org.apache.skywalking.mqe.rt.type.ExpressionResultType; +import org.joda.time.DateTime; @Slf4j public class MQEVisitor extends MQEVisitorBase { @@ -64,6 +65,7 @@ public MQEVisitor(final MetricsQuery metricsQuery, final RecordsQuery recordsQuery, final Entity entity, final Duration duration) { + super(duration.getStep()); this.metricsQuery = metricsQuery; this.recordsQuery = recordsQuery; this.entity = entity; @@ -87,14 +89,27 @@ public ExpressionResult visitMetric(MQEParser.MetricContext ctx) { if (Column.ValueDataType.COMMON_VALUE == dataType) { if (ctx.parent instanceof MQEParser.TopNOPContext) { MQEParser.TopNOPContext parent = (MQEParser.TopNOPContext) ctx.parent; - querySortMetrics(metricName, Integer.parseInt(parent.parameter().getText()), + int topN = Integer.parseInt(parent.INTEGER().getText()); + if (topN <= 0) { + throw new IllegalExpressionException("TopN value must be > 0."); + } + querySortMetrics(metricName, Integer.parseInt(parent.INTEGER().getText()), Order.valueOf(parent.order().getText().toUpperCase()), result ); + } else if (ctx.parent instanceof MQEParser.TrendOPContext) { + //trend query requires get previous data according to the trend range + MQEParser.TrendOPContext parent = (MQEParser.TrendOPContext) ctx.parent; + int trendRange = Integer.parseInt(parent.INTEGER().getText()); + queryMetrics(metricName, getTrendQueryDuration(trendRange), result); } else { - queryMetrics(metricName, result); + queryMetrics(metricName, this.duration, result); } } else if (Column.ValueDataType.LABELED_VALUE == dataType) { List queryLabelList = Collections.emptyList(); + if (ctx.parent instanceof MQEParser.TopNOPContext) { + throw new IllegalExpressionException( + "Metric: [" + metricName + "] is labeled value, dose not support top_n query."); + } if (ctx.label() != null) { String labelValue = ctx.label().labelValue().getText(); String labelValueTrim = labelValue.substring(1, labelValue.length() - 1); @@ -102,11 +117,21 @@ public ExpressionResult visitMetric(MQEParser.MetricContext ctx) { queryLabelList = Arrays.asList(labelValueTrim.split(Const.COMMA)); } } - queryLabeledMetrics(metricName, queryLabelList, result); + if (ctx.parent instanceof MQEParser.TrendOPContext) { + MQEParser.TrendOPContext parent = (MQEParser.TrendOPContext) ctx.parent; + int trendRange = Integer.parseInt(parent.INTEGER().getText()); + queryLabeledMetrics(metricName, queryLabelList, getTrendQueryDuration(trendRange), result); + } else { + queryLabeledMetrics(metricName, queryLabelList, this.duration, result); + } } else if (Column.ValueDataType.SAMPLED_RECORD == dataType) { if (ctx.parent instanceof MQEParser.TopNOPContext) { MQEParser.TopNOPContext parent = (MQEParser.TopNOPContext) ctx.parent; - queryRecords(metricName, Integer.parseInt(parent.parameter().getText()), + int topN = Integer.parseInt(parent.INTEGER().getText()); + if (topN <= 0) { + throw new IllegalExpressionException("TopN value must be > 0."); + } + queryRecords(metricName, Integer.parseInt(parent.INTEGER().getText()), Order.valueOf(parent.order().getText().toUpperCase()), result ); } else { @@ -182,15 +207,15 @@ private void queryRecords(String metricName, int topN, Order order, ExpressionRe result.setType(ExpressionResultType.RECORD_LIST); } - private void queryMetrics(String metricName, ExpressionResult result) throws IOException { + private void queryMetrics(String metricName, Duration queryDuration, ExpressionResult result) throws IOException { MetricsCondition metricsCondition = new MetricsCondition(); metricsCondition.setName(metricName); metricsCondition.setEntity(entity); - MetricsValues metricsValues = metricsQuery.readMetricsValues(metricsCondition, duration); - List times = duration.assembleDurationPoints(); + MetricsValues metricsValues = metricsQuery.readMetricsValues(metricsCondition, queryDuration); + List times = queryDuration.assembleDurationPoints(); List mqeValueList = new ArrayList<>(times.size()); for (int i = 0; i < times.size(); i++) { - long retTimestamp = DurationUtils.INSTANCE.parseToDateTime(duration.getStep(), times.get(i).getPoint()) + long retTimestamp = DurationUtils.INSTANCE.parseToDateTime(queryDuration.getStep(), times.get(i).getPoint()) .getMillis(); KVInt kvInt = metricsValues.getValues().getValues().get(i); MQEValue mqeValue = new MQEValue(); @@ -209,17 +234,18 @@ private void queryMetrics(String metricName, ExpressionResult result) throws IOE private void queryLabeledMetrics(String metricName, List queryLabelList, + Duration queryDuration, ExpressionResult result) throws IOException { MetricsCondition metricsCondition = new MetricsCondition(); metricsCondition.setName(metricName); metricsCondition.setEntity(entity); List metricsValuesList = metricsQuery.readLabeledMetricsValues( - metricsCondition, queryLabelList, duration); - List times = duration.assembleDurationPoints(); + metricsCondition, queryLabelList, queryDuration); + List times = queryDuration.assembleDurationPoints(); metricsValuesList.forEach(metricsValues -> { List mqeValueList = new ArrayList<>(times.size()); for (int i = 0; i < times.size(); i++) { - long retTimestamp = DurationUtils.INSTANCE.parseToDateTime(duration.getStep(), times.get(i).getPoint()) + long retTimestamp = DurationUtils.INSTANCE.parseToDateTime(queryDuration.getStep(), times.get(i).getPoint()) .getMillis(); KVInt kvInt = metricsValues.getValues().getValues().get(i); MQEValue mqeValue = new MQEValue(); @@ -242,4 +268,29 @@ private void queryLabeledMetrics(String metricName, result.setType(ExpressionResultType.TIME_SERIES_VALUES); result.setLabeledResult(true); } + + private Duration getTrendQueryDuration(int stepRange) { + Duration duration = new Duration(); + duration.setStep(this.duration.getStep()); + duration.setEnd(this.duration.getEnd()); + DateTime startDT = new DateTime(this.duration.getStartTimestamp()); + + switch (duration.getStep()) { + case DAY: + duration.setStart(startDT.minusDays(stepRange).toString(DurationUtils.YYYY_MM_DD)); + break; + case HOUR: + duration.setStart(startDT.minusHours(stepRange).toString(DurationUtils.YYYY_MM_DD_HH)); + break; + case MINUTE: + duration.setStart(startDT.minusMinutes(stepRange).toString(DurationUtils.YYYY_MM_DD_HHMM)); + break; + case SECOND: + duration.setStart(startDT.minusSeconds(stepRange).toString(DurationUtils.YYYY_MM_DD_HHMMSS)); + break; + default: + throw new IllegalArgumentException("Unsupported query step: " + duration.getStep()); + } + return duration; + } } diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/MetricsExpressionQuery.java b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/MetricsExpressionQuery.java index e10c71465e3b..89cb999dfea2 100644 --- a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/MetricsExpressionQuery.java +++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/MetricsExpressionQuery.java @@ -19,7 +19,7 @@ package org.apache.skywalking.oap.query.graphql.resolver; import graphql.kickstart.tools.GraphQLQueryResolver; -import graphql.org.antlr.v4.runtime.misc.ParseCancellationException; +import org.antlr.v4.runtime.misc.ParseCancellationException; import java.text.DecimalFormat; import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonTokenStream; diff --git a/test/e2e-v2/cases/alarm/alarm-settings.yml b/test/e2e-v2/cases/alarm/alarm-settings.yml index 40df6f0a75d8..abcc8c130aa9 100755 --- a/test/e2e-v2/cases/alarm/alarm-settings.yml +++ b/test/e2e-v2/cases/alarm/alarm-settings.yml @@ -16,10 +16,10 @@ rules: # service response time > 10ms service_resp_time_rule: - expression: sum(service_resp_time > 10) >= 1 + expression: sum(abs(increase(service_resp_time,1)) > 0) >= 1 period: 10 silence-period: 1 - message: Response time of service {name} is more than 10ms in 1 minutes of last 10 minutes. + message: Response time of service {name} is increase/decrease in 1 minutes of last 10 minutes. tags: level: WARNING receivers: lisi diff --git a/test/e2e-v2/cases/alarm/es/e2e.yaml b/test/e2e-v2/cases/alarm/es/e2e.yaml index e0ad564928fc..4dcb90bf0f7d 100644 --- a/test/e2e-v2/cases/alarm/es/e2e.yaml +++ b/test/e2e-v2/cases/alarm/es/e2e.yaml @@ -31,7 +31,7 @@ setup: trigger: action: http interval: 3s - times: 10 + times: 30 url: http://${provider_host}:${provider_9090}/users method: POST body: '{"id":"123","name":"skywalking"}' diff --git a/test/e2e-v2/cases/alarm/es/es-sharding/e2e.yaml b/test/e2e-v2/cases/alarm/es/es-sharding/e2e.yaml index 24e01c081230..a1fa0e36b91d 100644 --- a/test/e2e-v2/cases/alarm/es/es-sharding/e2e.yaml +++ b/test/e2e-v2/cases/alarm/es/es-sharding/e2e.yaml @@ -31,7 +31,7 @@ setup: trigger: action: http interval: 3s - times: 10 + times: 30 url: http://${provider_host}:${provider_9090}/users method: POST body: '{"id":"123","name":"skywalking"}' diff --git a/test/e2e-v2/cases/alarm/expected/silence-after-graphql-warn.yml b/test/e2e-v2/cases/alarm/expected/silence-after-graphql-warn.yml index 641150f9dac3..c3f71b81ce9c 100644 --- a/test/e2e-v2/cases/alarm/expected/silence-after-graphql-warn.yml +++ b/test/e2e-v2/cases/alarm/expected/silence-after-graphql-warn.yml @@ -42,7 +42,7 @@ msgs: - starttime: {{ gt .starttime 0 }} scope: Service id: ZTJlLXNlcnZpY2UtcHJvdmlkZXI=.1 - message: Response time of service e2e-service-provider is more than 10ms in 1 minutes of last 10 minutes. + message: Response time of service e2e-service-provider is increase/decrease in 1 minutes of last 10 minutes. tags: - key: level value: WARNING @@ -90,7 +90,7 @@ msgs: - starttime: {{ gt .starttime 0 }} scope: Service id: ZTJlLXNlcnZpY2UtcHJvdmlkZXI=.1 - message: Response time of service e2e-service-provider is more than 10ms in 1 minutes of last 10 minutes. + message: Response time of service e2e-service-provider is increase/decrease in 1 minutes of last 10 minutes. tags: - key: level value: WARNING diff --git a/test/e2e-v2/cases/alarm/expected/silence-after-webhook.yml b/test/e2e-v2/cases/alarm/expected/silence-after-webhook.yml index f1d0f0355dfe..3e9ad6d25bac 100644 --- a/test/e2e-v2/cases/alarm/expected/silence-after-webhook.yml +++ b/test/e2e-v2/cases/alarm/expected/silence-after-webhook.yml @@ -21,7 +21,7 @@ messages: id0: ZTJlLXNlcnZpY2UtcHJvdmlkZXI=.1 id1: "" ruleName: service_resp_time_rule - alarmMessage: Response time of service e2e-service-provider is more than 10ms in 1 minutes of last 10 minutes. + alarmMessage: Response time of service e2e-service-provider is increase/decrease in 1 minutes of last 10 minutes. startTime: {{ gt .startTime 0 }} tags: - key: level @@ -47,7 +47,7 @@ messages: id0: ZTJlLXNlcnZpY2UtcHJvdmlkZXI=.1 id1: "" ruleName: service_resp_time_rule - alarmMessage: Response time of service e2e-service-provider is more than 10ms in 1 minutes of last 10 minutes. + alarmMessage: Response time of service e2e-service-provider is increase/decrease in 1 minutes of last 10 minutes. startTime: {{ gt .startTime 0 }} tags: - key: level diff --git a/test/e2e-v2/cases/alarm/expected/silence-before-graphql-warn.yml b/test/e2e-v2/cases/alarm/expected/silence-before-graphql-warn.yml index e8d5c1ca882f..a766327f30c7 100644 --- a/test/e2e-v2/cases/alarm/expected/silence-before-graphql-warn.yml +++ b/test/e2e-v2/cases/alarm/expected/silence-before-graphql-warn.yml @@ -42,7 +42,7 @@ msgs: - starttime: {{ gt .starttime 0 }} scope: Service id: ZTJlLXNlcnZpY2UtcHJvdmlkZXI=.1 - message: Response time of service e2e-service-provider is more than 10ms in 1 minutes of last 10 minutes. + message: Response time of service e2e-service-provider is increase/decrease in 1 minutes of last 10 minutes. tags: - key: level value: WARNING diff --git a/test/e2e-v2/cases/alarm/expected/silence-before-webhook.yml b/test/e2e-v2/cases/alarm/expected/silence-before-webhook.yml index c076fd0c0bb1..d34f856f282f 100644 --- a/test/e2e-v2/cases/alarm/expected/silence-before-webhook.yml +++ b/test/e2e-v2/cases/alarm/expected/silence-before-webhook.yml @@ -21,7 +21,7 @@ messages: id0: ZTJlLXNlcnZpY2UtcHJvdmlkZXI=.1 id1: "" ruleName: service_resp_time_rule - alarmMessage: Response time of service e2e-service-provider is more than 10ms in 1 minutes of last 10 minutes. + alarmMessage: Response time of service e2e-service-provider is increase/decrease in 1 minutes of last 10 minutes. startTime: {{ gt .startTime 0 }} tags: - key: level diff --git a/test/e2e-v2/cases/alarm/h2/e2e.yaml b/test/e2e-v2/cases/alarm/h2/e2e.yaml index e0ad564928fc..4dcb90bf0f7d 100644 --- a/test/e2e-v2/cases/alarm/h2/e2e.yaml +++ b/test/e2e-v2/cases/alarm/h2/e2e.yaml @@ -31,7 +31,7 @@ setup: trigger: action: http interval: 3s - times: 10 + times: 30 url: http://${provider_host}:${provider_9090}/users method: POST body: '{"id":"123","name":"skywalking"}' diff --git a/test/e2e-v2/cases/alarm/mysql/e2e.yaml b/test/e2e-v2/cases/alarm/mysql/e2e.yaml index e0ad564928fc..4dcb90bf0f7d 100644 --- a/test/e2e-v2/cases/alarm/mysql/e2e.yaml +++ b/test/e2e-v2/cases/alarm/mysql/e2e.yaml @@ -31,7 +31,7 @@ setup: trigger: action: http interval: 3s - times: 10 + times: 30 url: http://${provider_host}:${provider_9090}/users method: POST body: '{"id":"123","name":"skywalking"}' diff --git a/test/e2e-v2/cases/alarm/postgres/e2e.yaml b/test/e2e-v2/cases/alarm/postgres/e2e.yaml index e0ad564928fc..4dcb90bf0f7d 100644 --- a/test/e2e-v2/cases/alarm/postgres/e2e.yaml +++ b/test/e2e-v2/cases/alarm/postgres/e2e.yaml @@ -31,7 +31,7 @@ setup: trigger: action: http interval: 3s - times: 10 + times: 30 url: http://${provider_host}:${provider_9090}/users method: POST body: '{"id":"123","name":"skywalking"}' diff --git a/test/e2e-v2/cases/mqe/expected/trend-OP.yml b/test/e2e-v2/cases/mqe/expected/trend-OP.yml new file mode 100644 index 000000000000..a4474f13e816 --- /dev/null +++ b/test/e2e-v2/cases/mqe/expected/trend-OP.yml @@ -0,0 +1,31 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +type: TIME_SERIES_VALUES +results: +{{- contains .results }} + - metric: + labels: [] + values: + {{- contains .values }} + - id: {{ notEmpty .id }} + value: {{ .value }} + traceid: null + - id: {{ notEmpty .id }} + value: null + traceid: null + {{- end}} +{{- end}} +error: null diff --git a/test/e2e-v2/cases/mqe/mqe-cases.yaml b/test/e2e-v2/cases/mqe/mqe-cases.yaml index d857cfbf378c..c9cfe7af77d4 100644 --- a/test/e2e-v2/cases/mqe/mqe-cases.yaml +++ b/test/e2e-v2/cases/mqe/mqe-cases.yaml @@ -67,3 +67,9 @@ cases: # viewAsSeq-OP - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression="view_as_seq(mq_service_consume_sla,service_sla)" --service-name=e2e-service-provider expected: expected/viewAsSeq-OP.yml + + # trend-OP + - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression="increase(service_resp_time,2)" --service-name=e2e-service-provider + expected: expected/trend-OP.yml + - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression="rate(service_resp_time,2)" --service-name=e2e-service-provider + expected: expected/trend-OP.yml