Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,14 @@
import org.apache.hertzbeat.alert.service.AlertDefineImExportService;
import org.apache.hertzbeat.alert.service.AlertDefineService;
import org.apache.hertzbeat.alert.service.DataSourceService;
import org.apache.hertzbeat.base.dao.LabelDao;
import org.apache.hertzbeat.base.service.LabelService;
import org.apache.hertzbeat.common.cache.CacheFactory;
import org.apache.hertzbeat.common.constants.CommonConstants;
import org.apache.hertzbeat.common.constants.ExportFileConstants;
import org.apache.hertzbeat.common.constants.SignConstants;
import org.apache.hertzbeat.common.entity.alerter.AlertDefine;
import org.apache.hertzbeat.common.entity.manager.Label;
import org.apache.hertzbeat.common.util.FileUtil;
import org.apache.hertzbeat.common.util.JexlExpressionRunner;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -48,6 +51,7 @@
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
Expand All @@ -58,6 +62,7 @@
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
* Alarm definition management interface implementation
Expand All @@ -69,10 +74,16 @@ public class AlertDefineServiceImpl implements AlertDefineService {

@Autowired
private AlertDefineDao alertDefineDao;

@Autowired
private PeriodicAlertRuleScheduler periodicAlertRuleScheduler;

@Resource
private LabelService labelService;

@Resource
private LabelDao labelDao;

private final DataSourceService dataSourceService;

private final Map<String, AlertDefineImExportService> alertDefineImExportServiceMap = new HashMap<>();
Expand All @@ -93,7 +104,7 @@ public void validate(AlertDefine alertDefine, boolean isModify) throws IllegalAr
JexlExpressionRunner.compile(alertDefine.getExpr());
} catch (Exception e) {
throw new IllegalArgumentException("alert expr error: " + e.getMessage());
}
}
}
}
// the name of the alarm rule is unique
Expand All @@ -107,18 +118,39 @@ public void validate(AlertDefine alertDefine, boolean isModify) throws IllegalAr

@Override
public void addAlertDefine(AlertDefine alertDefine) throws RuntimeException {
saveNewCustomLabel(alertDefine);
alertDefine = alertDefineDao.saveAndFlush(alertDefine);
periodicAlertRuleScheduler.updateSchedule(alertDefine);
CacheFactory.clearAlertDefineCache();
}

@Override
public void modifyAlertDefine(AlertDefine alertDefine) throws RuntimeException {
saveNewCustomLabel(alertDefine);
alertDefineDao.saveAndFlush(alertDefine);
periodicAlertRuleScheduler.updateSchedule(alertDefine);
CacheFactory.clearAlertDefineCache();
}

