Compare commits

..
28 changed files with 89 additions and 921 deletions
@@ -17,9 +17,6 @@
package org.apache.hertzbeat.alert.calculate;
import com.google.common.collect.Table;
import com.google.common.collect.Tables;
import org.apache.commons.lang3.StringUtils;
import org.apache.hertzbeat.alert.dao.SingleAlertDao;
import org.apache.hertzbeat.alert.util.AlertUtil;
import org.apache.hertzbeat.common.constants.CommonConstants;
@@ -27,6 +24,7 @@ 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;
/**
@@ -35,78 +33,49 @@ import java.util.concurrent.ConcurrentHashMap;
@Component
public class AlarmCacheManager {
private static final String CUSTOM_FIRING_ROW_KEY = "CUSTOM_FIRING_";
/**
* The alarm in the process is triggered
* rowKey - define id
* columnKey - labels fingerprint
* key - labels fingerprint
*/
private final Table<String, String, SingleAlert> pendingAlertMap;
private final Map<String, SingleAlert> pendingAlertMap;
/**
* The not recover alert
* rowKey - define id
* columnKey - labels fingerprint
* key - labels fingerprint
*/
private final Table<String, String, SingleAlert> firingAlertMap;
private final Map<String, SingleAlert> firingAlertMap;
public AlarmCacheManager(SingleAlertDao singleAlertDao) {
this.pendingAlertMap = Tables.newCustomTable(new ConcurrentHashMap<>(8), ConcurrentHashMap::new);
this.firingAlertMap = Tables.newCustomTable(new ConcurrentHashMap<>(8), ConcurrentHashMap::new);
this.pendingAlertMap = new ConcurrentHashMap<>(8);
this.firingAlertMap = new ConcurrentHashMap<>(8);
List<SingleAlert> singleAlerts = singleAlertDao.querySingleAlertsByStatus(CommonConstants.ALERT_STATUS_FIRING);
for (SingleAlert singleAlert : singleAlerts) {
String fingerprint = AlertUtil.calculateFingerprint(singleAlert.getLabels());
String defineId = singleAlert.getLabels().get(CommonConstants.LABEL_DEFINE_ID);
if (StringUtils.isBlank(defineId)) {
defineId = getCustomKey(fingerprint);
}
singleAlert.setId(null);
this.firingAlertMap.put(defineId, fingerprint, singleAlert);
this.firingAlertMap.put(fingerprint, singleAlert);
}
}
public void putPending(Long defineId, String fingerPrint, SingleAlert alert) {
this.pendingAlertMap.put(String.valueOf(defineId), fingerPrint, alert);
public void putPending(String fingerPrint, SingleAlert alert) {
this.pendingAlertMap.put(fingerPrint, alert);
}
public SingleAlert getPending(Long defineId, String fingerPrint) {
return this.pendingAlertMap.get(String.valueOf(defineId), fingerPrint);
public SingleAlert getPending(String fingerPrint) {
return this.pendingAlertMap.get(fingerPrint);
}
public void removePending(Long defineId, String fingerPrint) {
this.pendingAlertMap.remove(String.valueOf(defineId), fingerPrint);
}
public void putFiring(Long defineId, String fingerPrint, SingleAlert alert) {
this.firingAlertMap.put(String.valueOf(defineId), fingerPrint, alert);
public SingleAlert removePending(String fingerPrint) {
return this.pendingAlertMap.remove(fingerPrint);
}
public void putFiring(String fingerPrint, SingleAlert alert) {
this.firingAlertMap.put(getCustomKey(fingerPrint), fingerPrint, alert);
}
public SingleAlert getFiring(Long defineId, String fingerPrint) {
SingleAlert singleAlert = this.firingAlertMap.get(String.valueOf(defineId), fingerPrint);
if (null != singleAlert) {
return singleAlert;
}
return getFiring(fingerPrint);
}
public SingleAlert removeFiring(Long defineId, String fingerPrint) {
SingleAlert singleAlert = this.firingAlertMap.remove(String.valueOf(defineId), fingerPrint);
if (null == singleAlert) {
return this.firingAlertMap.remove(getCustomKey(fingerPrint), fingerPrint);
}
return singleAlert;
this.firingAlertMap.put(fingerPrint, alert);
}
public SingleAlert getFiring(String fingerPrint) {
return this.firingAlertMap.get(getCustomKey(fingerPrint), fingerPrint);
return this.firingAlertMap.get(fingerPrint);
}
private String getCustomKey(String fingerPrint) {
return CUSTOM_FIRING_ROW_KEY + fingerPrint;
public SingleAlert removeFiring(String fingerPrint) {
return this.firingAlertMap.remove(fingerPrint);
}
}
@@ -17,9 +17,8 @@
package org.apache.hertzbeat.alert.calculate;
import java.util.HashMap;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.hertzbeat.alert.reduce.AlarmCommonReduce;
import org.apache.hertzbeat.alert.service.DataSourceService;
import org.apache.hertzbeat.alert.util.AlertTemplateUtil;
@@ -27,11 +26,11 @@ 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 org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;
/**
* Periodic Alert Calculator
@@ -55,9 +54,9 @@ public class PeriodicAlertCalculator {
this.alarmCacheManager = alarmCacheManager;
}
public void calculate(AlertDefine define) {
if (!define.isEnable() || StringUtils.isEmpty(define.getExpr())) {
log.error("Periodic define {} is disabled or expression is empty", define.getName());
public void calculate(AlertDefine rule) {
if (!rule.isEnable() || StringUtils.isEmpty(rule.getExpr())) {
log.error("Periodic rule {} is disabled or expression is empty", rule.getName());
return;
}
long currentTimeMilli = System.currentTimeMillis();
@@ -67,8 +66,8 @@ public class PeriodicAlertCalculator {
// the return result should be matched with threshold
try {
List<Map<String, Object>> results = dataSourceService.calculate(
define.getDatasource(),
define.getExpr()
rule.getDatasource(),
rule.getExpr()
);
// if no match the expr threshold, the results item map {'value': null} should be null and others field keep
// if results has multi list, should trigger multi alert
@@ -78,9 +77,8 @@ public class PeriodicAlertCalculator {
for (Map<String, Object> result : results) {
Map<String, String> fingerPrints = new HashMap<>(8);
// here use the alert name as finger, not care the alert name may be changed
fingerPrints.put(CommonConstants.LABEL_DEFINE_ID, String.valueOf(define.getId()));
fingerPrints.put(CommonConstants.LABEL_ALERT_NAME, define.getName());
fingerPrints.putAll(define.getLabels());
fingerPrints.put(CommonConstants.LABEL_ALERT_NAME, rule.getName());
fingerPrints.putAll(rule.getLabels());
for (Map.Entry<String, Object> entry : result.entrySet()) {
if (entry.getValue() != null && !VALUE.equals(entry.getKey())
&& !TIMESTAMP.equals(entry.getKey())) {
@@ -89,33 +87,32 @@ public class PeriodicAlertCalculator {
}
if (result.get(VALUE) == null) {
// recovery the alert
handleRecoveredAlert(define.getId(), fingerPrints);
handleRecoveredAlert(fingerPrints);
continue;
}
Map<String, Object> fieldValueMap = new HashMap<>(8);
fieldValueMap.putAll(define.getLabels());
fieldValueMap.put(CommonConstants.LABEL_ALERT_NAME, define.getName());
fieldValueMap.putAll(rule.getLabels());
fieldValueMap.put(CommonConstants.LABEL_ALERT_NAME, rule.getName());
for (Map.Entry<String, Object> entry : result.entrySet()) {
if (entry.getValue() != null) {
fieldValueMap.put(entry.getKey(), entry.getValue());
}
}
afterThresholdRuleMatch(currentTimeMilli, fingerPrints, fieldValueMap, define);
afterThresholdRuleMatch(currentTimeMilli, fingerPrints, fieldValueMap, rule);
}
} catch (Exception ignored) {
// ignore the query exception eg: no result, timeout, etc
return;
}
} catch (Exception e) {
log.error("Calculate periodic define {} failed: {}", define.getName(), e.getMessage());
log.error("Calculate periodic rule {} failed: {}", rule.getName(), e.getMessage());
}
}
private void afterThresholdRuleMatch(long currentTimeMilli, Map<String, String> fingerPrints,
Map<String, Object> fieldValueMap, AlertDefine define) {
Long defineId = define.getId();
String fingerprint = AlertUtil.calculateFingerprint(fingerPrints);
SingleAlert existingAlert = alarmCacheManager.getPending(defineId, fingerprint);
SingleAlert existingAlert = alarmCacheManager.getPending(fingerprint);
Map<String, String> labels = new HashMap<>(8);
fieldValueMap.putAll(define.getLabels());
labels.putAll(fingerPrints);
@@ -136,11 +133,11 @@ public class PeriodicAlertCalculator {
// If required trigger times is 1, set to firing status directly
if (requiredTimes <= 1) {
newAlert.setStatus(CommonConstants.ALERT_STATUS_FIRING);
alarmCacheManager.putFiring(defineId, fingerprint, newAlert);
alarmCacheManager.putFiring(fingerprint, newAlert);
alarmCommonReduce.reduceAndSendAlarm(newAlert.clone());
} else {
// Otherwise put into pending queue first
alarmCacheManager.putPending(defineId, fingerprint, newAlert);
alarmCacheManager.putPending(fingerprint, newAlert);
}
} else {
// Update existing alert
@@ -150,17 +147,17 @@ public class PeriodicAlertCalculator {
// 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
alarmCacheManager.removePending(defineId, fingerprint);
alarmCacheManager.removePending(fingerprint);
existingAlert.setStatus(CommonConstants.ALERT_STATUS_FIRING);
alarmCacheManager.putFiring(defineId, fingerprint, existingAlert);
alarmCacheManager.putFiring(fingerprint, existingAlert);
alarmCommonReduce.reduceAndSendAlarm(existingAlert.clone());
}
}
}
private void handleRecoveredAlert(Long defineId, Map<String, String> fingerprints) {
private void handleRecoveredAlert(Map<String, String> fingerprints) {
String fingerprint = AlertUtil.calculateFingerprint(fingerprints);
SingleAlert firingAlert = alarmCacheManager.removeFiring(defineId, fingerprint);
SingleAlert firingAlert = alarmCacheManager.removeFiring(fingerprint);
if (firingAlert != null) {
// todo consider multi times to tig for resolved alert
firingAlert.setTriggerTimes(1);
@@ -168,7 +165,7 @@ public class PeriodicAlertCalculator {
firingAlert.setStatus(CommonConstants.ALERT_STATUS_RESOLVED);
alarmCommonReduce.reduceAndSendAlarm(firingAlert.clone());
}
alarmCacheManager.removePending(defineId, fingerprint);
alarmCacheManager.removePending(fingerprint);
}
}
@@ -183,11 +183,9 @@ public class RealTimeAlertCalculator {
if (StringUtils.isBlank(expr)) {
continue;
}
Long defineId = define.getId();
Map<String, String> commonFingerPrints = new HashMap<>(8);
commonFingerPrints.put(CommonConstants.LABEL_INSTANCE, instance);
// here use the alert name as finger, not care the alert name may be changed
commonFingerPrints.put(CommonConstants.LABEL_DEFINE_ID, String.valueOf(define.getId()));
commonFingerPrints.put(CommonConstants.LABEL_ALERT_NAME, define.getName());
commonFingerPrints.put(CommonConstants.LABEL_INSTANCE_NAME, instanceName);
commonFingerPrints.put(CommonConstants.LABEL_INSTANCE_HOST, instanceHost);
@@ -202,9 +200,9 @@ public class RealTimeAlertCalculator {
try {
if (match) {
// If the threshold rule matches, the number of times the threshold has been triggered is determined and an alarm is triggered
afterThresholdRuleMatch(defineId, currentTimeMilli, commonFingerPrints, fieldValueMap, define, annotations);
afterThresholdRuleMatch(currentTimeMilli, commonFingerPrints, fieldValueMap, define, annotations);
} else {
handleRecoveredAlert(defineId, commonFingerPrints);
handleRecoveredAlert(commonFingerPrints);
}
// if this threshold pre compile success, ignore blew
continue;
@@ -256,9 +254,9 @@ public class RealTimeAlertCalculator {
boolean match = execAlertExpression(fieldValueMap, expr, false);
try {
if (match) {
afterThresholdRuleMatch(defineId, currentTimeMilli, fingerPrints, fieldValueMap, define, annotations);
afterThresholdRuleMatch(currentTimeMilli, fingerPrints, fieldValueMap, define, annotations);
} else {
handleRecoveredAlert(defineId, fingerPrints);
handleRecoveredAlert(fingerPrints);
}
} catch (Exception e) {
log.error(e.getMessage(), e);
@@ -336,9 +334,9 @@ public class RealTimeAlertCalculator {
.collect(Collectors.toList());
}
private void handleRecoveredAlert(Long defineId, Map<String, String> fingerprints) {
private void handleRecoveredAlert(Map<String, String> fingerprints) {
String fingerprint = AlertUtil.calculateFingerprint(fingerprints);
SingleAlert firingAlert = alarmCacheManager.removeFiring(defineId, fingerprint);
SingleAlert firingAlert = alarmCacheManager.removeFiring(fingerprint);
if (firingAlert != null) {
// todo consider multi times to tig for resolved alert
firingAlert.setTriggerTimes(1);
@@ -346,14 +344,13 @@ public class RealTimeAlertCalculator {
firingAlert.setStatus(CommonConstants.ALERT_STATUS_RESOLVED);
alarmCommonReduce.reduceAndSendAlarm(firingAlert.clone());
}
alarmCacheManager.removePending(defineId, fingerprint);
alarmCacheManager.removePending(fingerprint);
}
private void afterThresholdRuleMatch(long defineId, long currentTimeMilli, Map<String, String> fingerPrints,
Map<String, Object> fieldValueMap, AlertDefine define,
Map<String, String> annotations) {
private void afterThresholdRuleMatch(long currentTimeMilli, Map<String, String> fingerPrints,
Map<String, Object> fieldValueMap, AlertDefine define, Map<String, String> annotations) {
String fingerprint = AlertUtil.calculateFingerprint(fingerPrints);
SingleAlert existingAlert = alarmCacheManager.getPending(defineId, fingerprint);
SingleAlert existingAlert = alarmCacheManager.getPending(fingerprint);
fieldValueMap.putAll(define.getLabels());
int requiredTimes = define.getTimes() == null ? 1 : define.getTimes();
if (existingAlert == null) {
@@ -385,11 +382,11 @@ public class RealTimeAlertCalculator {
// If required trigger times is 1, set to firing status directly
if (requiredTimes <= 1) {
newAlert.setStatus(CommonConstants.ALERT_STATUS_FIRING);
alarmCacheManager.putFiring(defineId, fingerprint, newAlert);
alarmCacheManager.putFiring(fingerprint, newAlert);
alarmCommonReduce.reduceAndSendAlarm(newAlert.clone());
} else {
// Otherwise put into pending queue first
alarmCacheManager.putPending(define.getId(), fingerprint, newAlert);
alarmCacheManager.putPending(fingerprint, newAlert);
}
} else {
// Update existing alert
@@ -399,9 +396,9 @@ public class RealTimeAlertCalculator {
// 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
alarmCacheManager.removePending(defineId, fingerprint);
alarmCacheManager.removePending(fingerprint);
existingAlert.setStatus(CommonConstants.ALERT_STATUS_FIRING);
alarmCacheManager.putFiring(defineId, fingerprint, existingAlert);
alarmCacheManager.putFiring(fingerprint, existingAlert);
alarmCommonReduce.reduceAndSendAlarm(existingAlert.clone());
}
}
@@ -28,9 +28,6 @@ import org.apache.hertzbeat.alert.dto.ExportAlertDefineDTO;
import org.apache.hertzbeat.alert.service.AlertDefineImExportService;
import org.apache.hertzbeat.alert.service.AlertDefineService;
import org.apache.hertzbeat.common.entity.alerter.AlertDefine;
import org.apache.hertzbeat.common.util.LogUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.util.CollectionUtils;
@@ -44,15 +41,12 @@ public abstract class AlertDefineAbstractImExportServiceImpl implements AlertDef
@Lazy
private AlertDefineService alertDefineService;
private static final Logger logger = LoggerFactory.getLogger(AlertDefineAbstractImExportServiceImpl.class);
@Override
public void importConfig(InputStream is) {
var formList = parseImport(is)
.stream()
.map(this::convert)
.toList();
LogUtil.info(logger, "Importing alert defines from {0}", formList);
if (!CollectionUtils.isEmpty(formList)) {
formList.forEach(alertDefine -> {
alertDefineService.validate(alertDefine, false);
@@ -27,14 +27,11 @@ import org.apache.hertzbeat.common.entity.alerter.NoticeReceiver;
import org.apache.hertzbeat.common.entity.alerter.NoticeTemplate;
import org.apache.hertzbeat.common.support.exception.SendMessageException;
import org.apache.hertzbeat.common.util.JsonUtil;
import org.apache.hertzbeat.common.util.LogUtil;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
@@ -65,7 +62,6 @@ public class AlibabaSmsClientImpl implements SmsClient {
private final String accessKeySecret;
private final String signName;
private final String templateCode;
private static final Logger logger = LoggerFactory.getLogger(AlibabaSmsClientImpl.class);
public AlibabaSmsClientImpl(AlibabaSmsProperties config) {
if (config != null) {
@@ -177,7 +173,7 @@ public class AlibabaSmsClientImpl implements SmsClient {
log.info("Successfully sent SMS to phone: {}", phoneNumber);
}
} catch (Exception e) {
LogUtil.warn(logger, "Failed to send SMS: {0}", e.getMessage());
log.warn("Failed to send SMS: {}", e.getMessage());
throw new SendMessageException(e.getMessage());
}
}
@@ -196,7 +192,6 @@ public class AlibabaSmsClientImpl implements SmsClient {
// Step 4: Build authorization header
return ALGORITHM + " Credential=" + accessKeyId + ",SignedHeaders=host;x-acs-action;x-acs-content-sha256;x-acs-date;" + "x-acs-signature-nonce;x-acs-version,Signature=" + signature;
} catch (Exception e) {
LogUtil.warn(logger, "Failed to calculate authorization {0}", e.getMessage());
throw new RuntimeException("Failed to calculate authorization", e);
}
}
@@ -1,135 +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.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.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.mockito.Mockito.when;
/**
* alert cache manager test
*/
@ExtendWith(MockitoExtension.class)
public class AlarmCacheManagerTest {
@Mock
private SingleAlertDao singleAlertDao;
private AlarmCacheManager alarmCacheManager;
@BeforeEach
public void setUp() {
Map<String, String> labels = new HashMap<>();
labels.put(CommonConstants.LABEL_ALERT_SEVERITY, CommonConstants.ALERT_SEVERITY_CRITICAL);
labels.put(CommonConstants.LABEL_DEFINE_ID, String.valueOf(1L));
SingleAlert alert = new SingleAlert();
alert.setContent("Alert cache manager test");
alert.setLabels(labels);
when(singleAlertDao.querySingleAlertsByStatus(CommonConstants.ALERT_STATUS_FIRING)).thenReturn(Collections.singletonList(alert));
alarmCacheManager = new AlarmCacheManager(singleAlertDao);
}
@Test
void testInit() {
Map<String, String> labels = new HashMap<>();
labels.put(CommonConstants.LABEL_ALERT_SEVERITY, CommonConstants.ALERT_SEVERITY_CRITICAL);
labels.put(CommonConstants.LABEL_DEFINE_ID, String.valueOf(1L));
String fingerprint = AlertUtil.calculateFingerprint(labels);
SingleAlert firingSingleAlert = alarmCacheManager.getFiring(1L, fingerprint);
assertNotNull(firingSingleAlert);
assertEquals("Alert cache manager test", firingSingleAlert.getContent());
alarmCacheManager.removeFiring(1L, fingerprint);
firingSingleAlert = alarmCacheManager.getFiring(1L, fingerprint);
assertNull(firingSingleAlert);
}
@Test
void testPending() {
Map<String, String> labels = new HashMap<>();
labels.put(CommonConstants.LABEL_ALERT_SEVERITY, CommonConstants.ALERT_SEVERITY_CRITICAL);
labels.put(CommonConstants.ALERT_SEVERITY_INFO, CommonConstants.ALERT_STATUS_PENDING);
labels.put(CommonConstants.LABEL_DEFINE_ID, String.valueOf(2L));
SingleAlert alert = new SingleAlert();
alert.setContent("Alert cache manager test");
alert.setLabels(labels);
String fingerprint = AlertUtil.calculateFingerprint(alert.getLabels());
alarmCacheManager.putPending(2L, fingerprint, alert);
SingleAlert pendingSingleAlert = alarmCacheManager.getPending(2L, fingerprint);
assertNotNull(pendingSingleAlert);
alarmCacheManager.removePending(2L, fingerprint);
pendingSingleAlert = alarmCacheManager.getPending(2L, fingerprint);
assertNull(pendingSingleAlert);
}
@Test
void testFiring() {
Map<String, String> labels = new HashMap<>();
labels.put(CommonConstants.LABEL_ALERT_SEVERITY, CommonConstants.ALERT_SEVERITY_CRITICAL);
labels.put(CommonConstants.ALERT_SEVERITY_INFO, CommonConstants.ALERT_STATUS_PENDING);
labels.put(CommonConstants.LABEL_DEFINE_ID, String.valueOf(3L));
SingleAlert alert = new SingleAlert();
alert.setContent("Alert cache manager test");
alert.setLabels(labels);
String fingerprint = AlertUtil.calculateFingerprint(alert.getLabels());
alarmCacheManager.putFiring(3L, fingerprint, alert);
SingleAlert firingSingleAlert = alarmCacheManager.getFiring(3L, fingerprint);
assertNotNull(firingSingleAlert);
alarmCacheManager.removeFiring(3L, fingerprint);
firingSingleAlert = alarmCacheManager.getFiring(3L, fingerprint);
assertNull(firingSingleAlert);
}
@Test
void testHistorical() {
SingleAlert alert = new SingleAlert();
alert.setContent("Alert cache manager test");
alert.setLabels(Collections.singletonMap(CommonConstants.LABEL_ALERT_SEVERITY, CommonConstants.ALERT_SEVERITY_CRITICAL));
when(singleAlertDao.querySingleAlertsByStatus(CommonConstants.ALERT_STATUS_FIRING)).thenReturn(Collections.singletonList(alert));
alarmCacheManager = new AlarmCacheManager(singleAlertDao);
String fingerprint = AlertUtil.calculateFingerprint(alert.getLabels());
SingleAlert historicalSingleAlert = alarmCacheManager.getFiring(4L, fingerprint);
assertNotNull(historicalSingleAlert);
SingleAlert singleAlert = alarmCacheManager.removeFiring(4L, fingerprint);
assertNotNull(singleAlert);
historicalSingleAlert = alarmCacheManager.getFiring(4L, fingerprint);
assertNull(historicalSingleAlert);
}
}
@@ -42,7 +42,6 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -93,12 +92,12 @@ class PeriodicAlertCalculatorTest {
result.put("__value__", 95.0); // Non-null, matched with threshold
result.put("__timestamp__", System.currentTimeMillis());
when(dataSourceService.calculate(anyString(), anyString())).thenReturn(List.of(result));
when(alarmCacheManager.getPending(eq(rule.getId()), anyString())).thenReturn(null);
when(alarmCacheManager.getPending(anyString())).thenReturn(null);
periodicAlertCalculator.calculate(rule);
// Verify that putFiring is called
ArgumentCaptor<String> idCaptor = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<SingleAlert> alertCaptor = ArgumentCaptor.forClass(SingleAlert.class);
verify(alarmCacheManager).putFiring(eq(rule.getId()), idCaptor.capture(), alertCaptor.capture());
verify(alarmCacheManager).putFiring(idCaptor.capture(), alertCaptor.capture());
// Assertion alarm status and content
SingleAlert alert = alertCaptor.getValue();
assertAll(() -> assertEquals(CommonConstants.ALERT_STATUS_FIRING, alert.getStatus()),
@@ -113,7 +112,7 @@ class PeriodicAlertCalculatorTest {
result.put("__timestamp__", System.currentTimeMillis());
when(dataSourceService.calculate(anyString(), anyString())).thenReturn(List.of(result));
periodicAlertCalculator.calculate(rule);
verify(alarmCacheManager, times(0)).putFiring(any(), any(), any());
verify(alarmCacheManager, times(0)).putFiring(any(), any());
}
@Test
@@ -127,7 +126,7 @@ class PeriodicAlertCalculatorTest {
.triggerTimes(2).startAt(System.currentTimeMillis() - 60000)
.activeAt(System.currentTimeMillis() - 30000)
.build();
when(alarmCacheManager.removeFiring(eq(rule.getId()), anyString())).thenReturn(pendingAlert);
when(alarmCacheManager.removeFiring(anyString())).thenReturn(pendingAlert);
when(dataSourceService.calculate(anyString(), anyString())).thenReturn(List.of(result));
periodicAlertCalculator.calculate(rule);
ArgumentCaptor<SingleAlert> resolvedCaptor = ArgumentCaptor.forClass(SingleAlert.class);
@@ -132,7 +132,6 @@ public class RealTimeAlertCalculatorMatchTest {
AlertDefine matchDefine = new AlertDefine();
matchDefine.setId(1L);
matchDefine.setName("test");
matchDefine.setExpr(
"equals(__app__,\"prometheus\") && "
@@ -152,8 +151,8 @@ public class RealTimeAlertCalculatorMatchTest {
Thread.sleep(3000);
verify(alarmCacheManager, times(1)).getPending(any(), any());
verify(alarmCacheManager, times(1)).putFiring(any(), any(), any());
verify(alarmCacheManager, times(1)).getPending(any());
verify(alarmCacheManager, times(1)).putFiring(any(), any());
verify(alarmCommonReduce, times(1)).reduceAndSendAlarm(any());
}
@@ -181,7 +180,6 @@ public class RealTimeAlertCalculatorMatchTest {
CollectRep.MetricsData metricsData = builder.build();
AlertDefine matchDefine = new AlertDefine();
matchDefine.setId(1L);
matchDefine.setName("test");
matchDefine.setExpr("equals(__app__,\"prometheus\") && equals(__metrics__,\"canal_instance\") && metric_value > 0");
matchDefine.setTemplate("Canal instance val: ${value}%");
@@ -196,8 +194,8 @@ public class RealTimeAlertCalculatorMatchTest {
Thread.sleep(3000);
verify(alarmCacheManager, times(1)).getPending(any(), any());
verify(alarmCacheManager, times(1)).putFiring(any(), any(), any());
verify(alarmCacheManager, times(1)).getPending(any());
verify(alarmCacheManager, times(1)).putFiring(any(), any());
verify(alarmCommonReduce, times(1)).reduceAndSendAlarm(any());
}
@@ -231,7 +229,6 @@ public class RealTimeAlertCalculatorMatchTest {
CollectRep.MetricsData metricsData = builder.build();
AlertDefine matchDefine = new AlertDefine();
matchDefine.setId(1L);
matchDefine.setName("test");
matchDefine.setExpr("equals(__app__,\"springboot3\") && equals(__metrics__,\"available\") && equals(__instance__, \"518679137103104\") && responseTime > 0");
matchDefine.setTemplate("Canal instance val: ${value}%");
@@ -246,8 +243,8 @@ public class RealTimeAlertCalculatorMatchTest {
Thread.sleep(3000);
verify(alarmCacheManager, times(1)).getPending(any(), any());
verify(alarmCacheManager, times(1)).putFiring(any(), any(), any());
verify(alarmCacheManager, times(1)).getPending(any());
verify(alarmCacheManager, times(1)).putFiring(any(), any());
verify(alarmCommonReduce, times(1)).reduceAndSendAlarm(any());
}
@@ -42,6 +42,7 @@ import javax.management.remote.JMXServiceURL;
import javax.management.remote.rmi.RMIConnectorServer;
import javax.naming.Context;
import javax.rmi.ssl.SslRMIClientSocketFactory;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.collector.collect.AbstractCollect;
import org.apache.hertzbeat.collector.collect.common.cache.AbstractConnection;
import org.apache.hertzbeat.collector.collect.common.cache.CacheIdentifier;
@@ -53,15 +54,13 @@ import org.apache.hertzbeat.common.entity.job.Metrics;
import org.apache.hertzbeat.common.entity.job.protocol.JmxProtocol;
import org.apache.hertzbeat.common.entity.message.CollectRep;
import org.apache.hertzbeat.common.util.CommonUtil;
import org.apache.hertzbeat.common.util.LogUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* jmx protocol acquisition implementation
*/
@Slf4j
public class JmxCollectImpl extends AbstractCollect {
private static final String JMX_URL_PREFIX = "service:jmx:rmi:///jndi/rmi://";
@@ -76,8 +75,6 @@ public class JmxCollectImpl extends AbstractCollect {
private final ClassLoader jmxClassLoader;
private static final Logger logger = LoggerFactory.getLogger(JmxCollectImpl.class);
public JmxCollectImpl() {
jmxClassLoader = new JmxClassLoader(ClassLoader.getSystemClassLoader());
}
@@ -198,12 +195,12 @@ public class JmxCollectImpl extends AbstractCollect {
}
} catch (IOException exception) {
String errorMsg = CommonUtil.getMessageFromThrowable(exception);
LogUtil.error(logger, "JMX IOException: {0}", errorMsg);
log.error("JMX IOException :{}", errorMsg);
builder.setCode(CollectRep.Code.UN_CONNECTABLE);
builder.setMsg(errorMsg);
} catch (Exception e) {
String errorMsg = CommonUtil.getMessageFromThrowable(e);
LogUtil.error(logger, "JMX Error: {0}", errorMsg);
log.error("JMX Error :{}", errorMsg);
builder.setCode(CollectRep.Code.FAIL);
builder.setMsg(errorMsg);
} finally {
@@ -224,7 +221,7 @@ public class JmxCollectImpl extends AbstractCollect {
for (Attribute attribute : attributeList.asList()) {
Object value = attribute.getValue();
if (value == null) {
LogUtil.info(logger, "attribute {0} value is null.", attribute.getName());
log.info("attribute {} value is null.", attribute.getName());
continue;
}
if (value instanceof Number || value instanceof String || value instanceof ObjectName
@@ -248,7 +245,7 @@ public class JmxCollectImpl extends AbstractCollect {
}
attributeValueMap.put(attribute.getName(), builder.toString());
} else {
LogUtil.warn(logger, "attribute value type {0} not support.", value.getClass().getName());
log.warn("attribute value type {} not support.", value.getClass().getName());
}
}
return attributeValueMap;
@@ -322,7 +319,7 @@ public class JmxCollectImpl extends AbstractCollect {
connectionCommonCache.addCache(identifier, new JmxConnect(conn));
return conn;
} catch (Exception e) {
LogUtil.error(logger, "Failed to connect to JMX connection: {0}", e.getMessage());
log.error("Failed to connect to JMX server: {}", e.getMessage());
throw new IOException("Failed to connect to JMX server: " + e.getMessage(), e);
}
}
@@ -87,11 +87,6 @@ public interface CommonConstants {
*/
String LABEL_INSTANCE = "instance";
/**
* label key: defineid
*/
String LABEL_DEFINE_ID = "defineid";
/**
* label key: alert name
*/
@@ -17,8 +17,6 @@
package org.apache.hertzbeat.common.util;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
@@ -46,7 +44,6 @@ public final class JsonUtil {
OBJECT_MAPPER
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
.registerModule(new JavaTimeModule());
}
@@ -1,167 +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.util;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.slf4j.Logger;
import java.text.MessageFormat;
/**
* Log utility class that provides formatted logging methods with location information.
* This class enhances standard SLF4J logging by automatically adding caller location details.
*/
public class LogUtil {
private static final String TEMPLATE_REGEX = "\\{\\d}";
/**
* Print debug level formatted log
* Example: LogUtil.debug(logger, "hello,{0},here has a {1} exception", "other information");
*/
@SuppressWarnings("unused")
public static void debug(Logger logger, String msg, Object... params) {
if (logger.isDebugEnabled()) {
if (ArrayUtils.isEmpty(params)) {
logger.debug(LogUtil.buildLocationInfo() + msg);
} else {
logger.debug(LogUtil.buildLocationInfo() + format(msg, params));
}
}
}
/**
* Print info level formatted log
* Example: LogUtil.info(logger, "hello,{0},{1} exception", "dear", "database operation");
*/
public static void info(Logger logger, String msg, Object... params) {
if (logger.isInfoEnabled()) {
if (ArrayUtils.isEmpty(params)) {
logger.info(LogUtil.buildLocationInfo() + msg);
} else {
logger.info(LogUtil.buildLocationInfo() + format(msg, params));
}
}
}
/**
* Print warn level formatted log
*/
public static void warn(Logger logger, String msg, Object... params) {
if (logger.isWarnEnabled()) {
if (ArrayUtils.isEmpty(params)) {
logger.warn(LogUtil.buildLocationInfo() + msg);
} else {
logger.warn(LogUtil.buildLocationInfo() + format(msg, params));
}
}
}
/**
* Print error level formatted log, use {0},{1},.. for parameter replacement
* Example: LogUtil.error(logger, "hello,{0}, a {1} exception occurred here", "dear", "database operation");
*/
public static void error(Logger logger, String msg, Object... params) {
if (logger.isErrorEnabled()) {
if (ArrayUtils.isEmpty(params)) {
logger.error(LogUtil.buildLocationInfo() + msg);
} else {
logger.error(LogUtil.buildLocationInfo() + format(msg, params));
}
}
}
/**
* Print warn level formatted log with exception, use {0},{1},.. for parameter replacement
* Example: LogUtil.warn(logger, e, "hello,{0}, a {1} exception occurred here", "dear", "database operation");
*/
public static void warn(Logger logger, Throwable e, String msg, Object... params) {
if (logger.isWarnEnabled()) {
if (ArrayUtils.isEmpty(params)) {
logger.warn(LogUtil.buildLocationInfo() + msg, e);
} else {
logger.warn(LogUtil.buildLocationInfo() + format(msg, params), e);
}
}
}
/**
* Print error level formatted log with exception, use {0},{1},.. for parameter replacement
* Example: LogUtil.error(logger, e, "hello,{0}, a {1} exception occurred here", "dear", "database operation");
*/
public static void error(Logger logger, Throwable e, String msg, Object... params) {
if (logger.isErrorEnabled()) {
if (ArrayUtils.isEmpty(params)) {
logger.error(LogUtil.buildLocationInfo() + msg, e);
} else {
logger.error(LogUtil.buildLocationInfo() + format(msg, params), e);
}
}
}
/**
* Get the class name, method and line number that calls LogUtil
*
* @return location information string
*/
private static String buildLocationInfo() {
StringBuilder header = new StringBuilder();
// LOG4J2-1029 new Throwable().getStackTrace is faster than Thread.currentThread().getStackTrace().
final StackTraceElement[] stackTraceElements = new Throwable().getStackTrace();
for (int i = 0; i < stackTraceElements.length - 1; i++) {
StackTraceElement currentStackTrace = stackTraceElements[i];
StackTraceElement nextStackTrace = stackTraceElements[i + 1];
// If current stack trace is in LogUtil
// and next stack trace is not in LogUtil
// then the next node is the caller of LogUtil
if (LogUtil.class.getName().equals(currentStackTrace.getClassName())
&& !LogUtil.class.getName().equals(nextStackTrace.getClassName())) {
String stackTrace = nextStackTrace.toString();
header.append(" ").append(StringUtils.removeStart(stackTrace, nextStackTrace.getClassName() + "."));
break;
}
}
return header.append(":").toString();
}
private static String format(String msg, Object... params) {
if (StringUtils.isEmpty(msg)) {
return StringUtils.EMPTY;
}
if (params != null && params.length > 0) {
msg = MessageFormat.format(msg, params);
}
return msg.replaceAll(TEMPLATE_REGEX, StringUtils.EMPTY);
}
private static String toString(Object object) {
return ToStringBuilder.reflectionToString(object, ToStringStyle.SHORT_PREFIX_STYLE);
}
}
@@ -1,117 +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.util;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.slf4j.Logger;
import java.lang.reflect.Method;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.contains;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
class LogUtilTest {
@Mock
private Logger mockLogger;
private AutoCloseable mocks;
@BeforeEach
void setUp() {
mocks = MockitoAnnotations.openMocks(this);
}
@AfterEach
void tearDown() throws Exception {
if (mocks != null) {
mocks.close();
}
}
@Test
void testFormat_noParams_returnsOriginalMessage() throws Exception {
String original = "hello world";
Method formatMethod = LogUtil.class.getDeclaredMethod("format", String.class, Object[].class);
formatMethod.setAccessible(true);
String formatted = (String) formatMethod.invoke(null, original, new Object[0]);
assertEquals(original, formatted);
}
@Test
void testFormat_withParams_replacesPlaceholders() throws Exception {
String template = "hello,{0}, world {1}!";
Method formatMethod = LogUtil.class.getDeclaredMethod("format", String.class, Object[].class);
formatMethod.setAccessible(true);
Object[] params = {"Alice", 123};
String result = (String) formatMethod.invoke(null, template, params);
assertTrue(result.contains("hello,Alice"));
assertTrue(result.contains("world 123!"));
}
@Test
void testDebug_noParams_logsRawMessage() {
when(mockLogger.isDebugEnabled()).thenReturn(true);
String msg = "test-debug";
LogUtil.debug(mockLogger, msg);
verify(mockLogger).debug(contains(msg));
}
@Test
void testDebug_withParams_logsFormattedMessage() {
when(mockLogger.isDebugEnabled()).thenReturn(true);
LogUtil.debug(mockLogger, "user={0}", "Bob");
verify(mockLogger).debug(contains("user=Bob"));
}
@Test
void testInfo_levelOff_doesNotLog() {
when(mockLogger.isInfoEnabled()).thenReturn(false);
LogUtil.info(mockLogger, "should-not-log");
verify(mockLogger, never()).info(anyString());
}
@Test
void testWarn_withException_logsMessageAndException() {
when(mockLogger.isWarnEnabled()).thenReturn(true);
RuntimeException ex = new RuntimeException("warn-ex");
LogUtil.warn(mockLogger, ex, "warning {0}", "occurred");
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
verify(mockLogger).warn(captor.capture(), eq(ex));
assertTrue(captor.getValue().contains("warning occurred"));
}
@Test
void testError_withExceptionAndParams_logsError() {
when(mockLogger.isErrorEnabled()).thenReturn(true);
RuntimeException ex = new RuntimeException("err");
LogUtil.error(mockLogger, ex, "fail code {0}", 500);
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
verify(mockLogger).error(captor.capture(), eq(ex));
assertTrue(captor.getValue().contains("fail code 500"));
}
}
@@ -121,14 +121,6 @@ public class MonitorsController {
monitorService.export(ids, type, res);
}
@GetMapping("/export/all")
@Operation(summary = "export all monitor config", description = "export all monitor config")
public void exportAll(
@Parameter(description = "Export Type:JSON,EXCEL,YAML") @RequestParam(defaultValue = "JSON") String type,
HttpServletResponse res) throws Exception {
monitorService.exportAll(type, res);
}
@PostMapping("/import")
@Operation(summary = "import monitor config", description = "import monitor config")
public ResponseEntity<Message<Void>> export(MultipartFile file) throws Exception {
@@ -173,15 +173,6 @@ public interface MonitorService {
*/
void export(List<Long> ids, String type, HttpServletResponse res) throws Exception;
/**
* Export All Monitoring Configuration
*
* @param type file type
* @param res response
* @throws Exception This exception will be thrown if the export fails
*/
void exportAll(String type, HttpServletResponse res) throws Exception;
/**
* Import Monitoring Configuration
*
@@ -235,18 +235,6 @@ public class MonitorServiceImpl implements MonitorService {
imExportService.exportConfig(res.getOutputStream(), ids);
}
@Override
public void exportAll(String type, HttpServletResponse res) throws Exception {
// Get all monitor IDs from the database
List<Long> allMonitorIds = monitorDao.findAll()
.stream()
.map(Monitor::getId)
.collect(Collectors.toList());
// Use the existing export method to export all monitors
export(allMonitorIds, type, res);
}
@Override
public void importConfig(MultipartFile file) throws Exception {
var fileName = FileUtil.getFileName(file);
@@ -21,13 +21,11 @@ app: jvm
name:
zh-CN: JVM虚拟机
en-US: JVM
ja-JP: Java仮想マシン
# The description and help of this monitoring type
help:
zh-CN: HertzBeat 使用 <a href="https://hertzbeat.apache.org/docs/advanced/extend-jmx">JMX 协议</a> 对 JVM 虚拟机的通用性能指标(基础信息,内存池,类加载,线程信息等)进行采集监控。<br>⚠️注意:您需要在 JVM 应用中开启 JMX 服务,应用启动时添加 JMX 参数, 可自定义暴露端口,对外IP。<a href="https://docs.oracle.com/javase/1.5.0/docs/guide/management/agent.html#remote">点击查看开启步骤</a>。
en-US: HertzBeat uses <a href='https://hertzbeat.apache.org/docs/advanced/extend-jmx'>JMX Protocol</a> to monitoring and collect general performance metric of jvm application. <br>⚠️Note:You need to enable JMX services in JVM application, and add the JXM parameters when the application start. You can also customize external IP address and exposed port.<a href='https://docs.oracle.com/javase/1.5.0/docs/guide/management/agent.html#remote'>Click here to view the activation steps.</a>"
zh-TW: HertzBeat 使用 <a href="https://hertzbeat.apache.org/docs/advanced/extend-jmx">JMX 協議</a> 對 JVM 虛擬機的通用性能指標(基礎信息,內存池,類加載,線程信息等)進行采集監控。<br>⚠️注意:您需要在 JVM 應用中開啓 JMX 服務,應用啓動時添加 JMX 參數, 可自定義暴露端口,對外IP。<a href="https://docs.oracle.com/javase/1.5.0/docs/guide/management/agent.html#remote">點擊查看開啓步驟</a>。
ja-JP: HertzBeat は <a href='https://hertzbeat.apache.org/docs/advanced/extend-jmx'> JMXプロトコルを介して</a> Java仮想マシンの一般的なパフォーマンスのメトリクスを監視します。<br>⚠️注意:Java仮想マシンの応用 で JMX サービスを有効にする必要があります。<a href='https://docs.oracle.com/javase/1.5.0/docs/guide/management/agent.html#remote'>クリックしてガイドを見ます</a>。
helpLink:
zh-CN: https://hertzbeat.apache.org/zh-cn/docs/help/jvm/
en-US: https://hertzbeat.apache.org/docs/help/jvm/
@@ -39,7 +37,6 @@ params:
name:
zh-CN: 目标Host
en-US: Target Host
ja-JP: 目標ホスト
# type-param field type(most mapping the html input type)
type: host
# required-true or false
@@ -50,7 +47,6 @@ params:
name:
zh-CN: 端口
en-US: Port
ja-JP: ポート
# type-param field type(most mapping the html input type)
type: number
# when type is number, range is required
@@ -65,7 +61,6 @@ params:
name:
zh-CN: JMX URL
en-US: JMX URL
ja-JP: JMX URL
# type-param field type(most mapping the html input type)
type: text
# required-true or false
@@ -80,7 +75,6 @@ params:
name:
zh-CN: 用户名
en-US: Username
ja-JP: ユーザー名
# type-param field type(most mapping the html input type)
type: text
# when type is text, use limit to limit string length
@@ -95,7 +89,6 @@ params:
name:
zh-CN: 密码
en-US: Password
ja-JP: パスワード
# type-param field type(most mapping the html input tag)
type: password
# required-true or false
@@ -112,7 +105,6 @@ metrics:
i18n:
zh-CN: 虚拟机基础信息
en-US: JVM Basic
ja-JP: Java仮想マシン基礎情報
# collect metrics content
fields:
# field-metric name, type-metric type(0-number,1-string), unit-metric unit('%','ms','MB'), label-whether it is a metrics label field
@@ -121,26 +113,22 @@ metrics:
i18n:
zh-CN: 名称
en-US: Vm Name
ja-JP: 仮想マシン名
- field: VmVendor
type: 1
i18n:
zh-CN: 厂商
en-US: Vm Vendor
ja-JP: 仮想マシンベンダー
- field: VmVersion
type: 1
i18n:
zh-CN: 版本
en-US: Vm Version
ja-JP: 仮想マシンバージョン
- field: Uptime
type: 0
unit: ms
i18n:
zh-CN: 运行时长
en-US: Up time
ja-JP: アップタイム
# the protocol used for monitoring, eg: sql, ssh, http, telnet, wmi, snmp, sdk
protocol: jmx
# the config content when protocol is jmx
@@ -160,7 +148,6 @@ metrics:
i18n:
zh-CN: 内存池
en-US: Memory Pool
ja-JP: メモリプール
fields:
- field: name
type: 1
@@ -168,35 +155,30 @@ metrics:
i18n:
zh-CN: 指标名称
en-US: Name
ja-JP: メトリクス名
- field: committed
type: 0
unit: MB
i18n:
zh-CN: 已分配内存
en-US: Committed
ja-JP: コミットされたメモリ
- field: init
type: 0
unit: MB
i18n:
zh-CN: 初始化内存
en-US: Init
ja-JP: イニシャルメモリ
- field: max
type: 0
unit: MB
i18n:
zh-CN: 最大内存
en-US: Max
ja-JP: 最大メモリ
- field: used
type: 0
unit: MB
i18n:
zh-CN: 已使用内存
en-US: Used
ja-JP: 使用したメモリ
units:
- committed=B->MB
- init=B->MB
@@ -233,32 +215,27 @@ metrics:
i18n:
zh-CN: 本地代码缓冲区
en-US: Code Cache
ja-JP: コードキャッシュ
fields:
- field: committed
type: 0
i18n:
zh-CN: 已分配内存
en-US: Committed
ja-JP: コミットされたメモリ
- field: init
type: 0
i18n:
zh-CN: 初始化内存
en-US: Init
ja-JP: イニシャルメモリ
- field: max
type: 0
i18n:
zh-CN: 最大内存
en-US: Max
ja-JP: 最大メモリ
- field: used
type: 0
i18n:
zh-CN: 已使用内存
en-US: Used
ja-JP: 使用したメモリ
aliasFields:
- Usage->committed
- Usage->init
@@ -285,7 +262,6 @@ metrics:
i18n:
zh-CN: 类加载信息
en-US: Class Loading
ja-JP: クラスローディング情報
# collect metrics content
fields:
# field-metric name, type-metric type(0-number,1-string), unit-metric unit('%','ms','MB'), label-whether it is a metrics label field
@@ -294,19 +270,16 @@ metrics:
i18n:
zh-CN: 当前已加载类数量
en-US: Loaded Class Count
ja-JP: ロードされたクラス数
- field: TotalLoadedClassCount
type: 0
i18n:
zh-CN: 已加载类总数量
en-US: Total Loaded Class Count
ja-JP: ロードされたクラス総数
- field: UnloadedClassCount
type: 0
i18n:
zh-CN: 未加载类总数量
en-US: Unloaded Class Count
ja-JP: アンロードされたクラス総数
protocol: jmx
jmx:
host: ^_^host^_^
@@ -321,7 +294,6 @@ metrics:
i18n:
zh-CN: 线程信息
en-US: Thread
ja-JP: スレッド情報
# collect metrics content
fields:
# field-metric name, type-metric type(0-number,1-string), unit-metric unit('%','ms','MB'), label-whether it is a metrics label field
@@ -330,39 +302,33 @@ metrics:
i18n:
zh-CN: 已启动线程总数
en-US: Total Started Thread Count
ja-JP: スレッド総数
- field: ThreadCount
type: 0
i18n:
zh-CN: 活跃线程数
en-US: Thread Count
ja-JP: 活躍スレッド数
- field: PeakThreadCount
type: 0
i18n:
zh-CN: 最大峰值线程数
en-US: Peak Thread Count
ja-JP: 最大スレッド数
- field: DaemonThreadCount
type: 0
i18n:
zh-CN: 活跃守护线程数
en-US: Daemon Thread Count
ja-JP: デーモンスレッド数
- field: CurrentThreadUserTime
type: 0
unit: s
i18n:
zh-CN: 线程占用的CPU时间(用户态)
en-US: Current Thread User Time
ja-JP: 現在のスレッドユーザー時間
- field: CurrentThreadCpuTime
type: 0
unit: s
i18n:
zh-CN: 线程占用的CPU时间
en-US: Current Thread CPU Time
ja-JP: 現在のスレッドシステム時間
units:
- CurrentThreadUserTime=NS->S
- CurrentThreadCpuTime=NS->S
@@ -21,13 +21,11 @@ app: kafka
name:
zh-CN: Kafka消息系统
en-US: Kafka Message
ja-JP: Kafkaメッセージングシステム
# The description and help of this monitoring type
help:
zh-CN: HertzBeat 使用 <a href="https://hertzbeat.apache.org/docs/advanced/extend-jmx">JMX 协议</a> 对 Kafka 的通用性能指标 (server info、code cache、active controller count、broker partition count、broker leader count、broker handler avg percent etc) 进行采集监控。<br><span class='help_module_span'>注意⚠️:您需要在 Kafka 开启 JMX 服务,应用启动时添加 JMX 参数,暴露端口,对外IP。下方配置的端口即为JMX暴露的端口,而非Kafka的server端口。<a class='help_module_content' href='https://hertzbeat.apache.org/zh-cn/docs/help/kafka'>点击查看开启步骤</a>。</span>
en-US: HertzBeat uses <a href='https://hertzbeat.apache.org/docs/advanced/extend-jmx'>JMX Protocol</a> to monitoring kafka general performance metrics (server info、code cache、active controller count、broker partition count、broker leader count、broker handler avg percent etc). <br><span class='help_module_span'>Note⚠️:You need to enable JMX service in Kafka, export JMX port and config params.The port configured below is the JMX exposed port, not the Kafka server port. <a class='help_module_content' href='https://hertzbeat.apache.org/docs/help/kafka'>Click here to view the specific steps.</a></span>
zh-TW: HertzBeat 使用 <a href="https://hertzbeat.apache.org/docs/advanced/extend-jmx">JMX 協議</a> 對 Kafka 的通用性能指標 (server info、code cache、active controller count、broker partition count、broker leader count、broker handler avg percent etc) 進行采集監控。<br><span class='help_module_span'>注意⚠️:您需要在 Kafka 開啓 JMX 服務,應用啓動時添加 JMX 參數,暴露端口,對外IP。下方配置的端口即為 JMX 暴露的端口,而非 Kafka 的伺服器端口。<a class='help_module_content' href='https://hertzbeat.apache.org/zh-cn/docs/help/kafka'>點擊查看開啓步驟</a>。</span>
ja-JP: HertzBeat は <a href='https://hertzbeat.apache.org/docs/advanced/extend-jmx'> JMXプロトコルを介して</a> Kafkaの一般的なパフォーマンスのメトリクスを監視します。<br><span class='help_module_span'>⚠️注意:Kafka で JMX サービスを有効にする必要があります。<a class='help_module_content' href='https://hertzbeat.apache.org/docs/help/kafka'>クリックしてガイドを見ます</a>。</span>
helpLink:
zh-CN: https://hertzbeat.apache.org/zh-cn/docs/help/kafka
en-US: https://hertzbeat.apache.org/docs/help/kafka
@@ -39,7 +37,6 @@ params:
name:
zh-CN: 目标Host
en-US: Target Host
ja-JP: 目標ホスト
# type-param field type(most mapping the html input type)
type: host
# required-true or false
@@ -48,7 +45,6 @@ params:
name:
zh-CN: 端口
en-US: Port
ja-JP: ポート
type: number
# when type is number, range is required
range: '[0,65535]'
@@ -58,7 +54,6 @@ params:
name:
zh-CN: JMX URL
en-US: JMX URL
ja-JP: JMX URL
type: text
required: false
hide: true
@@ -67,7 +62,6 @@ params:
name:
zh-CN: 用户名
en-US: Username
ja-JP: ユーザー名
type: text
limit: 50
required: false
@@ -76,7 +70,6 @@ params:
name:
zh-CN: 密码
en-US: Password
ja-JP: パスワード
type: password
required: false
hide: true
@@ -87,7 +80,6 @@ metrics:
i18n:
zh-CN: 服务器信息
en-US: Server Info
ja-JP: サーバー情報
# metrics scheduling priority(0->127)->(high->low), metrics with the same priority will be scheduled in parallel
# priority 0's metrics is availability metrics, it will be scheduled first, only availability metrics collect success will the scheduling continue
priority: 0
@@ -99,19 +91,16 @@ metrics:
i18n:
zh-CN: 版本
en-US: Version
ja-JP: バージョン
- field: StartTimeMs
type: 1
i18n:
zh-CN: 启动时间
en-US: Start Time
ja-JP: 起動時間
- field: CommitId
type: 1
i18n:
zh-CN: CommitId
en-US: CommitId
ja-JP: CommitId
# the protocol used for monitoring, eg: sql, ssh, http, telnet, wmi, snmp, sdk
protocol: jmx
# the config content when protocol is jmx
@@ -129,7 +118,6 @@ metrics:
i18n:
zh-CN: 虚拟机基础信息
en-US: JVM Basic
ja-JP: Java仮想マシン基礎情報
priority: 1
fields:
- field: VmName
@@ -137,26 +125,22 @@ metrics:
i18n:
zh-CN: 名称
en-US: Vm Name
ja-JP: 仮想マシン名
- field: VmVendor
type: 1
i18n:
zh-CN: 厂商
en-US: Vm Vendor
ja-JP: 仮想マシンベンダー
- field: VmVersion
type: 1
i18n:
zh-CN: 版本
en-US: Vm Version
ja-JP: 仮想マシンバージョン
- field: Uptime
type: 0
unit: ms
i18n:
zh-CN: 运行时长
en-US: Up time
ja-JP: アップタイム
protocol: jmx
jmx:
host: ^_^host^_^
@@ -171,7 +155,6 @@ metrics:
i18n:
zh-CN: 内存池
en-US: Memory Pool
ja-JP: メモリプール
priority: 2
fields:
- field: name
@@ -180,31 +163,26 @@ metrics:
i18n:
zh-CN: 指标名称
en-US: Name
ja-JP: メトリクス名
- field: committed
type: 0
i18n:
zh-CN: 已分配内存
en-US: Committed
ja-JP: コミットされたメモリ
- field: init
type: 0
i18n:
zh-CN: 初始化内存
en-US: Init
ja-JP: イニシャルメモリ
- field: max
type: 0
i18n:
zh-CN: 最大内存
en-US: Max
ja-JP: 最大メモリ
- field: used
type: 0
i18n:
zh-CN: 已使用内存
en-US: Used
ja-JP: 使用したメモリ
aliasFields:
- Name
- Usage->committed
@@ -230,7 +208,6 @@ metrics:
i18n:
zh-CN: Kafka控制器指标
en-US: Kafka Controller Metrics
ja-JP: Kafkaコントローラーのメトリクス
priority: 3
fields:
- field: ActiveBrokerCount
@@ -238,79 +215,66 @@ metrics:
i18n:
zh-CN: 活跃代理数量
en-US: Active Broker Count
ja-JP: 活動中のブローカー数
- field: ActiveControllerCount
type: 0
i18n:
zh-CN: 活跃控制器数量
en-US: Active Controller Count
ja-JP: 活動中のコントローラー数
- field: ControllerState
type: 0
i18n:
zh-CN: 控制器状态
en-US: Controller State
ja-JP: コントローラー状態
- field: FencedBrokerCount
type: 0
i18n:
zh-CN: 被隔离代理数量
en-US: Fenced Broker Count
ja-JP: フェンスのブローカー数
- field: GlobalPartitionCount
type: 0
i18n:
zh-CN: 全局分区数量
en-US: Global Partition Count
ja-JP: パーティション数
- field: GlobalTopicCount
type: 0
i18n:
zh-CN: 全局主题数量
en-US: Global Topic Count
ja-JP: トピック数
- field: OfflinePartitionsCount
type: 0
i18n:
zh-CN: 离线分区数量
en-US: Offline Partitions Count
ja-JP: オフラインのパーティション数
- field: PreferredReplicaImbalanceCount
type: 0
i18n:
zh-CN: 首选副本不平衡数量
en-US: Preferred Replica Imbalance Count
ja-JP: 優先レプリカ不均衡数
- field: ReplicasIneligibleToDeleteCount
type: 0
i18n:
zh-CN: 不能删除的副本数量
en-US: Replicas Ineligible To Delete Count
ja-JP: 削除できないレプリカ数
- field: ReplicasToDeleteCount
type: 0
i18n:
zh-CN: 待删除副本数量
en-US: Replicas To Delete Count
ja-JP: 削除待ちのレプリカ数
- field: TopicsIneligibleToDeleteCount
type: 0
i18n:
zh-CN: 不能删除的主题数量
en-US: Topics Ineligible To Delete Count
ja-JP: 削除できないトピック数
- field: TopicsToDeleteCount
type: 0
i18n:
zh-CN: 待删除主题数量
en-US: Topics To Delete Count
ja-JP: 削除待ちのトピック数
- field: ZkMigrationState
type: 0
i18n:
zh-CN: ZooKeeper迁移状态
en-US: Zk Migration State
ja-JP: ZooKeeperマイグレーション状態
aliasFields:
- Value->ActiveBrokerCount
- Value->ActiveControllerCount
@@ -354,7 +318,6 @@ metrics:
i18n:
zh-CN: Broker处理器平均百分比
en-US: Broker Handler Avg Percent
ja-JP: ブローカーハンドラの平均パーセント
priority: 6
fields:
- field: EventType
@@ -362,43 +325,36 @@ metrics:
i18n:
zh-CN: 事件类型
en-US: Event Type
ja-JP: イベントタイプ
- field: RateUnit
type: 1
i18n:
zh-CN: 速率单位
en-US: Rate Unit
ja-JP: レート単位
- field: Count
type: 0
i18n:
zh-CN: 计数
en-US: Count
ja-JP: カウント
- field: MeanRate
type: 0
i18n:
zh-CN: 平均速率
en-US: Mean Rate
ja-JP: 平均レート
- field: OneMinuteRate
type: 0
i18n:
zh-CN: 一分钟速率
en-US: One Minute Rate
ja-JP: 1分間のレート
- field: FiveMinuteRate
type: 0
i18n:
zh-CN: 五分钟速率
en-US: Five Minute Rate
ja-JP: 5分間のレート
- field: FifteenMinuteRate
type: 0
i18n:
zh-CN: 十五分钟速率
en-US: Fifteen Minute Rate
ja-JP: 15分間のレート
protocol: jmx
jmx:
host: ^_^host^_^
@@ -413,7 +369,6 @@ metrics:
i18n:
zh-CN: Kafka副本管理器指标
en-US: Kafka Replica Manager Metrics
ja-JP: Kafkaレプリカマネジャーのメトリクス
priority: 6
fields:
- field: AtMinIsrPartitionCount
@@ -421,73 +376,61 @@ metrics:
i18n:
zh-CN: 达到最小ISR的分区数
en-US: At Min ISR Partition Count
ja-JP: 最小ISRパーティション数
- field: FailedIsrUpdatesPerSec
type: 0
i18n:
zh-CN: 每秒失败ISR更新数
en-US: Failed ISR Updates Per Sec
ja-JP: 1秒あたりのISR更新失敗数
- field: IsrExpandsPerSec
type: 0
i18n:
zh-CN: 每秒ISR扩展数
en-US: ISR Expands Per Sec
ja-JP: 1秒あたりのISR拡張数
- field: IsrShrinksPerSec
type: 0
i18n:
zh-CN: 每秒ISR收缩数
en-US: ISR Shrinks Per Sec
ja-JP: 1秒あたりのISR収縮数
- field: LeaderCount
type: 0
i18n:
zh-CN: 领导者数量
en-US: Leader Count
ja-JP: リーダー数
- field: OfflineReplicaCount
type: 0
i18n:
zh-CN: 离线副本数量
en-US: Offline Replica Count
ja-JP: オフラインのレプリカ数
- field: PartitionCount
type: 0
i18n:
zh-CN: 分区总数
en-US: Partition Count
ja-JP: パーティション数
- field: PartitionsWithLateTransactionsCount
type: 0
i18n:
zh-CN: 含有延迟交易的分区数
en-US: Partitions With Late Transactions Count
ja-JP: 遅いトランザクションのあるパーティション数
- field: ProducerIdCount
type: 0
i18n:
zh-CN: 生产者ID数量
en-US: Producer ID Count
ja-JP: 生産者ID数
- field: ReassigningPartitions
type: 0
i18n:
zh-CN: 正在重新分配的分区数
en-US: Reassigning Partitions
ja-JP: 再割り当てのパーティション数
- field: UnderMinIsrPartitionCount
type: 0
i18n:
zh-CN: 低于最小ISR的分区数
en-US: Under Min ISR Partition Count
ja-JP: 最小ISR未満のパーティション数
- field: UnderReplicatedPartitions
type: 0
i18n:
zh-CN: 副本数低于预期的分区数量
en-US: Under Replicated Partitions
ja-JP: レプリカ未満のパーティション数
aliasFields:
- Value->LeaderCount
- Value->AtMinIsrPartitionCount
@@ -529,7 +472,6 @@ metrics:
i18n:
zh-CN: 每秒主题流入字节
en-US: Total Bytes In Per Second
ja-JP: 1秒あたりのトピック合計受信されたバイト
priority: 7
fields:
- field: EventType
@@ -537,43 +479,36 @@ metrics:
i18n:
zh-CN: 事件类型
en-US: Event Type
ja-JP: イベントタイプ
- field: RateUnit
type: 1
i18n:
zh-CN: 速率单位
en-US: Rate Unit
ja-JP: レート単位
- field: MeanRate
type: 0
i18n:
zh-CN: 平均速率
en-US: Mean Rate
ja-JP: 平均レート
- field: OneMinuteRate
type: 0
i18n:
zh-CN: 一分钟速率
en-US: One Minute Rate
ja-JP: 1分間のレート
- field: FiveMinuteRate
type: 0
i18n:
zh-CN: 五分钟速率
en-US: Five Minute Rate
ja-JP: 5分間のレート
- field: FifteenMinuteRate
type: 0
i18n:
zh-CN: 十五分钟速率
en-US: Fifteen Minute Rate
ja-JP: 15分間のレート
- field: Count
type: 0
i18n:
zh-CN: 计数
en-US: Count
ja-JP: カウント
protocol: jmx
jmx:
host: ^_^host^_^
@@ -588,7 +523,6 @@ metrics:
i18n:
zh-CN: 各主题每秒流入字节
en-US: Bytes In Per Topic Per Second
ja-JP: 各トピックの1秒あたりの受信されたバイト
priority: 7
fields:
- field: topic
@@ -596,49 +530,41 @@ metrics:
i18n:
zh-CN: 主题名称
en-US: Topic Name
ja-JP: トピック名
- field: EventType
type: 1
i18n:
zh-CN: 事件类型
en-US: Event Type
ja-JP: イベントタイプ
- field: RateUnit
type: 1
i18n:
zh-CN: 速率单位
en-US: Rate Unit
ja-JP: レート単位
- field: MeanRate
type: 0
i18n:
zh-CN: 平均速率
en-US: Mean Rate
ja-JP: 平均レート
- field: OneMinuteRate
type: 0
i18n:
zh-CN: 一分钟速率
en-US: One Minute Rate
ja-JP: 1分間のレート
- field: FiveMinuteRate
type: 0
i18n:
zh-CN: 五分钟速率
en-US: Five Minute Rate
ja-JP: 5分間のレート
- field: FifteenMinuteRate
type: 0
i18n:
zh-CN: 十五分钟速率
en-US: Fifteen Minute Rate
ja-JP: 15分間のレート
- field: Count
type: 0
i18n:
zh-CN: 计数
en-US: Count
ja-JP: カウント
protocol: jmx
jmx:
host: ^_^host^_^
@@ -653,7 +579,6 @@ metrics:
i18n:
zh-CN: 主题每秒流出字节
en-US: Total Bytes Out Per Second
ja-JP: 1秒あたりのトピック合計転送されたバイト
priority: 8
fields:
- field: EventType
@@ -661,43 +586,36 @@ metrics:
i18n:
zh-CN: 事件类型
en-US: Event Type
ja-JP: イベントタイプ
- field: RateUnit
type: 1
i18n:
zh-CN: 速率单位
en-US: Rate Unit
ja-JP: レート単位
- field: MeanRate
type: 0
i18n:
zh-CN: 平均速率
en-US: Mean Rate
ja-JP: 平均レート
- field: OneMinuteRate
type: 0
i18n:
zh-CN: 一分钟速率
en-US: One Minute Rate
ja-JP: 1分間のレート
- field: FiveMinuteRate
type: 0
i18n:
zh-CN: 五分钟速率
en-US: Five Minute Rate
ja-JP: 5分間のレート
- field: FifteenMinuteRate
type: 0
i18n:
zh-CN: 十五分钟速率
en-US: Fifteen Minute Rate
ja-JP: 15分間のレート
- field: Count
type: 0
i18n:
zh-CN: 计数
en-US: Count
ja-JP: カウント
protocol: jmx
jmx:
host: ^_^host^_^
@@ -712,7 +630,6 @@ metrics:
i18n:
zh-CN: 各主题每秒流出字节
en-US: Bytes Out Per Topic Per Second
ja-JP: 各トピックの1秒あたりの転送されたバイト
priority: 9
fields:
- field: topic
@@ -720,49 +637,41 @@ metrics:
i18n:
zh-CN: 主题名称
en-US: Topic Name
ja-JP: トピック名
- field: EventType
type: 1
i18n:
zh-CN: 事件类型
en-US: Event Type
ja-JP: イベントタイプ
- field: RateUnit
type: 1
i18n:
zh-CN: 速率单位
en-US: Rate Unit
ja-JP: レート単位
- field: MeanRate
type: 0
i18n:
zh-CN: 平均速率
en-US: Mean Rate
ja-JP: 平均レート
- field: OneMinuteRate
type: 0
i18n:
zh-CN: 一分钟速率
en-US: One Minute Rate
ja-JP: 1分間のレート
- field: FiveMinuteRate
type: 0
i18n:
zh-CN: 五分钟速率
en-US: Five Minute Rate
ja-JP: 5分間のレート
- field: FifteenMinuteRate
type: 0
i18n:
zh-CN: 十五分钟速率
en-US: Fifteen Minute Rate
ja-JP: 15分間のレート
- field: Count
type: 0
i18n:
zh-CN: 计数
en-US: Count
ja-JP: カウント
protocol: jmx
jmx:
host: ^_^host^_^
@@ -777,7 +686,6 @@ metrics:
i18n:
zh-CN: 每秒生产消息转换
en-US: Produce Message Conversions PerSec
ja-JP: 1秒あたりのメッセージ変換数
priority: 9
fields:
- field: EventType
@@ -785,43 +693,36 @@ metrics:
i18n:
zh-CN: 事件类型
en-US: Event Type
ja-JP: イベントタイプ
- field: RateUnit
type: 1
i18n:
zh-CN: 速率单位
en-US: Rate Unit
ja-JP: レート単位
- field: MeanRate
type: 0
i18n:
zh-CN: 平均速率
en-US: Mean Rate
ja-JP: 平均レート
- field: OneMinuteRate
type: 0
i18n:
zh-CN: 一分钟速率
en-US: One Minute Rate
ja-JP: 1分間のレート
- field: FiveMinuteRate
type: 0
i18n:
zh-CN: 五分钟速率
en-US: Five Minute Rate
ja-JP: 5分間のレート
- field: FifteenMinuteRate
type: 0
i18n:
zh-CN: 十五分钟速率
en-US: Fifteen Minute Rate
ja-JP: 15分間のレート
- field: Count
type: 0
i18n:
zh-CN: 计数
en-US: Count
ja-JP: カウント
protocol: jmx
jmx:
host: ^_^host^_^
@@ -836,7 +737,6 @@ metrics:
i18n:
zh-CN: 每秒生产总请求数
en-US: Produce Total Requests PerSec
ja-JP: 1秒あたりの合計リクエスト数
priority: 10
fields:
- field: EventType
@@ -844,43 +744,36 @@ metrics:
i18n:
zh-CN: 事件类型
en-US: Event Type
ja-JP: イベントタイプ
- field: RateUnit
type: 1
i18n:
zh-CN: 速率单位
en-US: Rate Unit
ja-JP: レート単位
- field: MeanRate
type: 0
i18n:
zh-CN: 平均速率
en-US: Mean Rate
ja-JP: 平均レート
- field: OneMinuteRate
type: 0
i18n:
zh-CN: 一分钟速率
en-US: One Minute Rate
ja-JP: 1分間のレート
- field: FiveMinuteRate
type: 0
i18n:
zh-CN: 五分钟速率
en-US: Five Minute Rate
ja-JP: 5分間のレート
- field: FifteenMinuteRate
type: 0
i18n:
zh-CN: 十五分钟速率
en-US: Fifteen Minute Rate
ja-JP: 15分間のレート
- field: Count
type: 0
i18n:
zh-CN: 计数
en-US: Count
ja-JP: カウント
protocol: jmx
jmx:
host: ^_^host^_^
@@ -895,7 +788,6 @@ metrics:
i18n:
zh-CN: Kafka消费者组指标
en-US: Kafka Group Metrics
ja-JP: Kafka消費者グループメトリクス
priority: 11
fields:
- field: NumGroups
@@ -903,43 +795,36 @@ metrics:
i18n:
zh-CN: 群组数量
en-US: Num Groups
ja-JP: 消費者グループ総数
- field: NumGroupsCompletingRebalance
type: 0
i18n:
zh-CN: 正在完成重新平衡的群组数量
en-US: Num Groups Completing Rebalance
ja-JP: リバランス中の消費者グループ数
- field: NumGroupsDead
type: 0
i18n:
zh-CN: 死亡群组数量
en-US: Num Groups Dead
ja-JP: デッドの消費者グループ数
- field: NumGroupsEmpty
type: 0
i18n:
zh-CN: 空群组数量
en-US: Num Groups Empty
ja-JP: 空の消費者グループ数
- field: NumGroupsPreparingRebalance
type: 0
i18n:
zh-CN: 正在准备重新平衡的群组数量
en-US: Num Groups Preparing Rebalance
ja-JP: リバランス準備中の消費者グループ数
- field: NumGroupsStable
type: 0
i18n:
zh-CN: 稳定群组数量
en-US: Num Groups Stable
ja-JP: 安定した消費者グループ数
- field: NumOffsets
type: 0
i18n:
zh-CN: 偏移量数量
en-US: Num Offsets
ja-JP: オフセット数
aliasFields:
- Value->NumGroups
- Value->NumGroupsCompletingRebalance
@@ -18,13 +18,11 @@ app: kafka_client
name:
zh-CN: Kafka消息系统(客户端)
en-US: Kafka MessageClient
ja-JP: Kafkaメッセージングシステム(クライアント)
help:
zh-CN: HertzBeat 使用 <a href="https://hertzbeat.apache.org/zh-cn/docs/help/kafka_client">Kafka Admin Client</a> 对 Kafka 的通用指标进行采集监控。</span>
en-US: HertzBeat uses <a href='https://hertzbeat.apache.org/docs/help/kafka_client'>Kafka Admin Client</a> to monitoring kafka general metrics. </span>
zh-TW: HertzBeat 使用 <a href="https://hertzbeat.apache.org/zh-cn/docs/help/kafka_client">Kafka Admin Client</a> 對 Kafka 的通用指標進行采集監控。</span>
ja-JP: HertzBeat は <a href="https://hertzbeat.apache.org/docs/help/kafka_client">Kafka Admin Clientを介して</a> Kafkaの一般的なパフォーマンスのメトリクスを監視します。</span>
helpLink:
zh-CN: https://hertzbeat.apache.org/zh-cn/docs/help/kafka_client
@@ -35,14 +33,12 @@ params:
name:
zh-CN: 目标Host
en-US: Target Host
ja-JP: 目標ホスト
type: host
required: true
- field: port
name:
zh-CN: 端口
en-US: Port
ja-JP: ポート
type: number
range: '[0,65535]'
required: true
@@ -51,7 +47,6 @@ params:
name:
zh-CN: 是否监控内部主题
en-US: Monitor Internal Topic
ja-JP: 内部トピックを監視するかどうか
type: boolean
required: true
defaultValue: false
@@ -61,7 +56,6 @@ metrics:
i18n:
zh-CN: 主题列表
en-US: Topic List
ja-JP: トピック一覧
priority: 0
fields:
- field: TopicName
@@ -69,7 +63,6 @@ metrics:
i18n:
zh-CN: 主题名称
en-US: Topic Name
ja-JP: トピック名
protocol: kclient
kclient:
host: ^_^host^_^
@@ -80,7 +73,6 @@ metrics:
i18n:
zh-CN: 主题详细信息
en-US: Topic Detail Info
ja-JP: トピック詳細情報
priority: 1
fields:
- field: TopicName
@@ -88,43 +80,36 @@ metrics:
i18n:
zh-CN: 主题名称
en-US: Topic Name
ja-JP: トピック名
- field: PartitionNum
type: 1
i18n:
zh-CN: 分区数量
en-US: Partition Num
ja-JP: パーティション数
- field: PartitionLeader
type: 1
i18n:
zh-CN: 分区领导者
en-US: Partition Leader
ja-JP: パーティションリーダー
- field: BrokerHost
type: 1
i18n:
zh-CN: Broker主机
en-US: Broker Host
ja-JP: ブローカーホスト
- field: BrokerPort
type: 1
i18n:
zh-CN: Broker端口
en-US: Broker Port
ja-JP: ブローカーポート
- field: ReplicationFactorSize
type: 1
i18n:
zh-CN: 复制因子大小
en-US: Replication Factor Size
ja-JP: レプリカファクターのサイズ
- field: ReplicationFactor
type: 1
i18n:
zh-CN: 复制因子
en-US: Replication Factor
ja-JP: レプリカファクター
protocol: kclient
kclient:
host: ^_^host^_^
@@ -135,7 +120,6 @@ metrics:
i18n:
zh-CN: 主题偏移量
en-US: Topic Offset
ja-JP: トピックオフセット
priority: 2
# Kafka offset does not need to be obtained frequently, as getting it too quickly will affect performance
interval: 300
@@ -146,26 +130,22 @@ metrics:
i18n:
zh-CN: 主题名称
en-US: Topic Name
ja-JP: トピック名
- field: PartitionNum
label: true
type: 1
i18n:
zh-CN: 分区号
en-US: Partition Num
ja-JP: パーティション数
- field: earliest
type: 0
i18n:
zh-CN: 最早偏移量
en-US: Earliest Offset
ja-JP: 最早オフセット
- field: latest
type: 0
i18n:
zh-CN: 最新偏移量
en-US: Latest Offset
ja-JP: 最新オフセット
protocol: kclient
kclient:
host: ^_^host^_^
@@ -176,7 +156,6 @@ metrics:
i18n:
zh-CN: 消费者组情况
en-US: Consumer Detail Info
ja-JP: 消費者グループ詳細情報
priority: 3
# Kafka offset does not need to be obtained frequently, as getting it too quickly will affect performance
interval: 300
@@ -187,32 +166,27 @@ metrics:
i18n:
zh-CN: 消费者组ID
en-US: Consumer Group ID
ja-JP: 消費者グループID
- field: Group Member Num
type: 1
i18n:
zh-CN: 消费者实例数量
en-US: Group Member Num
ja-JP: 消費者グループのメンバー数
- field: Topic
label: true
type: 1
i18n:
zh-CN: 订阅主题名称
en-US: Subscribed Topic Name
ja-JP: 購読されたトピック名
- field: Offset of Each Partition
type: 1
i18n:
zh-CN: 各分区偏移量
en-US: Offset of Each Partition
ja-JP: 各パーティションのオフセット
- field: Lag
type: 0
i18n:
zh-CN: 落后偏移量
en-US: Total Lag
ja-JP: ラグオフセット
protocol: kclient
kclient:
host: ^_^host^_^
@@ -145,18 +145,4 @@ class MonitorsControllerTest {
.andExpect(jsonPath("$.code").value("0"))
.andExpect(jsonPath("$.msg").value("Import success"));
}
@Test
void exportAll() throws Exception {
String type = "JSON";
// Mock the behavior of monitorService.exportAll
doNothing().when(monitorService).exportAll(Mockito.anyString(), Mockito.any());
// Perform the request and verify the response
this.mockMvc.perform(MockMvcRequestBuilders.get("/api/monitors/export/all")
.param("type", type))
.andExpect(status().isOk())
.andReturn();
}
}
@@ -745,33 +745,6 @@ class MonitorServiceTest {
when(monitorDao.findById(1L)).thenReturn(Optional.of(monitor));
when(paramDao.findParamsByMonitorId(1L)).thenReturn(params);
assertDoesNotThrow(() -> monitorService.copyMonitor(1L));
}
@Test
void exportAll() throws Exception {
// Create some test monitors
Monitor monitor1 = Monitor.builder().id(1L).name("test1").app("app1").build();
Monitor monitor2 = Monitor.builder().id(2L).name("test2").app("app2").build();
List<Monitor> allMonitors = List.of(monitor1, monitor2);
// Mock the behavior of monitorDao.findAll
when(monitorDao.findAll()).thenReturn(allMonitors);
// Create a mock HttpServletResponse
jakarta.servlet.http.HttpServletResponse mockResponse = org.mockito.Mockito.mock(jakarta.servlet.http.HttpServletResponse.class);
// Mock the ImExportService
org.apache.hertzbeat.manager.service.ImExportService mockImExportService = org.mockito.Mockito.mock(org.apache.hertzbeat.manager.service.ImExportService.class);
// Mock the getFileName method
when(mockImExportService.getFileName()).thenReturn("test.json");
// Set the field using reflection
java.lang.reflect.Field field = MonitorServiceImpl.class.getDeclaredField("imExportServiceMap");
field.setAccessible(true);
java.util.Map<String, org.apache.hertzbeat.manager.service.ImExportService> imExportServiceMap = new java.util.HashMap<>();
imExportServiceMap.put("JSON", mockImExportService);
field.set(monitorService, imExportServiceMap);
// Test the exportAll method
assertDoesNotThrow(() -> monitorService.exportAll("JSON", mockResponse));
}
}
+2 -2
View File
@@ -21,8 +21,8 @@ Previous releases of HertzBeat may be affected by security issues, please use th
:::
| Version | Date | Download | Release |
|---------|------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------|
| v1.7.2 | 2025.07.05 | [apache-hertzbeat-1.7.2-incubating-bin.tar.gz](https://www.apache.org/dyn/closer.lua/incubator/hertzbeat/1.7.2/apache-hertzbeat-1.7.2-incubating-bin.tar.gz) (Server) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.7.2/apache-hertzbeat-1.7.2-incubating-bin.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.7.2/apache-hertzbeat-1.7.2-incubating-bin.tar.gz.sha512) ) <br/> [apache-hertzbeat-collector-1.7.2-incubating-bin.tar.gz](https://www.apache.org/dyn/closer.lua/incubator/hertzbeat/1.7.2/apache-hertzbeat-collector-1.7.2-incubating-bin.tar.gz) (Collector) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.7.2/apache-hertzbeat-collector-1.7.2-incubating-bin.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.7.2/apache-hertzbeat-collector-1.7.2-incubating-bin.tar.gz.sha512) ) <br/> [apache-hertzbeat-1.7.2-incubating-src.tar.gz](https://www.apache.org/dyn/closer.lua/incubator/hertzbeat/1.7.2/apache-hertzbeat-1.7.2-incubating-src.tar.gz) (Source Code) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.7.2/apache-hertzbeat-1.7.2-incubating-src.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.7.2/apache-hertzbeat-1.7.2-incubating-src.tar.gz.sha512) ) <br/> [apache-hertzbeat-1.7.2-incubating-docker-compose.tar.gz](https://www.apache.org/dyn/closer.lua/incubator/hertzbeat/1.7.2/apache-hertzbeat-1.7.2-incubating-docker-compose.tar.gz) (Docker Compose) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.7.2/apache-hertzbeat-1.7.2-incubating-docker-compose.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.7.2/apache-hertzbeat-1.7.2-incubating-docker-compose.tar.gz.sha512) ) | [note](https://github.com/apache/hertzbeat/releases/tag/v1.7.2) |
| ------- |------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------|
| v1.7.1 | 2025.05.29 | [apache-hertzbeat-1.7.1-incubating-bin.tar.gz](https://www.apache.org/dyn/closer.lua/incubator/hertzbeat/1.7.1/apache-hertzbeat-1.7.1-incubating-bin.tar.gz) (Server) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.7.1/apache-hertzbeat-1.7.1-incubating-bin.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.7.1/apache-hertzbeat-1.7.1-incubating-bin.tar.gz.sha512) ) <br/> [apache-hertzbeat-collector-1.7.1-incubating-bin.tar.gz](https://www.apache.org/dyn/closer.lua/incubator/hertzbeat/1.7.1/apache-hertzbeat-collector-1.7.1-incubating-bin.tar.gz) (Collector) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.7.1/apache-hertzbeat-collector-1.7.1-incubating-bin.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.7.1/apache-hertzbeat-collector-1.7.1-incubating-bin.tar.gz.sha512) ) <br/> [apache-hertzbeat-1.7.1-incubating-src.tar.gz](https://www.apache.org/dyn/closer.lua/incubator/hertzbeat/1.7.1/apache-hertzbeat-1.7.1-incubating-src.tar.gz) (Source Code) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.7.1/apache-hertzbeat-1.7.1-incubating-src.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.7.1/apache-hertzbeat-1.7.1-incubating-src.tar.gz.sha512) ) <br/> [apache-hertzbeat-1.7.1-incubating-docker-compose.tar.gz](https://www.apache.org/dyn/closer.lua/incubator/hertzbeat/1.7.1/apache-hertzbeat-1.7.1-incubating-docker-compose.tar.gz) (Docker Compose) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.7.1/apache-hertzbeat-1.7.1-incubating-docker-compose.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.7.1/apache-hertzbeat-1.7.1-incubating-docker-compose.tar.gz.sha512) ) | [note](https://github.com/apache/hertzbeat/releases/tag/v1.7.1) |
## Release Docker Image
@@ -22,7 +22,7 @@ sidebar_label: Download
| 版本 | 日期 | 下载 | Release |
|--------|-------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------|
| v1.7.2 | 2025.07.05 | [apache-hertzbeat-1.7.2-incubating-bin.tar.gz](https://www.apache.org/dyn/closer.lua/incubator/hertzbeat/1.7.2/apache-hertzbeat-1.7.2-incubating-bin.tar.gz) (Server) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.7.2/apache-hertzbeat-1.7.2-incubating-bin.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.7.2/apache-hertzbeat-1.7.2-incubating-bin.tar.gz.sha512) ) <br/> [apache-hertzbeat-collector-1.7.2-incubating-bin.tar.gz](https://www.apache.org/dyn/closer.lua/incubator/hertzbeat/1.7.2/apache-hertzbeat-collector-1.7.2-incubating-bin.tar.gz) (Collector) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.7.2/apache-hertzbeat-collector-1.7.2-incubating-bin.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.7.2/apache-hertzbeat-collector-1.7.2-incubating-bin.tar.gz.sha512) ) <br/> [apache-hertzbeat-1.7.2-incubating-src.tar.gz](https://www.apache.org/dyn/closer.lua/incubator/hertzbeat/1.7.2/apache-hertzbeat-1.7.2-incubating-src.tar.gz) (Source Code) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.7.2/apache-hertzbeat-1.7.2-incubating-src.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.7.2/apache-hertzbeat-1.7.2-incubating-src.tar.gz.sha512) ) <br/> [apache-hertzbeat-1.7.2-incubating-docker-compose.tar.gz](https://www.apache.org/dyn/closer.lua/incubator/hertzbeat/1.7.2/apache-hertzbeat-1.7.2-incubating-docker-compose.tar.gz) (Docker Compose) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.7.2/apache-hertzbeat-1.7.2-incubating-docker-compose.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.7.2/apache-hertzbeat-1.7.2-incubating-docker-compose.tar.gz.sha512) ) | [note](https://github.com/apache/hertzbeat/releases/tag/v1.7.2) |
| v1.7.1 | 2025.05.29 | [apache-hertzbeat-1.7.1-incubating-bin.tar.gz](https://www.apache.org/dyn/closer.lua/incubator/hertzbeat/1.7.1/apache-hertzbeat-1.7.1-incubating-bin.tar.gz) (主程序) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.7.1/apache-hertzbeat-1.7.1-incubating-bin.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.7.1/apache-hertzbeat-1.7.1-incubating-bin.tar.gz.sha512) ) <br/> [apache-hertzbeat-collector-1.7.1-incubating-bin.tar.gz](https://www.apache.org/dyn/closer.lua/incubator/hertzbeat/1.7.1/apache-hertzbeat-collector-1.7.1-incubating-bin.tar.gz) (采集器) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.7.1/apache-hertzbeat-collector-1.7.1-incubating-bin.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.7.1/apache-hertzbeat-collector-1.7.1-incubating-bin.tar.gz.sha512) ) <br/> [apache-hertzbeat-1.7.1-incubating-src.tar.gz](https://www.apache.org/dyn/closer.lua/incubator/hertzbeat/1.7.1/apache-hertzbeat-1.7.1-incubating-src.tar.gz) (源代码) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.7.1/apache-hertzbeat-1.7.1-incubating-src.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.7.1/apache-hertzbeat-1.7.1-incubating-src.tar.gz.sha512) ) <br/> [apache-hertzbeat-1.7.1-incubating-docker-compose.tar.gz](https://www.apache.org/dyn/closer.lua/incubator/hertzbeat/1.7.1/apache-hertzbeat-1.7.1-incubating-docker-compose.tar.gz) (Docker Compose) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.7.1/apache-hertzbeat-1.7.1-incubating-docker-compose.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.7.1/apache-hertzbeat-1.7.1-incubating-docker-compose.tar.gz.sha512) ) | [note](https://github.com/apache/hertzbeat/releases/tag/v1.7.1) |
## Docker 镜像版本
@@ -77,12 +77,6 @@
{{ 'monitor.export' | i18n }}
</button>
</li>
<li nz-menu-item>
<button nz-button (click)="onExportAllMonitors()">
<i nz-icon nzType="export" nzTheme="outline"></i>
{{ 'monitor.export-all' | i18n }}
</button>
</li>
<li nz-menu-item>
<nz-upload nzAction="/monitors/import" [nzLimit]="1" [nzShowUploadList]="false" (nzChange)="onImportMonitors($event)">
<button nz-button>
@@ -293,12 +287,7 @@
>
<ng-container *nzModalContent>
<div class="export-type-container">
<div
class="export-type-card"
(click)="exportMonitors('JSON')"
[class.loading]="exportJsonButtonLoading"
*ngIf="checkedMonitorIds.size > 0"
>
<div class="export-type-card" (click)="exportMonitors('JSON')" [class.loading]="exportJsonButtonLoading">
<div class="export-type-icon">
<i nz-icon nzType="code" nzTheme="outline"></i>
</div>
@@ -307,12 +296,7 @@
<p>{{ 'monitor.export.use-type' | i18n : { type: 'JSON' } }}</p>
</div>
</div>
<div
class="export-type-card"
(click)="exportMonitors('EXCEL')"
[class.loading]="exportExcelButtonLoading"
*ngIf="checkedMonitorIds.size > 0"
>
<div class="export-type-card" (click)="exportMonitors('EXCEL')" [class.loading]="exportExcelButtonLoading">
<div class="export-type-icon">
<i nz-icon nzType="file-excel" nzTheme="outline"></i>
</div>
@@ -321,34 +305,6 @@
<p>{{ 'monitor.export.use-type' | i18n : { type: 'EXCEL' } }}</p>
</div>
</div>
<div
class="export-type-card"
(click)="exportAllMonitors('JSON')"
[class.loading]="exportJsonButtonLoading"
*ngIf="checkedMonitorIds.size === 0"
>
<div class="export-type-icon">
<i nz-icon nzType="code" nzTheme="outline"></i>
</div>
<div class="export-type-info">
<h3>JSON</h3>
<p>{{ 'monitor.export-all.use-type' | i18n : { type: 'JSON' } }}</p>
</div>
</div>
<div
class="export-type-card"
(click)="exportAllMonitors('EXCEL')"
[class.loading]="exportExcelButtonLoading"
*ngIf="checkedMonitorIds.size === 0"
>
<div class="export-type-icon">
<i nz-icon nzType="file-excel" nzTheme="outline"></i>
</div>
<div class="export-type-info">
<h3>EXCEL</h3>
<p>{{ 'monitor.export-all.use-type' | i18n : { type: 'EXCEL' } }}</p>
</div>
</div>
</div>
</ng-container>
</nz-modal>
@@ -264,10 +264,6 @@ export class MonitorListComponent implements OnInit, OnDestroy {
this.isSwitchExportTypeModalVisible = true;
}
onExportAllMonitors() {
this.isSwitchExportTypeModalVisible = true;
}
onImportMonitors(info: NzUploadChangeParam): void {
console.log(info.type);
if (info.type === 'start') {
@@ -366,46 +362,6 @@ export class MonitorListComponent implements OnInit, OnDestroy {
);
}
exportAllMonitors(type: string) {
switch (type) {
case 'JSON':
this.exportJsonButtonLoading = true;
break;
case 'EXCEL':
this.exportExcelButtonLoading = true;
break;
}
const exportAllMonitors$ = this.monitorSvc
.exportAllMonitors(type)
.pipe(
finalize(() => {
this.exportExcelButtonLoading = false;
this.exportJsonButtonLoading = false;
exportAllMonitors$.unsubscribe();
})
)
.subscribe(
response => {
const message = response.body!;
if (message.type == 'application/json') {
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.export-fail'), '');
} else {
const blob = new Blob([message], { type: response.headers.get('Content-Type')! });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.download = response.headers.get('Content-Disposition')!.split(';')[1].split('filename=')[1];
a.href = url;
a.click();
window.URL.revokeObjectURL(url);
this.isSwitchExportTypeModalVisible = false;
}
},
error => {
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.export-fail'), error.msg);
}
);
}
onCancelManageMonitors() {
if (this.checkedMonitorIds == null || this.checkedMonitorIds.size === 0) {
this.notifySvc.warning(this.i18nSvc.fanyi('common.notify.no-select-cancel'), '');
@@ -30,7 +30,6 @@ const monitors_uri = '/monitors';
const detect_monitor_uri = '/monitor/detect';
const manage_monitors_uri = '/monitors/manage';
const export_monitors_uri = '/monitors/export';
const export_all_monitors_uri = '/monitors/export/all';
const summary_uri = '/summary';
const warehouse_storage_status_uri = '/warehouse/storage/status';
const grafana_dashboard_uri = '/grafana/dashboard';
@@ -75,16 +74,6 @@ export class MonitorService {
});
}
public exportAllMonitors(type: string): Observable<HttpResponse<Blob>> {
let httpParams = new HttpParams();
httpParams = httpParams.append('type', type);
return this.http.get(export_all_monitors_uri, {
params: httpParams,
observe: 'response',
responseType: 'blob'
});
}
public cancelManageMonitors(monitorIds: Set<number>): Observable<Message<any>> {
let httpParams = new HttpParams();
monitorIds.forEach(monitorId => {
+7 -10
View File
@@ -70,11 +70,11 @@
"alert.help.inhibit.link": "https://hertzbeat.apache.org/docs/help/alert_inhibit",
"alert.help.integration": "Unified management of alerts from different third-party platforms, integrating and receiving alert messages from third-party monitoring and observability systems, and performing actions such as grouping, aggregation, inhibition, silencing, and notification distribution.",
"alert.help.integration.link": "https://hertzbeat.apache.org",
"alert.help.notice": "Notification is used to config the receiver of alarm message and receiving method. The alarm message will be sent to the receiver by specified way(support email, discord, webhook etc). <a href='https://hertzbeat.apache.org/zh-cn/docs/help/alert_webhook'>Click here to see configuration steps.</a>.<br>\"<i>Notice Template</i>\" is message content structure template. The built-in template is used by default or you can customize the template to customize the message notification structure.<br><span class='help_module_span'>Note⚠️: After configuring the \"<i>Receiver</i>\", you also need to config the\"<i>Notice Policy</i>\"to specify which messages are sent to which receivers.</span><a href='https://hertzbeat.apache.org/docs/help/alert_email'> Click here to see potential issues</a>.",
"alert.help.notice": "Notification is used to config the receiver of alarm message and receiving method. The alarm message will be sent to the receiver by specified way(support email, discord, webhook etc). <a href='https://hertzbeat.apache.org/zh-cn/docs/help/alert_webhook'>Click here to see configuration steps.</a>.<br><i>Notice Template</i> is message content structure template. The built-in template is used by default or you can customize the template to customize the message notification structure.<br><span class='help_module_span'>Note⚠️: After configuring the <i>Receiver</i>, you also need to config the<i>Notice Policy</i>to specify which messages are sent to which receivers.</span><a href='https://hertzbeat.apache.org/docs/help/alert_email'> Click here to see potential issues</a>.",
"alert.help.notice.link": "https://hertzbeat.apache.org/docs/help/alert_email",
"alert.help.setting": "Threshold Rules are used for metrics alarm threshold rule management. Click the \"<i>New Threshold</i>\" to configure the alarm threshold for monitoring metrics. Hertzbeat will trigger alarms based on the threshold and metrics data.<br>Note⚠️: The alarm message that has been triggered can be checked in [Alter Center], and you can also set the notification method and personnel in [Notification].",
"alert.help.setting.link": "https://hertzbeat.apache.org/docs/help/alert_threshold",
"alert.help.silence": "Alarm Silence management is used when you don't want to be disturbed during system maintenance or on nights weekend. <br> Click \"<i>New Silence Strategy</i>\" and configure the time period to block messages so you would not get disturbed during breaks.",
"alert.help.silence": "Alarm Silence management is used when you dont want to be disturbed during system maintenance or on nights weekend. <br> Click \"<i>New Silence Strategy</i>\" and configure the time period to block messages so you would not get disturbed during breaks.",
"alert.help.silence.link": "https://hertzbeat.apache.org/docs",
"alert.inhibit.delete": "Delete Inhibit Rule",
"alert.inhibit.edit": "Edit Inhibit Rule",
@@ -702,12 +702,10 @@
"monitor.edit-monitor": "Edit Monitor",
"monitor.edit.failed": "Update Monitor Failed",
"monitor.edit.success": "Update Monitor Success",
"monitor.enable": "Enable",
"monitor.export": "Export Selected",
"monitor.export-all": "Export All",
"monitor.export.switch-type": "Please select the export file format",
"monitor.export.use-type": "Export selected monitors in {{type}} format",
"monitor.export-all.use-type": "Export all monitors in {{type}} format",
"monitor.enable": "Resume Monitor",
"monitor.export": "Export Monitor",
"monitor.export.switch-type": "Please select the export file format!",
"monitor.export.use-type": "Export monitors in {{type}} file format",
"monitor.grafana.enabled.label": "Enable Grafana",
"monitor.grafana.enabled.tip": "is enabled, the monitoring data will be displayed in Grafana",
"monitor.grafana.upload.label": "Upload Grafana Template",
@@ -915,6 +913,5 @@
"ai.bot.greeting": "Hello! I am an AI assistant. How can I help you?",
"ai.bot.input.placeholder": "Please enter a question...",
"ai.bot.send": "Send",
"ai.bot.connect-fail": "Sorry, there was an issue connecting to the AI assistant. Please try again later.",
"monitor.help": "Monitoring and management page, you can check the metric data and manage monitoring tasks here. The status of normal service is"
"ai.bot.connect-fail": "Sorry, there was an issue connecting to the AI assistant. Please try again later."
}
+3 -6
View File
@@ -703,11 +703,9 @@
"monitor.edit.failed": "修改监控失败",
"monitor.edit.success": "修改监控成功",
"monitor.enable": "恢复监控",
"monitor.export": "导出所选",
"monitor.export-all": "导出全部",
"monitor.export": "导出监控",
"monitor.export.switch-type": "请选择导出文件格式!",
"monitor.export.use-type": "以 {{type}} 文件格式导出所选监控",
"monitor.export-all.use-type": "以 {{type}} 文件格式导出全部监控",
"monitor.export.use-type": "以 {{type}} 文件格式导出监控",
"monitor.grafana.enabled.label": "启用Grafana",
"monitor.grafana.enabled.tip": "是否启用Grafana",
"monitor.grafana.upload.label": "上传Grafana模板",
@@ -915,6 +913,5 @@
"ai.bot.greeting": "你好!我是AI助手,有什么可以帮助你的吗?",
"ai.bot.input.placeholder": "请输入问题...",
"ai.bot.send": "发送",
"ai.bot.connect-fail": "抱歉,连接AI助手时出现问题,请稍后再试。",
"monitor.help": "监控管理页面,您可以在此查看指标数据并管理监控任务。正常服务的状态为"
"ai.bot.connect-fail": "抱歉,连接AI助手时出现问题,请稍后再试。"
}