This is an automated email from the ASF dual-hosted git repository.

gongchao pushed a commit to branch remove-avaitor
in repository https://gitbox.apache.org/repos/asf/hertzbeat.git

commit 9ef3db6180a3b54b061e6796acf38fe049c0ecaa
Author: tomsun28 <[email protected]>
AuthorDate: Fri Apr 26 18:03:17 2024 +0800

    use jexl express
    
    Signed-off-by: tomsun28 <[email protected]>
---
 .../hertzbeat/alert/calculate/CalculateAlarm.java  |  33 +-
 .../collector/dispatch/MetricsCollect.java         |  69 +--
 common/pom.xml                                     |   7 +
 .../common/config/AviatorConfiguration.java        | 200 --------
 .../hertzbeat/common/entity/job/Metrics.java       |   1 -
 .../hertzbeat/common/util/JexlCommonFunction.java  |  79 +++
 .../common/util/JexlExpressionRunner.java          |  51 ++
 .../common/config/AviatorConfigurationTest.java    | 134 -----
 .../org/apache/hertzbeat/common/util/JexlTest.java | 546 +++++++++++++++++++++
 .../org/apache/hertzbeat/manager/ManagerTest.java  |   8 +-
 pom.xml                                            |   8 +-
 11 files changed, 741 insertions(+), 395 deletions(-)

diff --git 
a/alerter/src/main/java/org/apache/hertzbeat/alert/calculate/CalculateAlarm.java
 
b/alerter/src/main/java/org/apache/hertzbeat/alert/calculate/CalculateAlarm.java
index f18738b3c..157c9f4ad 100644
--- 
a/alerter/src/main/java/org/apache/hertzbeat/alert/calculate/CalculateAlarm.java
+++ 
b/alerter/src/main/java/org/apache/hertzbeat/alert/calculate/CalculateAlarm.java
@@ -40,6 +40,8 @@ import java.util.ResourceBundle;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.stream.Collectors;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.jexl3.JexlException;
+import org.apache.commons.jexl3.JexlExpression;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.hertzbeat.alert.AlerterWorkerPool;
 import org.apache.hertzbeat.alert.dao.AlertMonitorDao;
@@ -57,6 +59,7 @@ import org.apache.hertzbeat.common.queue.CommonDataQueue;
 import org.apache.hertzbeat.common.support.event.MonitorDeletedEvent;
 import org.apache.hertzbeat.common.support.event.SystemConfigChangeEvent;
 import org.apache.hertzbeat.common.util.CommonUtil;
+import org.apache.hertzbeat.common.util.JexlExpressionRunner;
 import org.apache.hertzbeat.common.util.ResourceBundleUtil;
 import org.springframework.context.event.EventListener;
 import org.springframework.data.jpa.domain.Specification;
