You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2023/11/27 23:40:20 UTC
(skywalking) branch master updated: Support `increase/rate` function in the `MQE` query language. (#11591)
This is an automated email from the ASF dual-hosted git repository.
wusheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking.git
The following commit(s) were added to refs/heads/master by this push:
new 075b08ce74 Support `increase/rate` function in the `MQE` query language. (#11591)
075b08ce74 is described below
commit 075b08ce74868ed097b1ab76f06ee778ed8d5329
Author: Wan Kai <wa...@foxmail.com>
AuthorDate: Tue Nov 28 07:40:13 2023 +0800
Support `increase/rate` function in the `MQE` query language. (#11591)
---
docs/en/api/metrics-query-expression.md | 40 ++++++++
docs/en/changes/changes.md | 1 +
.../apache/skywalking/mqe/rt/grammar/MQELexer.g4 | 2 +
.../apache/skywalking/mqe/rt/grammar/MQEParser.g4 | 6 +-
.../apache/skywalking/mqe/rt/MQEVisitorBase.java | 35 +++++++
.../skywalking/mqe/rt/operation/TrendOp.java | 106 +++++++++++++++++++++
.../org/apache/skywalking/mqe/rt/TrendOpTest.java | 72 ++++++++++++++
.../oap/server/core/alarm/provider/AlarmRule.java | 3 +
.../server/core/alarm/provider/RunningRule.java | 17 ++--
.../provider/expr/rt/AlarmMQEVerifyVisitor.java | 25 +++++
.../alarm/provider/expr/rt/AlarmMQEVisitor.java | 35 ++++++-
.../server/core/alarm/provider/AlarmRuleTest.java | 3 +
.../core/alarm/provider/RunningRuleTest.java | 11 ++-
.../oap/query/promql/handler/PromQLApiHandler.java | 2 +-
.../promql/rt/exception/ParseErrorListener.java | 2 +-
.../oap/query/graphql/mqe/rt/MQEVisitor.java | 73 +++++++++++---
.../graphql/resolver/MetricsExpressionQuery.java | 2 +-
test/e2e-v2/cases/alarm/alarm-settings.yml | 4 +-
test/e2e-v2/cases/alarm/es/e2e.yaml | 2 +-
test/e2e-v2/cases/alarm/es/es-sharding/e2e.yaml | 2 +-
.../alarm/expected/silence-after-graphql-warn.yml | 4 +-
.../cases/alarm/expected/silence-after-webhook.yml | 4 +-
.../alarm/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(-)
diff --git a/docs/en/api/metrics-query-expression.md b/docs/en/api/metrics-query-expression.md
index 6c5798c3fa..2ca901e2eb 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
+<Trend-Operator>(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 b033310a19..97f0ebc485 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 b7a870a6bc..69687a8702 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 0c2d9a9317..e67414422d 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 2f272dc6c0..235abb30c8 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.BinaryOp;
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<ExpressionResult> {
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 abstract class MQEVisitorBase extends MQEParserBaseVisitor<ExpressionResu
}
}
+ @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 0000000000..60c0887be3
--- /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<MQEValue> mqeValues = resultValues.getValues();
+ List<MQEValue> 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 0000000000..3c55141238
--- /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 76c6e6cc1a..e5238719b7 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<String, String> tags;
private Set<String> hooks;
+ private int maxTrendRange;
/**
* Init includeMetrics and verify the expression.
@@ -67,6 +68,7 @@ public class AlarmRule {
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 class AlarmRule {
verifyIncludeMetrics(visitor.getIncludeMetrics(), expression);
this.expression = expression;
this.includeMetrics = visitor.getIncludeMetrics();
+ this.maxTrendRange = visitor.getMaxTrendRange();
}
private void verifyIncludeMetrics(Set<String> 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 961473bb0d..a42e73f560 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<String> hooks;
private final Set<String> 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 class RunningRule {
MQEParser parser = new MQEParser(new CommonTokenStream(lexer));
parser.addErrorListener(new ParseErrorListener());
this.exprTree = parser.expression();
+ this.additionalPeriod = alarmRule.getMaxTrendRange();
}
/**
@@ -134,7 +137,7 @@ public class RunningRule {
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 class RunningRule {
*/
public class Window {
private LocalDateTime endTime;
- private final int period;
+ private final int additionalPeriod;
+ private final int size;
private int silenceCountdown;
private LinkedList<Map<String, Metrics>> 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 class RunningRule {
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 class RunningRule {
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 c6c556f9c8..cc0b861339 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.MQEValue;
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 @@ import org.apache.skywalking.oap.server.library.util.StringUtil;
@Slf4j
public class AlarmMQEVerifyVisitor extends MQEVisitorBase {
private final Set<String> includeMetrics = new HashSet<>();
+ private int maxTrendRange = 0;
+
+ public AlarmMQEVerifyVisitor() {
+ super(Step.MINUTE);
+ }
@Override
public ExpressionResult visitMetric(MQEParser.MetricContext ctx) {
@@ -113,4 +119,23 @@ public class AlarmMQEVerifyVisitor extends MQEVisitorBase {
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 98a32d791b..712ff70e9a 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.LongValueHolder;
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<String> windowTimes;
+ private final int maxTrendRange;
public AlarmMQEVisitor(final LinkedList<Map<String, Metrics>> 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 class AlarmMQEVisitor extends MQEVisitorBase {
result.setError("Unsupported value type: " + dataType);
return result;
}
-
+ if (!(ctx.parent instanceof MQEParser.TrendOPContext)) {
+ //Trim the redundant data
+ result.getResults().forEach(resultValues -> {
+ List<MQEValue> 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<MQEValue> mqeValues = resultValues.getValues();
+ if (mqeValues.size() > trimIndex) {
+ resultValues.setValues(mqeValues.subList(trimIndex, mqeValues.size()));
+ }
+ });
+ }
+ return result;
+ }
+
private ArrayList<String> initWindowTimes() {
ArrayList<String> 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 64e353587a..5cf7cbcf18 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 class AlarmRuleTest {
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 60d2932fba..a0f66fc041 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 class RunningRuleTest {
@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<String, String>() {{
put("key", "value");
}});
@@ -90,11 +91,11 @@ public class RunningRuleTest {
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<Metrics> 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 e3195eb31e..519f142e00 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.Get;
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 e54481c458..769cb0735d 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 9f112429f6..9b36208bc3 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.oap.server.library.util.StringUtil;
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 class MQEVisitor extends MQEVisitorBase {
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 class MQEVisitor extends MQEVisitorBase {
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<String> 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 class MQEVisitor extends MQEVisitorBase {
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 @@ public class MQEVisitor extends MQEVisitorBase {
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<PointOfTime> times = duration.assembleDurationPoints();
+ MetricsValues metricsValues = metricsQuery.readMetricsValues(metricsCondition, queryDuration);
+ List<PointOfTime> times = queryDuration.assembleDurationPoints();
List<MQEValue> 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 @@ public class MQEVisitor extends MQEVisitorBase {
private void queryLabeledMetrics(String metricName,
List<String> queryLabelList,
+ Duration queryDuration,
ExpressionResult result) throws IOException {
MetricsCondition metricsCondition = new MetricsCondition();
metricsCondition.setName(metricName);
metricsCondition.setEntity(entity);
List<MetricsValues> metricsValuesList = metricsQuery.readLabeledMetricsValues(
- metricsCondition, queryLabelList, duration);
- List<PointOfTime> times = duration.assembleDurationPoints();
+ metricsCondition, queryLabelList, queryDuration);
+ List<PointOfTime> times = queryDuration.assembleDurationPoints();
metricsValuesList.forEach(metricsValues -> {
List<MQEValue> 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 @@ public class MQEVisitor extends MQEVisitorBase {
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 e10c71465e..89cb999dfe 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 40df6f0a75..abcc8c130a 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 e0ad564928..4dcb90bf0f 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 24e01c0812..a1fa0e36b9 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 641150f9da..c3f71b81ce 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 f1d0f0355d..3e9ad6d25b 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 e8d5c1ca88..a766327f30 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 c076fd0c0b..d34f856f28 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 e0ad564928..4dcb90bf0f 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 e0ad564928..4dcb90bf0f 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 e0ad564928..4dcb90bf0f 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 0000000000..a4474f13e8
--- /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 d857cfbf37..c9cfe7af77 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