private void saveNewCustomLabel(AlertDefine alertDefine) {
Map<String, String> labels = alertDefine.getLabels();
if (labels == null) {
labels = new HashMap<>(8);
alertDefine.setLabels(labels);
}
Map<String, String> customLabels = labels.entrySet().stream()
.filter(entry -> !isSystemBuiltInLabel(entry.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
List<Label> addLabels = labelService.determineNewLabels(customLabels.entrySet());
if (!addLabels.isEmpty()) {
labelDao.saveAll(addLabels);
}
}

private boolean isSystemBuiltInLabel(String labelKey) {
return CommonConstants.ALERT_MODE_LABEL.equals(labelKey) || CommonConstants.LABEL_ALERT_SEVERITY.contains(labelKey);
}

@Override
public void deleteAlertDefine(long alertId) throws RuntimeException {
alertDefineDao.deleteById(alertId);
Expand Down Expand Up @@ -256,7 +288,7 @@ public List<AlertDefine> getAlertDefinesByType(String type) {
if (!StringUtils.hasText(type)) {
throw new IllegalArgumentException("Alert definition type cannot be null or empty");
}

switch (type) {
case CommonConstants.METRIC_ALERT_THRESHOLD_TYPE_REALTIME:
case CommonConstants.METRIC_ALERT_THRESHOLD_TYPE_PERIODIC:
Expand All @@ -267,7 +299,7 @@ public List<AlertDefine> getAlertDefinesByType(String type) {
default:
throw new IllegalArgumentException("Unsupported alert definition type: " + type);
}

// Query enabled alert definitions by type
return alertDefineDao.findAlertDefinesByTypeAndEnableTrue(type);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import org.apache.hertzbeat.alert.calculate.periodic.PeriodicAlertRuleScheduler;
import org.apache.hertzbeat.alert.dao.AlertDefineDao;
import org.apache.hertzbeat.alert.service.impl.AlertDefineServiceImpl;
import org.apache.hertzbeat.base.dao.LabelDao;
import org.apache.hertzbeat.base.service.LabelService;
import org.apache.hertzbeat.common.cache.CacheFactory;
import org.apache.hertzbeat.common.entity.alerter.AlertDefine;
import org.junit.jupiter.api.BeforeEach;
Expand Down Expand Up @@ -69,7 +71,13 @@ class AlertDefineServiceTest {

@Mock
private AlertDefineDao alertDefineDao;


@Mock
private LabelService labelService;

@Mock
private LabelDao labelDao;

@Mock
private PeriodicAlertRuleScheduler periodicAlertRuleScheduler;

Expand All @@ -86,6 +94,8 @@ class AlertDefineServiceTest {
void setUp() {
ReflectionTestUtils.setField(this.alertDefineService, "alertDefineDao", alertDefineDao);
ReflectionTestUtils.setField(this.alertDefineService, "periodicAlertRuleScheduler", periodicAlertRuleScheduler);
ReflectionTestUtils.setField(this.alertDefineService, "labelService", labelService);
ReflectionTestUtils.setField(this.alertDefineService, "labelDao", labelDao);

this.alertDefine = AlertDefine.builder()
.id(1L)
Expand Down Expand Up @@ -187,40 +197,40 @@ void getMetricsRealTimeAlertDefines() {
AlertDefine.builder().id(1L).type(METRIC_ALERT_THRESHOLD_TYPE_REALTIME).enable(true).build(),
AlertDefine.builder().id(2L).type(METRIC_ALERT_THRESHOLD_TYPE_REALTIME).enable(true).build()
);

try (MockedStatic<CacheFactory> cacheFactoryMock = Mockito.mockStatic(CacheFactory.class)) {
// Mock cache hit
cacheFactoryMock.when(CacheFactory::getMetricsAlertDefineCache).thenReturn(cachedAlertDefines);

List<AlertDefine> result = alertDefineService.getMetricsRealTimeAlertDefines();

assertNotNull(result);
assertEquals(2, result.size());
assertEquals(1L, result.get(0).getId());
assertEquals(2L, result.get(1).getId());

// Verify no database query was called
verify(alertDefineDao, times(0)).findAlertDefinesByTypeAndEnableTrue(any());
cacheFactoryMock.verify(() -> CacheFactory.setMetricsAlertDefineCache(any()), times(0));
}

// Test cache miss scenario
List<AlertDefine> dbAlertDefines = Lists.newArrayList(
AlertDefine.builder().id(3L).type(METRIC_ALERT_THRESHOLD_TYPE_REALTIME).enable(true).build()
);

try (MockedStatic<CacheFactory> cacheFactoryMock = Mockito.mockStatic(CacheFactory.class)) {
// Mock cache miss
cacheFactoryMock.when(CacheFactory::getMetricsAlertDefineCache).thenReturn(null);
when(alertDefineDao.findAlertDefinesByTypeAndEnableTrue(METRIC_ALERT_THRESHOLD_TYPE_REALTIME))
.thenReturn(dbAlertDefines);

List<AlertDefine> result = alertDefineService.getMetricsRealTimeAlertDefines();

assertNotNull(result);
assertEquals(1, result.size());
assertEquals(3L, result.get(0).getId());

// Verify database query and cache setting were called
verify(alertDefineDao, times(1)).findAlertDefinesByTypeAndEnableTrue(METRIC_ALERT_THRESHOLD_TYPE_REALTIME);
cacheFactoryMock.verify(() -> CacheFactory.setMetricsAlertDefineCache(dbAlertDefines), times(1));
Expand All @@ -234,40 +244,40 @@ void getLogRealTimeAlertDefines() {
AlertDefine.builder().id(4L).type(LOG_ALERT_THRESHOLD_TYPE_REALTIME).enable(true).build(),
AlertDefine.builder().id(5L).type(LOG_ALERT_THRESHOLD_TYPE_REALTIME).enable(true).build()
);

try (MockedStatic<CacheFactory> cacheFactoryMock = Mockito.mockStatic(CacheFactory.class)) {
// Mock cache hit
cacheFactoryMock.when(CacheFactory::getLogAlertDefineCache).thenReturn(cachedAlertDefines);

List<AlertDefine> result = alertDefineService.getLogRealTimeAlertDefines();

assertNotNull(result);
assertEquals(2, result.size());
assertEquals(4L, result.get(0).getId());
assertEquals(5L, result.get(1).getId());

// Verify no database query was called
verify(alertDefineDao, times(0)).findAlertDefinesByTypeAndEnableTrue(any());
cacheFactoryMock.verify(() -> CacheFactory.setLogAlertDefineCache(any()), times(0));
}

// Test cache miss scenario
List<AlertDefine> dbAlertDefines = Lists.newArrayList(
AlertDefine.builder().id(6L).type(LOG_ALERT_THRESHOLD_TYPE_REALTIME).enable(true).build()
);

try (MockedStatic<CacheFactory> cacheFactoryMock = Mockito.mockStatic(CacheFactory.class)) {
// Mock cache miss
cacheFactoryMock.when(CacheFactory::getLogAlertDefineCache).thenReturn(null);
when(alertDefineDao.findAlertDefinesByTypeAndEnableTrue(LOG_ALERT_THRESHOLD_TYPE_REALTIME))
.thenReturn(dbAlertDefines);

List<AlertDefine> result = alertDefineService.getLogRealTimeAlertDefines();

assertNotNull(result);
assertEquals(1, result.size());
assertEquals(6L, result.get(0).getId());

// Verify database query and cache setting were called
verify(alertDefineDao, times(1)).findAlertDefinesByTypeAndEnableTrue(LOG_ALERT_THRESHOLD_TYPE_REALTIME);
cacheFactoryMock.verify(() -> CacheFactory.setLogAlertDefineCache(dbAlertDefines), times(1));
Expand All @@ -280,58 +290,58 @@ void getAlertDefinesByType() {
AlertDefine.builder().id(7L).type(METRIC_ALERT_THRESHOLD_TYPE_REALTIME).enable(true).build(),
AlertDefine.builder().id(8L).type(METRIC_ALERT_THRESHOLD_TYPE_REALTIME).enable(true).build()
);

// Test valid metric realtime alert type
when(alertDefineDao.findAlertDefinesByTypeAndEnableTrue(METRIC_ALERT_THRESHOLD_TYPE_REALTIME))
.thenReturn(mockAlertDefines);

List<AlertDefine> result = alertDefineService.getAlertDefinesByType(METRIC_ALERT_THRESHOLD_TYPE_REALTIME);

assertNotNull(result);
assertEquals(2, result.size());
assertEquals(7L, result.get(0).getId());
assertEquals(8L, result.get(1).getId());
verify(alertDefineDao, times(1)).findAlertDefinesByTypeAndEnableTrue(METRIC_ALERT_THRESHOLD_TYPE_REALTIME);

// Test valid metric periodic alert type
reset(alertDefineDao);
when(alertDefineDao.findAlertDefinesByTypeAndEnableTrue(METRIC_ALERT_THRESHOLD_TYPE_PERIODIC))
.thenReturn(Lists.newArrayList());

result = alertDefineService.getAlertDefinesByType(METRIC_ALERT_THRESHOLD_TYPE_PERIODIC);

assertNotNull(result);
assertEquals(0, result.size());
verify(alertDefineDao, times(1)).findAlertDefinesByTypeAndEnableTrue(METRIC_ALERT_THRESHOLD_TYPE_PERIODIC);

// Test valid log realtime alert type
reset(alertDefineDao);
when(alertDefineDao.findAlertDefinesByTypeAndEnableTrue(LOG_ALERT_THRESHOLD_TYPE_REALTIME))
.thenReturn(mockAlertDefines);

result = alertDefineService.getAlertDefinesByType(LOG_ALERT_THRESHOLD_TYPE_REALTIME);

assertNotNull(result);
assertEquals(2, result.size());
verify(alertDefineDao, times(1)).findAlertDefinesByTypeAndEnableTrue(LOG_ALERT_THRESHOLD_TYPE_REALTIME);

// Test valid log periodic alert type
reset(alertDefineDao);
when(alertDefineDao.findAlertDefinesByTypeAndEnableTrue(LOG_ALERT_THRESHOLD_TYPE_PERIODIC))
.thenReturn(Lists.newArrayList());

result = alertDefineService.getAlertDefinesByType(LOG_ALERT_THRESHOLD_TYPE_PERIODIC);

assertNotNull(result);
assertEquals(0, result.size());
verify(alertDefineDao, times(1)).findAlertDefinesByTypeAndEnableTrue(LOG_ALERT_THRESHOLD_TYPE_PERIODIC);

// Test empty string type
assertThrows(IllegalArgumentException.class, () -> alertDefineService.getAlertDefinesByType(""));

// Test null type
assertThrows(IllegalArgumentException.class, () -> alertDefineService.getAlertDefinesByType(null));

// Test invalid type
assertThrows(IllegalArgumentException.class, () -> alertDefineService.getAlertDefinesByType("invalid_type"));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* limitations under the License.
*/

package org.apache.hertzbeat.manager.dao;
package org.apache.hertzbeat.base.dao;

import java.util.Optional;
import java.util.Set;
Expand All @@ -33,13 +33,13 @@ public interface LabelDao extends JpaRepository<Label, Long>, JpaSpecificationEx
* @param ids id list
*/
void deleteLabelsByIdIn(Set<Long> ids);

/**
* find Label by name and value
* @param name Label name
* @param value Label value
* @return Label
*/
Optional<Label> findLabelByNameAndTagValue(String name, String value);

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* limitations under the License.
*/

package org.apache.hertzbeat.manager.service;
package org.apache.hertzbeat.base.service;

import java.util.HashSet;
import java.util.List;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import java.util.List;
import org.apache.hertzbeat.common.entity.dto.Message;
import org.apache.hertzbeat.common.entity.manager.Label;
import org.apache.hertzbeat.manager.service.LabelService;
import org.apache.hertzbeat.base.service.LabelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.http.ResponseEntity;
Expand All @@ -46,7 +46,7 @@
@RestController
@RequestMapping(path = "/api/label", produces = {APPLICATION_JSON_VALUE})
public class LabelController {

@Autowired
private LabelService labelService;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
import org.apache.hertzbeat.manager.pojo.dto.MonitorDto;
import org.apache.hertzbeat.manager.service.ImExportService;
import org.apache.hertzbeat.manager.service.MonitorService;
import org.apache.hertzbeat.manager.service.LabelService;
import org.apache.hertzbeat.base.service.LabelService;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.util.CollectionUtils;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.hertzbeat.common.entity.manager.Label;
import org.apache.hertzbeat.manager.dao.LabelDao;
import org.apache.hertzbeat.manager.service.LabelService;
import org.apache.hertzbeat.base.dao.LabelDao;
import org.apache.hertzbeat.base.service.LabelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
Expand Down
Loading
Loading