Support !=, like filter expressions in OAL (#5269)

This commit is contained in:
kezhenxu94 2020-08-11 09:37:21 +08:00 committed by GitHub
parent 7f7e96b088
commit ecc18b9be3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 472 additions and 137 deletions

7
.gitignore vendored
View File

@ -14,11 +14,12 @@ packages/
/docker/snapshot/*.gz /docker/snapshot/*.gz
.mvn/wrapper/*.jar .mvn/wrapper/*.jar
OALLexer.tokens OALLexer.tokens
.factorypath .factorypath
.vscode .vscode
.checkstyle .checkstyle
.externalToolBuilders .externalToolBuilders
/test/plugin/dist /test/plugin/dist
/test/plugin/workspace /test/plugin/workspace
/test/jacoco/classes /test/jacoco/classes
/test/jacoco/*.exec /test/jacoco/*.exec
oap-server/oal-grammar/**/gen/

View File

@ -34,7 +34,7 @@ Read [Scope Definitions](scope-definitions.md), you can find all existing Scopes
Use filter to build the conditions for the value of fields, by using field name and expression. Use filter to build the conditions for the value of fields, by using field name and expression.
The expressions support to link by `and`, `or` and `(...)`. The expressions support to link by `and`, `or` and `(...)`.
The OPs support `=`, `!=`, `>`, `<`, `in (v1, v2, ...`, `like "%..."`, with type detection based of field type. Trigger compile The OPs support `==`, `!=`, `>`, `<`, `>=`, `<=`, `like %...`, `like ...%` and `like %...%`, with type detection based of field type. Trigger compile
or code generation error if incompatible. or code generation error if incompatible.
## Aggregation Function ## Aggregation Function
@ -103,7 +103,7 @@ In default, no one is being disable.
Endpoint_p99 = from(Endpoint.latency).filter(name in ("Endpoint1", "Endpoint2")).summary(0.99) Endpoint_p99 = from(Endpoint.latency).filter(name in ("Endpoint1", "Endpoint2")).summary(0.99)
// Caculate p99 of Endpoint name started with `serv` // Caculate p99 of Endpoint name started with `serv`
serv_Endpoint_p99 = from(Endpoint.latency).filter(name like ("serv%")).summary(0.99) serv_Endpoint_p99 = from(Endpoint.latency).filter(name like "serv%").summary(0.99)
// Caculate the avg response time of each Endpoint // Caculate the avg response time of each Endpoint
Endpoint_avg = from(Endpoint.latency).avg() Endpoint_avg = from(Endpoint.latency).avg()
@ -112,7 +112,7 @@ Endpoint_avg = from(Endpoint.latency).avg()
Endpoint_percentile = from(Endpoint.latency).percentile(10) Endpoint_percentile = from(Endpoint.latency).percentile(10)
// Caculate the percent of response status is true, for each service. // Caculate the percent of response status is true, for each service.
Endpoint_success = from(Endpoint.*).filter(status = "true").percent() Endpoint_success = from(Endpoint.*).filter(status == true).percent()
// Caculate the percent of response code in [200, 299], for each service. // Caculate the percent of response code in [200, 299], for each service.
Endpoint_200 = from(Endpoint.*).filter(responseCode like "2%").percent() Endpoint_200 = from(Endpoint.*).filter(responseCode like "2%").percent()

View File

@ -133,4 +133,6 @@ ALL: '*';
GREATER: '>'; GREATER: '>';
LESS: '<'; LESS: '<';
GREATER_EQUAL: '>='; GREATER_EQUAL: '>=';
LESS_EQUAL: '<='; LESS_EQUAL: '<=';
NOT_EQUAL: '!=';
LIKE: 'like';

View File

@ -88,7 +88,7 @@ literalExpression
; ;
expression expression
: booleanMatch | stringMatch | greaterMatch | lessMatch | greaterEqualMatch | lessEqualMatch : booleanMatch | stringMatch | greaterMatch | lessMatch | greaterEqualMatch | lessEqualMatch | notEqualMatch | booleanNotEqualMatch | likeMatch
; ;
booleanMatch booleanMatch
@ -115,6 +115,18 @@ lessEqualMatch
: conditionAttribute LESS_EQUAL numberConditionValue : conditionAttribute LESS_EQUAL numberConditionValue
; ;
booleanNotEqualMatch
: conditionAttribute NOT_EQUAL booleanConditionValue
;
notEqualMatch
: conditionAttribute NOT_EQUAL (numberConditionValue | stringConditionValue | enumConditionValue)
;
likeMatch
: conditionAttribute LIKE stringConditionValue
;
conditionAttribute conditionAttribute
: IDENTIFIER : IDENTIFIER
; ;
@ -133,4 +145,4 @@ enumConditionValue
numberConditionValue numberConditionValue
: NUMBER_LITERAL : NUMBER_LITERAL
; ;

View File

@ -53,7 +53,6 @@ import org.apache.skywalking.apm.util.StringUtil;
import org.apache.skywalking.oal.rt.output.AllDispatcherContext; import org.apache.skywalking.oal.rt.output.AllDispatcherContext;
import org.apache.skywalking.oal.rt.output.DispatcherContext; import org.apache.skywalking.oal.rt.output.DispatcherContext;
import org.apache.skywalking.oal.rt.parser.AnalysisResult; import org.apache.skywalking.oal.rt.parser.AnalysisResult;
import org.apache.skywalking.oal.rt.parser.MetricsHolder;
import org.apache.skywalking.oal.rt.parser.OALScripts; import org.apache.skywalking.oal.rt.parser.OALScripts;
import org.apache.skywalking.oal.rt.parser.ScriptParser; import org.apache.skywalking.oal.rt.parser.ScriptParser;
import org.apache.skywalking.oal.rt.parser.SourceColumn; import org.apache.skywalking.oal.rt.parser.SourceColumn;
@ -144,12 +143,6 @@ public class OALRuntime implements OALEngine {
this.currentClassLoader = currentClassLoader; this.currentClassLoader = currentClassLoader;
Reader read; Reader read;
try {
MetricsHolder.init();
} catch (IOException e) {
throw new ModuleStartException("load metrics functions error.", e);
}
try { try {
read = ResourceUtils.read(oalDefine.getConfigFile()); read = ResourceUtils.read(oalDefine.getConfigFile());
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {

View File

@ -18,11 +18,15 @@
package org.apache.skywalking.oal.rt.parser; package org.apache.skywalking.oal.rt.parser;
import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
@Getter @Getter
@Setter @Setter
@NoArgsConstructor
@AllArgsConstructor
public class ConditionExpression { public class ConditionExpression {
// original from script // original from script
private String expressionType; private String expressionType;

View File

@ -24,6 +24,7 @@ import java.lang.reflect.Method;
import java.lang.reflect.Parameter; import java.lang.reflect.Parameter;
import java.util.List; import java.util.List;
import org.apache.skywalking.oal.rt.util.ClassMethodUtil; import org.apache.skywalking.oal.rt.util.ClassMethodUtil;
import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.Arg; import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.Arg;
import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.ConstOne; import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.ConstOne;
import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.Entrance; import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.Entrance;
@ -35,8 +36,7 @@ public class DeepAnalysis {
// 1. Set sub package name by source.metrics // 1. Set sub package name by source.metrics
result.setPackageName(result.getSourceName().toLowerCase()); result.setPackageName(result.getSourceName().toLowerCase());
Class<? extends org.apache.skywalking.oap.server.core.analysis.metrics.Metrics> metricsClass = MetricsHolder.find(result Class<? extends Metrics> metricsClass = MetricsHolder.find(result.getAggregationFunctionName());
.getAggregationFunctionName());
String metricsClassSimpleName = metricsClass.getSimpleName(); String metricsClassSimpleName = metricsClass.getSimpleName();
result.setMetricsClassName(metricsClassSimpleName); result.setMetricsClassName(metricsClassSimpleName);
@ -45,45 +45,22 @@ public class DeepAnalysis {
List<ConditionExpression> expressions = result.getFilterExpressionsParserResult(); List<ConditionExpression> expressions = result.getFilterExpressionsParserResult();
if (expressions != null && expressions.size() > 0) { if (expressions != null && expressions.size() > 0) {
for (ConditionExpression expression : expressions) { for (ConditionExpression expression : expressions) {
Expression filterExpression = new Expression(); final FilterMatchers.MatcherInfo matcherInfo = FilterMatchers.INSTANCE.find(expression.getExpressionType());
if ("booleanMatch".equals(expression.getExpressionType())) {
filterExpression.setExpressionObject("EqualMatch"); final String getter = matcherInfo.isBooleanType()
filterExpression.setLeft("source." + ClassMethodUtil.toIsMethod(expression.getAttribute()) + "()"); ? ClassMethodUtil.toIsMethod(expression.getAttribute())
filterExpression.setRight(expression.getValue()); : ClassMethodUtil.toGetMethod(expression.getAttribute());
result.addFilterExpressions(filterExpression);
} else if ("stringMatch".equals(expression.getExpressionType())) { final Expression filterExpression = new Expression();
filterExpression.setExpressionObject("EqualMatch"); filterExpression.setExpressionObject(matcherInfo.getMatcher().getName());
filterExpression.setLeft("source." + ClassMethodUtil.toGetMethod(expression.getAttribute()) + "()"); filterExpression.setLeft("source." + getter + "()");
filterExpression.setRight(expression.getValue()); filterExpression.setRight(expression.getValue());
result.addFilterExpressions(filterExpression); result.addFilterExpressions(filterExpression);
} else if ("greaterMatch".equals(expression.getExpressionType())) {
filterExpression.setExpressionObject("GreaterMatch");
filterExpression.setLeft("source." + ClassMethodUtil.toGetMethod(expression.getAttribute()) + "()");
filterExpression.setRight(expression.getValue());
result.addFilterExpressions(filterExpression);
} else if ("lessMatch".equals(expression.getExpressionType())) {
filterExpression.setExpressionObject("LessMatch");
filterExpression.setLeft("source." + ClassMethodUtil.toGetMethod(expression.getAttribute()) + "()");
filterExpression.setRight(expression.getValue());
result.addFilterExpressions(filterExpression);
} else if ("greaterEqualMatch".equals(expression.getExpressionType())) {
filterExpression.setExpressionObject("GreaterEqualMatch");
filterExpression.setLeft("source." + ClassMethodUtil.toGetMethod(expression.getAttribute()) + "()");
filterExpression.setRight(expression.getValue());
result.addFilterExpressions(filterExpression);
} else if ("lessEqualMatch".equals(expression.getExpressionType())) {
filterExpression.setExpressionObject("LessEqualMatch");
filterExpression.setLeft("source." + ClassMethodUtil.toGetMethod(expression.getAttribute()) + "()");
filterExpression.setRight(expression.getValue());
result.addFilterExpressions(filterExpression);
} else {
throw new IllegalArgumentException("filter expression [" + expression.getExpressionType() + "] not found");
}
} }
} }
// 3. Find Entrance method of this metrics // 3. Find Entrance method of this metrics
Class c = metricsClass; Class<?> c = metricsClass;
Method entranceMethod = null; Method entranceMethod = null;
SearchEntrance: SearchEntrance:
while (!c.equals(Object.class)) { while (!c.equals(Object.class)) {
@ -117,36 +94,17 @@ public class DeepAnalysis {
entryMethod.addArg(parameterType, "1"); entryMethod.addArg(parameterType, "1");
} else if (annotation instanceof org.apache.skywalking.oap.server.core.analysis.metrics.annotation.Expression) { } else if (annotation instanceof org.apache.skywalking.oap.server.core.analysis.metrics.annotation.Expression) {
if (result.getFuncConditionExpressions().size() == 1) { if (result.getFuncConditionExpressions().size() == 1) {
ConditionExpression expression = result.getFuncConditionExpressions().get(0); final ConditionExpression expression = result.getFuncConditionExpressions().get(0);
final FilterMatchers.MatcherInfo matcherInfo = FilterMatchers.INSTANCE.find(expression.getExpressionType());
Expression argExpression = new Expression(); final String getter = matcherInfo.isBooleanType()
if ("booleanMatch".equals(expression.getExpressionType())) { ? ClassMethodUtil.toIsMethod(expression.getAttribute())
argExpression.setExpressionObject("EqualMatch"); : ClassMethodUtil.toGetMethod(expression.getAttribute());
argExpression.setLeft("source." + ClassMethodUtil.toIsMethod(expression.getAttribute()) + "()");
argExpression.setRight(expression.getValue()); final Expression argExpression = new Expression();
} else if ("stringMatch".equals(expression.getExpressionType())) { argExpression.setRight(expression.getValue());
argExpression.setExpressionObject("EqualMatch"); argExpression.setExpressionObject(matcherInfo.getMatcher().getName());
argExpression.setLeft("source." + ClassMethodUtil.toGetMethod(expression.getAttribute()) + "()"); argExpression.setLeft("source." + getter + "()");
argExpression.setRight(expression.getValue());
} else if ("greaterMatch".equals(expression.getExpressionType())) {
argExpression.setExpressionObject("GreaterMatch");
argExpression.setLeft("source." + ClassMethodUtil.toGetMethod(expression.getAttribute()) + "()");
argExpression.setRight(expression.getValue());
} else if ("lessMatch".equals(expression.getExpressionType())) {
argExpression.setExpressionObject("LessMatch");
argExpression.setLeft("source." + ClassMethodUtil.toGetMethod(expression.getAttribute()) + "()");
argExpression.setRight(expression.getValue());
} else if ("greaterEqualMatch".equals(expression.getExpressionType())) {
argExpression.setExpressionObject("GreaterEqualMatch");
argExpression.setLeft("source." + ClassMethodUtil.toGetMethod(expression.getAttribute()) + "()");
argExpression.setRight(expression.getValue());
} else if ("lessEqualMatch".equals(expression.getExpressionType())) {
argExpression.setExpressionObject("LessEqualMatch");
argExpression.setLeft("source." + ClassMethodUtil.toGetMethod(expression.getAttribute()) + "()");
argExpression.setRight(expression.getValue());
} else {
throw new IllegalArgumentException("filter expression [" + expression.getExpressionType() + "] not found");
}
entryMethod.addArg(argExpression); entryMethod.addArg(argExpression);
} else { } else {

View File

@ -0,0 +1,95 @@
/*
* 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.oal.rt.parser;
import com.google.common.reflect.ClassPath;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.BooleanValueFilterMatcher;
import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.FilterMatcher;
@SuppressWarnings("UnstableApiUsage")
public enum FilterMatchers {
INSTANCE;
FilterMatchers() {
try {
init();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private final Map<String, MatcherInfo> matchersKeyedByType = new HashMap<>();
private void init() throws IOException {
final ClassPath classpath = ClassPath.from(FilterMatchers.class.getClassLoader());
final Set<ClassPath.ClassInfo> classes = classpath.getTopLevelClassesRecursive("org.apache.skywalking");
for (ClassPath.ClassInfo classInfo : classes) {
final Class<?> clazz = classInfo.load();
final FilterMatcher plainFilterMatcher = clazz.getAnnotation(FilterMatcher.class);
final BooleanValueFilterMatcher booleanFilterMatcher = clazz.getAnnotation(BooleanValueFilterMatcher.class);
if (plainFilterMatcher != null && booleanFilterMatcher != null) {
throw new IllegalStateException(
"A matcher class can not be annotated with both @FilterMatcher and @BooleanValueFilterMatcher"
);
}
if (plainFilterMatcher != null) {
for (final String type : plainFilterMatcher.value()) {
matchersKeyedByType.put(type, new MatcherInfo(clazz, false));
}
if (plainFilterMatcher.value().length == 0) {
final String defaultTypeName = StringUtils.uncapitalize(clazz.getSimpleName());
matchersKeyedByType.put(defaultTypeName, new MatcherInfo(clazz, false));
}
}
if (booleanFilterMatcher != null) {
for (final String type : booleanFilterMatcher.value()) {
matchersKeyedByType.put(type, new MatcherInfo(clazz, true));
}
if (booleanFilterMatcher.value().length == 0) {
final String defaultTypeName = StringUtils.uncapitalize(clazz.getSimpleName());
matchersKeyedByType.put(defaultTypeName, new MatcherInfo(clazz, true));
}
}
}
}
public MatcherInfo find(final String type) {
if (!matchersKeyedByType.containsKey(type)) {
throw new IllegalArgumentException("filter expression [" + type + "] not found");
}
return matchersKeyedByType.get(type);
}
@Getter
@AllArgsConstructor
public static class MatcherInfo {
private final Class<?> matcher;
private final boolean isBooleanType;
}
}

View File

@ -23,13 +23,16 @@ import com.google.common.reflect.ClassPath;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import lombok.SneakyThrows;
import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics; import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.MetricsFunction; import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.MetricsFunction;
@SuppressWarnings("UnstableApiUsage")
public class MetricsHolder { public class MetricsHolder {
private static Map<String, Class<? extends Metrics>> REGISTER = new HashMap<>(); private static final Map<String, Class<? extends Metrics>> REGISTER = new HashMap<>();
private static volatile boolean INITIALIZED = false;
public static void init() throws IOException { private static void init() throws IOException {
ClassPath classpath = ClassPath.from(MetricsHolder.class.getClassLoader()); ClassPath classpath = ClassPath.from(MetricsHolder.class.getClassLoader());
ImmutableSet<ClassPath.ClassInfo> classes = classpath.getTopLevelClassesRecursive("org.apache.skywalking"); ImmutableSet<ClassPath.ClassInfo> classes = classpath.getTopLevelClassesRecursive("org.apache.skywalking");
for (ClassPath.ClassInfo classInfo : classes) { for (ClassPath.ClassInfo classInfo : classes) {
@ -45,13 +48,16 @@ public class MetricsHolder {
} }
} }
public static Class<? extends Metrics> find( @SneakyThrows
String functionName) { public static Class<? extends Metrics> find(String functionName) {
String func = functionName; if (!INITIALIZED) {
Class<? extends Metrics> metricsClass = REGISTER.get( init();
func); INITIALIZED = true;
}
Class<? extends Metrics> metricsClass = REGISTER.get(functionName);
if (metricsClass == null) { if (metricsClass == null) {
throw new IllegalArgumentException("Can't find metrics, " + func); throw new IllegalArgumentException("Can't find metrics, " + functionName);
} }
return metricsClass; return metricsClass;
} }

View File

@ -3,7 +3,7 @@ ${metricsClassPackage}${metricsName}Metrics metrics = new ${metricsClassPackage}
<#if filterExpressions??> <#if filterExpressions??>
<#list filterExpressions as filterExpression> <#list filterExpressions as filterExpression>
if (!new org.apache.skywalking.oap.server.core.analysis.metrics.expression.${filterExpression.expressionObject}().match(${filterExpression.left}, ${filterExpression.right})) { if (!new ${filterExpression.expressionObject}().match(${filterExpression.left}, ${filterExpression.right})) {
return; return;
} }
</#list> </#list>
@ -18,7 +18,7 @@ metrics.${entryMethod.methodName}(
<#if entryMethod.argTypes[arg_index] < 3> <#if entryMethod.argTypes[arg_index] < 3>
${arg} ${arg}
<#else> <#else>
new org.apache.skywalking.oap.server.core.analysis.metrics.expression.${arg.expressionObject}().match(${arg.left}, ${arg.right}) new ${arg.expressionObject}().match(${arg.left}, ${arg.right})
</#if><#if arg_has_next>, </#if> </#if><#if arg_has_next>, </#if>
</#list>); </#list>);

View File

@ -20,6 +20,10 @@ package org.apache.skywalking.oal.rt.parser;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import org.apache.skywalking.oap.server.core.analysis.metrics.expression.BooleanMatch;
import org.apache.skywalking.oap.server.core.analysis.metrics.expression.BooleanNotEqualMatch;
import org.apache.skywalking.oap.server.core.analysis.metrics.expression.EqualMatch;
import org.apache.skywalking.oap.server.core.analysis.metrics.expression.NotEqualMatch;
import org.apache.skywalking.oap.server.core.annotation.AnnotationScan; import org.apache.skywalking.oap.server.core.annotation.AnnotationScan;
import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine; import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
import org.apache.skywalking.oap.server.core.storage.StorageException; import org.apache.skywalking.oap.server.core.storage.StorageException;
@ -28,14 +32,15 @@ import org.junit.Assert;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class DeepAnalysisTest { public class DeepAnalysisTest {
@BeforeClass @BeforeClass
public static void init() throws IOException, StorageException { public static void init() throws IOException, StorageException {
AnnotationScan scopeScan = new AnnotationScan(); AnnotationScan scopeScan = new AnnotationScan();
scopeScan.registerListener(new DefaultScopeDefine.Listener()); scopeScan.registerListener(new DefaultScopeDefine.Listener());
scopeScan.scan(); scopeScan.scan();
MetricsHolder.init();
} }
@AfterClass @AfterClass
@ -122,8 +127,53 @@ public class DeepAnalysisTest {
List<Expression> filterExpressions = result.getFilterExpressions(); List<Expression> filterExpressions = result.getFilterExpressions();
Assert.assertEquals(1, filterExpressions.size()); Assert.assertEquals(1, filterExpressions.size());
Expression filterExpression = filterExpressions.get(0); Expression filterExpression = filterExpressions.get(0);
Assert.assertEquals("EqualMatch", filterExpression.getExpressionObject()); Assert.assertEquals(EqualMatch.class.getName(), filterExpression.getExpressionObject());
Assert.assertEquals("source.getName()", filterExpression.getLeft()); Assert.assertEquals("source.getName()", filterExpression.getLeft());
Assert.assertEquals("\"/service/prod/save\"", filterExpression.getRight()); Assert.assertEquals("\"/service/prod/save\"", filterExpression.getRight());
} }
@Test
public void shouldUseCorrectMatcher() {
AnalysisResult result = new AnalysisResult();
result.setSourceName("Endpoint");
result.setPackageName("endpoint.endpointavg");
result.setSourceAttribute("latency");
result.setMetricsName("EndpointAvg");
result.setAggregationFunctionName("longAvg");
DeepAnalysis analysis = new DeepAnalysis();
result.setFilterExpressions(null);
result.setFilterExpressionsParserResult(null);
result.addFilterExpressionsParserResult(new ConditionExpression("booleanMatch", "valid", ""));
result = analysis.analysis(result);
assertTrue(result.getFilterExpressions().size() > 0);
assertEquals(BooleanMatch.class.getName(), result.getFilterExpressions().get(0).getExpressionObject());
assertEquals("source.isValid()", result.getFilterExpressions().get(0).getLeft());
result.setFilterExpressions(null);
result.setFilterExpressionsParserResult(null);
result.addFilterExpressionsParserResult(new ConditionExpression("stringMatch", "type", ""));
result = analysis.analysis(result);
assertTrue(result.getFilterExpressions().size() > 0);
assertEquals(EqualMatch.class.getName(), result.getFilterExpressions().get(0).getExpressionObject());
assertEquals("source.getType()", result.getFilterExpressions().get(0).getLeft());
result.setFilterExpressions(null);
result.setFilterExpressionsParserResult(null);
result.addFilterExpressionsParserResult(new ConditionExpression("notEqualMatch", "type", ""));
result = analysis.analysis(result);
assertTrue(result.getFilterExpressions().size() > 0);
assertEquals(NotEqualMatch.class.getName(), result.getFilterExpressions().get(0).getExpressionObject());
assertEquals("source.getType()", result.getFilterExpressions().get(0).getLeft());
result.setFilterExpressions(null);
result.setFilterExpressionsParserResult(null);
result.addFilterExpressionsParserResult(new ConditionExpression("booleanNotEqualMatch", "type", ""));
result = analysis.analysis(result);
assertTrue(result.getFilterExpressions().size() > 0);
assertEquals(BooleanNotEqualMatch.class.getName(), result.getFilterExpressions().get(0).getExpressionObject());
assertEquals("source.isType()", result.getFilterExpressions().get(0).getLeft());
}
} }

View File

@ -34,8 +34,6 @@ public class ScriptParserTest {
@BeforeClass @BeforeClass
public static void init() throws IOException, StorageException { public static void init() throws IOException, StorageException {
MetricsHolder.init();
AnnotationScan scopeScan = new AnnotationScan(); AnnotationScan scopeScan = new AnnotationScan();
scopeScan.registerListener(new DefaultScopeDefine.Listener()); scopeScan.registerListener(new DefaultScopeDefine.Listener());
scopeScan.scan(); scopeScan.scan();

View File

@ -0,0 +1,37 @@
/*
* 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.oap.server.core.analysis.metrics.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Exactly the same functionalities as {@link FilterMatcher} except for the value type of this matcher is {@code
* boolean}.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface BooleanValueFilterMatcher {
/**
* @return see {@link FilterMatcher#value()}.
*/
String[] value() default {};
}

View File

@ -0,0 +1,40 @@
/*
* 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.oap.server.core.analysis.metrics.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.apache.skywalking.oap.server.core.analysis.metrics.expression.BooleanMatch;
/**
* Classes annotated with {@code FilterMatcher} are processors of the expressions in {@code filter} of the OAL script.
* Take {@link BooleanMatch} as an example.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface FilterMatcher {
/**
* @return the operator name(s) defined in the .g4 files, such as {@code lessEqualMatch} and {@code notEqualMatch},
* the default value is the name of the class annotated with {@link FilterMatcher}, with the first letter being
* lowercase.
*/
String[] value() default {};
}

View File

@ -0,0 +1,32 @@
/*
* 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.oap.server.core.analysis.metrics.expression;
import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.BooleanValueFilterMatcher;
@BooleanValueFilterMatcher
public class BooleanMatch {
public boolean match(Boolean left, Boolean right) {
return left == right;
}
public boolean match(boolean left, boolean right) {
return left == right;
}
}

View File

@ -0,0 +1,32 @@
/*
* 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.oap.server.core.analysis.metrics.expression;
import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.BooleanValueFilterMatcher;
@BooleanValueFilterMatcher
public class BooleanNotEqualMatch {
public boolean match(Boolean left, Boolean right) {
return left != right;
}
public boolean match(boolean left, boolean right) {
return left != right;
}
}

View File

@ -19,48 +19,10 @@
package org.apache.skywalking.oap.server.core.analysis.metrics.expression; package org.apache.skywalking.oap.server.core.analysis.metrics.expression;
import java.util.Objects; import java.util.Objects;
import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.FilterMatcher;
@FilterMatcher("stringMatch")
public class EqualMatch { public class EqualMatch {
public boolean match(int left, int right) {
return left == right;
}
public boolean match(long left, long right) {
return left == right;
}
public boolean match(float left, float right) {
return left == right;
}
public boolean match(double left, double right) {
return left == right;
}
public boolean match(Integer left, Integer right) {
return Objects.equals(left, right);
}
public boolean match(Long left, Long right) {
return Objects.equals(left, right);
}
public boolean match(Float left, Float right) {
return Objects.equals(left, right);
}
public boolean match(Double left, Double right) {
return Objects.equals(left, right);
}
public boolean match(Boolean left, Boolean right) {
return left == right;
}
public boolean match(boolean left, boolean right) {
return left == right;
}
public boolean match(Object left, Object right) { public boolean match(Object left, Object right) {
return Objects.equals(left, right); return Objects.equals(left, right);
} }

View File

@ -18,6 +18,9 @@
package org.apache.skywalking.oap.server.core.analysis.metrics.expression; package org.apache.skywalking.oap.server.core.analysis.metrics.expression;
import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.FilterMatcher;
@FilterMatcher
public class GreaterEqualMatch { public class GreaterEqualMatch {
public boolean match(int left, int right) { public boolean match(int left, int right) {
return left >= right; return left >= right;

View File

@ -18,6 +18,9 @@
package org.apache.skywalking.oap.server.core.analysis.metrics.expression; package org.apache.skywalking.oap.server.core.analysis.metrics.expression;
import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.FilterMatcher;
@FilterMatcher
public class GreaterMatch { public class GreaterMatch {
public boolean match(int left, int right) { public boolean match(int left, int right) {
return left > right; return left > right;

View File

@ -18,6 +18,9 @@
package org.apache.skywalking.oap.server.core.analysis.metrics.expression; package org.apache.skywalking.oap.server.core.analysis.metrics.expression;
import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.FilterMatcher;
@FilterMatcher
public class LessEqualMatch { public class LessEqualMatch {
public boolean match(int left, int right) { public boolean match(int left, int right) {
return left <= right; return left <= right;

View File

@ -18,6 +18,9 @@
package org.apache.skywalking.oap.server.core.analysis.metrics.expression; package org.apache.skywalking.oap.server.core.analysis.metrics.expression;
import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.FilterMatcher;
@FilterMatcher
public class LessMatch { public class LessMatch {
public boolean match(int left, int right) { public boolean match(int left, int right) {
return left < right; return left < right;

View File

@ -0,0 +1,36 @@
/*
* 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.oap.server.core.analysis.metrics.expression;
import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.FilterMatcher;
@FilterMatcher
public class LikeMatch {
public boolean match(String left, String right) {
if (left == null || right == null) {
return false;
}
if (left.startsWith("%") && left.endsWith("%")) { // %keyword%
return right.contains(left.substring(1, left.length() - 1));
}
return (left.startsWith("%") && right.endsWith(left.substring(1))) // %suffix
|| (left.endsWith("%") && right.startsWith(left.substring(0, left.length() - 1))) // prefix%
;
}
}

View File

@ -0,0 +1,29 @@
/*
* 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.oap.server.core.analysis.metrics.expression;
import java.util.Objects;
import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.FilterMatcher;
@FilterMatcher
public class NotEqualMatch {
public boolean match(Object left, Object right) {
return !Objects.equals(left, right);
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.oap.server.core.analysis.metrics.expression;
import org.junit.Test;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
public class LikeMatchTest {
@Test
public void testLike() {
assertTrue(new LikeMatch().match("%Black", "MaxBlack"));
assertTrue(new LikeMatch().match("Max%", "MaxBlack"));
assertTrue(new LikeMatch().match("%axBl%", "MaxBlack"));
assertFalse(new LikeMatch().match("Max%", "CarolineChanning"));
assertFalse(new LikeMatch().match("%Max", "CarolineChanning"));
}
}