This is an automated email from the ASF dual-hosted git repository.
gongchao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hertzbeat.git
The following commit(s) were added to refs/heads/master by this push:
new 4aad08ca17 [feature]Support Alibaba Cloud 'Simple Log Service(SLS)'
alert source (#3422)
4aad08ca17 is described below
commit 4aad08ca17bf365162f9689bf0eae6dd19a4a38f
Author: Duansg <[email protected]>
AuthorDate: Wed Jun 4 21:05:57 2025 +0800
[feature]Support Alibaba Cloud 'Simple Log Service(SLS)' alert source
(#3422)
Co-authored-by: tomsun28 <[email protected]>
---
.../alert/dto/AlibabaCloudSlsExternAlert.java | 184 ++++++++++++++++++++
.../impl/AlibabaCloudSlsExternAlertService.java | 185 +++++++++++++++++++++
.../AlibabaCloudSlsExternAlertServiceTest.java | 152 +++++++++++++++++
.../alert/alert-center/alert-center.component.html | 4 +-
.../alert-integration.component.ts | 5 +
web-app/src/app/routes/alert/alert.module.ts | 4 +-
.../alert-integration/alibabacloud-sls.en-US.md | 68 ++++++++
.../alert-integration/alibabacloud-sls.zh-CN.md | 68 ++++++++
.../alert-integration/alibabacloud-sls.zh-TW.md | 68 ++++++++
web-app/src/assets/i18n/en-US.json | 1 +
web-app/src/assets/i18n/ja-JP.json | 1 +
web-app/src/assets/i18n/pt-BR.json | 1 +
web-app/src/assets/i18n/zh-CN.json | 1 +
web-app/src/assets/i18n/zh-TW.json | 1 +
.../src/assets/img/integration/alibabacloud.svg | 15 ++
15 files changed, 756 insertions(+), 2 deletions(-)
diff --git
a/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/dto/AlibabaCloudSlsExternAlert.java
b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/dto/AlibabaCloudSlsExternAlert.java
new file mode 100644
index 0000000000..01a40e3c1d
--- /dev/null
+++
b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/dto/AlibabaCloudSlsExternAlert.java
@@ -0,0 +1,184 @@
+/*
+ * 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.dto;
+
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+
+/**
+ * Alibaba Cloud 'Simple Log Service(SLS)' alert content entity.
+ *
+ * @see <a
href="https://help.aliyun.com/zh/sls/user-guide/variables-in-new-alert-templates"/>
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class AlibabaCloudSlsExternAlert {
+
+ /**
+ * The id of the instance on which the alarm was triggered
+ */
+ @JsonProperty("alert_instance_id")
+ private String alertInstanceId;
+
+ /**
+ * Alarm rule id, unique within project
+ */
+ @JsonProperty("alert_id")
+ private String alertId;
+
+ /**
+ * Alarm rule name
+ */
+ @JsonProperty("alert_name")
+ private String alertName;
+
+ /**
+ * Region
+ */
+ private String region;
+
+ /**
+ * Alarm rule belongs to Project
+ */
+ private String project;
+
+ /**
+ * Time of this evaluation
+ */
+ @JsonProperty("alert_time")
+ private int alertTime;
+
+ /**
+ * First trigger time
+ */
+ @JsonProperty("fire_time")
+ private int fireTime;
+
+ /**
+ * Alarm recovery time
+ * If the alarm status is firing, the value is 0.
+ * If the alarm state is resolved, the value is the specific recovery time.
+ */
+ @JsonProperty("resolve_time")
+ private int resolveTime;
+
+ /**
+ * Alarm status.
+ * firing: Triggers an alarm.
+ * resolved: Notification of resumption.
+ */
+ private String status;
+
+ /**
+ * The total number of entries in the data that triggered the alert,
+ * which may be more than 100, for example after a Cartesian product
operation.
+ */
+ @JsonProperty("fire_results_count")
+ private int fireResultsCount;
+
+ /**
+ * Tag list
+ * Example: {"env":"test"}
+ */
+ private Map<String, String> labels;
+
+ /**
+ * Labeled lists
+ * Example: { "title": "Alarm title","desc": "Alarm desc" }
+ */
+ private Map<String, String> annotations;
+
+ /**
+ * Alarm severity.
+ *
+ * 10: Critical
+ * 8: High
+ * 6: Medium
+ * 4: Low
+ * 2: Report only
+ */
+ private int severity;
+
+ /**
+ *
+ */
+ @JsonProperty("signin_url")
+ private String signinUrl;
+
+
+ public String getAnnotation(String key) {
+ if (null == this.annotations || this.annotations.isEmpty()) {
+ return "N/A";
+ }
+ return this.annotations.get(key);
+ }
+
+ /**
+ * Severity
+ */
+ public enum Severity {
+
+ CRITICAL(10, "Critical"),
+
+ HIGH(8, "High"),
+
+ MEDIUM(6, "Medium"),
+
+ LOW(4, "Low"),
+
+ REPORT_ONLY(2, "Report only");
+
+ private static final Map<Integer, Severity> STATUS_MAP;
+
+ static {
+ STATUS_MAP =
Arrays.stream(Severity.values()).collect(Collectors.toMap(Severity::getStatus,
t -> t, (oldVal, newVal) -> newVal));
+ }
+
+ private final int status;
+ private final String alias;
+
+ Severity(int status, String alias) {
+ this.status = status;
+ this.alias = alias;
+ }
+
+ public static Optional<Severity> convert(int severity) {
+ return Optional.ofNullable(STATUS_MAP.get(severity));
+ }
+
+ public int getStatus() {
+ return status;
+ }
+
+ public String getAlias() {
+ return alias;
+ }
+ }
+}
\ No newline at end of file
diff --git
a/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/service/impl/AlibabaCloudSlsExternAlertService.java
b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/service/impl/AlibabaCloudSlsExternAlertService.java
new file mode 100644
index 0000000000..220466eb97
--- /dev/null
+++
b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/service/impl/AlibabaCloudSlsExternAlertService.java
@@ -0,0 +1,185 @@
+/*
+ * 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.service.impl;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hertzbeat.alert.dto.AlibabaCloudSlsExternAlert;
+import org.apache.hertzbeat.alert.reduce.AlarmCommonReduce;
+import org.apache.hertzbeat.alert.service.ExternAlertService;
+import org.apache.hertzbeat.common.constants.CommonConstants;
+import org.apache.hertzbeat.common.entity.alerter.SingleAlert;
+import org.apache.hertzbeat.common.util.IpDomainUtil;
+import org.apache.hertzbeat.common.util.JsonUtil;
+import org.springframework.stereotype.Service;
+
+import java.text.MessageFormat;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * Alibaba Cloud 'Simple Log Service(SLS)' external alarm service impl
+ */
+@Slf4j
+@Service
+public class AlibabaCloudSlsExternAlertService implements ExternAlertService {
+
+ private final AlarmCommonReduce alarmCommonReduce;
+
+ public AlibabaCloudSlsExternAlertService(AlarmCommonReduce
alarmCommonReduce) {
+ this.alarmCommonReduce = alarmCommonReduce;
+ }
+
+ @Override
+ public void addExternAlert(String content) {
+ AlibabaCloudSlsExternAlert externAlert = JsonUtil.fromJson(content,
AlibabaCloudSlsExternAlert.class);
+ if (externAlert == null) {
+ log.warn("Failure to parse external alert content. content: {}",
content);
+ return;
+ }
+ SingleAlert singleAlert = new
AlibabaCloudSlsConverter().convert(externAlert);
+ alarmCommonReduce.reduceAndSendAlarm(singleAlert);
+ }
+
+ @Override
+ public String supportSource() {
+ return "alibabacloud-sls";
+ }
+
+ /**
+ *
+ */
+ public static class AlibabaCloudSlsConverter {
+
+ /**
+ * convert
+ *
+ * @param externAlert alert content entity
+ * @return Single alert
+ */
+ public SingleAlert convert(AlibabaCloudSlsExternAlert externAlert) {
+ return SingleAlert.builder()
+ .triggerTimes(1)
+ .status(externAlert.getStatus())
+
.startAt(Instant.ofEpochSecond(externAlert.getFireTime()).toEpochMilli())
+
.activeAt(Instant.ofEpochSecond(externAlert.getAlertTime()).toEpochMilli())
+ .endAt(convertResolveTime(externAlert.getStatus(),
externAlert.getResolveTime()))
+ .labels(buildLabels(externAlert))
+ .annotations(buildAnnotations(externAlert))
+ .content(formatContent(externAlert))
+ .build();
+ }
+
+ /**
+ * todo i18n
+ *
+ * @param externAlert alert content entity
+ * @return content
+ */
+ private String formatContent(AlibabaCloudSlsExternAlert externAlert) {
+ // convet severity
+ Optional<AlibabaCloudSlsExternAlert.Severity> severity =
AlibabaCloudSlsExternAlert.Severity.convert(externAlert.getSeverity());
+ // If the alarm state is resolved, the value is the specific
recovery time.
+ Long resolveTimeMilli =
convertResolveTime(externAlert.getStatus(), externAlert.getResolveTime());
+
+ return MessageFormat.format(
+ "AlibabaCloud-sls alert , {0} - [{1}], level: [{2}], desc: {3},
fire_time:{4}, resolve_time:{5}",
+ externAlert.getAnnotation("title"),
+ externAlert.getStatus(),
+ severity.isPresent() ? severity.get().getAlias() : "N/A",
+ externAlert.getAnnotation("desc"),
+
timeSecondToDate(Instant.ofEpochSecond(externAlert.getFireTime()).toEpochMilli()),
+ null != resolveTimeMilli ?
timeSecondToDate(resolveTimeMilli) : "N/A"
+ );
+ }
+
+ /**
+ * Converts a timestamp (milliseconds) to a formatted date-time string.
+ *
+ * @param timestampMillis timestamp in milliseconds
+ * @return formatted date-time string in the pattern: yyyy-MM-dd
HH:mm:ss
+ */
+ private String timeSecondToDate(long timestampMillis) {
+ LocalDateTime dateTime = LocalDateTime.ofInstant(
+ Instant.ofEpochMilli(timestampMillis),
+ ZoneId.systemDefault()
+ );
+ return dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd
HH:mm:ss"));
+ }
+
+ /**
+ * Build basic annotations and fill annotations for alibaba cloud sls.
+ *
+ * @param externAlert alert content entity
+ * @return annotations
+ */
+ private Map<String, String>
buildAnnotations(AlibabaCloudSlsExternAlert externAlert) {
+ Map<String, String> annotations = new HashMap<>(8);
+ Optional<AlibabaCloudSlsExternAlert.Severity> severity =
AlibabaCloudSlsExternAlert.Severity.convert(externAlert.getSeverity());
+ severity.ifPresent(value -> annotations.put("severity",
value.getAlias()));
+ // Notification templates for sls need to be configured.
+ if (StringUtils.isNotBlank(externAlert.getSigninUrl()) &&
IpDomainUtil.isHasSchema(externAlert.getSigninUrl())) {
+ annotations.put("signinUrl", "<a target=\"_blank\" href=\"" +
externAlert.getSigninUrl() + "\">View Details</a>");
+ }
+ // Filling the annotations with the alibaba cloud sls.
+ if (null != externAlert.getAnnotations() &&
!externAlert.getAnnotations().isEmpty()) {
+ annotations.putAll(externAlert.getAnnotations());
+ }
+
+ return annotations;
+ }
+
+ /**
+ * Build basic labels and fill labels for alibaba cloud sls.
+ *
+ * @param externAlert alert content entity
+ * @return labels
+ */
+ private Map<String, String> buildLabels(AlibabaCloudSlsExternAlert
externAlert) {
+ Map<String, String> labels = new HashMap<>(8);
+ labels.put("__source__", "alibabacloud-sls");
+ labels.put("alertname", externAlert.getAlertName());
+ labels.put("region", externAlert.getRegion());
+ // The project name is globally unique.
+ labels.put("project", externAlert.getProject());
+ // Filling the labels with the alibaba cloud sls.
+ if (null != externAlert.getLabels() &&
!externAlert.getLabels().isEmpty()){
+ labels.putAll(externAlert.getLabels());
+ }
+ return labels;
+ }
+
+ /**
+ * If the alarm status is firing, the value is 0.
+ * If the alarm state is resolved, the value is the specific recovery
time.
+ *
+ * @param status alert status
+ * @param resolveTimeSecond recovery time
+ * @return milliseconds
+ */
+ private Long convertResolveTime(String status, int resolveTimeSecond) {
+ return CommonConstants.ALERT_STATUS_RESOLVED.equals(status) ?
Instant.ofEpochSecond(resolveTimeSecond).toEpochMilli() : null;
+ }
+ }
+
+}
\ No newline at end of file
diff --git
a/hertzbeat-alerter/src/test/java/org/apache/hertzbeat/alert/service/AlibabaCloudSlsExternAlertServiceTest.java
b/hertzbeat-alerter/src/test/java/org/apache/hertzbeat/alert/service/AlibabaCloudSlsExternAlertServiceTest.java
new file mode 100644
index 0000000000..a518ba0081
--- /dev/null
+++
b/hertzbeat-alerter/src/test/java/org/apache/hertzbeat/alert/service/AlibabaCloudSlsExternAlertServiceTest.java
@@ -0,0 +1,152 @@
+/*
+ * 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.service;
+
+
+import org.apache.hertzbeat.alert.dto.AlibabaCloudSlsExternAlert;
+import org.apache.hertzbeat.alert.reduce.AlarmCommonReduce;
+import
org.apache.hertzbeat.alert.service.impl.AlibabaCloudSlsExternAlertService;
+import org.apache.hertzbeat.common.entity.alerter.SingleAlert;
+import org.apache.hertzbeat.common.util.JsonUtil;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.time.Instant;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+/**
+ * unit test for {@link AlibabaCloudSlsExternAlertServiceTest }
+ */
+@Disabled
+@ExtendWith(MockitoExtension.class)
+public class AlibabaCloudSlsExternAlertServiceTest {
+
+ @Mock
+ private AlarmCommonReduce alarmCommonReduce;
+
+ @InjectMocks
+ private AlibabaCloudSlsExternAlertService externAlertService;
+
+ @Test
+ void testAddExternAlertWithInvalidContent() {
+ String invalidContent = "invalid json";
+ externAlertService.addExternAlert(invalidContent);
+ verify(alarmCommonReduce,
never()).reduceAndSendAlarm(any(SingleAlert.class));
+ }
+
+ @Test
+ void testAddExternAlert() {
+ String source = externAlertService.supportSource();
+ assertEquals("alibabacloud-sls", source);
+
+ AlibabaCloudSlsExternAlert externAlert = new
AlibabaCloudSlsExternAlert();
+ externAlert.setAlertName("Test SLS alert");
+ externAlert.setFireTime((int) Instant.now().getEpochSecond());
+ externAlert.setAlertTime((int) Instant.now().getEpochSecond());
+ externAlert.setRegion("cn-hangzhou");
+ externAlert.setProject("project");
+ externAlert.setStatus("firing");
+
externAlert.setSeverity(AlibabaCloudSlsExternAlert.Severity.HIGH.getStatus());
+
+ Map<String, String> labels = new HashMap<>();
+ labels.put("labels-k", "labels-v");
+ externAlert.setLabels(labels);
+
+ Map<String, String> annotations = new HashMap<>();
+ annotations.put("annotations-k", "annotations-v");
+ externAlert.setAnnotations(annotations);
+
+ externAlertService.addExternAlert(JsonUtil.toJson(externAlert));
+
+ verify(alarmCommonReduce,
times(1)).reduceAndSendAlarm(any(SingleAlert.class));
+ }
+
+ @Test
+ void testAddExternAlertWithSigninUrl() {
+ AlibabaCloudSlsExternAlert alert = new AlibabaCloudSlsExternAlert();
+ alert.setAlertName("Test Alert");
+ alert.setFireTime((int) Instant.now().getEpochSecond());
+ alert.setAlertTime((int) Instant.now().getEpochSecond());
+ alert.setRegion("cn-hangzhou");
+ alert.setProject("test-project");
+ alert.setStatus("firing");
+
alert.setSeverity(AlibabaCloudSlsExternAlert.Severity.HIGH.getStatus());
+ alert.setSigninUrl("https://example.com");
+ externAlertService.addExternAlert(JsonUtil.toJson(alert));
+ verify(alarmCommonReduce,
times(1)).reduceAndSendAlarm(any(SingleAlert.class));
+ }
+
+ @Test
+ void testAddExternAlertWithDifferentSeverityLevels() {
+ for (AlibabaCloudSlsExternAlert.Severity severity :
AlibabaCloudSlsExternAlert.Severity.values()) {
+ AlibabaCloudSlsExternAlert alert = new
AlibabaCloudSlsExternAlert();
+ alert.setAlertName("Test Alert");
+ alert.setFireTime((int) Instant.now().getEpochSecond());
+ alert.setAlertTime((int) Instant.now().getEpochSecond());
+ alert.setRegion("cn-hangzhou");
+ alert.setProject("test-project");
+ alert.setStatus("firing");
+ alert.setSeverity(severity.getStatus());
+ externAlertService.addExternAlert(JsonUtil.toJson(alert));
+ }
+ verify(alarmCommonReduce,
times(AlibabaCloudSlsExternAlert.Severity.values().length))
+ .reduceAndSendAlarm(any(SingleAlert.class));
+ }
+
+ @Test
+ void testAddExternAlertWithEmptyLabelsAndAnnotations() {
+ AlibabaCloudSlsExternAlert alert = new AlibabaCloudSlsExternAlert();
+ alert.setAlertName("Test Alert");
+ alert.setFireTime((int) Instant.now().getEpochSecond());
+ alert.setAlertTime((int) Instant.now().getEpochSecond());
+ alert.setRegion("cn-hangzhou");
+ alert.setProject("test-project");
+ alert.setStatus("firing");
+
alert.setSeverity(AlibabaCloudSlsExternAlert.Severity.HIGH.getStatus());
+ alert.setLabels(new HashMap<>());
+ alert.setAnnotations(new HashMap<>());
+ externAlertService.addExternAlert(JsonUtil.toJson(alert));
+ verify(alarmCommonReduce,
times(1)).reduceAndSendAlarm(any(SingleAlert.class));
+ }
+
+ @Test
+ void testAddExternAlertWithInvalidSeverity() {
+ AlibabaCloudSlsExternAlert alert = new AlibabaCloudSlsExternAlert();
+ alert.setAlertName("Test Alert");
+ alert.setFireTime((int) Instant.now().getEpochSecond());
+ alert.setAlertTime((int) Instant.now().getEpochSecond());
+ alert.setRegion("cn-hangzhou");
+ alert.setProject("test-project");
+ alert.setStatus("firing");
+ alert.setSeverity(-99);
+ externAlertService.addExternAlert(JsonUtil.toJson(alert));
+ verify(alarmCommonReduce,
times(1)).reduceAndSendAlarm(any(SingleAlert.class));
+ }
+
+}
\ No newline at end of file
diff --git
a/web-app/src/app/routes/alert/alert-center/alert-center.component.html
b/web-app/src/app/routes/alert/alert-center/alert-center.component.html
index d1d5e44558..1aca0a8e14 100644
--- a/web-app/src/app/routes/alert/alert-center/alert-center.component.html
+++ b/web-app/src/app/routes/alert/alert-center/alert-center.component.html
@@ -163,7 +163,9 @@
<div class="alert-annotations">
<div *ngFor="let anno of item.annotations | keyvalue"
class="annotation-item">
<span class="annotation-key">{{ anno.key }}:</span>
- <span class="annotation-value">{{ anno.value }}</span>
+ <span class="annotation-value">
+ <markdown [data]="anno.value"></markdown>
+ </span>
</div>
</div>
</div>
diff --git
a/web-app/src/app/routes/alert/alert-integration/alert-integration.component.ts
b/web-app/src/app/routes/alert/alert-integration/alert-integration.component.ts
index 01bca77ea6..efcec7b9b1 100644
---
a/web-app/src/app/routes/alert/alert-integration/alert-integration.component.ts
+++
b/web-app/src/app/routes/alert/alert-integration/alert-integration.component.ts
@@ -82,6 +82,11 @@ export class AlertIntegrationComponent implements OnInit {
id: 'tencent',
name: this.i18nSvc.fanyi('alert.integration.source.tencent'),
icon: 'assets/img/integration/tencent.svg'
+ },
+ {
+ id: 'alibabacloud-sls',
+ name: this.i18nSvc.fanyi('alert.integration.source.alibabacloud-sls'),
+ icon: 'assets/img/integration/alibabacloud.svg'
}
];
diff --git a/web-app/src/app/routes/alert/alert.module.ts
b/web-app/src/app/routes/alert/alert.module.ts
index 81438969ef..3e2bce088b 100644
--- a/web-app/src/app/routes/alert/alert.module.ts
+++ b/web-app/src/app/routes/alert/alert.module.ts
@@ -35,6 +35,7 @@ import { NzTagModule } from 'ng-zorro-antd/tag';
import { NzTimePickerModule } from 'ng-zorro-antd/time-picker';
import { NzTransferModule } from 'ng-zorro-antd/transfer';
import { NzUploadModule } from 'ng-zorro-antd/upload';
+import { MarkdownComponent } from 'ngx-markdown';
import { AlertCenterComponent } from './alert-center/alert-center.component';
import { AlertGroupConvergeComponent } from
'./alert-group/alert-group-converge.component';
@@ -78,7 +79,8 @@ const COMPONENTS: Array<Type<void>> = [
NzUploadModule,
QueryBuilderModule,
NzPaginationModule,
- NzEmptyModule
+ NzEmptyModule,
+ MarkdownComponent
],
declarations: COMPONENTS
})
diff --git a/web-app/src/assets/doc/alert-integration/alibabacloud-sls.en-US.md
b/web-app/src/assets/doc/alert-integration/alibabacloud-sls.en-US.md
new file mode 100644
index 0000000000..0aa4e5612a
--- /dev/null
+++ b/web-app/src/assets/doc/alert-integration/alibabacloud-sls.en-US.md
@@ -0,0 +1,68 @@
+>Send Alibaba Cloud Simple Log Service(SLS) alerts to the HertzBeat alert
platform via Webhook.
+
+### Step 1: Setup Webhook Integration in SLS
+1. Login to AliCloud SLS Console > Project List
+2. Select **Alerts** > **Notification objects** > **Webhook integration**
+3. Adding HertzBeat as an Alert Receiver Configuration
+- Type: Universal Webhook
+- Request Method: POST
+- Request URL: http://{hertzbeat_host}:1157/api/alerts/report/alibabacloud-sls
+
+### Step 2: Setting up Notification Policies in SLS
+1. Login to AliCloud SLS Console > Project List
+2. Select **Alerts** > **Notification Management** > **Alert Template**
+3. Add or modify **Alert Template** > **Webhook-Custom**
+- Add the following content templates, or leave them blank to use them as
default content templates as well
+```
+{
+ "aliuid": {{ alert.aliuid | quote }},
+ "alert_instance_id": {{ alert.alert_instance_id | quote }},
+ "alert_id": {{ alert.alert_id | quote }},
+ "alert_name": {{ alert.alert_name | quote }},
+ "region": {{ alert.region | quote }},
+ "project": {{ alert.project | quote }},
+ "alert_time": {{ alert.alert_time }},
+ "fire_time": {{ alert.fire_time }},
+ "resolve_time": {{ alert.resolve_time }},
+ "status": {{ alert.status | quote }},
+ "results": {{ alert.results | to_json }},
+ "fire_results": {{ alert.fire_results | to_json }},
+ "fire_results_count": {{ alert.fire_results_count }},
+ "labels": {{ alert.labels | to_json }},
+ "annotations": {{ alert.annotations | to_json }},
+ "severity": {{ alert.severity }},
+ "fingerprint": {{ alert.fingerprint | quote }}
+}
+```
+
+### Step 3: Setting up an Action Policy in SLS
+1. Login to AliCloud SLS Console > Project List
+2. Select **Alerts** > **Notification Management** > **Action Policy**
+3. If you are adding a **Universal Webhook**, you can skip this step and just
focus on **Selecting a Webhook**, **Alert Template** Keeping it the same as
step 2
+4. If you are adding **Webhook-Custom**, you need to add HertzBeat as the
alert receiver configuration.
+- Request Method: POST
+- Request URL: http://{hertzbeat_host}:1157/api/alerts/report/alibabacloud-sls
+- Alert Template: Template for Step 2 Setup
+
+### Other configurations
+
+#### View alert details in logon-free mode
+The log service provides a no-login feature, allowing you to view alarm
details and manage alarm rules and alarm incidents without logging into the
console after receiving an alarm notification.
+1. Add the following configuration in **Alert Template** > **Webhook-Custom**
> **Content**
+```
+"signin_url": {{ alert.signin_url }}
+```
+
+
+### Common Issues
+
+#### The alarm is not triggered
+- Ensure correctness of **Notification Objects**、**Notification Management**
settings
+- Ensure that the Webhook URL is accessible for SLS notifications
+- Ensure that the conditions of the alert policy are correct by checking the
**Alert Overview** or **Alert History Statistics** for triggered alerts.
+
+#### For more information
+
+-
[default-alert-templates](https://www.alibabacloud.com/help/en/sls/user-guide/default-alert-templates)
+-
[sls-alerting](https://www.alibabacloud.com/help/en/sls/user-guide/sls-alerting/?spm=a2c63.p38356.help-menu-28958.d_2_8.56f869daRhPz8f&scm=20140722.H_207608._.OR_help-T_intl~en-V_1)
+- [View alert details in logon-free
mode](https://www.alibabacloud.com/help/en/sls/user-guide/view-alert-details-in-logon-free-mode#task-2139631)
diff --git a/web-app/src/assets/doc/alert-integration/alibabacloud-sls.zh-CN.md
b/web-app/src/assets/doc/alert-integration/alibabacloud-sls.zh-CN.md
new file mode 100644
index 0000000000..00b506ad70
--- /dev/null
+++ b/web-app/src/assets/doc/alert-integration/alibabacloud-sls.zh-CN.md
@@ -0,0 +1,68 @@
+>将 Alibaba Cloud Simple Log Service(SLS) 的告警通过 Webhook 方式发送到 HertzBeat 告警平台。
+
+### 步骤一: 在 SLS 设置 Webhook 集成
+1. 登录阿里云SLS控制台 > Project列表
+2. 选择 **告警** > **通知对象** > **Webhook集成**
+3. 添加 HertzBeat 作为告警接收端配置
+ - 类型: 通用 Webhook
+ - 请求方法: POST
+ - 请求地址: http://{hertzbeat_host}:1157/api/alerts/report/alibabacloud-sls
+
+### 步骤二: 在 SLS 设置通知策略
+1. 登录阿里云SLS控制台 > Project列表
+2. 选择 **告警** > **通知策略** > **内容模板**
+3. 新增或者修改 **内容模板** > **WebHook-自定义**
+ - 添加以下内容模板,或者留空时以下模板也作为默认内容模板使用
+```
+{
+ "aliuid": {{ alert.aliuid | quote }},
+ "alert_instance_id": {{ alert.alert_instance_id | quote }},
+ "alert_id": {{ alert.alert_id | quote }},
+ "alert_name": {{ alert.alert_name | quote }},
+ "region": {{ alert.region | quote }},
+ "project": {{ alert.project | quote }},
+ "alert_time": {{ alert.alert_time }},
+ "fire_time": {{ alert.fire_time }},
+ "resolve_time": {{ alert.resolve_time }},
+ "status": {{ alert.status | quote }},
+ "results": {{ alert.results | to_json }},
+ "fire_results": {{ alert.fire_results | to_json }},
+ "fire_results_count": {{ alert.fire_results_count }},
+ "labels": {{ alert.labels | to_json }},
+ "annotations": {{ alert.annotations | to_json }},
+ "severity": {{ alert.severity }},
+ "fingerprint": {{ alert.fingerprint | quote }}
+}
+```
+
+### 步骤三: 在 SLS 设置行动策略
+1. 登录阿里云SLS控制台 > Project列表
+2. 选择 **告警** > **通知策略** > **行动策略**
+3. 若添加的是**通用 Webhook**,可跳过此步骤,只需关注 **选择Webhook**、**内容模板** 与步骤二保持一致
+4. 若添加的是 **Webhook-自定义** ,需添加 HertzBeat 作为告警接收端配置
+ - 请求方法: POST
+ - 请求地址: http://{hertzbeat_host}:1157/api/alerts/report/alibabacloud-sls
+ - 内容模板: 步骤二设置的模板
+
+### 其他配置
+
+#### 免登录查看告警详情
+日志服务提供免登录功能,您收到告警通知后,无需登录控制台即可查看告警详情以及进行告警规则、告警事务的管理操作。
+1. 在**内容模板**中添加如下配置
+```
+"signin_url": {{ alert.signin_url }}
+```
+
+
+### 常见问题
+
+#### 告警未触发
+- 确保 **通知对象**、**通知策略** 设置的正确性
+- 确保 Webhook URL 可以被 SLS 通知访问
+- 确保告警策略的条件正确,可查阅 **告警概览** 或者 **告警历史** 是否有触发告警
+
+#### 更多信息请参考
+
+-
[默认内容模板](https://help.aliyun.com/zh/sls/user-guide/default-alert-templates#section-qxh-hos-yos)
+-
[日志服务-告警](https://help.aliyun.com/zh/sls/user-guide/sls-alerting/?spm=a2c4g.11186623.help-menu-28958.d_2_8.4d657c08YTGFNF)
+-
[免登录查看告警详情](https://help.aliyun.com/zh/sls/user-guide/view-alert-details-in-logon-free-mode?spm=a2c4g.11186623.help-menu-28958.d_2_8_12_2_7.67ee3c1bZUEA9k&scm=20140722.H_346631._.OR_help-T_cn~zh-V_1)
diff --git a/web-app/src/assets/doc/alert-integration/alibabacloud-sls.zh-TW.md
b/web-app/src/assets/doc/alert-integration/alibabacloud-sls.zh-TW.md
new file mode 100644
index 0000000000..44b8c23f13
--- /dev/null
+++ b/web-app/src/assets/doc/alert-integration/alibabacloud-sls.zh-TW.md
@@ -0,0 +1,68 @@
+>將 Alibaba Cloud Simple Log Service(SLS) 的告警通過 Webhook 方式發送到 HertzBeat 告警平台。
+
+### 步驟一: 在 SLS 設置 Webhook 集成
+1. 登錄阿里雲SLS控制枱 > Project列表
+2. 選擇 **告警** > **通知對象** > **Webhook集成**
+3. 添加 HertzBeat 作為告警接收端配置
+- 類型: 通用 Webhook
+- 請求方法: POST
+- 請求地址: http://{hertzbeat_host}:1157/api/alerts/report/alibabacloud-sls
+
+### 步驟二: 在 SLS 設置通知策略
+1. 登錄阿里雲SLS控制枱 > Project列表
+2. 選擇 **告警** > **通知策略** > **內容模板**
+3. 新增或者修改 **內容模板** > **WebHook-自定義**
+- 添加以下內容模板,或者留空時以下模板也作為默認內容模板使用
+```
+{
+ "aliuid": {{ alert.aliuid | quote }},
+ "alert_instance_id": {{ alert.alert_instance_id | quote }},
+ "alert_id": {{ alert.alert_id | quote }},
+ "alert_name": {{ alert.alert_name | quote }},
+ "region": {{ alert.region | quote }},
+ "project": {{ alert.project | quote }},
+ "alert_time": {{ alert.alert_time }},
+ "fire_time": {{ alert.fire_time }},
+ "resolve_time": {{ alert.resolve_time }},
+ "status": {{ alert.status | quote }},
+ "results": {{ alert.results | to_json }},
+ "fire_results": {{ alert.fire_results | to_json }},
+ "fire_results_count": {{ alert.fire_results_count }},
+ "labels": {{ alert.labels | to_json }},
+ "annotations": {{ alert.annotations | to_json }},
+ "severity": {{ alert.severity }},
+ "fingerprint": {{ alert.fingerprint | quote }}
+}
+```
+
+### 步驟三: 在 SLS 設置行動策略
+1. 登錄阿里雲SLS控制枱 > Project列表
+2. 選擇 **告警** > **通知策略** > **行動策略**
+3. 若添加的是**通用 Webhook**,可跳過此步驟,只需關注 **選擇Webhook**、**內容模板** 與步驟二保持一致
+4. 若添加的是 **Webhook-自定義** ,需添加 HertzBeat 作為告警接收端配置
+- 請求方法: POST
+- 請求地址: http://{hertzbeat_host}:1157/api/alerts/report/alibabacloud-sls
+- 內容模板: 步驟二設置的模板
+
+### 其他配置
+
+#### 免登錄查看告警詳情
+日誌服務提供免登錄功能,您收到告警通知後,無需登錄控制枱即可查看告警詳情以及進行告警規則、告警事務的管理操作。
+1. 在**內容模板**中添加如下配置
+```
+"signin_url": {{ alert.signin_url }}
+```
+
+
+### 常見問題
+
+#### 告警未觸發
+- 確保 **通知對象**、**通知策略** 設置的正確性
+- 確保 Webhook URL 可以被 SLS 通知訪問
+- 確保告警策略的條件正確,可查閲 **告警概覽** 或者 **告警歷史** 是否有觸發告警
+
+#### 更多信息請參考
+
+-
[默認內容模板](https://help.aliyun.com/zh/sls/user-guide/default-alert-templates#section-qxh-hos-yos)
+-
[日誌服務-告警](https://help.aliyun.com/zh/sls/user-guide/sls-alerting/?spm=a2c4g.11186623.help-menu-28958.d_2_8.4d657c08YTGFNF)
+-
[免登錄查看告警詳情](https://help.aliyun.com/zh/sls/user-guide/view-alert-details-in-logon-free-mode?spm=a2c4g.11186623.help-menu-28958.d_2_8_12_2_7.67ee3c1bZUEA9k&scm=20140722.H_346631._.OR_help-T_cn~zh-V_1)
diff --git a/web-app/src/assets/i18n/en-US.json
b/web-app/src/assets/i18n/en-US.json
index 0bf7140de9..ce74374127 100644
--- a/web-app/src/assets/i18n/en-US.json
+++ b/web-app/src/assets/i18n/en-US.json
@@ -100,6 +100,7 @@
"alert.integration.source.skywalking": "SkyWalking",
"alert.integration.source.uptime-kuma": "Uptime Kuma",
"alert.integration.source.zabbix": "Zabbix",
+ "alert.integration.source.alibabacloud-sls": "AlibabaCloud-SLS",
"alert.integration.token.desc": "Token you generated that can be used to
access the HertzBeat API.",
"alert.integration.token.new": "Click to Generate Token",
"alert.integration.token.notice": "Token only be displayed once. Please keep
your token secure. Do not share it with others.",
diff --git a/web-app/src/assets/i18n/ja-JP.json
b/web-app/src/assets/i18n/ja-JP.json
index 7194402e6c..6781ebbf39 100644
--- a/web-app/src/assets/i18n/ja-JP.json
+++ b/web-app/src/assets/i18n/ja-JP.json
@@ -100,6 +100,7 @@
"alert.integration.source.skywalking": "SkyWalking",
"alert.integration.source.uptime-kuma": "Uptime Kuma",
"alert.integration.source.zabbix": "Zabbix",
+ "alert.integration.source.alibabacloud-sls": "AlibabaCloud-SLS",
"alert.integration.token.desc": "HertzBeat APIにアクセスするために生成したトークン。",
"alert.integration.token.new": "トークンを生成するにはクリック",
"alert.integration.token.notice":
"トークンは一度だけ表示されます。トークンを安全に保管し、他人と共有しないでください。",
diff --git a/web-app/src/assets/i18n/pt-BR.json
b/web-app/src/assets/i18n/pt-BR.json
index d6e46475cf..bd25d96d6b 100644
--- a/web-app/src/assets/i18n/pt-BR.json
+++ b/web-app/src/assets/i18n/pt-BR.json
@@ -245,6 +245,7 @@
"alert.integration.source.skywalking": "SkyWalking",
"alert.integration.source.tencent": "Monitoramento de nuvem Tencent",
"alert.integration.source.webhook": "PadrãoWebhook",
+ "alert.integration.source.alibabacloud-sls": "AlibabaCloud-SLS",
"alert.integration.token.desc": "O token gerado pode ser usado para
acessar a API HertzBeat",
"alert.integration.token.new": "Clique para gerar token",
"alert.integration.token.notice": "Este conteúdo será exibido apenas uma
vez, por favor guarde seu token adequadamente e não o divulgue a terceiros.",
diff --git a/web-app/src/assets/i18n/zh-CN.json
b/web-app/src/assets/i18n/zh-CN.json
index 3c156e4624..4fa296ae88 100644
--- a/web-app/src/assets/i18n/zh-CN.json
+++ b/web-app/src/assets/i18n/zh-CN.json
@@ -100,6 +100,7 @@
"alert.integration.source.skywalking": "SkyWalking",
"alert.integration.source.uptime-kuma": "Uptime Kuma",
"alert.integration.source.zabbix": "Zabbix",
+ "alert.integration.source.alibabacloud-sls": "阿里云日志服务 SLS",
"alert.integration.token.desc": "生成的 Token 可用于访问 HertzBeat API",
"alert.integration.token.new": "点击生成 Token",
"alert.integration.token.notice": "此内容只会展示一次,请妥善保管您的 Token,不要泄露给他人",
diff --git a/web-app/src/assets/i18n/zh-TW.json
b/web-app/src/assets/i18n/zh-TW.json
index 88afe5f9d4..fc8b7e116c 100644
--- a/web-app/src/assets/i18n/zh-TW.json
+++ b/web-app/src/assets/i18n/zh-TW.json
@@ -100,6 +100,7 @@
"alert.integration.source.skywalking": "SkyWalking",
"alert.integration.source.uptime-kuma": "Uptime Kuma",
"alert.integration.source.zabbix": "Zabbix",
+ "alert.integration.source.alibabacloud-sls": "阿里雲端日誌服務 SLS",
"alert.integration.token.desc": "生成的 Token 可用于访问 HertzBeat API",
"alert.integration.token.new": "点击生成 Token",
"alert.integration.token.notice": "此内容只会展示一次,请妥善保管您的 Token,不要泄露给他人",
diff --git a/web-app/src/assets/img/integration/alibabacloud.svg
b/web-app/src/assets/img/integration/alibabacloud.svg
new file mode 100755
index 0000000000..4428a246cc
--- /dev/null
+++ b/web-app/src/assets/img/integration/alibabacloud.svg
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 26.0.2, SVG Export Plug-In . SVG Version:
6.00 Build 0) -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 512 319.2" style="enable-background:new 0 0 512 319.2;"
xml:space="preserve">
+<style type="text/css">
+ .st0{fill:#FF6A00;}
+</style>
+<g>
+ <rect x="170.8" y="139.6" class="st0" width="170.6" height="38.4"/>
+ <path class="st0"
d="M426.8,0H313.9l27.2,38.5l82.3,25.7c14.9,4.7,25,18.6,24.8,34.3v122.8l0,0c0.1,15.6-10,29.5-24.8,34.3
+
l-82.3,25.2l-27.2,38.5h112.9c47,0,85.2-38,85.2-85c0-0.2,0-0.4,0-0.6v-148C512,38.5,473.9,0.2,426.8,0z"/>
+ <path class="st0"
d="M85.6,0h112.5l-26.9,38.5L89,64.2c-14.9,4.7-25,18.6-24.9,34.3v122.8l0,0c-0.1,15.6,10,29.5,24.9,34.3
+
l82.3,25.2l27.2,38.5H85.6C38.3,319.2,0,280.9,0,233.6v-148C0,38.3,38.3,0,85.6,0z"/>
+</g>
+</svg>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]