@@ -321,22 +324,24 @@ public class CalculateAlarm {
 
     private boolean execAlertExpression(Map<String, Object> fieldValueMap, 
String expr) {
         Boolean match;
+        JexlExpression expression;
         try {
-            Expression expression = AviatorEvaluator.compile(expr, true);
-            expression.getVariableNames().forEach(variable -> {
-                if (!fieldValueMap.containsKey(variable)) {
-                    throw new ExpressionRuntimeException("metrics value not 
contains expr field: " + variable);
-                }
-            });
-            match = (Boolean) expression.execute(fieldValueMap);
-        } catch (CompileExpressionErrorException | 
ExpressionSyntaxErrorException compileException) {
-            log.error("Alert Define Rule: {} Compile Error: {}.", expr, 
compileException.getMessage());
-            throw compileException;
-        } catch (ExpressionRuntimeException expressionRuntimeException) {
-            log.error("Alert Define Rule: {} Run Error: {}.", expr, 
expressionRuntimeException.getMessage());
-            throw expressionRuntimeException;
+            expression = JexlExpressionRunner.compile(expr);
+        } catch (JexlException jexlException) {
+            log.error("Alarm Rule: {} Compile Error: {}.", expr, 
jexlException.getMessage());
+            throw jexlException;
+        } catch (Exception e) {
+            log.error("Alarm Rule: {} Unknown Error: {}.", expr, 
e.getMessage());
+            throw e;
+        }
+
+        try {
+            match = (Boolean) JexlExpressionRunner.evaluate(expression, 
fieldValueMap);
+        } catch (JexlException jexlException) {
+            log.error("Alarm Rule: {} Run Error: {}.", expr, 
jexlException.getMessage());
+            throw jexlException;
         } catch (Exception e) {
-            log.error("Alert Define Rule: {} Unknown Error: {}.", expr, 
e.getMessage());
+            log.error("Alarm Rule: {} Unknown Error: {}.", expr, 
e.getMessage());
             throw e;
         }
         return match != null && match;
diff --git 
a/collector/src/main/java/org/apache/hertzbeat/collector/dispatch/MetricsCollect.java
 
b/collector/src/main/java/org/apache/hertzbeat/collector/dispatch/MetricsCollect.java
index 6be9f859e..22ac738a4 100644
--- 
a/collector/src/main/java/org/apache/hertzbeat/collector/dispatch/MetricsCollect.java
+++ 
b/collector/src/main/java/org/apache/hertzbeat/collector/dispatch/MetricsCollect.java
@@ -28,6 +28,7 @@ import java.util.Objects;
 import java.util.stream.Collectors;
 import lombok.Data;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.jexl3.JexlExpression;
 import org.apache.hertzbeat.collector.collect.AbstractCollect;
 import 
org.apache.hertzbeat.collector.collect.prometheus.PrometheusAutoCollectImpl;
 import org.apache.hertzbeat.collector.collect.strategy.CollectStrategyFactory;
@@ -40,6 +41,7 @@ import org.apache.hertzbeat.common.entity.job.Job;
 import org.apache.hertzbeat.common.entity.job.Metrics;
 import org.apache.hertzbeat.common.entity.message.CollectRep;
 import org.apache.hertzbeat.common.util.CommonUtil;
+import org.apache.hertzbeat.common.util.JexlExpressionRunner;
 import org.apache.hertzbeat.common.util.Pair;
 
 /**
@@ -203,11 +205,11 @@ public class MetricsCollect implements Runnable, 
Comparable<MetricsCollect> {
         }
         // eg: database_pages=Database pages unconventional mapping 
         Map<String, String> fieldAliasMap = new HashMap<>(8);
-        Map<String, Expression> fieldExpressionMap = metrics.getCalculates()
+        Map<String, JexlExpression> fieldExpressionMap = 
metrics.getCalculates()
                 .stream()
                 .map(cal -> transformCal(cal, fieldAliasMap))
                 .filter(Objects::nonNull)
-                .collect(Collectors.toMap(arr -> (String) arr[0], arr -> 
(Expression) arr[1], (oldValue, newValue) -> newValue));
+                .collect(Collectors.toMap(arr -> (String) arr[0], arr -> 
(JexlExpression) arr[1], (oldValue, newValue) -> newValue));
 
         if (metrics.getUnits() == null) {
             metrics.setUnits(Collections.emptyList());
@@ -220,46 +222,47 @@ public class MetricsCollect implements Runnable, 
Comparable<MetricsCollect> {
 
         List<Metrics.Field> fields = metrics.getFields();
         List<String> aliasFields = metrics.getAliasFields();
-        Map<String, String> aliasFieldValueMap = new HashMap<>(16);
-        Map<String, Object> fieldValueMap = new HashMap<>(16);
+        Map<String, String> aliasFieldValueMap = new HashMap<>(8);
+        Map<String, Object> fieldValueMap = new HashMap<>(8);
+        Map<String, String> aliasFieldUnitMap = new HashMap<>(8);
         CollectRep.ValueRow.Builder realValueRowBuilder = 
CollectRep.ValueRow.newBuilder();
         for (CollectRep.ValueRow aliasRow : aliasRowList) {
             for (int aliasIndex = 0; aliasIndex < aliasFields.size(); 
aliasIndex++) {
                 String aliasFieldValue = aliasRow.getColumns(aliasIndex);
+                String aliasField = aliasFields.get(aliasIndex);
                 if (!CommonConstants.NULL_VALUE.equals(aliasFieldValue)) {
-                    aliasFieldValueMap.put(aliasFields.get(aliasIndex), 
aliasFieldValue);
+                    aliasFieldValueMap.put(aliasField, aliasFieldValue);
+                    // whether the alias field is a number
+                    CollectUtil.DoubleAndUnit doubleAndUnit = CollectUtil
+                            .extractDoubleAndUnitFromStr(aliasFieldValue);
+                    if (doubleAndUnit != null) {
+                        fieldValueMap.put(aliasField, 
doubleAndUnit.getValue());
+                        if (doubleAndUnit.getUnit() != null) {
+                            aliasFieldUnitMap.put(aliasField, 
doubleAndUnit.getUnit());
+                        }
+                    } else {
+                        fieldValueMap.put(aliasField, aliasFieldValue);
+                    }
+                } else {
+                    fieldValueMap.put(aliasField, null);
                 }
             }
 
             for (Metrics.Field field : fields) {
                 String realField = field.getField();
-                Expression expression = fieldExpressionMap.get(realField);
+                JexlExpression expression = fieldExpressionMap.get(realField);
                 String value = null;
                 String aliasFieldUnit = null;
                 if (expression != null) {
-                    // If there is a calculation expression, calculate the 
value
-                    if (CommonConstants.TYPE_NUMBER == field.getType()) {
-                        for (String variable : 
expression.getVariableFullNames()) {
-                            // extract double value and unit from aliasField 
value
-                            CollectUtil.DoubleAndUnit doubleAndUnit = 
CollectUtil
-                                    
.extractDoubleAndUnitFromStr(aliasFieldValueMap.get(variable));
-                            if (doubleAndUnit != null) {
-                                Double doubleValue = doubleAndUnit.getValue();
-                                aliasFieldUnit = doubleAndUnit.getUnit();
-                                fieldValueMap.put(variable, doubleValue);
-                            } else {
-                                fieldValueMap.put(variable, null);
+                    try {
+                        for (Map.Entry<String, String> unitEntry : 
aliasFieldUnitMap.entrySet()) {
+                            if 
(expression.getSourceText().contains(unitEntry.getKey())) {
+                                aliasFieldUnit = unitEntry.getValue();
+                                break;
                             }
                         }
-                    } else {
-                        for (String variable : 
expression.getVariableFullNames()) {
-                            String strValue = aliasFieldValueMap.get(variable);
-                            fieldValueMap.put(variable, strValue);
-                        }
-                    }
-                    try {
                         // valueList为空时也执行,涵盖纯字符串赋值表达式
-                        Object objValue = expression.execute(fieldValueMap);
+                        Object objValue = 
JexlExpressionRunner.evaluate(expression, fieldValueMap);
                         if (objValue != null) {
                             value = String.valueOf(objValue);
                         }
@@ -274,16 +277,15 @@ public class MetricsCollect implements Runnable, 
Comparable<MetricsCollect> {
                     } else {
                         value = aliasFieldValueMap.get(realField);
                     }
-
+                    
                     if (value != null) {
                         final byte fieldType = field.getType();
-
                         if (fieldType == CommonConstants.TYPE_NUMBER) {
                             CollectUtil.DoubleAndUnit doubleAndUnit = 
CollectUtil
                                     .extractDoubleAndUnitFromStr(value);
-                            final Double tempValue = doubleAndUnit.getValue();
+                            final Double tempValue = doubleAndUnit == null ? 
null : doubleAndUnit.getValue();
                             value = tempValue == null ? null : 
String.valueOf(tempValue);
-                            aliasFieldUnit = doubleAndUnit.getUnit();
+                            aliasFieldUnit = doubleAndUnit == null ? null : 
doubleAndUnit.getUnit();
                         } else if (fieldType == CommonConstants.TYPE_TIME) {
                             final int tempValue;
                             value = (tempValue = 
CommonUtil.parseTimeStrToSecond(value)) == -1 ? null : 
String.valueOf(tempValue);
@@ -314,9 +316,10 @@ public class MetricsCollect implements Runnable, 
Comparable<MetricsCollect> {
                     value = CommonConstants.NULL_VALUE;
                 }
                 realValueRowBuilder.addColumns(value);
-                fieldValueMap.clear();
             }
             aliasFieldValueMap.clear();
+            fieldValueMap.clear();
+            aliasFieldUnitMap.clear();
             collectData.addValues(realValueRowBuilder.build());
             realValueRowBuilder.clear();
         }
@@ -332,9 +335,9 @@ public class MetricsCollect implements Runnable, 
Comparable<MetricsCollect> {
         int splitIndex = cal.indexOf("=");
         String field = cal.substring(0, splitIndex).trim();
         String expressionStr = cal.substring(splitIndex + 
1).trim().replace("\\#", "#");
-        Expression expression;
+        JexlExpression expression;
         try {
-            expression = AviatorEvaluator.compile(expressionStr, true);
+            expression = JexlExpressionRunner.compile(expressionStr);
         } catch (Exception e) {
             fieldAliasMap.put(field, expressionStr);
             return null;
diff --git a/common/pom.xml b/common/pom.xml
index 20b6683ce..dc2d1b5db 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -82,6 +82,7 @@
         <dependency>
             <groupId>com.googlecode.aviator</groupId>
             <artifactId>aviator</artifactId>
+            <version>5.4.1</version>
         </dependency>
         <!-- Tool dependencies  -->
         <dependency>
@@ -120,6 +121,12 @@
             <groupId>org.apache.kafka</groupId>
             <artifactId>kafka-clients</artifactId>
         </dependency>
+        <!-- expr calculate -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-jexl3</artifactId>
+            <version>3.2.1</version>
+        </dependency>
 
         <dependency>
             <groupId>org.apache.commons</groupId>
diff --git 
a/common/src/main/java/org/apache/hertzbeat/common/config/AviatorConfiguration.java
 
b/common/src/main/java/org/apache/hertzbeat/common/config/AviatorConfiguration.java
deleted file mode 100644
index c690ef0f0..000000000
--- 
a/common/src/main/java/org/apache/hertzbeat/common/config/AviatorConfiguration.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * 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.hertzbeat.common.config;
-
-import com.googlecode.aviator.AviatorEvaluator;
-import com.googlecode.aviator.AviatorEvaluatorInstance;
-import com.googlecode.aviator.Feature;
-import com.googlecode.aviator.Options;
-import com.googlecode.aviator.lexer.token.OperatorType;
-import com.googlecode.aviator.runtime.function.AbstractFunction;
-import com.googlecode.aviator.runtime.type.AviatorBoolean;
-import com.googlecode.aviator.runtime.type.AviatorDouble;
-import com.googlecode.aviator.runtime.type.AviatorObject;
-import com.googlecode.aviator.runtime.type.AviatorString;
-import com.googlecode.aviator.runtime.type.AviatorType;
-import java.util.Map;
-import java.util.Objects;
-import java.util.regex.Pattern;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-
-/**
- * aviator config
- */
-@Configuration
-@Slf4j
-public class AviatorConfiguration {
-
-    private static final int AVIATOR_LRU_CACHE_SIZE = 1024;
-
-    @Bean
-    public AviatorEvaluatorInstance configAviatorEvaluator() {
-        AviatorEvaluatorInstance instance = AviatorEvaluator.getInstance();
-
-        // Configure AviatorEvaluator to cache compiled expressions using LRU
-        instance
-                .useLRUExpressionCache(AVIATOR_LRU_CACHE_SIZE)
-                .addFunction(new StrEqualFunction());
-
-        // limit loop Limit the number of loops
-        instance.setOption(Options.MAX_LOOP_COUNT, 10);
-        
-        // Enables a partial Aviator syntax feature collection
-        instance.setOption(Options.FEATURE_SET,
-                Feature.asSet(Feature.If,
-                        Feature.Assignment,
-                        Feature.Let,
-                        Feature.StringInterpolation));
-
-        // Configure the custom aviator function
-        instance.addOpFunction(OperatorType.BIT_OR, new AbstractFunction() {
-            @Override
-            public AviatorObject call(final Map<String, Object> env, final 
AviatorObject arg1,
-                                      final AviatorObject arg2) {
-                try {
-                    Object value1 = arg1.getValue(env);
-                    Object value2 = arg2.getValue(env);
-                    Object currentValue = value1 == null ? value2 : value1;
-                    if (arg1.getAviatorType() == AviatorType.String) {
-                        return new AviatorString(String.valueOf(currentValue));
-                    } else {
-                        return AviatorDouble.valueOf(currentValue);
-                    }
-                } catch (Exception e) {
-                    log.error(e.getMessage());
-                }
-                return arg1.bitOr(arg2, env);
-            }
-            
-            @Override
-            public String getName() {
-                return OperatorType.BIT_OR.getToken();
-            }
-        });
-
-        instance.addFunction(new StrContainsFunction());
-        instance.addFunction(new ObjectExistsFunction());
-        instance.addFunction(new StrMatchesFunction());
-        return instance;
-    }
-
-    /**
-     * Define a custom aviator string equality function
-     */
-    private static class StrEqualFunction extends AbstractFunction {
-        @Override
-        public AviatorObject call(Map<String, Object> env, AviatorObject arg1, 
AviatorObject arg2) {
-            if (arg1 == null || arg2 == null) {
-                return AviatorBoolean.FALSE;
-            }
-            Object leftTmp = arg1.getValue(env);
-            Object rightTmp = arg2.getValue(env);
-            if (leftTmp == null || rightTmp == null) {
-                return AviatorBoolean.FALSE;
-            }
-            String left = String.valueOf(leftTmp);
-            String right = String.valueOf(rightTmp);
-            return AviatorBoolean.valueOf(left.equalsIgnoreCase(right));
-        }
-        
-        @Override
-        public String getName() {
-            return "equals";
-        }
-    }
-
-    /**
-     * Custom aviator determines whether string 1 contains string 2 
(case-insensitive)
-     */
-    private static class StrContainsFunction extends AbstractFunction {
-        @Override
-        public AviatorObject call(Map<String, Object> env, AviatorObject arg1, 
AviatorObject arg2) {
-            if (arg1 == null || arg2 == null) {
-                return AviatorBoolean.FALSE;
-            }
-            Object leftTmp = arg1.getValue(env);
-            Object rightTmp = arg2.getValue(env);
-            if (leftTmp == null || rightTmp == null) {
-                return AviatorBoolean.FALSE;
-            }
-            String left = String.valueOf(leftTmp);
-            String right = String.valueOf(rightTmp);
-            return AviatorBoolean.valueOf(StringUtils.containsIgnoreCase(left, 
right));
-        }
-        
-        @Override
-        public String getName() {
-            return "contains";
-        }
-    }
-
-    /**
-     * Custom aviator determines if a value exists for this object in the 
environment
-     */
-    private static class ObjectExistsFunction extends AbstractFunction {
-        @Override
-        public AviatorObject call(Map<String, Object> env, AviatorObject arg) {
-            if (arg == null) {
-                return AviatorBoolean.FALSE;
-            }
-            Object keyTmp = arg.getValue(env);
-            if (Objects.isNull(keyTmp)) {
-                return AviatorBoolean.FALSE;
-            } else {
-                String key = String.valueOf(keyTmp);
-                return AviatorBoolean.valueOf(StringUtils.isNotEmpty(key));
-            }
-        }
-        
-        @Override
-        public String getName() {
-            return "exists";
-        }
-    }
-
-    /**
-     * Custom aviator determines if a string matches a regex
-     * - regex You need to add "" or ''
-     */
-    private static class StrMatchesFunction extends AbstractFunction {
-        @Override
-        public AviatorObject call(Map<String, Object> env, AviatorObject arg1, 
AviatorObject arg2) {
-            if (arg1 == null || arg2 == null) {
-                return AviatorBoolean.FALSE;
-            }
-            Object strTmp = arg1.getValue(env);
-            Object regexTmp = arg2.getValue(env);
-            if (strTmp == null || regexTmp == null) {
-                return AviatorBoolean.FALSE;
-            }
-            String str = String.valueOf(strTmp);
-            String regex = String.valueOf(regexTmp);
-            boolean isMatch = Pattern.compile(regex).matcher(str).matches();
-            return AviatorBoolean.valueOf(isMatch);
-        }
-        
-        @Override
-        public String getName() {
-            return "matches";
-        }
-    }
-}
diff --git 
a/common/src/main/java/org/apache/hertzbeat/common/entity/job/Metrics.java 
b/common/src/main/java/org/apache/hertzbeat/common/entity/job/Metrics.java
index 6bb96574e..1e517fd90 100644
--- a/common/src/main/java/org/apache/hertzbeat/common/entity/job/Metrics.java
+++ b/common/src/main/java/org/apache/hertzbeat/common/entity/job/Metrics.java
@@ -102,7 +102,6 @@ public class Metrics {
      * Public attribute - expression calculation, map the pre-query attribute 
(pre Fields)
      * with the final attribute (fields), and calculate the final attribute 
(fields) value
      * eg: size = size1 + size2, speed = speedSize
-     * <a 
href="https://www.yuque.com/boyan-avfmj/aviatorscript/ban32m";>www.yuque.com/boyan-avfmj/aviatorscript/ban32m</a>
      */
     private List<String> calculates;
     /**
diff --git 
a/common/src/main/java/org/apache/hertzbeat/common/util/JexlCommonFunction.java 
b/common/src/main/java/org/apache/hertzbeat/common/util/JexlCommonFunction.java
new file mode 100644
index 000000000..111214c91
--- /dev/null
+++ 
b/common/src/main/java/org/apache/hertzbeat/common/util/JexlCommonFunction.java
@@ -0,0 +1,79 @@
+package org.apache.hertzbeat.common.util;
+
+import java.util.regex.Pattern;
+import lombok.Data;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * the common function for jexl str equals, match, contains, etc.
+ * sys:now() 
+ */
+@Data
+public class JexlCommonFunction {
+
+    /**
+     * Get the current time in milliseconds
+     * @return current time
+     */
+    public long now() {
+        return System.currentTimeMillis();
+    }
+
+
+    /**
+     * Define a custom aviator string equality function
+     * @param left left
+     * @param right right
+     * @return true if equals
+     */
+    public boolean equals(String left, String right) {
+        if (left == null && right == null) {
+            return true;
+        }
+        if (left == null || right == null) {
+            return false;
+        }
+        return left.equals(right);
+    }
+
+    /**
+     * Custom aviator determines whether string 1 contains string 2 
(case-insensitive)
+     * @param left left
+     * @param right right
+     * @return true if contains
+     */
+    public boolean contains(String left, String right) {
+        if (left == null || right == null) {
+            return false;
+        }
+        return StringUtils.containsIgnoreCase(left, right);
+    }
+
+
+    /**
+     * Custom aviator determines if a value exists for this object in the 
environment
+     * @param arg arg
+     * @return true if exists
+     */
+    public boolean exists(Object arg) {
+        if (arg == null) {
+            return false;
+        }
+        return StringUtils.isNotEmpty(String.valueOf(arg));
+    }
+
+    /**
+     * Custom aviator determines if a string matches a regex
+     * - regex You need to add "" or ''
+     * @param str str
+     * @param regex regex
+     * @return true if matches
+     */
+    public boolean matches(String str, String regex) {
+        if (str == null || regex == null) {
+            return false;
+        }
+        return Pattern.compile(regex).matcher(str).matches();
+    }
+    
+}
diff --git 
a/common/src/main/java/org/apache/hertzbeat/common/util/JexlExpressionRunner.java
 
b/common/src/main/java/org/apache/hertzbeat/common/util/JexlExpressionRunner.java
new file mode 100644
index 000000000..d5455e3a1
--- /dev/null
+++ 
b/common/src/main/java/org/apache/hertzbeat/common/util/JexlExpressionRunner.java
@@ -0,0 +1,51 @@
+package org.apache.hertzbeat.common.util;
+
+import com.google.common.collect.Maps;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+import org.apache.commons.jexl3.JexlBuilder;
+import org.apache.commons.jexl3.JexlContext;
+import org.apache.commons.jexl3.JexlEngine;
+import org.apache.commons.jexl3.JexlExpression;
+import org.apache.commons.jexl3.MapContext;
+
+/**
+ * jexl express runner
+ */
+public class JexlExpressionRunner {
+
+    private static final JexlEngine jexlEngine;
+    
+    static {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        // set the root namespace function
+        functions.put(null, new JexlCommonFunction());
+        jexlEngine = new 
JexlBuilder().charset(StandardCharsets.UTF_8).cache(256)
+                .strict(true).silent(false).namespaces(functions).create();
+    }
+    
+    public static Object evaluate(String expression, Map<String, Object> 
context) {
+        JexlContext jexlContext = new MapContext();
+        for (Map.Entry<String, Object> entry : context.entrySet()) {
+            jexlContext.set(entry.getKey(), entry.getValue());
+        }
+        return jexlEngine.createExpression(expression).evaluate(jexlContext);
+    }
+
+    public static Object evaluate(JexlExpression expression, Map<String, 
Object> context) {
+        JexlContext jexlContext = new MapContext();
+        for (Map.Entry<String, Object> entry : context.entrySet()) {
+            jexlContext.set(entry.getKey(), entry.getValue());
+        }
+        return expression.evaluate(jexlContext);
+    }
+    
+    public static Object evaluate(String expression) {
+        return jexlEngine.createExpression(expression).evaluate(new 
MapContext());
+    }
+    
+    public static JexlExpression compile(String expression) {
+        return jexlEngine.createExpression(expression);
+    }
+    
+}
diff --git 
a/common/src/test/java/org/apache/hertzbeat/common/config/AviatorConfigurationTest.java
 
b/common/src/test/java/org/apache/hertzbeat/common/config/AviatorConfigurationTest.java
deleted file mode 100644
index 4ca9dda79..000000000
--- 
a/common/src/test/java/org/apache/hertzbeat/common/config/AviatorConfigurationTest.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * 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.hertzbeat.common.config;
-
-import com.googlecode.aviator.AviatorEvaluator;
-import com.googlecode.aviator.exception.UnsupportedFeatureException;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- *
- *
- */
-class AviatorConfigurationTest {
-
-    @BeforeAll
-    static void setUp() {
-        AviatorConfiguration aviatorConfig = new AviatorConfiguration();
-        aviatorConfig.configAviatorEvaluator();
-    }
-
-    @Test
-    void testCustomStringFunctions() {
-        Map<String, Object> env = new HashMap<>();
-        env.put("k1", "Intel");
-        env.put("k2", "intel");
-        env.put("k3", "Ubuntu 18.04.6 LTS");
-        env.put("k4", "ubuntu");
-        env.put("k5", "Ubntu");
-        env.put("k6", null);
-
-        // test StrEqualFunction
-        String expr1 = "equals(k1,k2)"; // case-insensitive
-        Boolean res1 = (Boolean) AviatorEvaluator.compile(expr1).execute(env);
-        Assertions.assertTrue(res1);
-
-        String expr2 = "equals(k1,k3)";
-        Boolean res2 = (Boolean) AviatorEvaluator.compile(expr2).execute(env);
-        Assertions.assertFalse(res2);
-
-        // test StrContainsFunction
-        String expr3 = "contains(k3,k4)"; // case-insensitive
-        Boolean res3 = (Boolean) AviatorEvaluator.compile(expr3).execute(env);
-        Assertions.assertTrue(res3);
-
-        String expr4 = "contains(k4,k3)";
-        Boolean res4 = (Boolean) AviatorEvaluator.compile(expr4).execute(env);
-        Assertions.assertFalse(res4);
-
-        String expr5 = "contains(k3,k5)"; // subsequence
-        Boolean res5 = (Boolean) AviatorEvaluator.compile(expr5).execute(env);
-        Assertions.assertFalse(res5);
-
-        // test StrExistsFunction
-        String expr6 = "exists('DNE_Key1')";
-        Boolean res6 = (Boolean) AviatorEvaluator.compile(expr6).execute(env);
-        Assertions.assertTrue(res6);
-
-        String expr7 = "exists(k6)";
-        Boolean res7 = (Boolean) AviatorEvaluator.compile(expr7).execute(env);
-        Assertions.assertFalse(res7);
-        
-        String expr21 = "exists('k5')";
-        Boolean res21 = (Boolean) 
AviatorEvaluator.compile(expr21).execute(env);
-        Assertions.assertTrue(res21);
-        
-        String expr22 = "exists(k5)";
-        Boolean res22 = (Boolean) 
AviatorEvaluator.compile(expr22).execute(env);
-        Assertions.assertTrue(res22);
-
-        // test StrMatchesFunction
-        String regex1 = "'^[a-zA-Z0-9]+$'"; // only alphanumeric
-        String expr8 = "matches(k6," + regex1 + ")";
-        env.put("k6", "Ubntu50681269");
-        Boolean res8 = (Boolean) AviatorEvaluator.compile(expr8).execute(env);
-        Assertions.assertTrue(res8);
-        env.put("k6", "Ubnt_u50681269");
-        Boolean res9 = (Boolean) AviatorEvaluator.compile(expr8).execute(env);
-        Assertions.assertFalse(res9);
-
-        String regex2 = "'^Ubuntu.*'"; // starts with
-        String expr9 = "matches(k3," + regex2 + ")";
-        Boolean res10 = (Boolean) AviatorEvaluator.compile(expr9).execute(env);
-        Assertions.assertTrue(res10);
-        env.put("k3", "Ubunt_u50681269");
-        Boolean res11 = (Boolean) AviatorEvaluator.compile(expr9).execute(env);
-        Assertions.assertFalse(res11);
-
-        String regex3 = "\"^\\\\[LOG\\\\].*error$\""; // starts & ends with
-        String expr10 = "matches(k7," + regex3 + ")";
-        env.put("k7", "[LOG] detected system error");
-        Boolean res12 = (Boolean) 
AviatorEvaluator.compile(expr10).execute(env);
-        Assertions.assertTrue(res12);
-        env.put("k7", "[LOG detected system error");
-        Boolean res13 = (Boolean) 
AviatorEvaluator.compile(expr10).execute(env);
-        Assertions.assertFalse(res13);
-    }
-
-    @Test
-    void testRCE() {
-        // test if 'new' syntax is disabled to prevent RCE
-        Assertions.assertThrows(UnsupportedFeatureException.class, () -> {
-            String expr1 = "let d = new java.util.Date();\n" +
-                    "p(type(d));\n" +
-                    "p(d);";
-            AviatorEvaluator.compile(expr1, true).execute();
-        });
-        // test allowed features
-        String expr2 = "let a = 0;\n" +
-                "if (\"#{a}\" == \"0\") { a = -1; }\n" +
-                "a == -1";
-        Boolean result = (Boolean) AviatorEvaluator.compile(expr2, 
true).execute();
-        Assertions.assertTrue(result);
-    }
-}
diff --git 
a/common/src/test/java/org/apache/hertzbeat/common/util/JexlTest.java 
b/common/src/test/java/org/apache/hertzbeat/common/util/JexlTest.java
new file mode 100644
index 000000000..8bb80910c
--- /dev/null
+++ b/common/src/test/java/org/apache/hertzbeat/common/util/JexlTest.java
@@ -0,0 +1,546 @@
+package org.apache.hertzbeat.common.util;
+
+import com.google.common.collect.Maps;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+import org.apache.commons.jexl3.JexlBuilder;
+import org.apache.commons.jexl3.JexlContext;
+import org.apache.commons.jexl3.JexlEngine;
+import org.apache.commons.jexl3.JexlException;
+import org.apache.commons.jexl3.JexlExpression;
+import org.apache.commons.jexl3.MapContext;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ * test case for java expression language
+ */
+public class JexlTest {
+
+    private JexlBuilder jexlBuilder;
+    
+    @BeforeEach
+    void setUp() {
+        jexlBuilder = new 
JexlBuilder().charset(StandardCharsets.UTF_8).cache(256)
+                .strict(true).silent(false);
+    }
+    
+    
+    @Test
+    void testMultiExpression() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 1);
+        JexlExpression e = jexl.createExpression("x * y");
+        Object o = e.evaluate(context);
+        Assertions.assertEquals(8, o);
+    }
+    
+    @Test
+    void testDivisionExpression() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 1);
+        JexlExpression e = jexl.createExpression("x / y");
+        Object o = e.evaluate(context);
+        Assertions.assertEquals(8, o);
+    }
+    
+    @Test
+    void testAdditionExpression() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 1);
+        JexlExpression e = jexl.createExpression("x + y");
+        Object o = e.evaluate(context);
+        Assertions.assertEquals(9, o);
+        context.set("x", "hello");
+        context.set("y", 3.0);
+        e = jexl.createExpression("x + y");
+        o = e.evaluate(context);
+        Assertions.assertEquals("hello3.0", o);
+    }
+    
+    @Test
+    void testSubtractionExpression() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 1);
+        JexlExpression e = jexl.createExpression("x - y");
+        Object o = e.evaluate(context);
+        Assertions.assertEquals(7, o);
+    }
+    
+    @Test
+    void testModulusExpression() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 3);
+        JexlExpression e = jexl.createExpression("x % y");
+        Object o = e.evaluate(context);
+        Assertions.assertEquals(2, o);
+    }
+    
+    @Test
+    void testComplicatedExpression() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 1);
+        JexlExpression e = jexl.createExpression("x * y + 2 * x - y");
+        Object o = e.evaluate(context);
+        Assertions.assertEquals(23, o);
+    }
+    
+    @Test
+    void testComplicatedExpressionWithParentheses() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 1);
+        JexlExpression e = jexl.createExpression("(x * y) + (2 * x) - y");
+        Object o = e.evaluate(context);
+        Assertions.assertEquals(23, o);
+    }
+    
+    @Test
+    void testComplicatedExpressionWithParenthesesAndSpaces() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 1);
+        JexlExpression e = jexl.createExpression(" ( x * y ) + ( 2 * x ) - y 
");
+        Object o = e.evaluate(context);
+        Assertions.assertEquals(23, o);
+    }
+    
+    @Test
+    void testComplicatedSpecialVariableNameExpression() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x.y", 8);
+        context.set("y", 1);
+        context.set("$.os.cpu.load_average.1m", 23);
+        context.set("$.os.load_average", 55);
+        context.set("$.fs.total.total_in_bytes", 20.0);
+        JexlExpression e = jexl.createExpression("x.y * y + 2 * x.y - y + 
$.os.cpu.load_average.1m + $.os.load_average + $.fs.total.total_in_bytes");
+        Object o = e.evaluate(context);
+        Assertions.assertEquals(121.0, o);
+    }
+    
+    @Test
+    void 
testComplicatedSpecialVariableNameExpressionWithParenthesesAndSpaces() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x.y", 8);
+        context.set("y", 1);
+        context.set("$.os.cpu.load_average.1m", 23);
+        context.set("$.os.load_average", 55);
+        context.set("$.fs.total.total_in_bytes", 20.0);
+        JexlExpression e = jexl.createExpression(" ( x.y * y ) + ( 2 * x.y ) - 
y + $.os.cpu.load_average.1m + $.os.load_average + $.fs.total.total_in_bytes ");
+        Object o = e.evaluate(context);
+        Assertions.assertEquals(121.0, o);
+    }
+    
+    @Test
+    void testVariableAssignment() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("$.fs.total.total_in_bytes", 20.0);
+        JexlExpression e = jexl.createExpression(" $.fs.total.total_in_bytes 
");
+        Object o = e.evaluate(context);
+        Assertions.assertEquals(20.0, o);
+    }
+    
+    @Test
+    void testSpecialVariableNameWithoutSpacesExpression() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("$.fs.total.free_in_bytes", 12.0);
+        context.set("$.fs.total.total_in_bytes", 23.0);
+        JexlExpression e = 
jexl.createExpression("(1-$.fs.total.free_in_bytes/$.fs.total.total_in_bytes)*100");
+        Object o = e.evaluate(context);
+        Assertions.assertEquals(47.82608695652174, o);
+    }
+
+    @Test
+    void testSpecialVariableNameWithSpacesExpression() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("$.fs.total.free_in_bytes", 12.0);
+        context.set("$.fs.total.total_in_bytes", 23.0);
+        JexlExpression e = jexl.createExpression("( 1 - 
$.fs.total.free_in_bytes / $.fs.total.total_in_bytes ) * 100");
+        Object o = e.evaluate(context);
+        Assertions.assertEquals(47.82608695652174, o);
+    }
+    
+    @Test
+    void testJudgmentExpression() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 1);
+        JexlExpression e = jexl.createExpression("x > y");
+        Object o = e.evaluate(context);
+        Assertions.assertTrue((Boolean) o);
+    }
+    
+    @Test
+    void testJudgmentExpressionWithParentheses() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 1);
+        JexlExpression e = jexl.createExpression("(x > y)");
+        Object o = e.evaluate(context);
+        Assertions.assertTrue((Boolean) o);
+    }
+    
+    @Test
+    void testJudgmentExpressionWithParenthesesAndSpaces() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 1);
+        JexlExpression e = jexl.createExpression(" ( x > y ) ");
+        Object o = e.evaluate(context);
+        Assertions.assertTrue((Boolean) o);
+    }
+    
+    @Test
+    void testJudgmentExpressionWithAndOperator() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 1);
+        context.set("z", 2);
+        JexlExpression e = jexl.createExpression("x > y && x < z");
+        Object o = e.evaluate(context);
+        Assertions.assertFalse((Boolean) o);
+    }
+    
+    @Test
+    void testJudgmentExpressionWithOrOperator() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 1);
+        context.set("z", 2);
+        JexlExpression e = jexl.createExpression("x > y || x < z");
+        Object o = e.evaluate(context);
+        Assertions.assertTrue((Boolean) o);
+    }
+    
+    @Test
+    void testJudgmentExpressionWithNotOperator() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        JexlExpression e = jexl.createExpression("!(x == 8)");
+        Object o = e.evaluate(context);
+        Assertions.assertFalse((Boolean) o);
+    }
+    
+    @Test
+    void testJudgmentExpressionWithNotOperatorAndParentheses() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("$.fs.total.free_in_bytes", 8);
+        JexlExpression e = jexl.createExpression("!($.fs.total.free_in_bytes 
== 8)");
+        Object o = e.evaluate(context);
+        Assertions.assertFalse((Boolean) o);
+    }
+
+    @Test
+    void testCustomFunction() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put("date", new DateFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 1);
+        JexlExpression e = jexl.createExpression("date:now(x,y)");
+        Object o = e.evaluate(context);
+        String result = (String) o;
+        Assertions.assertTrue(result.endsWith("2"));
+    }
+    
+    @Test
+    void testZeroThrowException() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 0);
+        JexlExpression e = jexl.createExpression("x / y");
+        Assertions.assertThrows(JexlException.class, () -> 
e.evaluate(context));
+    }
+    
+    @Test
+    void testNullThrowException() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", null);
+        JexlExpression e = jexl.createExpression("x / y");
+        Assertions.assertThrows(JexlException.class, () -> 
e.evaluate(context));
+    }
+    
+    @Test
+    void testEmptyStringThrowException() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", "");
+        JexlExpression e = jexl.createExpression("x / y");
+        Assertions.assertThrows(JexlException.class, () -> 
e.evaluate(context));
+    }
+    
+    @Test
+    void testEqualsFunction() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put("sys", new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", "hello");
+        context.set("y", "hello");
+        JexlExpression e = jexl.createExpression("sys:equals(x, y)");
+        Object o = e.evaluate(context);
+        Assertions.assertTrue((Boolean) o);
+    }
+    
+    @Test
+    void testNotEqualsFunction() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put("sys", new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", "hellos");
+        context.set("y", "hello");
+        JexlExpression e = jexl.createExpression("sys:equals(x, y)");
+        Object o = e.evaluate(context);
+        Assertions.assertFalse((Boolean) o);
+    }
+
+    @Test
+    void testContainsFunction() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put(null, new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", "hello");
+        context.set("y", "e");
+        JexlExpression e = jexl.createExpression("contains(x, y)");
+        Object o = e.evaluate(context);
+        Assertions.assertTrue((Boolean) o);
+    }
+    
+    @Test
+    void testExistsFunction() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put("sys", new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", "hello");
+        JexlExpression e = jexl.createExpression("sys:exists(x)");
+        Object o = e.evaluate(context);
+        Assertions.assertTrue((Boolean) o);
+    }
+    
+    @Test
+    void testExistsFunctionWithNull() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put("sys", new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        JexlExpression e = jexl.createExpression("sys:exists(x)");
+        Assertions.assertThrows(JexlException.class, () -> 
e.evaluate(context));
+    }
+    
+    @Test
+    void testExistsFunctionWithEmptyString() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put("sys", new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", "");
+        JexlExpression e = jexl.createExpression("sys:exists(x)");
+        Object o = e.evaluate(context);
+        Assertions.assertFalse((Boolean) o);
+    }
+
+    @Test
+    void testExistsFunctionWithEmptyStringAndSpace() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put("sys", new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", " ");
+        JexlExpression e = jexl.createExpression("sys:exists(x)");
+        Object o = e.evaluate(context);
+        Assertions.assertTrue((Boolean) o);
+    }
+
+    @Test
+    void testMatchesFunction() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put("sys", new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", "hello");
+        JexlExpression e = jexl.createExpression("sys:matches(x, '.*')");
+        Object o = e.evaluate(context);
+        Assertions.assertTrue((Boolean) o);
+    }
+    
+    @Test
+    void testMatchesFunctionWithNull() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put("sys", new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", null);
+        JexlExpression e = jexl.createExpression("sys:matches(x, '.*')");
+        Object o = e.evaluate(context);
+        Assertions.assertFalse((Boolean) o);
+    }
+    
+    @Test
+    void testMatchesFunctionWithEmptyString() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put("sys", new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", "");
+        JexlExpression e = jexl.createExpression("sys:matches(x, '.*')");
+        Object o = e.evaluate(context);
+        Assertions.assertTrue((Boolean) o);
+    }
+    
+    @Test
+    void testMatchesFunctionWithEmptyStringAndSpace() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put("sys", new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", " ");
+        JexlExpression e = jexl.createExpression("sys:matches(x, '.*')");
+        Object o = e.evaluate(context);
+        Assertions.assertTrue((Boolean) o);
+    }
+    
+    @Test
+    void testMatchesFunctionWithRegex() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put("sys", new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", "hello");
+        JexlExpression e = jexl.createExpression("sys:matches(x, 'he.*')");
+        Object o = e.evaluate(context);
+        Assertions.assertTrue((Boolean) o);
+    }
+    
+    @Test
+    void testMatchesFunctionWithRegexNotMatch() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put("sys", new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", "hello");
+        JexlExpression e = jexl.createExpression("sys:matches(x, 'he')");
+        Object o = e.evaluate(context);
+        Assertions.assertFalse((Boolean) o);
+    }
+    
+    @Test
+    void testMatchesFunctionWithRegexAndSpace() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put("sys", new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", "hello");
+        JexlExpression e = jexl.createExpression("sys:matches(x, 'he.* ')");
+        Object o = e.evaluate(context);
+        Assertions.assertFalse((Boolean) o);
+    }
+    
+    @Test
+    void testMatchesFunctionWithRegexAndSpace2() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put(null, new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", "Ubuntu50681269");
+        JexlExpression e = jexl.createExpression("matches(x, 
'^[a-zA-Z0-9]+$')");
+        Object o = e.evaluate(context);
+        Assertions.assertTrue((Boolean) o);
+        context.set("x", "Ubuntu_u50681269");
+        o = e.evaluate(context);
+        Assertions.assertFalse((Boolean) o);
+    }
+    
+    @Test
+    void testNowFunction() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put(null, new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        JexlExpression e = jexl.createExpression("now() + '-0'");
+        Object o = e.evaluate(context);
+        String result = (String) o;
+        Assertions.assertTrue(result.endsWith("-0"));
+    }
+    
+    @Test
+    void testUnconventionalMapping() {
+        // database_pages=Database pages
+        // name=User Commits Per Sec
+        JexlEngine jexl = jexlBuilder.create();
+        Assertions.assertThrows(JexlException.class, () -> 
jexl.createExpression("Database pages"));
+        Assertions.assertDoesNotThrow(() -> 
jexl.createExpression("Database_pages"));
+        Assertions.assertThrows(JexlException.class, () -> 
jexl.createExpression("User Commits Per Sec"));
+        Assertions.assertThrows(JexlException.class, () -> 
jexl.createExpression("System I/O"));
+        Assertions.assertThrows(JexlException.class, () -> 
jexl.createExpression("User I/O"));
+        Assertions.assertThrows(JexlException.class, () -> 
jexl.createExpression("Library Cache Hit Ratio"));
+        Assertions.assertThrows(JexlException.class, () -> 
jexl.createExpression("Buffer Cache Hit Ratio"));
+        Assertions.assertThrows(JexlException.class, () -> 
jexl.createExpression("Page reads/sec"));
+    }
+    
+    @Test
+    void testRecException() {
+        JexlEngine jexl = jexlBuilder.create();
+        Assertions.assertThrows(JexlException.class, () -> 
jexl.createExpression("new java.util.Date()"));
+    }
+    
+    /**
+     * custom function
+     */
+    public static class DateFunction {
+        public String now(Object... args) {
+            return System.currentTimeMillis() + "-" + args.length;
+        }
+    }
+}
diff --git 
a/manager/src/test/java/org/apache/hertzbeat/manager/ManagerTest.java 
b/manager/src/test/java/org/apache/hertzbeat/manager/ManagerTest.java
index f50761afe..91240d814 100644
--- a/manager/src/test/java/org/apache/hertzbeat/manager/ManagerTest.java
+++ b/manager/src/test/java/org/apache/hertzbeat/manager/ManagerTest.java
@@ -17,6 +17,8 @@
 
 package org.apache.hertzbeat.manager;
 
