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

zhaoqingran pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hertzbeat.git


The following commit(s) were added to refs/heads/master by this push:
     new a8ce48b50d [bugfix] support no-whitespace alert expressions in 
instance filtering (#3276)
a8ce48b50d is described below

commit a8ce48b50dbadee71e9f52700ba6b49160d5b4fa
Author: Yang Chen <1597081...@qq.com>
AuthorDate: Mon Apr 21 15:46:16 2025 +0800

    [bugfix] support no-whitespace alert expressions in instance filtering 
(#3276)
    
    Co-authored-by: Logic <zqr10...@dromara.org>
---
 .../alert/calculate/RealTimeAlertCalculator.java   |  29 +++++-
 .../calculate/RealTimeAlertCalculatorTest.java     | 100 +++++++++++++++++++++
 2 files changed, 125 insertions(+), 4 deletions(-)

diff --git 
a/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/calculate/RealTimeAlertCalculator.java
 
b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/calculate/RealTimeAlertCalculator.java
index 35b0334270..0db6bb15cc 100644
--- 
a/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/calculate/RealTimeAlertCalculator.java
+++ 
b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/calculate/RealTimeAlertCalculator.java
@@ -44,6 +44,7 @@ import org.apache.hertzbeat.common.entity.message.CollectRep;
 import org.apache.hertzbeat.common.queue.CommonDataQueue;
 import org.apache.hertzbeat.common.util.CommonUtil;
 import org.apache.hertzbeat.common.util.JexlExpressionRunner;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;
 
@@ -72,7 +73,7 @@ public class RealTimeAlertCalculator {
     private static final Pattern APP_PATTERN = 
Pattern.compile("equals\\(__app__,\"([^\"]+)\"\\)");
     private static final Pattern AVAILABLE_PATTERN = 
Pattern.compile("equals\\(__available__,\"([^\"]+)\"\\)");
     private static final Pattern LABEL_PATTERN = 
Pattern.compile("contains\\(__labels__,\\s*\"([^\"]+)\"\\)");
-    private static final Pattern INSTANCE_PATTERN = 
Pattern.compile("equals\\(__instance__,\\s\"(\\d+)\"\\)");
+    private static final Pattern INSTANCE_PATTERN = 
Pattern.compile("equals\\(__instance__,\\s*\"(\\d+)\"\\)");
     private static final Pattern METRICS_PATTERN = 
Pattern.compile("equals\\(__metrics__,\"([^\"]+)\"\\)");
 
     private final AlerterWorkerPool workerPool;
@@ -81,18 +82,38 @@ public class RealTimeAlertCalculator {
     private final AlarmCommonReduce alarmCommonReduce;
     private final AlarmCacheManager alarmCacheManager;
 
+    @Autowired
     public RealTimeAlertCalculator(AlerterWorkerPool workerPool, 
CommonDataQueue dataQueue,
                                    AlertDefineService alertDefineService, 
SingleAlertDao singleAlertDao,
                                    AlarmCommonReduce alarmCommonReduce, 
AlarmCacheManager alarmCacheManager) {
+        this(workerPool, dataQueue, alertDefineService, singleAlertDao, 
alarmCommonReduce, alarmCacheManager, true);
+    }
+
+    /**
+     * Constructor for RealTimeAlertCalculator with a toggle to control 
whether to start alert calculation threads.
+     *
+     * @param workerPool          The worker pool used for concurrent alert 
calculation.
+     * @param dataQueue           The queue from which metric data is pulled 
and pushed.
+     * @param alertDefineService  The service providing alert definition rules.
+     * @param singleAlertDao      The DAO for fetching persisted alert states 
from storage.
+     * @param alarmCommonReduce   The component responsible for reducing and 
sending alerts.
+     * @param start               If true, the alert calculation threads will 
start automatically;
+     *                            set to false to disable thread start (useful 
for unit testing).
+     */
+    public RealTimeAlertCalculator(AlerterWorkerPool workerPool, 
CommonDataQueue dataQueue,
+                                   AlertDefineService alertDefineService, 
SingleAlertDao singleAlertDao,
+                                   AlarmCommonReduce alarmCommonReduce, 
AlarmCacheManager alarmCacheManager, boolean start) {
         this.workerPool = workerPool;
         this.dataQueue = dataQueue;
         this.alarmCommonReduce = alarmCommonReduce;
         this.alertDefineService = alertDefineService;
         this.alarmCacheManager = alarmCacheManager;
-        startCalculate();
+        if (start) {
+            startCalculate();
+        }
     }
 
-    private void startCalculate() {
+    public void startCalculate() {
         Runnable runnable = () -> {
             while (!Thread.currentThread().isInterrupted()) {
                 try {
@@ -252,7 +273,7 @@ public class RealTimeAlertCalculator {
      * @param priority  Current priority
      * @return Filtered alert definitions
      */
-    private List<AlertDefine> 
filterThresholdsByAppAndMetrics(List<AlertDefine> thresholds, String app, 
String metrics, Map<String, String> labels, String instance, int priority) {
+    public List<AlertDefine> filterThresholdsByAppAndMetrics(List<AlertDefine> 
thresholds, String app, String metrics, Map<String, String> labels, String 
instance, int priority) {
         return thresholds.stream()
                 .filter(define -> {
                     if (StringUtils.isBlank(define.getExpr())) {
diff --git 
a/hertzbeat-alerter/src/test/java/org/apache/hertzbeat/alert/calculate/RealTimeAlertCalculatorTest.java
 
b/hertzbeat-alerter/src/test/java/org/apache/hertzbeat/alert/calculate/RealTimeAlertCalculatorTest.java
new file mode 100644
index 0000000000..bdcc34ff77
--- /dev/null
+++ 
b/hertzbeat-alerter/src/test/java/org/apache/hertzbeat/alert/calculate/RealTimeAlertCalculatorTest.java
@@ -0,0 +1,100 @@
+/*
+ * 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.alert.calculate;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.apache.hertzbeat.alert.AlerterWorkerPool;
+import org.apache.hertzbeat.alert.dao.SingleAlertDao;
+import org.apache.hertzbeat.alert.reduce.AlarmCommonReduce;
+import org.apache.hertzbeat.alert.service.AlertDefineService;
+import org.apache.hertzbeat.common.entity.alerter.AlertDefine;
+import org.apache.hertzbeat.common.queue.CommonDataQueue;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+
+class RealTimeAlertCalculatorTest {
+
+    private RealTimeAlertCalculator calculator;
+
+    @BeforeEach
+    void setUp() {
+        AlerterWorkerPool mockPool = Mockito.mock(AlerterWorkerPool.class);
+        CommonDataQueue mockQueue = Mockito.mock(CommonDataQueue.class);
+        AlertDefineService mockAlertDefineService = 
Mockito.mock(AlertDefineService.class);
+        SingleAlertDao mockDao = Mockito.mock(SingleAlertDao.class);
+        AlarmCommonReduce mockReduce = Mockito.mock(AlarmCommonReduce.class);
+        AlarmCacheManager alarmCacheManager = 
Mockito.mock(AlarmCacheManager.class);
+
+        Mockito.when(mockDao.querySingleAlertsByStatus(Mockito.anyString()))
+                .thenReturn(Collections.emptyList());
+
+        calculator = new RealTimeAlertCalculator(mockPool, mockQueue, 
mockAlertDefineService, mockDao, mockReduce, alarmCacheManager, false);
+    }
+
+    @Test
+    void testFilterThresholdsByAppAndMetrics_withInstanceExpr_HasSpace() {
+        String app = "redis";
+        String instanceId = "501045327364864";
+        int priority = 0;
+
+        AlertDefine matchDefine = new AlertDefine();
+        matchDefine.setExpr("equals(__app__,\"redis\") && equals(__instance__, 
\"501045327364864\")");
+
+        AlertDefine unmatchDefine = new AlertDefine();
+        unmatchDefine.setExpr("equals(__app__,\"redis\") && 
equals(__instance__, \"999999999\")");
+
+        List<AlertDefine> allDefines = Arrays.asList(matchDefine, 
unmatchDefine);
+
+        List<AlertDefine> filtered = 
calculator.filterThresholdsByAppAndMetrics(allDefines, app, "", Map.of(), 
instanceId, priority);
+
+        // It should filter out 999999999.
+        assertEquals(1, filtered.size());
+        assertEquals("equals(__app__,\"redis\") && equals(__instance__, 
\"501045327364864\")",
+                filtered.get(0).getExpr());
+    }
+
+    @Test
+    void testFilterThresholdsByAppAndMetrics_withInstanceExpr_NoSpace() {
+        String app = "redis";
+        String instanceId = "501045327364864";
+        int priority = 0;
+
+        AlertDefine matchDefine = new AlertDefine();
+        matchDefine.setExpr("equals(__app__,\"redis\") && 
equals(__instance__,\"501045327364864\")");
+
+        AlertDefine unmatchDefine = new AlertDefine();
+        unmatchDefine.setExpr("equals(__app__,\"redis\") && 
equals(__instance__,\"999999999\")");
+
+        List<AlertDefine> allDefines = Arrays.asList(matchDefine, 
unmatchDefine);
+
+        List<AlertDefine> filtered = 
calculator.filterThresholdsByAppAndMetrics(allDefines, app, "", Map.of(), 
instanceId, priority);
+
+        // It should filter out 999999999.
+        assertEquals(1, filtered.size());
+        assertEquals("equals(__app__,\"redis\") && 
equals(__instance__,\"501045327364864\")",
+                filtered.get(0).getExpr());
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscr...@hertzbeat.apache.org
For additional commands, e-mail: notifications-h...@hertzbeat.apache.org

Reply via email to