This is an automated email from the ASF dual-hosted git repository.
Aias00 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 6671f4603b [fix] never send null template variables to Aliyun SMS
(#4331)
6671f4603b is described below
commit 6671f4603bc9446b70545cdfeaadd9cfb1060efe
Author: NekoPunch <[email protected]>
AuthorDate: Sun Aug 23 03:49:55 2026 -0700
[fix] never send null template variables to Aliyun SMS (#4331)
Co-authored-by: aias00 <[email protected]>
---
.../alert/service/impl/AlibabaSmsClientImpl.java | 39 ++++++------
.../service/impl/NoticeConfigServiceImpl.java | 3 +-
.../service/impl/AlibabaSmsClientImplTest.java | 74 ++++++++++++++++++++++
home/docs/help/alert_sms.md | 4 +-
.../current/help/alert_sms.md | 4 +-
5 files changed, 101 insertions(+), 23 deletions(-)
diff --git
a/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/service/impl/AlibabaSmsClientImpl.java
b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/service/impl/AlibabaSmsClientImpl.java
index 1876d53940..2fdc05f812 100644
---
a/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/service/impl/AlibabaSmsClientImpl.java
+++
b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/service/impl/AlibabaSmsClientImpl.java
@@ -78,27 +78,30 @@ public class AlibabaSmsClientImpl implements SmsClient {
@Override
public void sendMessage(NoticeReceiver receiver, NoticeTemplate
noticeTemplate, GroupAlert alert) {
- // Extract alert info
- String instance = null;
- String priority = null;
- String content = null;
- if (alert.getCommonLabels() != null) {
- instance = alert.getCommonLabels().get("instance");
- priority = alert.getCommonLabels().get("priority");
- content = alert.getCommonAnnotations().get("summary");
- content = content == null ?
alert.getCommonAnnotations().get("description") : content;
- if (content == null) {
- content =
alert.getCommonAnnotations().values().stream().findFirst().orElse(null);
- }
- }
+ sendSms(receiver.getPhone(), buildTemplateParam(alert));
+ }
+
+ // Aliyun rejects the whole request when any template variable is null or
blank,
+ // so every value must fall back to non-blank text
+ String buildTemplateParam(GroupAlert alert) {
+ Map<String, String> labels = alert.getCommonLabels() == null ?
Map.of() : alert.getCommonLabels();
+ Map<String, String> annotations = alert.getCommonAnnotations() == null
? Map.of() : alert.getCommonAnnotations();
- // Build template parameters
Map<String, String> templateParam = new HashMap<>();
- templateParam.put("instance", instance == null ? alert.getGroupKey() :
instance);
- templateParam.put("priority", priority == null ? "unknown" : priority);
- templateParam.put("content", content);
+ templateParam.put("instance", firstNonBlank(labels.get("instance"),
alert.getGroupKey(), "unknown"));
+ templateParam.put("priority", firstNonBlank(labels.get("priority"),
"unknown"));
+ templateParam.put("content", firstNonBlank(annotations.get("summary"),
annotations.get("description"),
+ annotations.values().stream().findFirst().orElse(null), "alert
triggered"));
+ return JsonUtil.toJson(templateParam);
+ }
- sendSms(receiver.getPhone(), JsonUtil.toJson(templateParam));
+ private static String firstNonBlank(String... values) {
+ for (String value : values) {
+ if (value != null && !value.isBlank()) {
+ return value;
+ }
+ }
+ return "unknown";
}
private void sendSms(String phoneNumber, String templateParam) {
diff --git
a/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/service/impl/NoticeConfigServiceImpl.java
b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/service/impl/NoticeConfigServiceImpl.java
index 8469315c5d..7399146636 100644
---
a/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/service/impl/NoticeConfigServiceImpl.java
+++
b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/service/impl/NoticeConfigServiceImpl.java
@@ -377,7 +377,8 @@ public class NoticeConfigServiceImpl implements
NoticeConfigService, CommandLine
.status("firing")
.build();
GroupAlert groupAlert = GroupAlert.builder()
- .commonLabels(Map.of(CommonConstants.LABEL_ALERT_NAME, "CPU Usage
Alert"))
+ .commonLabels(Map.of(CommonConstants.LABEL_ALERT_NAME, "CPU Usage
Alert",
+ CommonConstants.LABEL_INSTANCE, "127.0.0.1"))
.commonAnnotations(annotations)
.alerts(List.of(singleAlert1, singleAlert2))
.status("firing")
diff --git
a/hertzbeat-alerter/src/test/java/org/apache/hertzbeat/alert/service/impl/AlibabaSmsClientImplTest.java
b/hertzbeat-alerter/src/test/java/org/apache/hertzbeat/alert/service/impl/AlibabaSmsClientImplTest.java
new file mode 100644
index 0000000000..8ef633860f
--- /dev/null
+++
b/hertzbeat-alerter/src/test/java/org/apache/hertzbeat/alert/service/impl/AlibabaSmsClientImplTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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 java.util.Map;
+import org.apache.hertzbeat.common.entity.alerter.GroupAlert;
+import org.apache.hertzbeat.common.util.JsonUtil;
+import org.junit.jupiter.api.Test;
+import tools.jackson.core.type.TypeReference;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Test case for {@link AlibabaSmsClientImpl}: Aliyun rejects a template
variable
+ * whose value is null or blank, so the built param JSON must never contain
one.
+ */
+class AlibabaSmsClientImplTest {
+
+ private final AlibabaSmsClientImpl client = new AlibabaSmsClientImpl(null);
+
+ private Map<String, String> params(GroupAlert alert) {
+ return JsonUtil.fromJson(client.buildTemplateParam(alert), new
TypeReference<>() { });
+ }
+
+ @Test
+ void testAlertShapedLikeSendTestMsgHasNoNullVariables() {
+ GroupAlert alert = GroupAlert.builder()
+ .commonLabels(Map.of("alertname", "CPU Usage Alert"))
+ .commonAnnotations(Map.of("suggest", "Please check the CPU
usage of the server"))
+ .build();
+
+ Map<String, String> params = params(alert);
+ assertEquals(3, params.size());
+ params.forEach((k, v) -> assertFalse(v == null || v.isBlank(), k + "
must not be null/blank"));
+ assertEquals("unknown", params.get("instance"));
+ }
+
+ @Test
+ void alertWithoutLabelsAndAnnotationsHasNoNullVariables() {
+ Map<String, String> params = params(GroupAlert.builder().build());
+ params.forEach((k, v) -> assertFalse(v == null || v.isBlank(), k + "
must not be null/blank"));
+ }
+
+ @Test
+ void realAlertValuesPassThrough() {
+ GroupAlert alert = GroupAlert.builder()
+ .commonLabels(Map.of("instance", "192.168.1.10:3306",
"priority", "critical"))
+ .commonAnnotations(Map.of("summary", "mysql down"))
+ .build();
+
+ Map<String, String> params = params(alert);
+ assertEquals("192.168.1.10:3306", params.get("instance"));
+ assertEquals("critical", params.get("priority"));
+ assertEquals("mysql down", params.get("content"));
+ assertTrue(params.values().stream().noneMatch(String::isBlank));
+ }
+}
diff --git a/home/docs/help/alert_sms.md b/home/docs/help/alert_sms.md
index cf2b0e8d46..7c2ba190dc 100644
--- a/home/docs/help/alert_sms.md
+++ b/home/docs/help/alert_sms.md
@@ -81,10 +81,10 @@ alerter:
3. Create a message template (template-code)
- Go to "Template Management" page
- Click "Add Template"
- - Create a template with the following format:
+ - Create a template with the following content (Aliyun placeholders use the
`${...}` syntax, and the template must declare exactly these three variables —
no more, no less — otherwise sending fails with a "template
variable/placeholder mismatch" error):
```text
- Monitor: `instance`, Alert Level: `priority`. Content: `content`
+ Monitor: ${instance}, Alert Level: ${priority}. Content: ${content}
```
- Submit the template for review
diff --git
a/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/help/alert_sms.md
b/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/help/alert_sms.md
index c40a7b8e2b..8ae126e4ab 100644
--- a/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/help/alert_sms.md
+++ b/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/help/alert_sms.md
@@ -80,10 +80,10 @@ alerter:
3. 创建短信模板(template-code)
- 进入"模板管理"页面
- 点击"添加模板"
- - 创建如下格式的模板:
+ - 创建如下内容的模板(阿里云占位符语法为 `${...}`,且模板必须恰好声明这三个变量——多一个少一个都会报"模板变量与占位符不一致"错误):
```text
- 监控项:`instance`,告警级别:`priority`。内容:`content`
+ 监控项:${instance},告警级别:${priority}。内容:${content}
```
- 提交模板等待审核
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]