diff --git a/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/calculate/AlarmCacheManager.java b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/calculate/AlarmCacheManager.java new file mode 100644 index 00000000000..803d0305ae4 --- /dev/null +++ b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/calculate/AlarmCacheManager.java @@ -0,0 +1,81 @@ +/* + * 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 org.apache.hertzbeat.alert.dao.SingleAlertDao; +import org.apache.hertzbeat.alert.util.AlertUtil; +import org.apache.hertzbeat.common.constants.CommonConstants; +import org.apache.hertzbeat.common.entity.alerter.SingleAlert; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * alert cache manager + */ +@Component +public class AlarmCacheManager { + + /** + * The alarm in the process is triggered + * key - labels fingerprint + */ + private final Map pendingAlertMap; + /** + * The not recover alert + * key - labels fingerprint + */ + private final Map firingAlertMap; + + public AlarmCacheManager(SingleAlertDao singleAlertDao) { + this.pendingAlertMap = new ConcurrentHashMap<>(8); + this.firingAlertMap = new ConcurrentHashMap<>(8); + List singleAlerts = singleAlertDao.querySingleAlertsByStatus(CommonConstants.ALERT_STATUS_FIRING); + for (SingleAlert singleAlert : singleAlerts) { + String fingerprint = AlertUtil.calculateFingerprint(singleAlert.getLabels()); + singleAlert.setId(null); + this.firingAlertMap.put(fingerprint, singleAlert); + } + } + + public void putPending(String fingerPrint, SingleAlert alert) { + this.pendingAlertMap.put(fingerPrint, alert); + } + + public SingleAlert getPending(String fingerPrint) { + return this.pendingAlertMap.get(fingerPrint); + } + + public SingleAlert removePending(String fingerPrint) { + return this.pendingAlertMap.remove(fingerPrint); + } + + public void putFiring(String fingerPrint, SingleAlert alert) { + this.firingAlertMap.put(fingerPrint, alert); + } + + public SingleAlert getFiring(String fingerPrint) { + return this.firingAlertMap.get(fingerPrint); + } + + public SingleAlert removeFiring(String fingerPrint) { + return this.firingAlertMap.remove(fingerPrint); + } +} diff --git a/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/calculate/CollectorAlertHandler.java b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/calculate/CollectorAlertHandler.java new file mode 100644 index 00000000000..e25bbb2ba14 --- /dev/null +++ b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/calculate/CollectorAlertHandler.java @@ -0,0 +1,129 @@ +/* + * 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 lombok.extern.slf4j.Slf4j; +import org.apache.hertzbeat.alert.dao.AlertCollectorDao; +import org.apache.hertzbeat.alert.reduce.AlarmCommonReduce; +import org.apache.hertzbeat.alert.util.AlertUtil; +import org.apache.hertzbeat.common.constants.CommonConstants; +import org.apache.hertzbeat.common.entity.alerter.SingleAlert; +import org.apache.hertzbeat.common.entity.manager.Collector; +import org.apache.hertzbeat.common.support.event.SystemConfigChangeEvent; +import org.apache.hertzbeat.common.util.ResourceBundleUtil; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; +import java.util.ResourceBundle; + +/** + * handle collector alarm + */ +@Component +@Slf4j +public class CollectorAlertHandler { + + private static final String KEY_COLLECTOR_NAME = "collectorName"; + private static final String KEY_COLLECTOR_VERSION = "collectorVersion"; + private static final String KEY_COLLECTOR_HOST = "collectorHost"; + + private final AlertCollectorDao alertCollectorDao; + + private final AlarmCommonReduce alarmCommonReduce; + + private final AlarmCacheManager alarmCacheManager; + + private ResourceBundle bundle; + + + public CollectorAlertHandler(AlarmCommonReduce alarmCommonReduce, AlertCollectorDao alertCollectorDao, + AlarmCacheManager alarmCacheManager) { + this.alarmCommonReduce = alarmCommonReduce; + this.alertCollectorDao = alertCollectorDao; + this.alarmCacheManager = alarmCacheManager; + this.bundle = ResourceBundleUtil.getBundle("alerter"); + } + + /** + * handle collector online + * + * @param identity collector name + */ + public void online(final String identity) { + Collector collector = alertCollectorDao.findCollectorByName(identity); + if (collector == null) { + return; + } + Map fingerPrints = new HashMap<>(8); + fingerPrints.put(KEY_COLLECTOR_NAME, collector.getName()); + fingerPrints.put(KEY_COLLECTOR_VERSION, collector.getVersion()); + fingerPrints.put(KEY_COLLECTOR_HOST, collector.getIp()); + String fingerprint = AlertUtil.calculateFingerprint(fingerPrints); + SingleAlert firingAlert = alarmCacheManager.getFiring(fingerprint); + if (firingAlert != null) { + firingAlert.setTriggerTimes(1); + firingAlert.setEndAt(System.currentTimeMillis()); + firingAlert.setStatus(CommonConstants.ALERT_STATUS_RESOLVED); + alarmCommonReduce.reduceAndSendAlarm(firingAlert.clone()); + } + } + + + /** + * handle collector offline + * + * @param identity collector name + */ + public void offline(final String identity) { + Collector collector = alertCollectorDao.findCollectorByName(identity); + if (collector == null) { + return; + } + long currentTimeMill = System.currentTimeMillis(); + Map fingerPrints = new HashMap<>(8); + fingerPrints.put(KEY_COLLECTOR_NAME, collector.getName()); + fingerPrints.put(KEY_COLLECTOR_VERSION, collector.getVersion()); + fingerPrints.put(KEY_COLLECTOR_HOST, collector.getIp()); + String fingerprint = AlertUtil.calculateFingerprint(fingerPrints); + SingleAlert existingAlert = alarmCacheManager.getFiring(fingerprint); + if (existingAlert == null) { + SingleAlert newAlert = SingleAlert.builder() + .labels(fingerPrints) + .annotations(fingerPrints) + .content(this.bundle.getString("alerter.availability.collector.offline")) + .status(CommonConstants.ALERT_STATUS_FIRING) + .triggerTimes(1) + .startAt(currentTimeMill) + .activeAt(currentTimeMill) + .build(); + alarmCacheManager.putFiring(fingerprint, newAlert); + alarmCommonReduce.reduceAndSendAlarm(newAlert.clone()); + } + + } + + + @EventListener(SystemConfigChangeEvent.class) + public void onSystemConfigChangeEvent(SystemConfigChangeEvent event) { + log.info("calculate alarm receive system config change event: {}.", event.getSource()); + this.bundle = ResourceBundleUtil.getBundle("alerter"); + } + +} diff --git a/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/calculate/PeriodicAlertCalculator.java b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/calculate/PeriodicAlertCalculator.java index 82bbd85cf9b..eb6ebf55900 100644 --- a/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/calculate/PeriodicAlertCalculator.java +++ b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/calculate/PeriodicAlertCalculator.java @@ -17,19 +17,17 @@ package org.apache.hertzbeat.alert.calculate; -import java.util.Arrays; import java.util.HashMap; -import java.util.Objects; import lombok.extern.slf4j.Slf4j; import org.apache.hertzbeat.alert.reduce.AlarmCommonReduce; import org.apache.hertzbeat.alert.service.DataSourceService; import org.apache.hertzbeat.alert.util.AlertTemplateUtil; +import org.apache.hertzbeat.alert.util.AlertUtil; import org.apache.hertzbeat.common.constants.CommonConstants; import org.apache.hertzbeat.common.entity.alerter.AlertDefine; import org.apache.hertzbeat.common.entity.alerter.SingleAlert; import java.util.List; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.lang3.StringUtils; import org.apache.commons.collections4.CollectionUtils; import org.springframework.stereotype.Component; @@ -47,22 +45,13 @@ public class PeriodicAlertCalculator { private final DataSourceService dataSourceService; private final AlarmCommonReduce alarmCommonReduce; - /** - * The alarm in the process is triggered - * key - labels fingerprint - */ - private final Map pendingAlertMap; - /** - * The not recover alert - * key - labels fingerprint - */ - private final Map firingAlertMap; - - public PeriodicAlertCalculator(DataSourceService dataSourceService, AlarmCommonReduce alarmCommonReduce) { + private final AlarmCacheManager alarmCacheManager; + + public PeriodicAlertCalculator(DataSourceService dataSourceService, AlarmCommonReduce alarmCommonReduce, + AlarmCacheManager alarmCacheManager) { this.dataSourceService = dataSourceService; this.alarmCommonReduce = alarmCommonReduce; - this.pendingAlertMap = new ConcurrentHashMap<>(8); - this.firingAlertMap = new ConcurrentHashMap<>(8); + this.alarmCacheManager = alarmCacheManager; } public void calculate(AlertDefine rule) { @@ -122,8 +111,8 @@ public void calculate(AlertDefine rule) { private void afterThresholdRuleMatch(long currentTimeMilli, Map fingerPrints, Map fieldValueMap, AlertDefine define) { - String fingerprint = calculateFingerprint(fingerPrints); - SingleAlert existingAlert = pendingAlertMap.get(fingerprint); + String fingerprint = AlertUtil.calculateFingerprint(fingerPrints); + SingleAlert existingAlert = alarmCacheManager.getPending(fingerprint); Map labels = new HashMap<>(8); fieldValueMap.putAll(define.getLabels()); labels.putAll(fingerPrints); @@ -144,11 +133,11 @@ private void afterThresholdRuleMatch(long currentTimeMilli, Map // If required trigger times is 1, set to firing status directly if (requiredTimes <= 1) { newAlert.setStatus(CommonConstants.ALERT_STATUS_FIRING); - firingAlertMap.put(fingerprint, newAlert); + alarmCacheManager.putFiring(fingerprint, newAlert); alarmCommonReduce.reduceAndSendAlarm(newAlert.clone()); } else { // Otherwise put into pending queue first - pendingAlertMap.put(fingerprint, newAlert); + alarmCacheManager.putPending(fingerprint, newAlert); } } else { // Update existing alert @@ -158,17 +147,17 @@ private void afterThresholdRuleMatch(long currentTimeMilli, Map // Check if required trigger times reached if (existingAlert.getStatus().equals(CommonConstants.ALERT_STATUS_PENDING) && existingAlert.getTriggerTimes() >= requiredTimes) { // Reached trigger times threshold, change to firing status - pendingAlertMap.remove(fingerprint); + alarmCacheManager.removePending(fingerprint); existingAlert.setStatus(CommonConstants.ALERT_STATUS_FIRING); - firingAlertMap.put(fingerprint, existingAlert); + alarmCacheManager.putFiring(fingerprint, existingAlert); alarmCommonReduce.reduceAndSendAlarm(existingAlert.clone()); } } } private void handleRecoveredAlert(Map fingerprints) { - String fingerprint = calculateFingerprint(fingerprints); - SingleAlert firingAlert = firingAlertMap.remove(fingerprint); + String fingerprint = AlertUtil.calculateFingerprint(fingerprints); + SingleAlert firingAlert = alarmCacheManager.removeFiring(fingerprint); if (firingAlert != null) { // todo consider multi times to tig for resolved alert firingAlert.setTriggerTimes(1); @@ -176,13 +165,7 @@ private void handleRecoveredAlert(Map fingerprints) { firingAlert.setStatus(CommonConstants.ALERT_STATUS_RESOLVED); alarmCommonReduce.reduceAndSendAlarm(firingAlert.clone()); } - pendingAlertMap.remove(fingerprint); + alarmCacheManager.removePending(fingerprint); } - private String calculateFingerprint(Map fingerPrints) { - List keyList = fingerPrints.keySet().stream().filter(Objects::nonNull).sorted().toList(); - List valueList = fingerPrints.values().stream().filter(Objects::nonNull).sorted().toList(); - return Arrays.hashCode(keyList.toArray(new String[0])) + "-" - + Arrays.hashCode(valueList.toArray(new String[0])); - } } 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 bc4861322f4..e2ad52d2f50 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 @@ -17,12 +17,11 @@ package org.apache.hertzbeat.alert.calculate; -import java.util.Arrays; + import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -35,6 +34,7 @@ import org.apache.hertzbeat.alert.reduce.AlarmCommonReduce; import org.apache.hertzbeat.alert.service.AlertDefineService; import org.apache.hertzbeat.alert.util.AlertTemplateUtil; +import org.apache.hertzbeat.alert.util.AlertUtil; import org.apache.hertzbeat.common.constants.CommonConstants; import org.apache.hertzbeat.common.entity.alerter.AlertDefine; import org.apache.hertzbeat.common.entity.alerter.SingleAlert; @@ -69,37 +69,20 @@ public class RealTimeAlertCalculator { private static final Pattern INSTANCE_PATTERN = Pattern.compile("equals\\(__instance__,\"(\\d+)\"\\)"); private static final Pattern METRICS_PATTERN = Pattern.compile("equals\\(__metrics__,\"([^\"]+)\"\\)"); - /** - * The alarm in the process is triggered - * key - labels fingerprint - */ - private final Map pendingAlertMap; - /** - * The not recover alert - * key - labels fingerprint - */ - private final Map firingAlertMap; private final AlerterWorkerPool workerPool; private final CommonDataQueue dataQueue; private final AlertDefineService alertDefineService; private final AlarmCommonReduce alarmCommonReduce; + private final AlarmCacheManager alarmCacheManager; public RealTimeAlertCalculator(AlerterWorkerPool workerPool, CommonDataQueue dataQueue, AlertDefineService alertDefineService, SingleAlertDao singleAlertDao, - AlarmCommonReduce alarmCommonReduce) { + AlarmCommonReduce alarmCommonReduce, AlarmCacheManager alarmCacheManager) { this.workerPool = workerPool; this.dataQueue = dataQueue; this.alarmCommonReduce = alarmCommonReduce; this.alertDefineService = alertDefineService; - this.pendingAlertMap = new ConcurrentHashMap<>(8); - this.firingAlertMap = new ConcurrentHashMap<>(8); - // Initialize firing stateAlertMap - List singleAlerts = singleAlertDao.querySingleAlertsByStatus(CommonConstants.ALERT_STATUS_FIRING); - for (SingleAlert singleAlert : singleAlerts) { - String fingerprint = calculateFingerprint(singleAlert.getLabels()); - singleAlert.setId(null); - firingAlertMap.put(fingerprint, singleAlert); - } + this.alarmCacheManager = alarmCacheManager; startCalculate(); } @@ -299,8 +282,8 @@ private List filterThresholdsByAppAndMetrics(List thre } private void handleRecoveredAlert(Map fingerprints) { - String fingerprint = calculateFingerprint(fingerprints); - SingleAlert firingAlert = firingAlertMap.remove(fingerprint); + String fingerprint = AlertUtil.calculateFingerprint(fingerprints); + SingleAlert firingAlert = alarmCacheManager.removeFiring(fingerprint); if (firingAlert != null) { // todo consider multi times to tig for resolved alert firingAlert.setTriggerTimes(1); @@ -308,13 +291,13 @@ private void handleRecoveredAlert(Map fingerprints) { firingAlert.setStatus(CommonConstants.ALERT_STATUS_RESOLVED); alarmCommonReduce.reduceAndSendAlarm(firingAlert.clone()); } - pendingAlertMap.remove(fingerprint); + alarmCacheManager.removePending(fingerprint); } private void afterThresholdRuleMatch(long currentTimeMilli, Map fingerPrints, Map fieldValueMap, AlertDefine define) { - String fingerprint = calculateFingerprint(fingerPrints); - SingleAlert existingAlert = pendingAlertMap.get(fingerprint); + String fingerprint = AlertUtil.calculateFingerprint(fingerPrints); + SingleAlert existingAlert = alarmCacheManager.getPending(fingerprint); Map labels = new HashMap<>(8); fieldValueMap.putAll(define.getLabels()); labels.putAll(fingerPrints); @@ -335,11 +318,11 @@ private void afterThresholdRuleMatch(long currentTimeMilli, Map // If required trigger times is 1, set to firing status directly if (requiredTimes <= 1) { newAlert.setStatus(CommonConstants.ALERT_STATUS_FIRING); - firingAlertMap.put(fingerprint, newAlert); + alarmCacheManager.putFiring(fingerprint, newAlert); alarmCommonReduce.reduceAndSendAlarm(newAlert.clone()); } else { // Otherwise put into pending queue first - pendingAlertMap.put(fingerprint, newAlert); + alarmCacheManager.putPending(fingerprint, newAlert); } } else { // Update existing alert @@ -349,9 +332,9 @@ private void afterThresholdRuleMatch(long currentTimeMilli, Map // Check if required trigger times reached if (existingAlert.getStatus().equals(CommonConstants.ALERT_STATUS_PENDING) && existingAlert.getTriggerTimes() >= requiredTimes) { // Reached trigger times threshold, change to firing status - pendingAlertMap.remove(fingerprint); + alarmCacheManager.removePending(fingerprint); existingAlert.setStatus(CommonConstants.ALERT_STATUS_FIRING); - firingAlertMap.put(fingerprint, existingAlert); + alarmCacheManager.putFiring(fingerprint, existingAlert); alarmCommonReduce.reduceAndSendAlarm(existingAlert.clone()); } } @@ -385,11 +368,4 @@ private boolean execAlertExpression(Map fieldValueMap, String ex } return match != null && match; } - - private String calculateFingerprint(Map fingerPrints) { - List keyList = fingerPrints.keySet().stream().filter(Objects::nonNull).sorted().toList(); - List valueList = fingerPrints.values().stream().filter(Objects::nonNull).sorted().toList(); - return Arrays.hashCode(keyList.toArray(new String[0])) + "-" - + Arrays.hashCode(valueList.toArray(new String[0])); - } } diff --git a/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/dao/AlertCollectorDao.java b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/dao/AlertCollectorDao.java new file mode 100644 index 00000000000..c76a06e6dca --- /dev/null +++ b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/dao/AlertCollectorDao.java @@ -0,0 +1,35 @@ +/* + * 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.dao; + +import org.apache.hertzbeat.common.entity.manager.Collector; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +/** + * Alert Collector Dao + */ +public interface AlertCollectorDao extends JpaRepository, JpaSpecificationExecutor { + + /** + * Query collector by name + * @param name collector name + * @return collector + */ + Collector findCollectorByName(String name); +} diff --git a/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/util/AlertUtil.java b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/util/AlertUtil.java new file mode 100644 index 00000000000..a1ed180c3f8 --- /dev/null +++ b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/util/AlertUtil.java @@ -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.hertzbeat.alert.util; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * alert util + */ +public class AlertUtil { + + /** + * calculate fingerprint + * @param fingerPrints finger prints + */ + public static String calculateFingerprint(Map fingerPrints) { + List keyList = fingerPrints.keySet().stream().filter(Objects::nonNull).sorted().toList(); + List valueList = fingerPrints.values().stream().filter(Objects::nonNull).sorted().toList(); + return Arrays.hashCode(keyList.toArray(new String[0])) + "-" + + Arrays.hashCode(valueList.toArray(new String[0])); + } +} diff --git a/hertzbeat-alerter/src/main/resources/alerter_en_US.properties b/hertzbeat-alerter/src/main/resources/alerter_en_US.properties index 938da98ac31..e05324b2d02 100644 --- a/hertzbeat-alerter/src/main/resources/alerter_en_US.properties +++ b/hertzbeat-alerter/src/main/resources/alerter_en_US.properties @@ -14,6 +14,8 @@ # limitations under the License. alerter.availability.recover = Availability Alert Resolved, Monitor Status Normal Now +alerter.availability.collector.recover = Collector Availability Alert Resolved, The collector is online +alerter.availability.collector.offline = Collector Availability Alert Notify, The collector is offline alerter.alarm.recover = Alert Resolved Notice alerter.notify.title = HertzBeat Alert Notify alerter.notify.target = Monitor Target diff --git a/hertzbeat-alerter/src/main/resources/alerter_zh_CN.properties b/hertzbeat-alerter/src/main/resources/alerter_zh_CN.properties index b1f11e284de..33f4e88d525 100644 --- a/hertzbeat-alerter/src/main/resources/alerter_zh_CN.properties +++ b/hertzbeat-alerter/src/main/resources/alerter_zh_CN.properties @@ -14,6 +14,8 @@ # limitations under the License. alerter.availability.recover = 可用性告警恢复通知, 任务状态已恢复正常 +alerter.availability.collector.recover = 采集器可用性恢复通知,采集器已上线 +alerter.availability.collector.offline = 采集器可用性告警通知,采集器已下线 alerter.alarm.recover = 告警恢复通知 alerter.notify.title = HertzBeat告警通知 alerter.notify.target = 告警目标对象 diff --git a/hertzbeat-alerter/src/main/resources/alerter_zh_TW.properties b/hertzbeat-alerter/src/main/resources/alerter_zh_TW.properties index a038fc9ec84..bc9331430b4 100644 --- a/hertzbeat-alerter/src/main/resources/alerter_zh_TW.properties +++ b/hertzbeat-alerter/src/main/resources/alerter_zh_TW.properties @@ -15,6 +15,8 @@ alerter.availability.recover = 可用性警報已解決,監視狀態現在正常 alerter.alarm.recover = 警報解決通知 +alerter.availability.collector.recover = 采集器可用性恢復通知,采集器已上線 +alerter.availability.collector.offline = 采集器可用性告警通知,采集器已下線 alerter.notify.title = HertzBeat 警報通知 alerter.notify.target = 監視目標 alerter.notify.monitorId = 監視 ID diff --git a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/support/event/MonitorDeletedEvent.java b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/support/event/MonitorDeletedEvent.java index 5049a46b5de..a451aa91ba4 100644 --- a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/support/event/MonitorDeletedEvent.java +++ b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/support/event/MonitorDeletedEvent.java @@ -20,7 +20,7 @@ import org.springframework.context.ApplicationEvent; /** - * the event for system config change + * the event for monitor delete */ public class MonitorDeletedEvent extends ApplicationEvent { diff --git a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/dao/CollectorDao.java b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/dao/CollectorDao.java index 4aefaa2e799..8affacd3ae8 100644 --- a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/dao/CollectorDao.java +++ b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/dao/CollectorDao.java @@ -17,6 +17,7 @@ package org.apache.hertzbeat.manager.dao; +import java.util.List; import java.util.Optional; import org.apache.hertzbeat.common.entity.manager.Collector; import org.springframework.data.jpa.repository.JpaRepository; @@ -34,7 +35,14 @@ public interface CollectorDao extends JpaRepository, JpaSpecifi * @return collector */ Optional findCollectorByName(String name); - + + /** + * find collectors by names + * @param names collector name list + * @return collector list + */ + List findCollectorsByNameIn(List names); + /** * delete collector by name * @param collector collector name diff --git a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/scheduler/netty/ManageServer.java b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/scheduler/netty/ManageServer.java index 68513fd5c5f..352415b65f0 100644 --- a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/scheduler/netty/ManageServer.java +++ b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/scheduler/netty/ManageServer.java @@ -24,6 +24,7 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import lombok.extern.slf4j.Slf4j; +import org.apache.hertzbeat.alert.calculate.CollectorAlertHandler; import org.apache.hertzbeat.common.entity.message.ClusterMsg; import org.apache.hertzbeat.common.support.CommonThreadPool; import org.apache.hertzbeat.manager.scheduler.CollectorJobScheduler; @@ -56,6 +57,8 @@ public class ManageServer implements CommandLineRunner { private final CollectorJobScheduler collectorJobScheduler; + private final CollectorAlertHandler collectorAlertHandler; + private ScheduledExecutorService channelSchedule; private RemotingServer remotingServer; @@ -64,9 +67,11 @@ public class ManageServer implements CommandLineRunner { public ManageServer(final SchedulerProperties schedulerProperties, final CollectorJobScheduler collectorJobScheduler, - final CommonThreadPool threadPool) { + final CommonThreadPool threadPool, + final CollectorAlertHandler collectorAlertHandler) { this.collectorJobScheduler = collectorJobScheduler; this.collectorJobScheduler.setManageServer(this); + this.collectorAlertHandler = collectorAlertHandler; this.init(schedulerProperties, threadPool); } @@ -98,6 +103,7 @@ public void start() { channel.closeFuture(); this.clientChannelTable.remove(collector); this.collectorJobScheduler.collectorGoOffline(collector); + this.collectorAlertHandler.offline(collector); } }); } catch (Exception e) { @@ -131,6 +137,7 @@ public void addChannel(final String identity, Channel channel) { preChannel.close(); } this.clientChannelTable.put(identity, channel); + this.collectorAlertHandler.online(identity); } public void closeChannel(final String identity) { diff --git a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/impl/CollectorServiceImpl.java b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/impl/CollectorServiceImpl.java index 4be9c982b3f..cafa02f291f 100644 --- a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/impl/CollectorServiceImpl.java +++ b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/impl/CollectorServiceImpl.java @@ -61,7 +61,7 @@ public class CollectorServiceImpl implements CollectorService { @Autowired(required = false) private ManageServer manageServer; - + @Override @Transactional(readOnly = true) public Page getCollectors(String name, int pageIndex, Integer pageSize) { diff --git a/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/dao/CollectorDaoTest.java b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/dao/CollectorDaoTest.java index fab01262500..997ebeaa565 100644 --- a/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/dao/CollectorDaoTest.java +++ b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/dao/CollectorDaoTest.java @@ -19,6 +19,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; import javax.annotation.Resource; import org.apache.hertzbeat.common.entity.manager.Collector; import org.apache.hertzbeat.manager.AbstractSpringIntegrationTest; @@ -27,6 +28,8 @@ import org.junit.jupiter.api.Test; import org.springframework.transaction.annotation.Transactional; +import java.util.List; + /** * Test case for {@link CollectorDao} */ @@ -66,5 +69,8 @@ public void findCollectorByName() { assertTrue(collectorDao.findCollectorByName("test").isPresent()); } - + @Test + public void findCollectorsByNameIn(){ + assertFalse(collectorDao.findCollectorsByNameIn(List.of("test")).isEmpty()); + } } diff --git a/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/service/CollectorServiceTest.java b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/service/CollectorServiceTest.java index c31ec4c8b6c..f5dc2095b76 100644 --- a/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/service/CollectorServiceTest.java +++ b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/service/CollectorServiceTest.java @@ -41,6 +41,7 @@ import org.mockito.Mock; import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.context.ApplicationContext; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.jpa.domain.Specification; @@ -67,6 +68,9 @@ public class CollectorServiceTest { @Mock private ManageServer manageServer; + @Mock + private ApplicationContext applicationContext; + @Test public void getCollectors() {