+import javax.annotation.Resource;
+import javax.naming.NamingException;
 import org.apache.hertzbeat.alert.AlerterProperties;
 import org.apache.hertzbeat.alert.AlerterWorkerPool;
 import org.apache.hertzbeat.alert.calculate.CalculateAlarm;
@@ -35,7 +37,6 @@ import org.apache.hertzbeat.collector.dispatch.WorkerPool;
 import 
org.apache.hertzbeat.collector.dispatch.entrance.internal.CollectJobService;
 import org.apache.hertzbeat.collector.dispatch.timer.TimerDispatcher;
 import org.apache.hertzbeat.collector.dispatch.unit.impl.DataSizeConvert;
-import org.apache.hertzbeat.common.config.AviatorConfiguration;
 import org.apache.hertzbeat.common.config.CommonConfig;
 import org.apache.hertzbeat.common.config.CommonProperties;
 import org.apache.hertzbeat.common.queue.impl.InMemoryCommonDataQueue;
@@ -51,10 +52,6 @@ import 
org.apache.hertzbeat.warehouse.store.RealTimeRedisDataStorage;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.NoSuchBeanDefinitionException;
 import org.springframework.context.ApplicationContext;
-
-import javax.annotation.Resource;
-import javax.naming.NamingException;
-
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
@@ -95,7 +92,6 @@ class ManagerTest extends AbstractSpringIntegrationTest {
         // test common module
         assertNotNull(ctx.getBean(CommonProperties.class));
         assertNotNull(ctx.getBean(CommonConfig.class));
-        assertNotNull(ctx.getBean(AviatorConfiguration.class));
         assertNotNull(ctx.getBean(InMemoryCommonDataQueue.class));
         // condition on common.sms.tencent.app-id
         assertThrows(NoSuchBeanDefinitionException.class, () -> 
ctx.getBean(TencentSmsClient.class));
diff --git a/pom.xml b/pom.xml
index a95019724..2cf13ea1b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -107,7 +107,6 @@
 
         <nekohtml.version>1.9.22</nekohtml.version>
         <json-path.version>2.9.0</json-path.version>
-        <aviator.version>5.4.1</aviator.version>
         <gson.version>2.10.1</gson.version>
         <guava.version>32.1.2-jre</guava.version>
         <protobuf.version>3.19.6</protobuf.version>
@@ -318,12 +317,7 @@
                 <artifactId>json-path</artifactId>
                 <version>${json-path.version}</version>
             </dependency>
-            <!-- 表达式计算 -->
-            <dependency>
-                <groupId>com.googlecode.aviator</groupId>
-                <artifactId>aviator</artifactId>
-                <version>${aviator.version}</version>
-            </dependency>
+            <!-- protobuf -->
             <dependency>
                 <groupId>com.google.protobuf</groupId>
                 <artifactId>protobuf-java-util</artifactId>


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to