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]


Reply via email to