mirror of
https://github.com/dromara/hertzbeat.git
synced 2026-09-17 18:19:02 +00:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f3e6825d0c | ||
|
|
e7e38f3aa3 |
@@ -2325,42 +2325,6 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "JuJinPark",
|
||||
"name": "jujin",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/44892459?v=4",
|
||||
"profile": "https://github.com/JuJinPark",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "LL-LIN",
|
||||
"name": "LL-LIN",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/43002118?v=4",
|
||||
"profile": "https://github.com/LL-LIN",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "bigcyy",
|
||||
"name": "Yang Chen",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/73413979?v=4",
|
||||
"profile": "https://bigcyy.github.io/",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "sarthakeash",
|
||||
"name": "Sarthak Arora",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/74091160?v=4",
|
||||
"profile": "https://github.com/sarthakeash",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
||||
@@ -17,9 +17,7 @@
|
||||
|
||||
/home export-ignore
|
||||
/hip export-ignore
|
||||
/template-marketplace export-ignore
|
||||
/.github export-ignore
|
||||
/.idea export-ignore
|
||||
/.devcontainer export-ignore
|
||||
.gitattributes export-ignore
|
||||
.gitignore export-ignore
|
||||
|
||||
@@ -31,8 +31,6 @@ name: "CodeQL"
|
||||
on:
|
||||
schedule:
|
||||
- cron: '21 13 * * 4'
|
||||
push:
|
||||
branches: [ action* ]
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
|
||||
@@ -19,7 +19,7 @@ name: DOC CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master, dev, action* ]
|
||||
branches: [ master, dev ]
|
||||
paths:
|
||||
- 'home/**'
|
||||
pull_request:
|
||||
|
||||
@@ -17,8 +17,7 @@
|
||||
|
||||
name: 'HertzBeat Doc Pdf Builder'
|
||||
on:
|
||||
push:
|
||||
branches: [ page_build* ]
|
||||
page_build
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
@@ -22,7 +22,7 @@ name: Frontend CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master, dev, action* ]
|
||||
branches: [ master, dev ]
|
||||
paths:
|
||||
- 'web-app/**'
|
||||
pull_request:
|
||||
|
||||
@@ -22,7 +22,7 @@ name: License Checker
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master, dev, action* ]
|
||||
branches: [ master, dev ]
|
||||
pull_request:
|
||||
branches: [ master, dev ]
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
run: |
|
||||
mvn clean install
|
||||
mvn clean package -Prelease -DskipTests
|
||||
cd hertzbeat-collector
|
||||
cd collector
|
||||
mvn clean package -Pcluster -DskipTests
|
||||
|
||||
- uses: docker/setup-qemu-action@v3
|
||||
|
||||
@@ -13,7 +13,6 @@ mvnw.bat
|
||||
package-lock.json
|
||||
*.zip
|
||||
jdk/
|
||||
data/
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
@@ -55,5 +54,3 @@ node_modules
|
||||
application-dev.yml
|
||||
application-mysql.yml
|
||||
application-pg.yml
|
||||
/package.json
|
||||
/yarn.lock
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Apache HertzBeat (incubating)
|
||||
Copyright 2024-2025 The Apache Software Foundation
|
||||
Copyright 2024 The Apache Software Foundation
|
||||
|
||||
This product includes software developed at
|
||||
The Apache Software Foundation (http://www.apache.org/).
|
||||
|
||||
@@ -510,12 +510,6 @@ Thanks to these wonderful people, welcome to join us:
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yasminvo"><img src="https://avatars.githubusercontent.com/u/107528848?v=4?s=100" width="100px;" alt="yasminvo"/><br /><sub><b>yasminvo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yasminvo" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/notbugggg"><img src="https://avatars.githubusercontent.com/u/147966331?v=4?s=100" width="100px;" alt="不关银渐层的事哦"/><br /><sub><b>不关银渐层的事哦</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=notbugggg" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yyahang"><img src="https://avatars.githubusercontent.com/u/90464876?v=4?s=100" width="100px;" alt="yyahang"/><br /><sub><b>yyahang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yyahang" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JuJinPark"><img src="https://avatars.githubusercontent.com/u/44892459?v=4?s=100" width="100px;" alt="jujin"/><br /><sub><b>jujin</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=JuJinPark" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LL-LIN"><img src="https://avatars.githubusercontent.com/u/43002118?v=4?s=100" width="100px;" alt="LL-LIN"/><br /><sub><b>LL-LIN</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=LL-LIN" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://bigcyy.github.io/"><img src="https://avatars.githubusercontent.com/u/73413979?v=4?s=100" width="100px;" alt="Yang Chen"/><br /><sub><b>Yang Chen</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=bigcyy" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sarthakeash"><img src="https://avatars.githubusercontent.com/u/74091160?v=4?s=100" width="100px;" alt="Sarthak Arora"/><br /><sub><b>Sarthak Arora</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=sarthakeash" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -509,12 +509,6 @@ Thanks these wonderful people, welcome to join us:
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yasminvo"><img src="https://avatars.githubusercontent.com/u/107528848?v=4?s=100" width="100px;" alt="yasminvo"/><br /><sub><b>yasminvo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yasminvo" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/notbugggg"><img src="https://avatars.githubusercontent.com/u/147966331?v=4?s=100" width="100px;" alt="不关银渐层的事哦"/><br /><sub><b>不关银渐层的事哦</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=notbugggg" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yyahang"><img src="https://avatars.githubusercontent.com/u/90464876?v=4?s=100" width="100px;" alt="yyahang"/><br /><sub><b>yyahang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yyahang" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JuJinPark"><img src="https://avatars.githubusercontent.com/u/44892459?v=4?s=100" width="100px;" alt="jujin"/><br /><sub><b>jujin</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=JuJinPark" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LL-LIN"><img src="https://avatars.githubusercontent.com/u/43002118?v=4?s=100" width="100px;" alt="LL-LIN"/><br /><sub><b>LL-LIN</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=LL-LIN" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://bigcyy.github.io/"><img src="https://avatars.githubusercontent.com/u/73413979?v=4?s=100" width="100px;" alt="Yang Chen"/><br /><sub><b>Yang Chen</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=bigcyy" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sarthakeash"><img src="https://avatars.githubusercontent.com/u/74091160?v=4?s=100" width="100px;" alt="Sarthak Arora"/><br /><sub><b>Sarthak Arora</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=sarthakeash" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -73,11 +73,6 @@
|
||||
"field": "successCode",
|
||||
"type": 4,
|
||||
"paramValue": "200, 201"
|
||||
},
|
||||
{
|
||||
"field": "enableUrlEncoding",
|
||||
"type": 1,
|
||||
"paramValue": true
|
||||
}
|
||||
]
|
||||
}
|
||||
-9
@@ -17,39 +17,30 @@
|
||||
|
||||
package org.apache.hertzbeat.alert.config;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* Alibaba Cloud SMS configuration properties
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class AlibabaSmsProperties {
|
||||
/**
|
||||
* Alibaba Cloud access key id
|
||||
*/
|
||||
@NotBlank(message = "AccessKeyId cannot be empty")
|
||||
private String accessKeyId;
|
||||
|
||||
/**
|
||||
* Alibaba Cloud access key secret
|
||||
*/
|
||||
@NotBlank(message = "AccessKeySecret cannot be empty")
|
||||
private String accessKeySecret;
|
||||
|
||||
/**
|
||||
* SMS signature
|
||||
*/
|
||||
@NotBlank(message = "SignName cannot be empty")
|
||||
private String signName;
|
||||
|
||||
/**
|
||||
* SMS template Code
|
||||
*/
|
||||
@NotBlank(message = "TemplateCode cannot be null")
|
||||
private String templateCode;
|
||||
}
|
||||
|
||||
-4
@@ -17,7 +17,6 @@
|
||||
|
||||
package org.apache.hertzbeat.alert.config;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
@@ -28,19 +27,16 @@ public class AwsSmsProperties {
|
||||
/**
|
||||
* AWS Cloud access key id
|
||||
*/
|
||||
@NotBlank(message = "AccessKeyId cannot be empty")
|
||||
private String accessKeyId;
|
||||
|
||||
/**
|
||||
* AWS Cloud access key secret
|
||||
*/
|
||||
@NotBlank(message = "AccessKeySecret cannot be empty")
|
||||
private String accessKeySecret;
|
||||
|
||||
/**
|
||||
* AWS Cloud region
|
||||
*/
|
||||
@NotBlank(message = "region cannot be empty")
|
||||
private String region;
|
||||
|
||||
}
|
||||
|
||||
@@ -17,10 +17,7 @@
|
||||
|
||||
package org.apache.hertzbeat.alert.config;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -28,8 +25,6 @@ import org.springframework.stereotype.Component;
|
||||
* SMS configuration
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "alerter.sms")
|
||||
public class SmsConfig {
|
||||
@@ -42,7 +37,6 @@ public class SmsConfig {
|
||||
/**
|
||||
* sms service provider
|
||||
*/
|
||||
@NotBlank(message = "Type cannot be empty")
|
||||
private String type;
|
||||
|
||||
/**
|
||||
@@ -64,12 +58,6 @@ public class SmsConfig {
|
||||
* Aws configuration
|
||||
*/
|
||||
private AwsSmsProperties aws;
|
||||
|
||||
/**
|
||||
* Twilio SMS configuration
|
||||
*/
|
||||
private TwilioSmsProperties twilio;
|
||||
|
||||
/**
|
||||
* Smslocal SMS configuration
|
||||
*/
|
||||
|
||||
-4
@@ -18,16 +18,12 @@
|
||||
package org.apache.hertzbeat.alert.config;
|
||||
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* Smslocal SMS Properties
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SmslocalSmsProperties {
|
||||
/**
|
||||
* SmsLocal account api key
|
||||
|
||||
-10
@@ -17,45 +17,35 @@
|
||||
|
||||
package org.apache.hertzbeat.alert.config;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* Tencent Cloud SMS properties
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class TencentSmsProperties {
|
||||
/**
|
||||
* Tencent cloud account secret id
|
||||
*/
|
||||
@NotBlank(message = "SecretId cannot be empty")
|
||||
private String secretId;
|
||||
|
||||
/**
|
||||
* Tencent cloud account secret key
|
||||
*/
|
||||
@NotBlank(message = "SecretKey cannot be empty")
|
||||
private String secretKey;
|
||||
|
||||
/**
|
||||
* SMS app id
|
||||
*/
|
||||
@NotBlank(message = "AppId cannot be null")
|
||||
private String appId;
|
||||
|
||||
/**
|
||||
* SMS signature
|
||||
*/
|
||||
@NotBlank(message = "SignName cannot be empty")
|
||||
private String signName;
|
||||
|
||||
/**
|
||||
* SMS template ID
|
||||
*/
|
||||
@NotBlank(message = "templateId cannot be null")
|
||||
private String templateId;
|
||||
}
|
||||
-9
@@ -17,22 +17,16 @@
|
||||
|
||||
package org.apache.hertzbeat.alert.config;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* UniSMS properties
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class UniSmsProperties {
|
||||
/**
|
||||
* UniSMS access key id
|
||||
*/
|
||||
@NotBlank(message = "accessKeyId cannot be empty")
|
||||
private String accessKeyId;
|
||||
|
||||
/**
|
||||
@@ -43,18 +37,15 @@ public class UniSmsProperties {
|
||||
/**
|
||||
* SMS signature
|
||||
*/
|
||||
@NotBlank(message = "signature cannot be null")
|
||||
private String signature;
|
||||
|
||||
/**
|
||||
* SMS template ID
|
||||
*/
|
||||
@NotBlank(message = "templateId cannot be null")
|
||||
private String templateId;
|
||||
|
||||
/**
|
||||
* Authentication mode: simple or hmac, default is simple
|
||||
*/
|
||||
@NotBlank(message = "authMode cannot be null")
|
||||
private String authMode = "simple";
|
||||
}
|
||||
+2
-2
@@ -118,11 +118,11 @@ public class TencentCloudExternAlert {
|
||||
/**
|
||||
* Transaction alarm
|
||||
*/
|
||||
public static final String EVENT = "event";
|
||||
private static final String EVENT = "event";
|
||||
|
||||
/**
|
||||
* Indicator alarm
|
||||
*/
|
||||
public static final String METRIC = "metric";
|
||||
private static final String METRIC = "metric";
|
||||
|
||||
}
|
||||
|
||||
-3
@@ -48,7 +48,6 @@ final class TelegramBotAlertNotifyHandlerImpl extends AbstractAlertNotifyHandler
|
||||
TelegramBotNotifyDTO notifyBody = TelegramBotNotifyDTO.builder()
|
||||
.chatId(receiver.getTgUserId())
|
||||
.text(renderContent(noticeTemplate, alert))
|
||||
.messageThreadId(receiver.getTgMessageThreadId())
|
||||
.disableWebPagePreview(true)
|
||||
.build();
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
@@ -85,8 +84,6 @@ final class TelegramBotAlertNotifyHandlerImpl extends AbstractAlertNotifyHandler
|
||||
private String text;
|
||||
@JsonProperty("disable_web_page_preview")
|
||||
private Boolean disableWebPagePreview;
|
||||
@JsonProperty("message_thread_id")
|
||||
private String messageThreadId;
|
||||
}
|
||||
|
||||
@NoArgsConstructor
|
||||
|
||||
+1
-6
@@ -23,7 +23,6 @@ import org.apache.hertzbeat.alert.config.SmsConfig;
|
||||
import org.apache.hertzbeat.alert.service.impl.SmsLocalSmsClientImpl;
|
||||
import org.apache.hertzbeat.alert.service.impl.AwsSmsClientImpl;
|
||||
import org.apache.hertzbeat.alert.service.impl.TencentSmsClientImpl;
|
||||
import org.apache.hertzbeat.alert.service.impl.TwilioSmsClientImpl;
|
||||
import org.apache.hertzbeat.alert.service.impl.UniSmsClientImpl;
|
||||
import org.apache.hertzbeat.alert.service.impl.AlibabaSmsClientImpl;
|
||||
import org.apache.hertzbeat.base.dao.GeneralConfigDao;
|
||||
@@ -36,7 +35,6 @@ import org.springframework.stereotype.Component;
|
||||
import static org.apache.hertzbeat.common.constants.SmsConstants.ALIBABA;
|
||||
import static org.apache.hertzbeat.common.constants.SmsConstants.AWS;
|
||||
import static org.apache.hertzbeat.common.constants.SmsConstants.TENCENT;
|
||||
import static org.apache.hertzbeat.common.constants.SmsConstants.TWILIO;
|
||||
import static org.apache.hertzbeat.common.constants.SmsConstants.UNISMS;
|
||||
import static org.apache.hertzbeat.common.constants.SmsConstants.SMSLOCAL;
|
||||
|
||||
@@ -143,12 +141,9 @@ public class SmsClientFactory {
|
||||
case AWS:
|
||||
currentSmsClient = new AwsSmsClientImpl(smsConfig.getAws());
|
||||
break;
|
||||
case TWILIO:
|
||||
currentSmsClient = new TwilioSmsClientImpl(smsConfig.getTwilio());
|
||||
break;
|
||||
default:
|
||||
log.warn("[SmsClientFactory] Unsupported SMS provider type: {}", smsConfig.getType());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-174
@@ -18,22 +18,14 @@
|
||||
package org.apache.hertzbeat.alert.service.impl;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.hertzbeat.alert.dto.TencentCloudExternAlert;
|
||||
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.JsonUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Default external alarm service impl
|
||||
*/
|
||||
@@ -51,7 +43,8 @@ public class TencentExternAlertService implements ExternAlertService {
|
||||
log.warn("parse extern alert content failed! content: {}", content);
|
||||
return;
|
||||
}
|
||||
SingleAlert alert = new TencentCloudAlertConverter().convert(report);
|
||||
// todo convert TenCloudAlertReport to SingleAlert
|
||||
SingleAlert alert = new SingleAlert();
|
||||
alarmCommonReduce.reduceAndSendAlarm(alert);
|
||||
}
|
||||
|
||||
@@ -59,169 +52,4 @@ public class TencentExternAlertService implements ExternAlertService {
|
||||
public String supportSource() {
|
||||
return "tencent";
|
||||
}
|
||||
|
||||
/**
|
||||
* Converter: TencentCloud alert to SingleAlert
|
||||
*/
|
||||
public static class TencentCloudAlertConverter {
|
||||
|
||||
/**
|
||||
* Metric alert content template
|
||||
*/
|
||||
private final String metricTemplate = "Tencent Cloud Metric Alert: {metricShowName} {calcType} {calcValue}{calcUnit}, Current: {currentValue}{unit}";
|
||||
|
||||
/**
|
||||
* Event alert content template
|
||||
*/
|
||||
private final String eventTemplate = "Tencent Cloud Event Alert: {productShowName} - {eventShowName}";
|
||||
|
||||
|
||||
/**
|
||||
* Convert TencentCloud alert to SingleAlert
|
||||
*/
|
||||
public SingleAlert convert(TencentCloudExternAlert tencentAlert) {
|
||||
// Building basic information
|
||||
SingleAlert.SingleAlertBuilder builder = SingleAlert.builder()
|
||||
.status(convertStatus(tencentAlert.getAlarmStatus()))
|
||||
.startAt(parseTime(tencentAlert.getFirstOccurTime()))
|
||||
.activeAt(parseTime(tencentAlert.getFirstOccurTime()))
|
||||
.triggerTimes(1);
|
||||
// If it is a recovery state, set the end time.
|
||||
if ("0".equals(tencentAlert.getAlarmStatus())) {
|
||||
builder.endAt(parseTime(tencentAlert.getRecoverTime()));
|
||||
}
|
||||
|
||||
// Build labels
|
||||
Map<String, String> labels = new HashMap<>();
|
||||
buildLabels(labels, tencentAlert);
|
||||
|
||||
// Build annotations
|
||||
Map<String, String> annotations = new HashMap<>();
|
||||
buildAnnotations(annotations, tencentAlert);
|
||||
|
||||
// Build content
|
||||
String content = generateContent(tencentAlert);
|
||||
|
||||
return builder
|
||||
.labels(labels)
|
||||
.annotations(annotations)
|
||||
.content(content)
|
||||
.build();
|
||||
}
|
||||
|
||||
private void buildLabels(Map<String, String> labels, TencentCloudExternAlert alert) {
|
||||
labels.put("__source__", "tencent_cloud");
|
||||
labels.put("alert_type", alert.getAlarmType());
|
||||
if (TencentCloudExternAlert.METRIC.equals(alert.getAlarmType())) {
|
||||
labels.put("metric_name", alert.getAlarmPolicyInfo().getConditions().getMetricName());
|
||||
labels.put("namespace", alert.getAlarmObjInfo().getNamespace());
|
||||
} else {
|
||||
labels.put("event_name", alert.getAlarmPolicyInfo().getConditions().getEventName());
|
||||
labels.put("product_name", alert.getAlarmPolicyInfo().getConditions().getProductName());
|
||||
}
|
||||
}
|
||||
|
||||
private void buildAnnotations(Map<String, String> annotations, TencentCloudExternAlert alert) {
|
||||
TencentCloudExternAlert.AlarmPolicyInfo alarmPolicyInfo = alert.getAlarmPolicyInfo();
|
||||
TencentCloudExternAlert.AlarmObjInfo alarmObjInfo = alert.getAlarmObjInfo();
|
||||
TencentCloudExternAlert.Dimensions dimensions = alert.getAlarmObjInfo().getDimensions();
|
||||
|
||||
putIfNotNull(annotations, "policy_id", alarmPolicyInfo.getPolicyId());
|
||||
putIfNotNull(annotations, "policy_type", alarmPolicyInfo.getPolicyType());
|
||||
putIfNotNull(annotations, "policy_name", alarmPolicyInfo.getPolicyName());
|
||||
putIfNotNull(annotations, "policy_type_cname", alarmPolicyInfo.getPolicyTypeCname());
|
||||
|
||||
putIfNotNull(annotations, "namespace", alarmObjInfo.getNamespace());
|
||||
putIfNotNull(annotations, "region", alarmObjInfo.getRegion());
|
||||
putIfNotNull(annotations, "app_id", alarmObjInfo.getAppId());
|
||||
putIfNotNull(annotations, "uin", alarmObjInfo.getUin());
|
||||
|
||||
putIfNotNull(annotations, "instance_id", dimensions.getUnInstanceId());
|
||||
putIfNotNull(annotations, "obj_id", dimensions.getObjId());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate alert content with template
|
||||
*/
|
||||
private String generateContent(TencentCloudExternAlert alert) {
|
||||
if (TencentCloudExternAlert.METRIC.equals(alert.getAlarmType())) {
|
||||
return generateMetricContent(alert);
|
||||
} else {
|
||||
return generateEventContent(alert);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate metric alert content
|
||||
*/
|
||||
private String generateMetricContent(TencentCloudExternAlert alert) {
|
||||
TencentCloudExternAlert.Conditions conditions = alert.getAlarmPolicyInfo().getConditions();
|
||||
Map<String, String> params = new HashMap<>();
|
||||
|
||||
params.put("metricShowName", conditions.getMetricShowName());
|
||||
|
||||
if (StringUtils.isNotEmpty(conditions.getCalcType())
|
||||
&& StringUtils.isNotEmpty(conditions.getCalcValue())) {
|
||||
params.put("calcType", conditions.getCalcType());
|
||||
params.put("calcValue", conditions.getCalcValue());
|
||||
params.put("calcUnit", Objects.toString(conditions.getCalcUnit(), ""));
|
||||
} else {
|
||||
params.put("calcType", "");
|
||||
params.put("calcValue", "N/A");
|
||||
params.put("calcUnit", "");
|
||||
}
|
||||
|
||||
if (StringUtils.isNotEmpty(conditions.getCurrentValue())) {
|
||||
params.put("currentValue", conditions.getCurrentValue());
|
||||
params.put("unit", Objects.toString(conditions.getUnit(), ""));
|
||||
} else {
|
||||
params.put("currentValue", "N/A");
|
||||
params.put("unit", "");
|
||||
}
|
||||
return replacePlaceholders(metricTemplate, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate event alert content
|
||||
*/
|
||||
private String generateEventContent(TencentCloudExternAlert alert) {
|
||||
TencentCloudExternAlert.Conditions conditions = alert.getAlarmPolicyInfo().getConditions();
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("productShowName", conditions.getProductShowName());
|
||||
params.put("eventShowName", conditions.getEventShowName());
|
||||
return replacePlaceholders(eventTemplate, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace placeholders in template with actual values
|
||||
*/
|
||||
private String replacePlaceholders(String template, Map<String, String> params) {
|
||||
String result = template;
|
||||
for (Map.Entry<String, String> entry : params.entrySet()) {
|
||||
result = result.replace("{" + entry.getKey() + "}", Objects.toString(entry.getValue(), "NULL"));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private String convertStatus(String alarmStatus) {
|
||||
return "1".equals(alarmStatus) ? CommonConstants.ALERT_STATUS_FIRING : CommonConstants.ALERT_STATUS_RESOLVED;
|
||||
}
|
||||
|
||||
private Long parseTime(String timeStr) {
|
||||
try {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
return sdf.parse(timeStr).getTime();
|
||||
} catch (ParseException e) {
|
||||
log.error("Failed to parse time: {}", timeStr);
|
||||
throw new IllegalArgumentException("Failed to parse time: " + timeStr, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void putIfNotNull(Map<String, String> map, String key, String value){
|
||||
if (StringUtils.isNotEmpty(value)){
|
||||
map.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -17,7 +17,6 @@
|
||||
|
||||
package org.apache.hertzbeat.alert.service.impl;
|
||||
|
||||
import jakarta.xml.bind.DatatypeConverter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.alert.config.TencentSmsProperties;
|
||||
import org.apache.hertzbeat.alert.service.SmsClient;
|
||||
@@ -35,6 +34,7 @@ import org.apache.http.util.EntityUtils;
|
||||
import org.apache.hertzbeat.common.util.JsonUtil;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
-171
@@ -1,171 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.alert.service.impl;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.alert.config.TwilioSmsProperties;
|
||||
import org.apache.hertzbeat.alert.service.SmsClient;
|
||||
import org.apache.hertzbeat.common.entity.alerter.GroupAlert;
|
||||
import org.apache.hertzbeat.common.entity.alerter.NoticeReceiver;
|
||||
import org.apache.hertzbeat.common.entity.alerter.NoticeTemplate;
|
||||
import org.apache.hertzbeat.common.support.exception.SendMessageException;
|
||||
import org.apache.hertzbeat.common.util.JsonUtil;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
|
||||
import static org.apache.hertzbeat.common.constants.SmsConstants.TWILIO;
|
||||
|
||||
/**
|
||||
* Twilio SMS Client Implementation<br>
|
||||
* API doc: <a href=
|
||||
* "https://www.twilio.com/docs/sms/api">https://www.twilio.com/docs/sms/api</a>
|
||||
*/
|
||||
@Slf4j
|
||||
public class TwilioSmsClientImpl implements SmsClient {
|
||||
|
||||
private static final String API_URL_FORMAT = "https://api.twilio.com/2010-04-01/Accounts/%s/Messages.json";
|
||||
private static final String MESSAGE_TEMPLATE = "Instance: %s, Priority: %s, Content: %s";
|
||||
|
||||
private final String accountSid;
|
||||
private final String authToken;
|
||||
private final String twilioPhoneNumber;
|
||||
|
||||
public TwilioSmsClientImpl(TwilioSmsProperties config) {
|
||||
if (config != null) {
|
||||
this.accountSid = config.getAccountSid();
|
||||
this.authToken = config.getAuthToken();
|
||||
this.twilioPhoneNumber = config.getTwilioPhoneNumber();
|
||||
} else {
|
||||
this.accountSid = "";
|
||||
this.authToken = "";
|
||||
this.twilioPhoneNumber = "";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(NoticeReceiver receiver, NoticeTemplate noticeTemplate, GroupAlert alert) {
|
||||
String instance = null;
|
||||
String priority = null;
|
||||
String content = null;
|
||||
if (alert.getCommonLabels() != null) {
|
||||
instance = alert.getCommonLabels().get("instance") == null ? alert.getGroupKey()
|
||||
: alert.getCommonLabels().get("instance");
|
||||
priority = alert.getCommonLabels().get("priority") == null ? "unknown"
|
||||
: 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);
|
||||
}
|
||||
}
|
||||
this.send(receiver.getPhone(), createMessage(instance, priority, content));
|
||||
}
|
||||
|
||||
private String createMessage(String instance, String priority, String content) {
|
||||
return String.format(MESSAGE_TEMPLATE, instance, priority, content);
|
||||
}
|
||||
|
||||
private void send(String phoneNumber, String message) {
|
||||
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
|
||||
String endpoint = String.format(API_URL_FORMAT, accountSid);
|
||||
URI requestUri = new URI(endpoint);
|
||||
|
||||
HttpPost httpPost = createHttpPost(requestUri, phoneNumber, message);
|
||||
log.info("Sending Twilio SMS request to {}", requestUri);
|
||||
executeRequest(httpClient, httpPost, phoneNumber);
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to send SMS: {}", e.getMessage());
|
||||
throw new SendMessageException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private HttpPost createHttpPost(URI requestUri, String toNumber, String message) {
|
||||
HttpPost httpPost = new HttpPost(requestUri);
|
||||
|
||||
String auth = accountSid + ":" + authToken;
|
||||
String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes());
|
||||
httpPost.setHeader("Authorization", "Basic " + encodedAuth);
|
||||
|
||||
List<BasicNameValuePair> parameters = new ArrayList<>();
|
||||
parameters.add(new BasicNameValuePair("To", toNumber));
|
||||
parameters.add(new BasicNameValuePair("From", twilioPhoneNumber));
|
||||
parameters.add(new BasicNameValuePair("Body", message));
|
||||
|
||||
try {
|
||||
httpPost.setEntity(new UrlEncodedFormEntity(parameters));
|
||||
return httpPost;
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to create HTTP request: {}", e.getMessage());
|
||||
throw new SendMessageException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void executeRequest(CloseableHttpClient httpClient, HttpPost httpPost, String phoneNumber)
|
||||
throws Exception {
|
||||
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
String responseBody = EntityUtils.toString(response.getEntity());
|
||||
log.info("SMS response status: {}, body: {}", statusCode, responseBody);
|
||||
|
||||
if (statusCode < 200 || statusCode >= 300) {
|
||||
|
||||
if (responseBody.contains("21608")) {
|
||||
throw new SendMessageException(
|
||||
"The Twilio trial account can only send SMS to verified phone numbers");
|
||||
} else {
|
||||
throw new SendMessageException(
|
||||
"HTTP request failed with status code: " + statusCode + ", response: " + responseBody);
|
||||
}
|
||||
}
|
||||
|
||||
JsonNode jsonResponse = JsonUtil.fromJson(responseBody);
|
||||
if (jsonResponse == null) {
|
||||
throw new SendMessageException(statusCode + ":" + responseBody);
|
||||
}
|
||||
|
||||
JsonNode sidNode = jsonResponse.get("sid");
|
||||
if (sidNode == null) {
|
||||
throw new SendMessageException(statusCode + ":" + responseBody);
|
||||
}
|
||||
|
||||
String sid = sidNode.asText();
|
||||
log.info("Successfully sent SMS to phone: {}, sid: {}", phoneNumber, sid);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return TWILIO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkConfig() {
|
||||
return !(accountSid.isBlank() || authToken.isBlank() || twilioPhoneNumber.isBlank());
|
||||
}
|
||||
}
|
||||
-64
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.alert.service;
|
||||
|
||||
import org.apache.hertzbeat.alert.config.TwilioSmsProperties;
|
||||
import org.apache.hertzbeat.alert.service.impl.TwilioSmsClientImpl;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* Test case for {@link TwilioSmsClientImpl}
|
||||
*/
|
||||
class TwilioSmsClientImplTest {
|
||||
|
||||
@Test
|
||||
void getType() {
|
||||
TwilioSmsProperties twilioSmsProperties = new TwilioSmsProperties();
|
||||
twilioSmsProperties.setAccountSid("accountSid");
|
||||
twilioSmsProperties.setAuthToken("authToken");
|
||||
twilioSmsProperties.setTwilioPhoneNumber("twilioPhoneNumber");
|
||||
TwilioSmsClientImpl twilioSmsClient = new TwilioSmsClientImpl(twilioSmsProperties);
|
||||
|
||||
assertEquals("twilio", twilioSmsClient.getType());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource({
|
||||
"accountSid, authToken, twilioPhoneNumber, true",
|
||||
"accountSid, authToken, '', false",
|
||||
"accountSid, '', twilioPhoneNumber, false",
|
||||
"accountSid, '', '', false",
|
||||
"'', authToken, twilioPhoneNumber, false",
|
||||
"'', authToken, '', false",
|
||||
"'', '', twilioPhoneNumber, false",
|
||||
"'', '', '', false",
|
||||
})
|
||||
void checkConfig(String accountSid, String authToken, String twilioPhoneNumber, boolean expected) {
|
||||
TwilioSmsProperties twilioSmsProperties = new TwilioSmsProperties();
|
||||
twilioSmsProperties.setAccountSid(accountSid);
|
||||
twilioSmsProperties.setAuthToken(authToken);
|
||||
twilioSmsProperties.setTwilioPhoneNumber(twilioPhoneNumber);
|
||||
TwilioSmsClientImpl twilioSmsClient = new TwilioSmsClientImpl(twilioSmsProperties);
|
||||
|
||||
assertEquals(expected, twilioSmsClient.checkConfig());
|
||||
}
|
||||
}
|
||||
+10
-59
@@ -86,7 +86,6 @@ import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.util.UriUtils;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
@@ -510,37 +509,13 @@ public class HttpCollectImpl extends AbstractCollect {
|
||||
}
|
||||
// params
|
||||
Map<String, String> params = httpProtocol.getParams();
|
||||
boolean enableUrlEncoding = Boolean.parseBoolean(httpProtocol.getEnableUrlEncoding());
|
||||
StringBuilder queryParams = new StringBuilder();
|
||||
|
||||
if (params != null && !params.isEmpty()) {
|
||||
for (Map.Entry<String, String> param : params.entrySet()) {
|
||||
String key = param.getKey();
|
||||
String value = param.getValue();
|
||||
|
||||
if (!StringUtils.hasText(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (queryParams.length() > 0) {
|
||||
queryParams.append("&");
|
||||
}
|
||||
|
||||
if (enableUrlEncoding) {
|
||||
key = UriUtils.encodeQueryParam(key, "UTF-8");
|
||||
}
|
||||
queryParams.append(key);
|
||||
|
||||
if (StringUtils.hasText(value)) {
|
||||
String calculatedValue = TimeExpressionUtil.calculate(value);
|
||||
if (enableUrlEncoding) {
|
||||
calculatedValue = UriUtils.encodeQueryParam(calculatedValue, "UTF-8");
|
||||
}
|
||||
queryParams.append("=").append(calculatedValue);
|
||||
if (StringUtils.hasText(param.getValue())) {
|
||||
requestBuilder.addParameter(param.getKey(), TimeExpressionUtil.calculate(param.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The default request header can be overridden if customized
|
||||
// keep-alive
|
||||
requestBuilder.addHeader(HttpHeaders.CONNECTION, NetworkConstants.KEEP_ALIVE);
|
||||
@@ -550,7 +525,8 @@ public class HttpCollectImpl extends AbstractCollect {
|
||||
if (headers != null && !headers.isEmpty()) {
|
||||
for (Map.Entry<String, String> header : headers.entrySet()) {
|
||||
if (StringUtils.hasText(header.getValue())) {
|
||||
requestBuilder.addHeader(header.getKey(), header.getValue());
|
||||
requestBuilder.addHeader(CollectUtil.replaceUriSpecialChar(header.getKey()),
|
||||
CollectUtil.replaceUriSpecialChar(header.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -584,29 +560,11 @@ public class HttpCollectImpl extends AbstractCollect {
|
||||
requestBuilder.setEntity(new StringEntity(httpProtocol.getPayload(), StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
// uri encode
|
||||
String uri;
|
||||
if (enableUrlEncoding) {
|
||||
// if the url contains parameters directly
|
||||
if (httpProtocol.getUrl().contains("?")) {
|
||||
String path = httpProtocol.getUrl().substring(0, httpProtocol.getUrl().indexOf("?"));
|
||||
String query = httpProtocol.getUrl().substring(httpProtocol.getUrl().indexOf("?") + 1);
|
||||
uri = UriUtils.encodePath(path, "UTF-8") + "?" + UriUtils.encodeQuery(query, "UTF-8");
|
||||
} else {
|
||||
uri = UriUtils.encodePath(httpProtocol.getUrl(), "UTF-8");
|
||||
}
|
||||
} else {
|
||||
uri = httpProtocol.getUrl();
|
||||
}
|
||||
|
||||
// append query params
|
||||
if (queryParams.length() > 0) {
|
||||
uri += (uri.contains("?") ? "&" : "?") + queryParams.toString();
|
||||
}
|
||||
|
||||
String finalUri;
|
||||
// uri
|
||||
String uri = CollectUtil.replaceUriSpecialChar(httpProtocol.getUrl());
|
||||
if (IpDomainUtil.isHasSchema(httpProtocol.getHost())) {
|
||||
finalUri = httpProtocol.getHost() + ":" + httpProtocol.getPort() + uri;
|
||||
|
||||
requestBuilder.setUri(httpProtocol.getHost() + ":" + httpProtocol.getPort() + uri);
|
||||
} else {
|
||||
String ipAddressType = IpDomainUtil.checkIpAddressType(httpProtocol.getHost());
|
||||
String baseUri = NetworkConstants.IPV6.equals(ipAddressType)
|
||||
@@ -614,18 +572,11 @@ public class HttpCollectImpl extends AbstractCollect {
|
||||
: String.format("%s:%s%s", httpProtocol.getHost(), httpProtocol.getPort(), uri);
|
||||
boolean ssl = Boolean.parseBoolean(httpProtocol.getSsl());
|
||||
if (ssl) {
|
||||
finalUri = NetworkConstants.HTTPS_HEADER + baseUri;
|
||||
requestBuilder.setUri(NetworkConstants.HTTPS_HEADER + baseUri);
|
||||
} else {
|
||||
finalUri = NetworkConstants.HTTP_HEADER + baseUri;
|
||||
requestBuilder.setUri(NetworkConstants.HTTP_HEADER + baseUri);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
requestBuilder.setUri(finalUri);
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.warn("Invalid URI with illegal characters: {}. User has disabled URL encoding, not applying any encoding.", finalUri);
|
||||
throw e;
|
||||
}
|
||||
|
||||
// custom timeout
|
||||
int timeout = CollectUtil.getTimeout(httpProtocol.getTimeout(), 0);
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ spring:
|
||||
|
||||
collector:
|
||||
info:
|
||||
version: ${COLLECTOR_VERSION:1.7.0}
|
||||
version: ${COLLECTOR_VERSION:1.6.1}
|
||||
ip: ${COLLECTOR_IP:}
|
||||
dispatch:
|
||||
entrance:
|
||||
|
||||
@@ -35,7 +35,4 @@ public interface SmsConstants {
|
||||
|
||||
// Aws cloud SMS
|
||||
String AWS = "aws";
|
||||
|
||||
// Twilio SMS
|
||||
String TWILIO = "twilio";
|
||||
}
|
||||
|
||||
-5
@@ -122,11 +122,6 @@ public class NoticeReceiver {
|
||||
example = "779294123", accessMode = READ_WRITE)
|
||||
private String tgUserId;
|
||||
|
||||
@Schema(title = "Telegram message thread id: The notification method is valid for Telegram Bot",
|
||||
description = "TTelegram message thread id: The notification method is valid for Telegram Bot",
|
||||
example = "779294123", accessMode = READ_WRITE)
|
||||
private String tgMessageThreadId;
|
||||
|
||||
@Schema(title = "DingTalk,FeiShu,WeWork user id: The notification method is valid for DingTalk,FeiShu,WeWork Bot",
|
||||
description = "DingTalk,FeiShu,WeWork user id: The notification method is valid for DingTalk,FeiShu,WeWork Bot",
|
||||
example = "779294123", accessMode = READ_WRITE)
|
||||
|
||||
-6
@@ -95,12 +95,6 @@ public class HttpProtocol implements CommonRequestProtocol, Protocol {
|
||||
*/
|
||||
private List<String> successCodes;
|
||||
|
||||
/**
|
||||
* Whether to enable URL encoding for the path. Default is true.
|
||||
* When true, the URL path will be encoded. When false, the URL path will not be encoded.
|
||||
*/
|
||||
private String enableUrlEncoding = "true";
|
||||
|
||||
/**
|
||||
* authentication information
|
||||
*/
|
||||
|
||||
+9
-1
@@ -445,7 +445,15 @@ public final class CollectRep {
|
||||
if (value != null) {
|
||||
// Check byte array size, Arrow buffer size is 32768 bytes
|
||||
byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
|
||||
vector.setSafe(rowIndex, bytes);
|
||||
if (bytes.length > 32700) {
|
||||
log.warn("Value too large for Arrow buffer ({}), truncating to 32700 bytes. Meta: {}",
|
||||
bytes.length, JsonUtil.toJson(metadata));
|
||||
byte[] truncatedBytes = new byte[32700];
|
||||
System.arraycopy(bytes, 0, truncatedBytes, 0, 32700);
|
||||
vector.set(rowIndex, truncatedBytes);
|
||||
} else {
|
||||
vector.set(rowIndex, bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.manager.pojo.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Alibaba Sms Sender configuration dto
|
||||
*/
|
||||
@Data
|
||||
public class SmsAlibabaConfig {
|
||||
|
||||
@NotBlank(message = "AccessKeyId cannot be empty")
|
||||
private String accessKeyId;
|
||||
|
||||
@NotBlank(message = "AccessKeySecret cannot be empty")
|
||||
private String accessKeySecret;
|
||||
|
||||
@NotBlank(message = "SignName cannot be empty")
|
||||
private String signName;
|
||||
|
||||
@NotBlank(message = "TemplateCode cannot be null")
|
||||
private String templateCode;
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.manager.pojo.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* AWS Sms Sender configuration dto
|
||||
*/
|
||||
@Data
|
||||
public class SmsAwsConfig {
|
||||
|
||||
@NotBlank(message = "AccessKeyId cannot be empty")
|
||||
private String accessKeyId;
|
||||
|
||||
@NotBlank(message = "AccessKeySecret cannot be empty")
|
||||
private String accessKeySecret;
|
||||
|
||||
@NotBlank(message = "region cannot be empty")
|
||||
private String region;
|
||||
|
||||
}
|
||||
+18
-20
@@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.alert.config;
|
||||
package org.apache.hertzbeat.manager.pojo.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.AllArgsConstructor;
|
||||
@@ -23,27 +23,25 @@ import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* Twilio SMS configuration properties
|
||||
* Sms Sender configuration dto
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class TwilioSmsProperties {
|
||||
/**
|
||||
* Twilio Account SID
|
||||
*/
|
||||
@NotBlank(message = "Account SID cannot be empty")
|
||||
private String accountSid;
|
||||
@AllArgsConstructor
|
||||
public class SmsNoticeSender {
|
||||
|
||||
@NotBlank(message = "Type cannot be empty")
|
||||
private String type;
|
||||
|
||||
private SmsTencentConfig tencent;
|
||||
|
||||
private SmsAlibabaConfig alibaba;
|
||||
|
||||
/**
|
||||
* Twilio Auth Token
|
||||
*/
|
||||
@NotBlank(message = "Auth Token cannot be empty")
|
||||
private String authToken;
|
||||
private SmsUniSmsConfig unisms;
|
||||
|
||||
/**
|
||||
* Twilio Issued Phone Number
|
||||
*/
|
||||
@NotBlank(message = "Twilio Phone Number cannot be empty")
|
||||
private String twilioPhoneNumber;
|
||||
}
|
||||
private SmslocalConfig smslocal;
|
||||
|
||||
private SmsAwsConfig aws;
|
||||
|
||||
private boolean enable = true;
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.manager.pojo.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* Tencent Sms Sender configuration dto
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SmsTencentConfig {
|
||||
|
||||
@NotBlank(message = "SecretId cannot be empty")
|
||||
private String secretId;
|
||||
|
||||
@NotBlank(message = "SecretKey cannot be empty")
|
||||
private String secretKey;
|
||||
|
||||
@NotBlank(message = "SignName cannot be empty")
|
||||
private String signName;
|
||||
|
||||
@NotBlank(message = "AppId cannot be null")
|
||||
private String appId;
|
||||
|
||||
@NotBlank(message = "templateId cannot be null")
|
||||
private String templateId;
|
||||
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.manager.pojo.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.logging.log4j.core.config.plugins.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* UniSMS configuration
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SmsUniSmsConfig {
|
||||
/**
|
||||
* UniSMS access key id
|
||||
*/
|
||||
@NotBlank(message = "accessKeyId cannot be empty")
|
||||
private String accessKeyId;
|
||||
|
||||
/**
|
||||
* UniSMS access key secret, required for HMAC mode
|
||||
*/
|
||||
private String accessKeySecret;
|
||||
|
||||
/**
|
||||
* SMS signature
|
||||
*/
|
||||
@NotBlank(message = "signature cannot be null")
|
||||
private String signature;
|
||||
|
||||
/**
|
||||
* SMS template ID
|
||||
*/
|
||||
@NotBlank(message = "templateId cannot be null")
|
||||
private String templateId;
|
||||
|
||||
/**
|
||||
* Authentication mode: simple or hmac, default is simple
|
||||
*/
|
||||
@NotBlank(message = "authMode cannot be null")
|
||||
private String authMode = "simple";
|
||||
}
|
||||
+18
-4
@@ -17,8 +17,22 @@
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
export class TwilioSmsConfig {
|
||||
accountSid!: string;
|
||||
authToken!: string;
|
||||
twilioPhoneNumber!: string;
|
||||
package org.apache.hertzbeat.manager.pojo.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
|
||||
/**
|
||||
* Smslocal SMS configuration
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SmslocalConfig {
|
||||
/**
|
||||
* Smslocal api key
|
||||
*/
|
||||
private String apiKey;
|
||||
}
|
||||
+1
-2
@@ -75,8 +75,7 @@ import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
/**
|
||||
* Monitoring Type Management Implementation
|
||||
* Temporarily stores the monitoring configuration and parameter configuration in memory,
|
||||
* and then persists it to a storage system.
|
||||
* temporarily stores the monitoring configuration and parameter configuration in memory and then stores it in the
|
||||
*/
|
||||
@Service
|
||||
@Order(value = Ordered.HIGHEST_PRECEDENCE)
|
||||
|
||||
+5
-5
@@ -22,10 +22,10 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.hertzbeat.alert.config.SmsConfig;
|
||||
import org.apache.hertzbeat.common.constants.GeneralConfigTypeEnum;
|
||||
import org.apache.hertzbeat.base.dao.GeneralConfigDao;
|
||||
import org.apache.hertzbeat.common.support.event.SmsConfigChangeEvent;
|
||||
import org.apache.hertzbeat.manager.pojo.dto.SmsNoticeSender;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -35,7 +35,7 @@ import org.springframework.stereotype.Service;
|
||||
*/
|
||||
|
||||
@Service
|
||||
public class SmsGeneralConfigServiceImpl extends AbstractGeneralConfigServiceImpl<SmsConfig> {
|
||||
public class SmsGeneralConfigServiceImpl extends AbstractGeneralConfigServiceImpl<SmsNoticeSender> {
|
||||
@Resource
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@@ -55,7 +55,7 @@ public class SmsGeneralConfigServiceImpl extends AbstractGeneralConfigServiceImp
|
||||
* This method is used to handle the sms configuration change event.
|
||||
*/
|
||||
@Override
|
||||
public void handler(SmsConfig smsConfig) {
|
||||
public void handler(SmsNoticeSender smsNoticeSender) {
|
||||
applicationContext.publishEvent(new SmsConfigChangeEvent(applicationContext));
|
||||
}
|
||||
|
||||
@@ -69,11 +69,11 @@ public class SmsGeneralConfigServiceImpl extends AbstractGeneralConfigServiceImp
|
||||
* a TypeReference of NoticeSender type
|
||||
*/
|
||||
@Override
|
||||
public TypeReference<SmsConfig> getTypeReference() {
|
||||
public TypeReference<SmsNoticeSender> getTypeReference() {
|
||||
return new TypeReference<>() {
|
||||
@Override
|
||||
public Type getType() {
|
||||
return SmsConfig.class;
|
||||
return SmsNoticeSender.class;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -72,22 +72,14 @@ warehouse:
|
||||
rpc-port: 6667
|
||||
username: root
|
||||
password: root
|
||||
# store real-time metrics data, enable only one below
|
||||
real-time:
|
||||
redis:
|
||||
enabled: false
|
||||
host: 127.0.0.1
|
||||
port: 6379
|
||||
password: 123456
|
||||
memory:
|
||||
enabled: true
|
||||
init-size: 16
|
||||
redis:
|
||||
enabled: false
|
||||
# redis mode: single, sentinel, cluster. Default is single
|
||||
mode: single
|
||||
# separate each address with comma when using cluster mode, eg: 127.0.0.1:6379,127.0.0.1:6380
|
||||
address: 127.0.0.1:6379
|
||||
# enter master name when using sentinel mode
|
||||
masterName: mymaster
|
||||
password: 123456
|
||||
# redis db index, default: DB0
|
||||
db: 0
|
||||
|
||||
scheduler:
|
||||
server:
|
||||
@@ -110,4 +102,4 @@ ai:
|
||||
# api key
|
||||
api-key:
|
||||
#At present, only IFLYTEK large model needs to be filled in
|
||||
api-secret:
|
||||
api-secret:
|
||||
@@ -231,10 +231,6 @@ alerter:
|
||||
access-key-id: YOUR_ACCESS_KEY_ID
|
||||
access-key-secret: YOUR_ACCESS_KEY_SECRET
|
||||
region: AWS_REGION_FOR_END_USER_MESSAGING
|
||||
twilio:
|
||||
account-sid: YOUR_ACCOUNT_SID
|
||||
auth-token: YOUR_AUTH_TOKEN
|
||||
twilio-phone-number: YOUR_TWILIO_PHONE_NUMBER
|
||||
scheduler:
|
||||
server:
|
||||
enabled: true
|
||||
|
||||
@@ -17,44 +17,71 @@
|
||||
|
||||
-- ensure every sql can rerun without error
|
||||
|
||||
-- add repair table sql
|
||||
REPAIR TABLE HZB_ALERT_DEFINE;
|
||||
|
||||
DELIMITER //
|
||||
CREATE PROCEDURE AddOrDropColumns()
|
||||
BEGIN
|
||||
DECLARE col_exists INT;
|
||||
|
||||
-- Check and add 'app' column if it does not exist
|
||||
SELECT COUNT(*) INTO col_exists FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='HZB_ALERT_DEFINE' AND COLUMN_NAME='app';
|
||||
IF col_exists = 0 THEN
|
||||
ALTER TABLE HZB_ALERT_DEFINE ADD COLUMN app VARCHAR(255);
|
||||
END IF;
|
||||
-- Drop 'app' column if it exists
|
||||
SELECT COUNT(*) INTO col_exists FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='HZB_ALERT_DEFINE' AND COLUMN_NAME='app';
|
||||
IF col_exists = 1 THEN
|
||||
ALTER TABLE HZB_ALERT_DEFINE DROP COLUMN app;
|
||||
END IF;
|
||||
|
||||
-- Check and add 'metric' column if it does not exist
|
||||
SELECT COUNT(*) INTO col_exists FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='HZB_ALERT_DEFINE' AND COLUMN_NAME='metric';
|
||||
IF col_exists = 0 THEN
|
||||
ALTER TABLE HZB_ALERT_DEFINE ADD COLUMN metric VARCHAR(255);
|
||||
END IF;
|
||||
-- Drop 'metric' column if it exists
|
||||
SELECT COUNT(*) INTO col_exists FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='HZB_ALERT_DEFINE' AND COLUMN_NAME='metric';
|
||||
IF col_exists = 1 THEN
|
||||
ALTER TABLE HZB_ALERT_DEFINE DROP COLUMN metric;
|
||||
END IF;
|
||||
|
||||
-- Check and add 'field' column if it does not exist
|
||||
SELECT COUNT(*) INTO col_exists FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='HZB_ALERT_DEFINE' AND COLUMN_NAME='field';
|
||||
IF col_exists = 0 THEN
|
||||
ALTER TABLE HZB_ALERT_DEFINE ADD COLUMN field VARCHAR(255);
|
||||
END IF;
|
||||
-- Drop 'field' column if it exists
|
||||
SELECT COUNT(*) INTO col_exists FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='HZB_ALERT_DEFINE' AND COLUMN_NAME='field';
|
||||
IF col_exists = 1 THEN
|
||||
ALTER TABLE HZB_ALERT_DEFINE DROP COLUMN field;
|
||||
END IF;
|
||||
|
||||
-- Check and add 'preset' column if it does not exist
|
||||
SELECT COUNT(*) INTO col_exists FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='HZB_ALERT_DEFINE' AND COLUMN_NAME='preset';
|
||||
IF col_exists = 0 THEN
|
||||
ALTER TABLE HZB_ALERT_DEFINE ADD COLUMN preset BOOLEAN;
|
||||
END IF;
|
||||
-- Drop 'preset' column if it exists
|
||||
SELECT COUNT(*) INTO col_exists FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='HZB_ALERT_DEFINE' AND COLUMN_NAME='preset';
|
||||
IF col_exists = 1 THEN
|
||||
ALTER TABLE HZB_ALERT_DEFINE DROP COLUMN preset;
|
||||
END IF;
|
||||
|
||||
-- Check and add 'priority' column if it does not exist
|
||||
SELECT COUNT(*) INTO col_exists FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='HZB_ALERT_DEFINE' AND COLUMN_NAME='priority';
|
||||
IF col_exists = 0 THEN
|
||||
ALTER TABLE HZB_ALERT_DEFINE ADD COLUMN priority INTEGER;
|
||||
END IF;
|
||||
-- Drop 'priority' column if it exists
|
||||
SELECT COUNT(*) INTO col_exists FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='HZB_ALERT_DEFINE' AND COLUMN_NAME='priority';
|
||||
IF col_exists = 1 THEN
|
||||
ALTER TABLE HZB_ALERT_DEFINE DROP COLUMN priority;
|
||||
END IF;
|
||||
|
||||
-- Check and add 'tags' column if it does not exist
|
||||
SELECT COUNT(*) INTO col_exists FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='HZB_ALERT_DEFINE' AND COLUMN_NAME='tags';
|
||||
IF col_exists = 0 THEN
|
||||
ALTER TABLE HZB_ALERT_DEFINE ADD COLUMN tags VARCHAR(255);
|
||||
END IF;
|
||||
-- Drop 'tags' column if it exists
|
||||
SELECT COUNT(*) INTO col_exists FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='HZB_ALERT_DEFINE' AND COLUMN_NAME='tags';
|
||||
IF col_exists = 1 THEN
|
||||
@@ -66,5 +93,4 @@ DELIMITER ;
|
||||
|
||||
|
||||
CALL AddOrDropColumns();
|
||||
DROP PROCEDURE IF EXISTS AddOrDropColumns;
|
||||
commit;
|
||||
DROP PROCEDURE IF EXISTS AddOrDropColumns;
|
||||
@@ -246,20 +246,6 @@ params:
|
||||
defaultValue: '200, 201'
|
||||
# hide param-true or false
|
||||
hide: true
|
||||
# field-param field key
|
||||
- field: enableUrlEncoding
|
||||
# name-param field display i18n name
|
||||
name:
|
||||
zh-CN: 启用URL编码(UTF-8)
|
||||
en-US: Enable URL Encoding(UTF-8)
|
||||
# type-param field type(most mapping the html input type)
|
||||
type: boolean
|
||||
# required-true or false
|
||||
required: true
|
||||
# default value
|
||||
defaultValue: true
|
||||
# hide param-true or false
|
||||
hide: true
|
||||
# collect metrics config list
|
||||
metrics:
|
||||
# metrics - summary
|
||||
@@ -300,8 +286,6 @@ metrics:
|
||||
method: ^_^httpMethod^_^
|
||||
# if enabled https
|
||||
ssl: ^_^ssl^_^
|
||||
# enable url encoding
|
||||
enableUrlEncoding: ^_^enableUrlEncoding^_^
|
||||
# http request payload
|
||||
payload: ^_^payload^_^
|
||||
# http request header content
|
||||
@@ -360,8 +344,6 @@ metrics:
|
||||
method: GET
|
||||
# if enabled https
|
||||
ssl: ^_^ssl^_^
|
||||
# enable url encoding
|
||||
enableUrlEncoding: ^_^enableUrlEncoding^_^
|
||||
authorization:
|
||||
# http auth type: Basic Auth, Digest Auth, Bearer Token
|
||||
type: ^_^authType^_^
|
||||
|
||||
+3
-3
@@ -21,9 +21,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.hertzbeat.alert.config.SmsConfig;
|
||||
import org.apache.hertzbeat.common.constants.GeneralConfigTypeEnum;
|
||||
import org.apache.hertzbeat.base.dao.GeneralConfigDao;
|
||||
import org.apache.hertzbeat.manager.pojo.dto.SmsNoticeSender;
|
||||
import org.apache.hertzbeat.manager.service.impl.SmsGeneralConfigServiceImpl;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -66,9 +66,9 @@ class SmsGeneralConfigServiceTest {
|
||||
@Test
|
||||
void testGetTypeReference() {
|
||||
|
||||
TypeReference<SmsConfig> typeReference = service.getTypeReference();
|
||||
TypeReference<SmsNoticeSender> typeReference = service.getTypeReference();
|
||||
assertNotNull(typeReference);
|
||||
assertEquals(SmsConfig.class, typeReference.getType());
|
||||
assertEquals(SmsNoticeSender.class, typeReference.getType());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
---
|
||||
title: "Behind the Scenes of HertzBeat: How Metric Collection Works"
|
||||
author: JuJinPark
|
||||
author_title: JuJin
|
||||
author_url: https://github.com/JuJinPark
|
||||
tags: [opensource, practice]
|
||||
keywords: [open source monitoring system]
|
||||
---
|
||||
## Behind the Scenes of HertzBeat: How Metric Collection Works
|
||||
|
||||
HertzBeat is an open-source, real-time monitoring system designed for flexibility and ease of use. But how exactly does it collect, process, and store metrics from various systems?
|
||||
|
||||
In this post, we’ll walk through the internal architecture behind **HertzBeat’s metric collection pipeline** — from job distribution to alerting and storage — with the help of a high-level system diagram.
|
||||
|
||||
---
|
||||
|
||||
### HertzBeat’s Metric Collection Architecture
|
||||
|
||||

|
||||
|
||||
> **Figure:** High-level architecture of HertzBeat's metric collection system. The Manager handles job scheduling, alerting, and storage, while Collectors (external or internal) perform the actual metric collection. Communication between the Manager and Collectors uses a custom Netty TCP protocol.
|
||||
|
||||
---
|
||||
|
||||
### 1. Job Distribution: Assigning What to Monitor
|
||||
|
||||
When the **Manager** component starts, it loads monitoring targets from the database. These targets define the host, collection interval, and other parameters.
|
||||
|
||||
To distribute the workload, the Manager sends jobs to **external Collectors** over a custom **Netty-based TCP protocol**. The `CollectJobScheduling` module handles this logic using **consistent hashing**, ensuring jobs are evenly distributed across collectors.
|
||||
|
||||
> 💡 HertzBeat also includes a built-in **main collector** (identified as `MAIN_COLLECTOR_NODE`) that runs directly inside the Manager. This allows HertzBeat to operate in **standalone mode** without requiring any external collectors.
|
||||
|
||||
---
|
||||
|
||||
### 2. Task Scheduling: When to Monitor
|
||||
|
||||
Once a Collector receives a job, it registers it with the **`TimerDispatch`** system.
|
||||
|
||||
- For **external collectors**, the Manager sends the task via the TCP connection.
|
||||
- For the **main collector**, the Manager directly invokes `CollectJobService` within the same process.
|
||||
|
||||
Each Collector runs a **`Timer`** in a background thread, which schedules tasks according to their configured intervals. When the time is up, the timer triggers a `TimerTask` to begin metric collection.
|
||||
|
||||
---
|
||||
|
||||
### 3. Task Execution: How Metrics Are Collected
|
||||
|
||||
When a `TimerTask` is triggered, it creates a `MetricsCollect` task and passes it to `MetricsTaskDispatch`, which places it in the **`MetricsCollectorQueue`**.
|
||||
|
||||
- A dedicated thread (`CommonDispatcher`) continuously polls this queue.
|
||||
- Tasks are executed by a **worker thread pool**, allowing multiple metric collections to run concurrently.
|
||||
- Each task uses a specific **collector strategy** (e.g., HTTP, JDBC, SSH) to fetch metrics from the target system.
|
||||
|
||||
---
|
||||
|
||||
### 4. Result Processing: What Happens to Collected Data
|
||||
|
||||
Once metrics are collected, the results are processed by the **`CollectDataDispatch`** module.
|
||||
|
||||
- If the task is recurring, it is rescheduled via `TimerDispatch`.
|
||||
- Results are added to a **`CommonDataQueue`** for further handling.
|
||||
|
||||
For external collectors, results are sent **back to the Manager** via the Netty TCP connection. For the main collector, results are forwarded **directly** to the next processing stage without network overhead.
|
||||
|
||||
---
|
||||
|
||||
### 5. Alerting & Storage: Making Metrics Useful
|
||||
|
||||
The Manager receives metric data and pushes it into the `MetricsDataToAlertQueue`, where it is processed through two main pipelines:
|
||||
|
||||
#### 🔔 Alerting
|
||||
|
||||
- The `RealTimeAlertCalculator` consumes metrics from the alert queue.
|
||||
- It checks each metric against user-defined alert rules and triggers alerts if conditions are met.
|
||||
|
||||
#### 🧠 Storage
|
||||
|
||||
- After alert evaluation, metrics are added to the `MetricsDataToStorageQueue`.
|
||||
- A background thread (`DataStorageDispatch`) processes this queue and stores the metrics in a database for long-term analysis and dashboard visualization.
|
||||
|
||||
---
|
||||
|
||||
### Standalone Mode: No External Collectors Required
|
||||
|
||||
Thanks to the built-in **main collector**, HertzBeat can operate entirely in standalone mode. This is especially useful for testing, small deployments, or quick setup. All core components — job scheduling, collection, alerting, and storage — run within a single process.
|
||||
|
||||
---
|
||||
|
||||
### 🧠 Conclusion
|
||||
|
||||
HertzBeat’s metric collection system is designed for **performance, scalability, and flexibility**. With its:
|
||||
|
||||
- **Queue-based, multi-threaded architecture**
|
||||
- **Persistent TCP connections** for reliable job/result flow
|
||||
- **Built-in main collector** for standalone operation
|
||||
|
||||
it handles large-scale monitoring workloads with minimal overhead and high efficiency.
|
||||
|
||||
---
|
||||
|
||||
### 🙌 What’s Next?
|
||||
|
||||
If you're curious to explore more:
|
||||
|
||||
- ⭐️ [Star the project on GitHub](https://github.com/apache/hertzbeat)
|
||||
- 🤝 [Contribute or open an issue](https://github.com/apache/hertzbeat/issues)
|
||||
@@ -62,8 +62,8 @@ The HertzBeat install package will at `dist/hertzbeat-{version}.tar.gz`
|
||||
|
||||
2. Execute under the project root directory: `mvn clean install`
|
||||
|
||||
3. Cd to the `hertzbeat-collector` directory: `cd hertzbeat-collector`
|
||||
3. Cd to the `collector` directory: `cd collector`
|
||||
|
||||
4. Execute under `hertzbeat-collector` directory: `mvn clean package -Pcluster`
|
||||
4. Execute under `collector` directory: `mvn clean package -Pcluster`
|
||||
|
||||
The HertzBeat collector package will at `dist/hertzbeat-collector-{version}.tar.gz`
|
||||
|
||||
@@ -215,7 +215,6 @@ The release package are here:
|
||||
|
||||
- `dist/apache-hertzbeat-{version}-incubating-bin.tar.gz`
|
||||
- `dist/apache-hertzbeat-collector-{version}-incubating-bin.tar.gz`
|
||||
- `dist/apache-hertzbeat-{version}-incubating-docker-compose.tar.gz`
|
||||
|
||||
#### 3.4 Package the source code
|
||||
|
||||
@@ -258,9 +257,6 @@ apache-hertzbeat-1.6.0-incubating-src.tar.gz.sha512
|
||||
apache-hertzbeat-1.6.0-incubating-bin.tar.gz
|
||||
apache-hertzbeat-1.6.0-incubating-bin.tar.gz.asc
|
||||
apache-hertzbeat-1.6.0-incubating-bin.tar.gz.sha512
|
||||
apache-hertzbeat-1.6.0-incubating-docker-compose.tar.gz
|
||||
apache-hertzbeat-1.6.0-incubating-docker-compose.tar.gz.asc
|
||||
apache-hertzbeat-1.6.0-incubating-docker-compose.tar.gz.sha512
|
||||
apache-hertzbeat-collector-1.6.0-incubating-bin.tar.gz
|
||||
apache-hertzbeat-collector-1.6.0-incubating-bin.tar.gz.asc
|
||||
apache-hertzbeat-collector-1.6.0-incubating-bin.tar.gz.sha512
|
||||
@@ -294,8 +290,6 @@ apache-hertzbeat-1.6.0-incubating-src.tar.gz
|
||||
apache-hertzbeat-1.6.0-incubating-src.tar.gz: OK
|
||||
apache-hertzbeat-1.6.0-incubating-bin.tar.gz
|
||||
apache-hertzbeat-1.6.0-incubating-bin.tar.gz: OK
|
||||
apache-hertzbeat-1.6.0-incubating-docker-compose.tar.gz
|
||||
apache-hertzbeat-1.6.0-incubating-docker-compose.tar.gz: OK
|
||||
apache-hertzbeat-collector-1.6.0-incubating-bin.tar.gz
|
||||
apache-hertzbeat-collector-1.6.0-incubating-bin.tar.gz: OK
|
||||
```
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
---
|
||||
id: alarm_center
|
||||
title: Alarm Center
|
||||
sidebar_label: Alarm Center
|
||||
keywords:
|
||||
[open-source monitoring system, alarm center, alarm management, alarm display]
|
||||
---
|
||||
|
||||
> The Alarm Center serves as a comprehensive visualization platform that displays all alarms after undergoing grouping, consolidation, suppression, and silencing processes. It encompasses both internally triggered threshold-based alarms and integrated third-party notifications.
|
||||
|
||||
## Alarm Sources
|
||||
|
||||
The HertzBeat Alarm Center manages notifications from two primary sources:
|
||||
|
||||
1. Internal Threshold-Triggered Alarms
|
||||
- Generated when monitoring metrics exceed predefined thresholds
|
||||
- Directly correlated with monitoring tasks and threshold rules configured within the system
|
||||
- Manageable through adjustment of monitoring parameters and threshold configurations
|
||||
2. Third-Party Integrated Alarms
|
||||
- Received through API interfaces from external systems
|
||||
- Compatible with various monitoring systems and alarm platforms
|
||||
- Processed through identical workflow as internal alarms
|
||||
|
||||
## Alarm Processing Mechanism
|
||||
|
||||
Before appearing in the Alarm Center, all notifications undergo several processing stages:
|
||||
|
||||
1. Grouping
|
||||
- Categorizes related alarms based on source, type, severity, and other attributes (labels)
|
||||
- Facilitates efficient management of high-volume alarms
|
||||
- Supports customizable grouping rules for diverse scenarios
|
||||
2. Consolidation
|
||||
- Mitigates notification fatigue from multiple similar alarms within short intervals
|
||||
- Presents consolidated alarms in a streamlined format, eliminating redundancy
|
||||
3. Suppression
|
||||
- Manages alarm dependencies
|
||||
- Suppresses secondary alarms when primary alarms are triggered
|
||||
- Supports configurable suppression rules based on alarm dependencies
|
||||
4. Silencing
|
||||
- Temporarily mutes specific alarms during designated periods
|
||||
- Ideal for system maintenance windows and known issue handling
|
||||
- Enables time-based silence rule configuration
|
||||
|
||||
## Alarm Center Interface
|
||||
|
||||

|
||||
|
||||
The Alarm Center provides a comprehensive view of all system alarms:
|
||||
|
||||
1. Alarm Display
|
||||
- Lists all alarms with crucial information including status, source, labels, and timestamps
|
||||
- Offers detailed view functionality for comprehensive alarm information and context
|
||||
2. Search Functionality
|
||||
- Enables rapid alarm identification
|
||||
- Supports multiple search criteria (labels, annotations, alarm status)
|
||||
3. Alarm Management
|
||||
- Alarm Deletion: Removes alarms no longer requiring attention
|
||||
@@ -225,52 +225,6 @@ alerter:
|
||||
|
||||
Now you can configure this information in your hertzbeat application.
|
||||
|
||||
### Twilio SMS Configuration
|
||||
|
||||
To activate and use the Twilio SMS service, refer to the official Twilio documentation: [SMS Getting Started Guide](https://www.twilio.com/docs/sms/quickstart)
|
||||
|
||||
You can configure the Twilio SMS service either through the graphical interface or in the `application.yml` file.
|
||||
To use `application.yml`, add/fill in the following Twilio SMS configuration (replace parameters with your own SMS server configuration):
|
||||
|
||||
```yaml
|
||||
alerter:
|
||||
sms:
|
||||
enable: true # Whether to enable
|
||||
type: twilio # SMS provider type, supports "twilio"
|
||||
twilio: # Twilio SMS configuration
|
||||
account-sid: # Your Twilio Account SID
|
||||
auth-token: # Your Twilio Auth Token
|
||||
twilio-phone-number: # Your Twilio Phone Number
|
||||
```
|
||||
|
||||
1. Create a Twilio account
|
||||
|
||||
- If you don't have a Twilio account, sign up at [Twilio Console](https://www.twilio.com/console)
|
||||
- You'll get a free trial account that allows you to test the SMS service
|
||||
|
||||
2. Obtain Twilio credentials
|
||||
|
||||
- After signing in, locate your Account SID and Auth Token on the dashboard
|
||||
- These credentials will be used to authenticate API requests
|
||||
|
||||
3. Get a Twilio Phone Number
|
||||
|
||||
- In the Twilio Console, navigate to "Phone Numbers" > "Manage" > "Active Numbers"
|
||||
- Click "Buy a Number" or use the trial number provided by Twilio
|
||||
- Make sure the number has SMS capabilities enabled
|
||||
- This number will be used as the sender for your SMS alerts
|
||||
- A phone number is required for the Twilio SMS service to work
|
||||
|
||||
4. Testing Your Configuration on Twilio
|
||||
|
||||
- Twilio provides a sandbox environment for testing
|
||||
- If you are in the trial period, you will only be able to send SMS to verified phone numbers
|
||||
- To verify a phone number, add it to your verified phone numbers list in the Twilio Console
|
||||
|
||||
> The message follows the format: "Instance: {}, Priority: {}, Content: {}"
|
||||
|
||||
This information can be configured in the Hertzbeat application.
|
||||
|
||||
## Operation steps
|
||||
|
||||
1. **【Alarm notification】->【Add new recipient】 ->【Select SMS notification method】**
|
||||
|
||||
@@ -9,7 +9,7 @@ keywords: [bulletin, custom]
|
||||
|
||||
### Add Bulletin Item
|
||||
|
||||
1. Click `Add New Bulletin Item`, enter the `Bulletin Name`, scroll down to select the `Monitoring Type`, select the associated `Monitoring Task Name`, You can filter `Monitor Task Name` by `Label`, and then select the `Monitoring Metrics` you want to show in the shuttle box.
|
||||
1. Click `Add New Bulletin Item`, enter the `Bulletin Name`, scroll down to select the `Monitoring Type`, select the associated `Monitoring Task Name`, and then select the `Monitoring Metrics` you want to show in the shuttle box.
|
||||
|
||||
2. Click `OK` button to finish creating the customized bulletin.
|
||||
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
---
|
||||
id: collector
|
||||
title: HertzBeat Collector
|
||||
sidebar_label: Collector
|
||||
keywords: [monitoring, observability, collector, metrics]
|
||||
---
|
||||
|
||||
> HertzBeat Collector is a lightweight data collection module that enables metrics collection, high availability deployments, and cloud-edge collaboration in Apache HertzBeat (incubating).
|
||||
|
||||
## Introduction
|
||||
|
||||
HertzBeat Collector is a versatile and lightweight metrics collection module within the Apache HertzBeat monitoring system. It's designed to gather monitoring data from various targets and send the collected metrics to the main HertzBeat server for processing, alerting, and visualization.
|
||||
|
||||
With the collector module, you can implement:
|
||||
|
||||
- **High Availability**: Deploy multiple collectors to ensure continuous monitoring even if some collector instances fail
|
||||
- **Load Balancing**: Distribute monitoring tasks across multiple collectors to improve performance
|
||||
- **Cloud-Edge Collaboration**: Monitor resources in isolated networks while managing everything from a central HertzBeat server
|
||||
|
||||
## Collector Architecture
|
||||
|
||||
The collector module is built with a modular design to make it easily extensible for various monitoring scenarios. The architecture consists of:
|
||||
|
||||
1. **Collector Entry Point**: The main entry point for running the collector module, from which collection tasks are executed after startup.
|
||||
|
||||
2. **collector-basic**: Contains implementations for common protocols like HTTP, JDBC, SSH, SNMP, etc. These collectors typically don't require additional proprietary dependencies and can handle most basic monitoring needs.
|
||||
|
||||
3. **collector-common**: Provides general utility classes and methods, such as connection pools and caching mechanisms that other modules can reuse.
|
||||
|
||||
4. **collector-xxx**: Extension modules for specific services or protocols (MongoDB, RocketMQ, Kafka, NebulaGraph, etc.). These modules often require specific dependencies for their respective services.
|
||||
|
||||
## Supported Protocols
|
||||
|
||||
HertzBeat Collector supports an extensive list of monitoring protocols:
|
||||
|
||||
| Protocol Category | Protocols |
|
||||
| ----------------- | ------------------------------------------------------------------------------------- |
|
||||
| Web/API | `http`, `ssl_cert`, `websocket` |
|
||||
| Databases | `jdbc`, `redis`, `mongodb`, `memcached` |
|
||||
| Operating Systems | `ssh`, `ipmi` |
|
||||
| Network | `icmp` (ping), `telnet`, `snmp`, `modbus` |
|
||||
| Messaging | `mqtt`, `rocketmq`, `kafka` |
|
||||
| Email | `pop3`, `smtp`, `imap` |
|
||||
| Cloud Services | `prometheus`, `nebulagraph`, `ngql` |
|
||||
| Others | `jmx`, `dns`, `ftp`, `ntp`, `udp`, `nginx`, `redfish`, `script`, `registry`, `httpsd` |
|
||||
|
||||
## Deployment Options
|
||||
|
||||
You can deploy HertzBeat Collector in several ways depending on your environment and needs, once you log in to the HertzBeat web interface and go to the collector, you can see the deployment options.
|
||||
|
||||
Parameters explanation:
|
||||
|
||||
- `-e IDENTITY=custom-collector-name`: (Optional) Set a unique identifier for this collector. Must be unique across all collectors.
|
||||
- `-e MODE=public`: Set the running mode (public or private), for public cluster or private cloud-edge mode.
|
||||
- `-e MANAGER_HOST=192.168.1.100`: Important! Set the IP address of the main HertzBeat server. Replace with your actual server IP.
|
||||
- `-e MANAGER_PORT=1158`: (Optional) Set the port of the main HertzBeat server, default is 1158.
|
||||
- `-v $(pwd)/logs:/opt/hertzbeat-collector/logs`: (Optional) Mount the log files to the local host.
|
||||
|
||||
## Operating Modes
|
||||
|
||||
HertzBeat Collector supports two operating modes:
|
||||
|
||||
### Public Mode (Cluster Mode)
|
||||
|
||||
In public mode, collectors form a cluster with the main HertzBeat server. Tasks are automatically distributed among collectors, providing high availability and load balancing.
|
||||
|
||||
- Set `MODE=public` when deploying the collector
|
||||
- All collectors must have connectivity to the main HertzBeat server
|
||||
- Great for horizontal scaling to handle large numbers of monitoring tasks
|
||||
|
||||
### Private Mode (Cloud-Edge Mode)
|
||||
|
||||
In private mode, collectors operate in isolated networks while still reporting to a central HertzBeat server. This allows monitoring of resources in multiple separate networks.
|
||||
|
||||
- Set `MODE=private` when deploying the collector
|
||||
- Collectors need outbound connectivity to the HertzBeat server, but inbound connectivity is not required
|
||||
- Ideal for monitoring resources across different data centers, cloud providers, or network segments
|
||||
|
||||
## Configuration Parameters
|
||||
|
||||
| Parameter | Description | Default |
|
||||
| -------------- | ----------------------------------- | ------------------------- |
|
||||
| `identity` | Unique identifier for the collector | Auto-generated if not set |
|
||||
| `mode` | Operating mode (public/private) | public |
|
||||
| `manager-host` | IP address of the HertzBeat server | IP |
|
||||
| `manager-port` | Port of the HertzBeat server | 1158 |
|
||||
|
||||
## Collector Management
|
||||
|
||||
You can manage collectors through the HertzBeat web interface:
|
||||
|
||||
1. Navigate to the Overview page to see all registered collectors
|
||||
2. Monitor collector status (online/offline), metrics tasks, and system information
|
||||
3. Enable or disable collectors as needed
|
||||
|
||||
## High Availability Setup
|
||||
|
||||
To achieve high availability with HertzBeat collectors:
|
||||
|
||||
1. Deploy multiple collector instances across different servers or containers
|
||||
2. Ensure all collectors have the same `mode` setting
|
||||
3. Connect all collectors to the same HertzBeat server
|
||||
4. HertzBeat will automatically distribute monitoring tasks and handle failover
|
||||
|
||||
If a collector goes offline, its tasks will be reassigned to other available collectors. When the collector comes back online, it will receive new tasks based on the current load distribution.
|
||||
|
||||
## Cloud-Edge Collaboration
|
||||
|
||||
For monitoring across isolated networks:
|
||||
|
||||
1. Deploy HertzBeat Server in your central management network
|
||||
2. Deploy collectors in each isolated network you need to monitor
|
||||
3. Configure collectors with:
|
||||
- `MODE=private`
|
||||
- `MANAGER_HOST=` pointing to your central HertzBeat server
|
||||
4. Ensure outbound connectivity from each isolated network to the central server
|
||||
5. Manage all monitoring tasks from the central HertzBeat dashboard
|
||||
|
||||
## Advanced Features
|
||||
|
||||
### Custom Protocol Support
|
||||
|
||||
HertzBeat's architecture allows for extending the collector with custom protocols. Developers can create new collector modules following the project's modular design.
|
||||
|
||||
### Task Scheduling
|
||||
|
||||
The collector automatically handles task scheduling based on task priority, available resources, and current system load. Tasks are processed with intelligent prioritization to ensure critical monitoring is performed first.
|
||||
|
||||
### Resource Utilization
|
||||
|
||||
Collectors are designed to be lightweight and efficient with system resources, making them suitable for deployment on various hardware, from small edge devices to powerful servers.
|
||||
@@ -107,8 +107,6 @@ sidebar_label: Help Center
|
||||
|
||||
> The triggered alarm information center provides query and filtering of alarm deletion, alarm processing, mark unprocessed, alarm level status, etc.
|
||||
|
||||
More details see 👉 [Alarm center](alarm_center)
|
||||
|
||||
### Alarm configuration
|
||||
|
||||
> The Metric threshold configuration provides the Metric threshold configuration in the form of expression, which can set the alarm level, trigger times, alarm notification template and whether it is enabled, correlation monitoring and other functions.
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
"description": "The label of footer link with label=contact linking to /docs/community/contact"
|
||||
},
|
||||
"copyright": {
|
||||
"message": "\n <div style=\"text-align: left;margin-top:30px\">\n <div style=\"align-items: center; display: flex\">\n <div style=\"width: 1200px; background-color: #282c77; padding: 10px; border-radius: 6px\">\n <a href=\"https://incubator.apache.org/\">\n <img src=\"/img/icons/apache-incubator.svg\" alt=\"Apache Incubator logo\">\n </a>\n </div>\n <div style=\"margin-left: 40px\">\n <p style=\"font-size: 14px;line-height: 25px;\">\n Apache HertzBeat is an effort undergoing incubation at The Apache Software Foundation (ASF), sponsored by the Apache Incubator. Incubation is required of all newly accepted projects until a further review indicates that the infrastructure, communications, and decision making process have stabilized in a manner consistent with other successful ASF projects. While incubation status is not necessarily a reflection of the completeness or stability of the code, it does indicate that the project has yet to be fully endorsed by the ASF.\n </p>\n </div>\n </div>\n\n <div style=\"border-top: 1px solid #525252;min-height: 60px;line-height: 25px;text-align: left;font-size: 14px;display: flex;align-items: center;\">\n <span>\n Copyright © 2024-2025 The Apache Software Foundation. Apache HertzBeat, HertzBeat, and its feather logo are trademarks of The Apache Software Foundation.\n </span>\n </div>\n </div>",
|
||||
"message": "\n <div style=\"text-align: left;margin-top:30px\">\n <div style=\"align-items: center; display: flex\">\n <div style=\"width: 1200px; background-color: #282c77; padding: 10px; border-radius: 6px\">\n <a href=\"https://incubator.apache.org/\">\n <img src=\"/img/icons/apache-incubator.svg\" alt=\"Apache Incubator logo\">\n </a>\n </div>\n <div style=\"margin-left: 40px\">\n <p style=\"font-size: 14px;line-height: 25px;\">\n Apache HertzBeat is an effort undergoing incubation at The Apache Software Foundation (ASF), sponsored by the Apache Incubator. Incubation is required of all newly accepted projects until a further review indicates that the infrastructure, communications, and decision making process have stabilized in a manner consistent with other successful ASF projects. While incubation status is not necessarily a reflection of the completeness or stability of the code, it does indicate that the project has yet to be fully endorsed by the ASF.\n </p>\n </div>\n </div>\n\n <div style=\"border-top: 1px solid #525252;min-height: 60px;line-height: 25px;text-align: left;font-size: 14px;display: flex;align-items: center;\">\n <span>\n Copyright © 2024 The Apache Software Foundation. Apache HertzBeat, HertzBeat, and its feather logo are trademarks of The Apache Software Foundation.\n </span>\n </div>\n </div>",
|
||||
"description": "The footer copyright"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,11 +128,11 @@
|
||||
"description": "The label for category NGQL in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.llm": {
|
||||
"message": "AI大模型监控",
|
||||
"message": "Ai大模型监控",
|
||||
"description": "The label for category llm in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.aiConfig": {
|
||||
"message": "AI大模型配置",
|
||||
"message": "Ai大模型配置",
|
||||
"description": "The label for category aiConfig in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.install": {
|
||||
|
||||
@@ -65,8 +65,8 @@ HertzBeat 包将生成为 `dist/hertzbeat-{version}.tar.gz`
|
||||
|
||||
2. 在项目根目录运行: `mvn clean install`
|
||||
|
||||
3. 切换到 `hertzbeat-collector` 目录: `cd hertzbeat-collector`
|
||||
3. 切换到 `collector` 目录: `cd collector`
|
||||
|
||||
4. 在 `hertzbeat-collector` 目录下执行: `mvn clean package -Pcluster`
|
||||
4. 在 `collector` 目录下执行: `mvn clean package -Pcluster`
|
||||
|
||||
HertzBeat 采样器包将生成为 `dist/hertzbeat-collector-{version}.tar.gz`
|
||||
|
||||
@@ -215,7 +215,6 @@ mvn clean package -Pcluster
|
||||
|
||||
- `dist/apache-hertzbeat-{version}-incubating-bin.tar.gz`
|
||||
- `dist/apache-hertzbeat-collector-{version}-incubating-bin.tar.gz`
|
||||
- `dist/apache-hertzbeat-{version}-incubating-docker-compose.tar.gz`
|
||||
|
||||
#### 3.4 打包项目源代码
|
||||
|
||||
@@ -260,9 +259,6 @@ apache-hertzbeat-1.6.0-incubating-src.tar.gz.sha512
|
||||
apache-hertzbeat-1.6.0-incubating-bin.tar.gz
|
||||
apache-hertzbeat-1.6.0-incubating-bin.tar.gz.asc
|
||||
apache-hertzbeat-1.6.0-incubating-bin.tar.gz.sha512
|
||||
apache-hertzbeat-1.6.0-incubating-docker-compose.tar.gz
|
||||
apache-hertzbeat-1.6.0-incubating-docker-compose.tar.gz.asc
|
||||
apache-hertzbeat-1.6.0-incubating-docker-compose.tar.gz.sha512
|
||||
apache-hertzbeat-collector-1.6.0-incubating-bin.tar.gz
|
||||
apache-hertzbeat-collector-1.6.0-incubating-bin.tar.gz.asc
|
||||
apache-hertzbeat-collector-1.6.0-incubating-bin.tar.gz.sha512
|
||||
@@ -296,8 +292,6 @@ apache-hertzbeat-1.6.0-incubating-src.tar.gz
|
||||
apache-hertzbeat-1.6.0-incubating-src.tar.gz: OK
|
||||
apache-hertzbeat-1.6.0-incubating-bin.tar.gz
|
||||
apache-hertzbeat-1.6.0-incubating-bin.tar.gz: OK
|
||||
apache-hertzbeat-1.6.0-incubating-docker-compose.tar.gz
|
||||
apache-hertzbeat-1.6.0-incubating-docker-compose.tar.gz: OK
|
||||
apache-hertzbeat-collector-1.6.0-incubating-bin.tar.gz
|
||||
apache-hertzbeat-collector-1.6.0-incubating-bin.tar.gz: OK
|
||||
```
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
---
|
||||
id: alarm_center
|
||||
title: 告警中心
|
||||
sidebar_label: 告警中心
|
||||
keywords: [开源监控系统, 告警中心, 告警管理,告警显示]
|
||||
---
|
||||
|
||||
> 告警中心是一个展示平台,用于显示所有经过分组、收敛、抑制、静默等处理的告警,包括由内部系统阈值触发的告警和第三方接入告警。
|
||||
|
||||
## 告警来源
|
||||
|
||||
HertzBeat 的告警中心管理来自两个主要来源的告警:
|
||||
|
||||
1. 系统内部阈值触发的告警
|
||||
- 当监控指标超过预定义阈值时生成
|
||||
- 与系统中配置的监控任务和阈值规则直接相关
|
||||
- 可以通过调整监控任务和阈值设置进行控制
|
||||
2. 第三方接入告警
|
||||
- 通过 API 接口从外部系统接收
|
||||
- 支持与其他监控系统或告警平台集成
|
||||
- 与内部告警一样经过相同的处理流程
|
||||
|
||||
## 告警处理机制
|
||||
|
||||
在显示到告警中心之前,所有告警都会经过几个处理步骤:
|
||||
|
||||
1. 分组
|
||||
- 基于来源、类型、严重程度和其他属性(标签)对相关告警进行分类
|
||||
- 帮助高效管理大量告警
|
||||
- 支持针对不同场景的自定义分组规则
|
||||
2. 收敛
|
||||
- 减少短时间内发生的多个类似告警产生的干扰
|
||||
- 以更简洁的方式呈现收敛后的告警,避免信息冗余
|
||||
3. 抑制
|
||||
- 处理告警之间的依赖关系
|
||||
- 当关键告警触发时,可以抑制相关的次要告警
|
||||
- 支持配置定义告警依赖关系的抑制规则
|
||||
4. 静默
|
||||
- 在特定时间段内暂时屏蔽某些告警
|
||||
- 适用于系统维护、已知问题处理等场景
|
||||
- 可以基于时间设置静默规则
|
||||
|
||||
## 告警中心界面
|
||||
|
||||

|
||||
|
||||
告警中心提供了系统所有告警的全面视图:
|
||||
|
||||
1. 告警显示
|
||||
- 列出所有告警,包含告警状态、来源、标签和时间等关键信息
|
||||
- 提供详细视图功能,显示完整的告警信息和上下文
|
||||
2. 搜索功能
|
||||
- 帮助快速定位特定告警
|
||||
- 支持多种搜索(标签、注解、告警状态等)
|
||||
3. 告警管理
|
||||
- 告警删除:移除不再需要关注的告警
|
||||
@@ -9,7 +9,7 @@ keywords: [看板, 自定义]
|
||||
|
||||
### 新增看板项
|
||||
|
||||
1. 点击新增看板项, 输入`看板名称`, 下拉选择`监控类型`, 可根据`标签`对`监控任务名称`进行筛选,再选择关联的`监控任务名称`, 最后在穿梭框中选择需要展示的`监控指标`。
|
||||
1. 点击新增看板项, 输入`看板名称`, 下拉选择`监控类型`, 再选择关联的`监控任务名称`, 最后在穿梭框中选择需要展示的`监控指标`。
|
||||
|
||||
2. 点击`确定`按钮, 即可完成自定义看板的创建。
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ sidebar_label: 帮助入门
|
||||
 👉 [ElasticSearch](elasticsearch) <br />
|
||||
 👉 [Flink](flink) <br />
|
||||
|
||||
### AI大模型监控
|
||||
### Ai大模型监控
|
||||
|
||||
 👉 [OpenAi](openai) <br />
|
||||
|
||||
@@ -107,8 +107,6 @@ sidebar_label: 帮助入门
|
||||
|
||||
> 已触发的告警信息中心,提供告警删除,告警处理,标记未处理,告警级别状态等查询过滤。
|
||||
|
||||
详见 👉 [告警中心](alarm_center)
|
||||
|
||||
### 告警配置
|
||||
|
||||
> 指标阈值配置,提供表达式形式的指标阈值配置,可设置告警级别,触发次数,告警通知模版和是否启用,关联监控等功能。
|
||||
|
||||
@@ -87,7 +87,7 @@ sidebar_label: 帮助入门
|
||||
 👉 [ElasticSearch](elasticsearch) <br />
|
||||
 👉 [Flink](flink) <br />
|
||||
|
||||
### AI大模型监控
|
||||
### Ai大模型监控
|
||||
|
||||
 👉 [OpenAi](openai) <br />
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
"description": "The label of footer link with label=contact linking to /docs/community/contact"
|
||||
},
|
||||
"copyright": {
|
||||
"message": "\n <div style=\"text-align: left;margin-top:30px\">\n <div style=\"align-items: center; display: flex\">\n <div style=\"width: 1200px; background-color: #282c77; padding: 10px; border-radius: 6px\">\n <a href=\"https://incubator.apache.org/\">\n <img src=\"/img/icons/apache-incubator.svg\" alt=\"Apache Incubator logo\">\n </a>\n </div>\n <div style=\"margin-left: 40px\">\n <p style=\"font-size: 14px;line-height: 25px;\">\n Apache HertzBeat is an effort undergoing incubation at The Apache Software Foundation (ASF), sponsored by the Apache Incubator. Incubation is required of all newly accepted projects until a further review indicates that the infrastructure, communications, and decision making process have stabilized in a manner consistent with other successful ASF projects. While incubation status is not necessarily a reflection of the completeness or stability of the code, it does indicate that the project has yet to be fully endorsed by the ASF.\n </p>\n </div>\n </div>\n\n <div style=\"border-top: 1px solid #525252;min-height: 60px;line-height: 25px;text-align: left;font-size: 14px;display: flex;align-items: center;\">\n <span>\n Copyright © 2024-2025 The Apache Software Foundation. Apache HertzBeat, HertzBeat, and its feather logo are trademarks of The Apache Software Foundation.\n </span>\n </div>\n </div>",
|
||||
"message": "\n <div style=\"text-align: left;margin-top:30px\">\n <div style=\"align-items: center; display: flex\">\n <div style=\"width: 1200px; background-color: #282c77; padding: 10px; border-radius: 6px\">\n <a href=\"https://incubator.apache.org/\">\n <img src=\"/img/icons/apache-incubator.svg\" alt=\"Apache Incubator logo\">\n </a>\n </div>\n <div style=\"margin-left: 40px\">\n <p style=\"font-size: 14px;line-height: 25px;\">\n Apache HertzBeat is an effort undergoing incubation at The Apache Software Foundation (ASF), sponsored by the Apache Incubator. Incubation is required of all newly accepted projects until a further review indicates that the infrastructure, communications, and decision making process have stabilized in a manner consistent with other successful ASF projects. While incubation status is not necessarily a reflection of the completeness or stability of the code, it does indicate that the project has yet to be fully endorsed by the ASF.\n </p>\n </div>\n </div>\n\n <div style=\"border-top: 1px solid #525252;min-height: 60px;line-height: 25px;text-align: left;font-size: 14px;display: flex;align-items: center;\">\n <span>\n Copyright © 2024 The Apache Software Foundation. Apache HertzBeat, HertzBeat, and its feather logo are trademarks of The Apache Software Foundation.\n </span>\n </div>\n </div>",
|
||||
"description": "The footer copyright"
|
||||
}
|
||||
}
|
||||
|
||||
+67
-27
@@ -23,19 +23,28 @@
|
||||
{
|
||||
"type": "category",
|
||||
"label": "extern-deploy",
|
||||
"items": ["start/baota-deploy", "start/rainbond-deploy"]
|
||||
"items": [
|
||||
"start/baota-deploy",
|
||||
"start/rainbond-deploy"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "upgrade",
|
||||
"items": ["start/1.6.0-update", "start/upgrade"]
|
||||
"items": [
|
||||
"start/1.6.0-update",
|
||||
"start/upgrade"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "setting",
|
||||
"items": ["start/account-modify", "start/custom-config"]
|
||||
"items": [
|
||||
"start/account-modify",
|
||||
"start/custom-config"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
@@ -51,7 +60,9 @@
|
||||
{
|
||||
"type": "category",
|
||||
"label": "use-case",
|
||||
"items": ["start/ssl-cert-practice"]
|
||||
"items": [
|
||||
"start/ssl-cert-practice"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -121,7 +132,11 @@
|
||||
{
|
||||
"type": "category",
|
||||
"label": "cache",
|
||||
"items": ["help/redis", "help/memcached", "help/valkey"]
|
||||
"items": [
|
||||
"help/redis",
|
||||
"help/memcached",
|
||||
"help/valkey"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
@@ -142,11 +157,6 @@
|
||||
"help/windows_script"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "server",
|
||||
"items": ["help/ipmi"]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "mid",
|
||||
@@ -195,37 +205,55 @@
|
||||
{
|
||||
"type": "category",
|
||||
"label": "webserver",
|
||||
"items": ["help/tomcat", "help/jetty"]
|
||||
"items": [
|
||||
"help/tomcat",
|
||||
"help/jetty"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "cloud-native",
|
||||
"items": ["help/docker", "help/kubernetes"]
|
||||
"items": [
|
||||
"help/docker",
|
||||
"help/kubernetes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "llm",
|
||||
"items": ["help/openai"]
|
||||
"items": [
|
||||
"help/openai"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "aiConfig",
|
||||
"items": ["help/aiConfig"]
|
||||
"items": [
|
||||
"help/aiConfig"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "custom",
|
||||
"items": ["help/kafka_promql", "help/influxdb_promql"]
|
||||
"items": [
|
||||
"help/kafka_promql",
|
||||
"help/influxdb_promql"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "network",
|
||||
"items": ["help/huawei_switch"]
|
||||
"items": [
|
||||
"help/huawei_switch"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "threshold",
|
||||
"items": ["help/alert_threshold", "help/alert_threshold_expr"]
|
||||
"items": [
|
||||
"help/alert_threshold",
|
||||
"help/alert_threshold_expr"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
@@ -249,8 +277,6 @@
|
||||
"help/plugin",
|
||||
"help/time_expression",
|
||||
"help/grafana_dashboard",
|
||||
"help/collector",
|
||||
"help/alarm_center",
|
||||
"help/issue"
|
||||
]
|
||||
},
|
||||
@@ -274,32 +300,44 @@
|
||||
{
|
||||
"type": "category",
|
||||
"label": "jdbc",
|
||||
"items": ["advanced/extend-jdbc"]
|
||||
"items": [
|
||||
"advanced/extend-jdbc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "ssh",
|
||||
"items": ["advanced/extend-ssh"]
|
||||
"items": [
|
||||
"advanced/extend-ssh"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "telnet",
|
||||
"items": ["advanced/extend-telnet"]
|
||||
"items": [
|
||||
"advanced/extend-telnet"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "jmx",
|
||||
"items": ["advanced/extend-jmx"]
|
||||
"items": [
|
||||
"advanced/extend-jmx"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "snmp",
|
||||
"items": ["advanced/extend-snmp"]
|
||||
"items": [
|
||||
"advanced/extend-snmp"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "NGQL",
|
||||
"items": ["advanced/extend-ngql"]
|
||||
"items": [
|
||||
"advanced/extend-ngql"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -344,11 +382,13 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"type": "category",
|
||||
"label": "Others",
|
||||
"items": ["others/resource"]
|
||||
"items": [
|
||||
"others/resource"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -448,12 +448,6 @@ export default function () {
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yasminvo"><img src="https://avatars.githubusercontent.com/u/107528848?v=4?s=100" width="100px;" alt="yasminvo"/><br /><sub><b>yasminvo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yasminvo" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/notbugggg"><img src="https://avatars.githubusercontent.com/u/147966331?v=4?s=100" width="100px;" alt="不关银渐层的事哦"/><br /><sub><b>不关银渐层的事哦</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=notbugggg" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yyahang"><img src="https://avatars.githubusercontent.com/u/90464876?v=4?s=100" width="100px;" alt="yyahang"/><br /><sub><b>yyahang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yyahang" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JuJinPark"><img src="https://avatars.githubusercontent.com/u/44892459?v=4?s=100" width="100px;" alt="jujin"/><br /><sub><b>jujin</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=JuJinPark" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LL-LIN"><img src="https://avatars.githubusercontent.com/u/43002118?v=4?s=100" width="100px;" alt="LL-LIN"/><br /><sub><b>LL-LIN</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=LL-LIN" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://bigcyy.github.io/"><img src="https://avatars.githubusercontent.com/u/73413979?v=4?s=100" width="100px;" alt="Yang Chen"/><br /><sub><b>Yang Chen</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=bigcyy" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sarthakeash"><img src="https://avatars.githubusercontent.com/u/74091160?v=4?s=100" width="100px;" alt="Sarthak Arora"/><br /><sub><b>Sarthak Arora</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=sarthakeash" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -76,14 +76,14 @@
|
||||
"githubId": "76642201",
|
||||
"gitUrl": "https://github.com/cuipiheqiuqiu",
|
||||
"name": "Dong Xiang"
|
||||
},
|
||||
}
|
||||
],
|
||||
"committer" : [
|
||||
{
|
||||
"githubId": "29418975",
|
||||
"gitUrl": "https://github.com/zhangshenghang",
|
||||
"name": "Shenghang Zhang"
|
||||
}
|
||||
],
|
||||
"committer" : [
|
||||
},
|
||||
{
|
||||
"githubId": "15684156",
|
||||
"gitUrl": "https://github.com/crossoverJie",
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 242 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 78 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 394 KiB |
@@ -1,5 +1,5 @@
|
||||
Apache HertzBeat (incubating)
|
||||
Copyright 2024-2025 The Apache Software Foundation
|
||||
Copyright 2024 The Apache Software Foundation
|
||||
|
||||
This product includes software developed at
|
||||
The Apache Software Foundation (http://www.apache.org/).
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Apache HertzBeat (incubating)
|
||||
Copyright 2024-2025 The Apache Software Foundation
|
||||
Copyright 2024 The Apache Software Foundation
|
||||
|
||||
This product includes software developed at
|
||||
The Apache Software Foundation (http://www.apache.org/).
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<hzb.version>1.7.0</hzb.version>
|
||||
<hzb.version>1.6.1</hzb.version>
|
||||
|
||||
<java.version>17</java.version>
|
||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||
|
||||
@@ -230,10 +230,6 @@ alerter:
|
||||
access-key-id: YOUR_ACCESS_KEY_ID
|
||||
access-key-secret: YOUR_ACCESS_KEY_SECRET
|
||||
region: AWS_REGION_FOR_END_USER_MESSAGING
|
||||
twilio:
|
||||
account-sid: YOUR_ACCOUNT_SID
|
||||
auth-token: YOUR_AUTH_TOKEN
|
||||
twilio-phone-number: YOUR_TWILIO_PHONE_NUMBER
|
||||
scheduler:
|
||||
server:
|
||||
enabled: true
|
||||
|
||||
@@ -34,10 +34,6 @@ spring:
|
||||
exclude: org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration, org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration
|
||||
freemarker:
|
||||
enabled: false
|
||||
servlet:
|
||||
multipart:
|
||||
max-file-size: 100MB
|
||||
max-request-size: 100MB
|
||||
|
||||
management:
|
||||
health:
|
||||
@@ -201,10 +197,6 @@ alerter:
|
||||
access-key-id: YOUR_ACCESS_KEY_ID
|
||||
access-key-secret: YOUR_ACCESS_KEY_SECRET
|
||||
region: AWS_REGION_FOR_END_USER_MESSAGING
|
||||
twilio:
|
||||
account-sid: YOUR_ACCOUNT_SID
|
||||
auth-token: YOUR_AUTH_TOKEN
|
||||
twilio-phone-number: YOUR_TWILIO_PHONE_NUMBER
|
||||
scheduler:
|
||||
server:
|
||||
enabled: true
|
||||
|
||||
@@ -21,20 +21,20 @@ networks:
|
||||
|
||||
services:
|
||||
mysql:
|
||||
image: mariadb:11.7
|
||||
image: mysql:8
|
||||
container_name: compose-mysql
|
||||
hostname: mysql
|
||||
restart: always
|
||||
healthcheck:
|
||||
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
||||
interval: 10s
|
||||
test: ['CMD-SHELL', 'mysqladmin ping -h 127.0.0.1 --silent']
|
||||
interval: 3s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
start_period: 3m
|
||||
ports:
|
||||
- '13306:3306'
|
||||
- "3306"
|
||||
environment:
|
||||
TZ: Asia/Shanghai
|
||||
MARIADB_ROOT_PASSWORD: 123456
|
||||
MYSQL_ROOT_PASSWORD: 123456
|
||||
volumes:
|
||||
- ./dbdata/mysqldata:/var/lib/mysql/
|
||||
- ./conf/sql:/docker-entrypoint-initdb.d/
|
||||
@@ -55,15 +55,15 @@ services:
|
||||
environment:
|
||||
TZ: Asia/Shanghai
|
||||
ports:
|
||||
- "18181:8181"
|
||||
- "16667:6667"
|
||||
- "8181"
|
||||
- "6667"
|
||||
volumes:
|
||||
- ./dbdata/iotdbdata:/iotdb/data
|
||||
networks:
|
||||
- hertzbeat
|
||||
|
||||
hertzbeat:
|
||||
image: apache/hertzbeat:1.7.0
|
||||
image: apache/hertzbeat
|
||||
container_name: compose-hertzbeat
|
||||
hostname: hertzbeat
|
||||
restart: always
|
||||
|
||||
@@ -34,10 +34,6 @@ spring:
|
||||
exclude: org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration, org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration
|
||||
freemarker:
|
||||
enabled: false
|
||||
servlet:
|
||||
multipart:
|
||||
max-file-size: 100MB
|
||||
max-request-size: 100MB
|
||||
|
||||
management:
|
||||
health:
|
||||
@@ -197,10 +193,6 @@ alerter:
|
||||
access-key-id: YOUR_ACCESS_KEY_ID
|
||||
access-key-secret: YOUR_ACCESS_KEY_SECRET
|
||||
region: AWS_REGION_FOR_END_USER_MESSAGING
|
||||
twilio:
|
||||
account-sid: YOUR_ACCOUNT_SID
|
||||
auth-token: YOUR_AUTH_TOKEN
|
||||
twilio-phone-number: YOUR_TWILIO_PHONE_NUMBER
|
||||
scheduler:
|
||||
server:
|
||||
enabled: true
|
||||
|
||||
@@ -21,20 +21,20 @@ networks:
|
||||
|
||||
services:
|
||||
mysql:
|
||||
image: mariadb:11.7
|
||||
image: mysql:8
|
||||
container_name: compose-mysql
|
||||
hostname: mysql
|
||||
restart: always
|
||||
healthcheck:
|
||||
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
||||
interval: 10s
|
||||
test: ['CMD-SHELL', 'mysqladmin ping -h 127.0.0.1 --silent']
|
||||
interval: 3s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
start_period: 3m
|
||||
ports:
|
||||
- '13306:3306'
|
||||
- "3306"
|
||||
environment:
|
||||
TZ: Asia/Shanghai
|
||||
MARIADB_ROOT_PASSWORD: 123456
|
||||
MYSQL_ROOT_PASSWORD: 123456
|
||||
volumes:
|
||||
- ./dbdata/mysqldata:/var/lib/mysql/
|
||||
- ./conf/sql:/docker-entrypoint-initdb.d/
|
||||
@@ -55,14 +55,14 @@ services:
|
||||
environment:
|
||||
TZ: Asia/Shanghai
|
||||
ports:
|
||||
- "16041:6041"
|
||||
- "6041"
|
||||
volumes:
|
||||
- ./dbdata/taosdata:/var/lib/taos/
|
||||
networks:
|
||||
- hertzbeat
|
||||
|
||||
hertzbeat:
|
||||
image: apache/hertzbeat:1.7.0
|
||||
image: apache/hertzbeat
|
||||
container_name: compose-hertzbeat
|
||||
hostname: hertzbeat
|
||||
restart: always
|
||||
|
||||
@@ -34,10 +34,6 @@ spring:
|
||||
exclude: org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration, org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration
|
||||
freemarker:
|
||||
enabled: false
|
||||
servlet:
|
||||
multipart:
|
||||
max-file-size: 100MB
|
||||
max-request-size: 100MB
|
||||
|
||||
management:
|
||||
health:
|
||||
@@ -195,10 +191,6 @@ alerter:
|
||||
access-key-id: YOUR_ACCESS_KEY_ID
|
||||
access-key-secret: YOUR_ACCESS_KEY_SECRET
|
||||
region: AWS_REGION_FOR_END_USER_MESSAGING
|
||||
twilio:
|
||||
account-sid: YOUR_ACCOUNT_SID
|
||||
auth-token: YOUR_AUTH_TOKEN
|
||||
twilio-phone-number: YOUR_TWILIO_PHONE_NUMBER
|
||||
scheduler:
|
||||
server:
|
||||
enabled: true
|
||||
|
||||
@@ -21,20 +21,20 @@ networks:
|
||||
|
||||
services:
|
||||
mysql:
|
||||
image: mariadb:11.7
|
||||
image: mysql:8
|
||||
container_name: compose-mysql
|
||||
hostname: mysql
|
||||
restart: always
|
||||
healthcheck:
|
||||
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
||||
interval: 10s
|
||||
test: ['CMD-SHELL', 'mysqladmin ping -h 127.0.0.1 --silent']
|
||||
interval: 3s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
start_period: 3m
|
||||
ports:
|
||||
- '13306:3306'
|
||||
- "3306"
|
||||
environment:
|
||||
TZ: Asia/Shanghai
|
||||
MARIADB_ROOT_PASSWORD: 123456
|
||||
MYSQL_ROOT_PASSWORD: 123456
|
||||
volumes:
|
||||
- ./dbdata/mysqldata:/var/lib/mysql/
|
||||
- ./conf/sql:/docker-entrypoint-initdb.d/
|
||||
@@ -55,14 +55,14 @@ services:
|
||||
environment:
|
||||
TZ: Asia/Shanghai
|
||||
ports:
|
||||
- "18428:8428"
|
||||
- "8428"
|
||||
volumes:
|
||||
- ./dbdata/tsdbdata:/victoria-metrics-data
|
||||
networks:
|
||||
- hertzbeat
|
||||
|
||||
hertzbeat:
|
||||
image: apache/hertzbeat:1.7.0
|
||||
image: apache/hertzbeat
|
||||
container_name: compose-hertzbeat
|
||||
hostname: hertzbeat
|
||||
restart: always
|
||||
|
||||
@@ -34,10 +34,6 @@ spring:
|
||||
exclude: org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration, org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration
|
||||
freemarker:
|
||||
enabled: false
|
||||
servlet:
|
||||
multipart:
|
||||
max-file-size: 100MB
|
||||
max-request-size: 100MB
|
||||
|
||||
management:
|
||||
health:
|
||||
@@ -194,10 +190,6 @@ alerter:
|
||||
access-key-id: YOUR_ACCESS_KEY_ID
|
||||
access-key-secret: YOUR_ACCESS_KEY_SECRET
|
||||
region: AWS_REGION_FOR_END_USER_MESSAGING
|
||||
twilio:
|
||||
account-sid: YOUR_ACCOUNT_SID
|
||||
auth-token: YOUR_AUTH_TOKEN
|
||||
twilio-phone-number: YOUR_TWILIO_PHONE_NUMBER
|
||||
scheduler:
|
||||
server:
|
||||
enabled: true
|
||||
|
||||
@@ -32,15 +32,14 @@ services:
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
ports:
|
||||
- '15432:5432'
|
||||
- '5432:5432'
|
||||
environment:
|
||||
POSTGRES_USER: root
|
||||
POSTGRES_PASSWORD: 123456
|
||||
TZ: Asia/Shanghai
|
||||
PGDATA: /var/lib/postgresql/data/pgdata
|
||||
volumes:
|
||||
- ./dbdata/pgdata:/var/lib/postgresql/data
|
||||
- ./conf/sql:/docker-entrypoint-initdb.d/
|
||||
- ./dbdata/pgdata/data:/var/lib/postgresql/data
|
||||
- ./conf/sql:/docker-entrypoint-initdb.d/
|
||||
networks:
|
||||
- hertzbeat
|
||||
|
||||
@@ -58,14 +57,14 @@ services:
|
||||
environment:
|
||||
TZ: Asia/Shanghai
|
||||
ports:
|
||||
- "18428:8428"
|
||||
- "8428"
|
||||
volumes:
|
||||
- ./dbdata/tsdbdata:/victoria-metrics-data
|
||||
networks:
|
||||
- hertzbeat
|
||||
|
||||
hertzbeat:
|
||||
image: apache/hertzbeat:1.7.0
|
||||
image: apache/hertzbeat
|
||||
container_name: compose-hertzbeat
|
||||
hostname: hertzbeat
|
||||
restart: always
|
||||
|
||||
@@ -19,11 +19,11 @@ $ docker buildx use mybuilder
|
||||
|
||||
```shell
|
||||
# Use the --platform flag to specify the target platforms for the build --push flag to push the image to a registry
|
||||
$ docker buildx build --platform linux/arm64,linux/amd64 -t apache/hertzbeat-collector:1.0.0 . --push
|
||||
$ docker buildx build --platform linux/arm64,linux/amd64 -t apache/hertzbeat-collector:v1.0.0 . --push
|
||||
|
||||
$ docker buildx build --platform linux/arm64,linux/amd64 -t quay.io/tancloud/hertzbeat-collector:latest . --push
|
||||
|
||||
# Inspect the image info
|
||||
$ docker buildx imagetools inspect apache/hertzbeat-collector:1.0.0
|
||||
$ docker buildx imagetools inspect apache/hertzbeat-collector:v1.0.0
|
||||
|
||||
```
|
||||
|
||||
@@ -31,17 +31,17 @@ fi
|
||||
# docker compile context
|
||||
CONTEXT_DIR=`pwd`
|
||||
|
||||
COMMAND="docker buildx build --platform linux/arm64,linux/amd64 -t apache/hertzbeat-collector:$VERSION -f $CURRENT_DIR/Dockerfile $CONTEXT_DIR --build-arg VERSION="$VERSION" --push"
|
||||
COMMAND="docker buildx build --platform linux/arm64,linux/amd64 -t apache/hertzbeat-collector:v$VERSION -f $CURRENT_DIR/Dockerfile $CONTEXT_DIR --build-arg VERSION="$VERSION" --push"
|
||||
|
||||
#COMMAND="docker buildx build --platform linux/arm64,linux/amd64 -t apache/hertzbeat-collector:latest -f $CURRENT_DIR/Dockerfile $CONTEXT_DIR --build-arg VERSION="$VERSION" --push"
|
||||
|
||||
#COMMAND="docker buildx build --platform linux/arm64,linux/amd64 -t quay.io/tancloud/hertzbeat-collector:$VERSION -f $CURRENT_DIR/Dockerfile $CONTEXT_DIR --build-arg VERSION="$VERSION" --push"
|
||||
#COMMAND="docker buildx build --platform linux/arm64,linux/amd64 -t quay.io/tancloud/hertzbeat-collector:v$VERSION -f $CURRENT_DIR/Dockerfile $CONTEXT_DIR --build-arg VERSION="$VERSION" --push"
|
||||
|
||||
#COMMAND="docker buildx build --platform linux/arm64,linux/amd64 -t quay.io/tancloud/hertzbeat-collector:latest -f $CURRENT_DIR/Dockerfile $CONTEXT_DIR --build-arg VERSION="$VERSION" --push"
|
||||
|
||||
# Build Local
|
||||
|
||||
#COMMAND="docker build -t apache/hertzbeat-collector:$VERSION -f $CURRENT_DIR/Dockerfile $CONTEXT_DIR --build-arg VERSION="$VERSION" "
|
||||
#COMMAND="docker build -t apache/hertzbeat-collector:latest -f $CURRENT_DIR/Dockerfile $CONTEXT_DIR "
|
||||
|
||||
echo "$COMMAND"
|
||||
|
||||
|
||||
@@ -19,10 +19,10 @@ $ docker buildx use mybuilder
|
||||
|
||||
```shell
|
||||
# Use the --platform flag to specify the target platforms for the build --push flag to push the image to a registry
|
||||
$ docker buildx build --platform linux/arm64,linux/amd64 -t apache/hertzbeat:1.0.0 . --push
|
||||
$ docker buildx build --platform linux/arm64,linux/amd64 -t apache/hertzbeat:v1.0.0 . --push
|
||||
|
||||
$ docker buildx build --platform linux/arm64,linux/amd64 -t quay.io/tancloud/hertzbeat:latest . --push
|
||||
|
||||
# Inspect the image info
|
||||
$ docker buildx imagetools inspect apache/hertzbeat:1.0.0
|
||||
$ docker buildx imagetools inspect apache/hertzbeat:v1.0.0
|
||||
```
|
||||
|
||||
@@ -27,19 +27,23 @@ VERSION=`ls apache-hertzbeat-*-incubating-docker-compose.tar.gz| awk -F"-" '{pri
|
||||
# compile context dir
|
||||
CONTEXT_DIR=`pwd`
|
||||
|
||||
COMMAND="docker buildx build --platform ${IMAGE_PLATFORM:-linux/arm64,linux/amd64} -t apache/hertzbeat:$VERSION -f $CURRENT_DIR/Dockerfile $CONTEXT_DIR --push=${IMAGE_PUSH:-true} --load=${IMAGE_LOAD:-false}"
|
||||
COMMAND="docker buildx build --platform ${IMAGE_PLATFORM:-linux/arm64,linux/amd64} -t apache/hertzbeat:v$VERSION -f $CURRENT_DIR/Dockerfile $CONTEXT_DIR --push=${IMAGE_PUSH:-true} --load=${IMAGE_LOAD:-false}"
|
||||
|
||||
#COMMAND="docker buildx build --platform linux/arm64,linux/amd64 -t apache/hertzbeat:latest -f $CURRENT_DIR/Dockerfile $CONTEXT_DIR --push"
|
||||
|
||||
#COMMAND="docker buildx build --platform linux/arm64,linux/amd64 -t quay.io/tancloud/hertzbeat:$VERSION -f $CURRENT_DIR/Dockerfile $CONTEXT_DIR --push"
|
||||
#COMMAND="docker buildx build --platform linux/arm64,linux/amd64 -t quay.io/tancloud/hertzbeat:v$VERSION -f $CURRENT_DIR/Dockerfile $CONTEXT_DIR --push"
|
||||
|
||||
#COMMAND="docker buildx build --platform linux/arm64,linux/amd64 -t quay.io/tancloud/hertzbeat:latest -f $CURRENT_DIR/Dockerfile $CONTEXT_DIR --push"
|
||||
|
||||
# Build Local
|
||||
|
||||
#COMMAND="docker build -t apache/hertzbeat:$VERSION -f $CURRENT_DIR/Dockerfile $CONTEXT_DIR "
|
||||
#COMMAND="docker build -t apache/hertzbeat:latest -f $CURRENT_DIR/Dockerfile $CONTEXT_DIR "
|
||||
|
||||
#COMMAND="docker tag apache/hertzbeat:$VERSION apache/hertzbeat:${IMAGE_VERSION:-latest}"
|
||||
echo "$COMMAND"
|
||||
|
||||
$COMMAND
|
||||
|
||||
COMMAND="docker tag apache/hertzbeat:v$VERSION apache/hertzbeat:${IMAGE_VERSION:-latest}"
|
||||
|
||||
echo "$COMMAND"
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ $gpgKeyId = "********"
|
||||
|
||||
# ********************************************************
|
||||
# Set version and release candidate number
|
||||
$version = "1.7.0"
|
||||
$version = "1.6.1"
|
||||
$rcNumber = "rc1"
|
||||
# ********************************************************
|
||||
|
||||
|
||||
@@ -86,8 +86,8 @@
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "50kb",
|
||||
"maximumError": "100kb"
|
||||
"maximumWarning": "6kb",
|
||||
"maximumError": "10kb"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -27,7 +27,6 @@ export class NoticeReceiver {
|
||||
email!: string;
|
||||
tgBotToken!: string;
|
||||
tgUserId!: string;
|
||||
tgMessageThreadId!: string;
|
||||
userId!: string;
|
||||
slackWebHookUrl!: string;
|
||||
discordChannelId!: string;
|
||||
|
||||
@@ -21,7 +21,6 @@ import { AlibabaSmsConfig } from './AlibabaSmsConfig';
|
||||
import { AwsSmsConfig } from './AwsSmsConfig';
|
||||
import { SmslocalSmsConfig } from './SmslocalSmsConfig';
|
||||
import { TencentSmsConfig } from './TencentSmsConfig';
|
||||
import { TwilioSmsConfig } from './TwilioSmsConfig';
|
||||
import { UniSmsConfig } from './UniSmsConfig';
|
||||
import { SmsType } from './enums/sms-type.enum';
|
||||
|
||||
@@ -33,7 +32,6 @@ export class SmsNoticeSender {
|
||||
unisms: UniSmsConfig = new UniSmsConfig();
|
||||
smslocal: SmslocalSmsConfig = new SmslocalSmsConfig();
|
||||
aws: AwsSmsConfig = new AwsSmsConfig();
|
||||
twilio: TwilioSmsConfig = new TwilioSmsConfig();
|
||||
enable: boolean = false;
|
||||
creator!: string;
|
||||
modifier!: string;
|
||||
|
||||
@@ -22,8 +22,7 @@ export enum SmsType {
|
||||
ALIBABA = 'alibaba',
|
||||
UNISMS = 'unisms',
|
||||
SMSLOCAL = 'smslocal',
|
||||
AWS = 'aws',
|
||||
TWILIO = 'twilio'
|
||||
AWS = 'aws'
|
||||
}
|
||||
|
||||
export enum UniSmsAuthMode {
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
[help_message_content]="'alert.help.inhibit' | i18n"
|
||||
[guild_link]="'alert.help.inhibit.link' | i18n"
|
||||
[module_name]="'menu.alert.inhibit'"
|
||||
[icon_name]="'delete-column'"
|
||||
[icon_name]="'filter'"
|
||||
></app-help-message-show>
|
||||
|
||||
<nz-divider></nz-divider>
|
||||
@@ -163,15 +163,7 @@
|
||||
{{ 'alert.inhibit.source_labels' | i18n }}
|
||||
</nz-form-label>
|
||||
<nz-form-control [nzSpan]="12">
|
||||
<app-form-field
|
||||
[item]="{
|
||||
field: 'labels',
|
||||
type: 'labels',
|
||||
required: true
|
||||
}"
|
||||
[name]="'sourceLabels'"
|
||||
[(ngModel)]="alertInhibit.sourceLabels"
|
||||
/>
|
||||
<app-labels-input [(ngModel)]="alertInhibit.sourceLabels" name="sourceLabels" required></app-labels-input>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item>
|
||||
@@ -179,15 +171,7 @@
|
||||
{{ 'alert.inhibit.target_labels' | i18n }}
|
||||
</nz-form-label>
|
||||
<nz-form-control [nzSpan]="12">
|
||||
<app-form-field
|
||||
[item]="{
|
||||
field: 'labels',
|
||||
type: 'labels',
|
||||
required: true
|
||||
}"
|
||||
[name]="'targetLabels'"
|
||||
[(ngModel)]="alertInhibit.targetLabels"
|
||||
/>
|
||||
<app-labels-input [(ngModel)]="alertInhibit.targetLabels" name="targetLabels" required></app-labels-input>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
[help_message_content]="'alert.help.integration' | i18n"
|
||||
[guild_link]="'alert.help.integration.link' | i18n"
|
||||
[module_name]="'menu.alert.integration'"
|
||||
[icon_name]="'api'"
|
||||
[icon_name]="'filter'"
|
||||
></app-help-message-show>
|
||||
|
||||
<nz-divider></nz-divider>
|
||||
|
||||
@@ -67,12 +67,12 @@ export class AlertIntegrationComponent implements OnInit {
|
||||
id: 'skywalking',
|
||||
name: this.i18nSvc.fanyi('alert.integration.source.skywalking'),
|
||||
icon: 'assets/img/integration/skywalking.svg'
|
||||
},
|
||||
{
|
||||
id: 'tencent',
|
||||
name: this.i18nSvc.fanyi('alert.integration.source.tencent'),
|
||||
icon: 'assets/img/integration/tencent.svg'
|
||||
}
|
||||
// {
|
||||
// id: 'tencent',
|
||||
// name: this.i18nSvc.fanyi('alert.integration.source.tencent'),
|
||||
// icon: 'assets/img/integration/tencent.svg'
|
||||
// }
|
||||
];
|
||||
|
||||
selectedSource: DataSource | null = null;
|
||||
|
||||
-6
@@ -344,12 +344,6 @@
|
||||
<input [(ngModel)]="receiver.tgUserId" [required]="receiver.type === 7" name="tgUserId" nz-input type="text" />
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item *ngIf="receiver.type === 7">
|
||||
<nz-form-label [nzSpan]="7" nzFor="tgMessageThreadId">{{ 'alert.notice.type.telegram-message-thread-id' | i18n }}</nz-form-label>
|
||||
<nz-form-control [nzErrorTip]="'validation.required' | i18n" [nzSpan]="12">
|
||||
<input [(ngModel)]="receiver.tgMessageThreadId" name="tgMessageThreadId" nz-input type="text" />
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item *ngIf="receiver.type === 8">
|
||||
<nz-form-label [nzRequired]="receiver.type === 8" [nzSpan]="7" nzFor="slackWebHookUrl"
|
||||
>{{ 'alert.notice.type.slack-webHook-url' | i18n }}
|
||||
|
||||
+1
-9
@@ -186,15 +186,7 @@
|
||||
<nz-form-item *ngIf="!rule.filterAll">
|
||||
<nz-form-label nzFor="labels" nzSpan="7" nzRequired="true">{{ 'alert.notice.rule.tag' | i18n }} </nz-form-label>
|
||||
<nz-form-control nzSpan="12" [nzErrorTip]="'validation.required' | i18n">
|
||||
<app-form-field
|
||||
[item]="{
|
||||
field: 'labels',
|
||||
type: 'labels',
|
||||
required: true
|
||||
}"
|
||||
[name]="'labels'"
|
||||
[(ngModel)]="rule.labels"
|
||||
/>
|
||||
<app-labels-input [(ngModel)]="rule.labels" name="labels" required></app-labels-input>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item>
|
||||
|
||||
@@ -538,14 +538,7 @@
|
||||
<nz-form-item>
|
||||
<nz-form-label nzSpan="7" [nzFor]="'labels'" [nzTooltipTitle]="'label.bind.tip' | i18n">{{ 'label.bind' | i18n }} </nz-form-label>
|
||||
<nz-form-control nzSpan="12">
|
||||
<app-form-field
|
||||
[item]="{
|
||||
field: 'labels',
|
||||
type: 'labels'
|
||||
}"
|
||||
[name]="'labels'"
|
||||
[(ngModel)]="define.labels"
|
||||
/>
|
||||
<app-labels-input [(ngModel)]="define.labels" name="labels"></app-labels-input>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item>
|
||||
@@ -553,14 +546,7 @@
|
||||
>{{ 'common.annotation.bind' | i18n }}
|
||||
</nz-form-label>
|
||||
<nz-form-control nzSpan="12">
|
||||
<app-form-field
|
||||
[item]="{
|
||||
field: 'labels',
|
||||
type: 'labels'
|
||||
}"
|
||||
[name]="'annotations'"
|
||||
[(ngModel)]="define.annotations"
|
||||
/>
|
||||
<app-labels-input [(ngModel)]="define.annotations" name="annotations"></app-labels-input>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item>
|
||||
|
||||
@@ -848,7 +848,7 @@ export class AlertSettingComponent implements OnInit {
|
||||
if (!this.define.labels) {
|
||||
this.define.labels = {};
|
||||
}
|
||||
this.define.labels = { ...this.define.labels, severity: this.severity };
|
||||
this.define.labels['severity'] = this.severity;
|
||||
}
|
||||
|
||||
onManageModalCancel() {
|
||||
|
||||
@@ -179,15 +179,7 @@
|
||||
<nz-form-item *ngIf="!silence.matchAll">
|
||||
<nz-form-label nzSpan="7" nzFor="labels" nzRequired="true">{{ 'alert.silence.labels' | i18n }}</nz-form-label>
|
||||
<nz-form-control nzSpan="12" [nzErrorTip]="'validation.required' | i18n">
|
||||
<app-form-field
|
||||
[item]="{
|
||||
field: 'labels',
|
||||
type: 'labels',
|
||||
required: true
|
||||
}"
|
||||
[name]="'labels'"
|
||||
[(ngModel)]="silence.labels"
|
||||
/>
|
||||
<app-labels-input [(ngModel)]="silence.labels" name="labels" required></app-labels-input>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
[help_message_content]="'bulletin.help.content' | i18n"
|
||||
[guild_link]="'bulletin.help.link' | i18n"
|
||||
[module_name]="'menu.monitor.bulletin'"
|
||||
[icon_name]="'book'"
|
||||
[icon_name]="'calculator'"
|
||||
></app-help-message-show>
|
||||
|
||||
<nz-divider></nz-divider>
|
||||
@@ -181,21 +181,6 @@
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
|
||||
<nz-form-item>
|
||||
<nz-form-label nzSpan="7" [nzFor]="'filterLabels'">{{ 'monitor.search.label' | i18n }} </nz-form-label>
|
||||
<nz-form-control nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
|
||||
<app-form-field
|
||||
[item]="{
|
||||
field: 'labels',
|
||||
type: 'labels'
|
||||
}"
|
||||
[name]="'labels'"
|
||||
[(ngModel)]="filterLabels"
|
||||
(ngModelChange)="onFilterInputChange($event)"
|
||||
/>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
|
||||
<nz-form-item>
|
||||
<nz-form-label [nzSpan]="7" nzFor="dropdown" nzRequired="true">{{ 'bulletin.monitor.name' | i18n }}</nz-form-label>
|
||||
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
|
||||
@@ -208,7 +193,7 @@
|
||||
nzMode="multiple"
|
||||
required
|
||||
>
|
||||
<ng-container *ngFor="let monitor of filteredMonitors">
|
||||
<ng-container *ngFor="let monitor of monitors">
|
||||
<nz-option *ngIf="isMonitorListLoading" [nzValue]="monitor.id" [nzLabel]="monitor.name"></nz-option>
|
||||
</ng-container>
|
||||
</nz-select>
|
||||
|
||||
@@ -25,8 +25,7 @@ import { NzNotificationService } from 'ng-zorro-antd/notification';
|
||||
import { NzTableQueryParams } from 'ng-zorro-antd/table';
|
||||
import { TransferChange } from 'ng-zorro-antd/transfer';
|
||||
import { NzFormatEmitEvent, NzTreeNode, NzTreeNodeOptions } from 'ng-zorro-antd/tree';
|
||||
import { Subject } from 'rxjs';
|
||||
import { finalize, debounceTime, distinctUntilChanged } from 'rxjs/operators';
|
||||
import { finalize } from 'rxjs/operators';
|
||||
|
||||
import { BulletinDefine } from '../../pojo/BulletinDefine';
|
||||
import { Fields } from '../../pojo/Fields';
|
||||
@@ -74,35 +73,22 @@ export class BulletinComponent implements OnInit, OnDestroy {
|
||||
refreshInterval: any;
|
||||
deadline = 30;
|
||||
countDownTime: number = 0;
|
||||
filterLabels: Record<string, string> = {};
|
||||
filteredMonitors: Monitor[] = [];
|
||||
private filterSubject = new Subject<string>(); //filter logic debouncing
|
||||
|
||||
ngOnInit() {
|
||||
this.loadTabs();
|
||||
this.refreshInterval = setInterval(() => {
|
||||
this.countDown();
|
||||
}, 1000); // every 30 seconds refresh the tabs
|
||||
this.filterSubject
|
||||
.pipe(
|
||||
debounceTime(300), // triggered after the user stops typing for 300ms
|
||||
distinctUntilChanged()
|
||||
)
|
||||
.subscribe(value => {
|
||||
this.filterMonitors();
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
if (this.refreshInterval) {
|
||||
clearInterval(this.refreshInterval);
|
||||
}
|
||||
this.filterSubject.complete();
|
||||
}
|
||||
|
||||
sync() {
|
||||
this.loadCurrentBulletinData();
|
||||
this.clearFilters();
|
||||
}
|
||||
|
||||
configRefreshDeadline(deadlineTime: number) {
|
||||
@@ -172,7 +158,6 @@ export class BulletinComponent implements OnInit, OnDestroy {
|
||||
this.isManageModalVisible = false;
|
||||
// clear fields
|
||||
this.fields = {};
|
||||
this.clearFilters();
|
||||
}
|
||||
|
||||
resetManageModalData() {
|
||||
@@ -269,7 +254,6 @@ export class BulletinComponent implements OnInit, OnDestroy {
|
||||
message => {
|
||||
if (message.code === 0) {
|
||||
this.monitors = message.data;
|
||||
this.filterMonitors();
|
||||
if (this.monitors != null) {
|
||||
this.isMonitorListLoading = true;
|
||||
}
|
||||
@@ -584,47 +568,4 @@ export class BulletinComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
onFilterInputChange(value: string): void {
|
||||
this.filterSubject.next(value); // push the input value to the debounce Subject
|
||||
}
|
||||
|
||||
filterMonitors(): void {
|
||||
const validLabels = this.cleanFilterLabels(this.filterLabels);
|
||||
const activeFilters = Object.entries(validLabels).filter(([k, v]) => k !== '' && k !== 'null'); // Second filtering ensures key validity
|
||||
|
||||
if (activeFilters.length === 0) {
|
||||
this.filteredMonitors = [...this.monitors];
|
||||
return;
|
||||
}
|
||||
|
||||
this.filteredMonitors = this.monitors.filter(monitor => {
|
||||
if (!monitor.labels || typeof monitor.labels !== 'object') return false;
|
||||
|
||||
return activeFilters.every(([filterKey, filterValue]) => {
|
||||
const keyExists = Object.prototype.hasOwnProperty.call(monitor.labels, filterKey);
|
||||
const actualValue = (monitor.labels[filterKey] ?? '').toLowerCase();
|
||||
return filterValue === '' ? keyExists : actualValue.includes(filterValue.toLowerCase());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private cleanFilterLabels(labels: any): Record<string, string> {
|
||||
const cleaned: Record<string, string> = {};
|
||||
Object.entries(labels ?? {}).forEach(([k, v]) => {
|
||||
if (typeof k === 'string') {
|
||||
const trimmedKey = k.trim();
|
||||
if (trimmedKey !== '' && trimmedKey !== 'null') {
|
||||
cleaned[trimmedKey] = (v ?? '').toString().trim();
|
||||
}
|
||||
}
|
||||
});
|
||||
return cleaned;
|
||||
}
|
||||
|
||||
clearFilters(): void {
|
||||
this.filterLabels = {};
|
||||
this.filterMonitors();
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
}
|
||||
|
||||
+72
-46
@@ -29,59 +29,85 @@
|
||||
[nzLoading]="!app || loading"
|
||||
[nzExtra]="card ? (!monitor ? metrics_card_extra : monitor_card_extra) : ''"
|
||||
>
|
||||
<div *ngIf="!!monitor" class="monitor-detail-container">
|
||||
<div class="monitor-basic-info">
|
||||
<div class="monitor-info-header">
|
||||
<div class="monitor-name">{{ monitor.name }}</div>
|
||||
<nz-tag *ngIf="monitor.status == 0" [nzColor]="'#b2b2b2'" class="status-tag">
|
||||
<div *ngIf="!!monitor">
|
||||
<div nz-row nzGutter="16">
|
||||
<div nz-col nzSpan="8"><p style="text-align: right">ID</p></div>
|
||||
<div nz-col nzSpan="16"
|
||||
><p style="text-align: left">{{ monitorId }}</p></div
|
||||
>
|
||||
</div>
|
||||
<div nz-row nzGutter="16">
|
||||
<div nz-col nzSpan="8"
|
||||
><p style="text-align: right">{{ 'monitor.detail.name' | i18n }}</p></div
|
||||
>
|
||||
<div nz-col nzSpan="16"
|
||||
><p style="text-align: left">{{ monitor.name }}</p></div
|
||||
>
|
||||
</div>
|
||||
<div nz-row nzGutter="16">
|
||||
<div nz-col nzSpan="8"><p style="text-align: right">HOST</p></div>
|
||||
<div nz-col nzSpan="16"
|
||||
><p style="text-align: left">{{ monitor.host }}</p></div
|
||||
>
|
||||
</div>
|
||||
<div nz-row nzGutter="16">
|
||||
<div nz-col nzSpan="8"
|
||||
><p style="text-align: right">{{ 'monitor.detail.port' | i18n }}</p></div
|
||||
>
|
||||
<div nz-col nzSpan="16"
|
||||
><p style="text-align: left">{{ port }}</p></div
|
||||
>
|
||||
</div>
|
||||
<div nz-row nzGutter="16">
|
||||
<div nz-col nzSpan="8"
|
||||
><p style="text-align: right">{{ 'monitor.detail.description' | i18n }}</p></div
|
||||
>
|
||||
<div nz-col nzSpan="16"
|
||||
><p style="text-align: left">{{ monitor.description }}</p></div
|
||||
>
|
||||
</div>
|
||||
<div nz-row nzGutter="16">
|
||||
<div nz-col nzSpan="8"
|
||||
><p style="text-align: right">{{ 'monitor.detail.status' | i18n }}</p></div
|
||||
>
|
||||
<div nz-col nzSpan="16">
|
||||
<nz-tag *ngIf="monitor.status == 0" nzColor="default">
|
||||
<i nz-icon nzType="meh" nzTheme="outline"></i>
|
||||
<span>{{ 'monitor.status.paused' | i18n }}</span>
|
||||
</nz-tag>
|
||||
<nz-tag *ngIf="monitor.status == 1" [nzColor]="'#498765'" class="status-tag">
|
||||
<nz-tag *ngIf="monitor.status == 1" nzColor="success">
|
||||
<i nz-icon nzType="smile" nzTheme="outline"></i>
|
||||
<span>{{ 'monitor.status.up' | i18n }}</span>
|
||||
</nz-tag>
|
||||
<nz-tag *ngIf="monitor.status == 2" [nzColor]="'#fd4357'" class="status-tag">
|
||||
<nz-tag *ngIf="monitor.status == 2" nzColor="error">
|
||||
<i nz-icon nzType="frown" nzTheme="outline"></i>
|
||||
<span>{{ 'monitor.status.down' | i18n }}</span>
|
||||
</nz-tag>
|
||||
</div>
|
||||
|
||||
<div nz-row [nzGutter]="16">
|
||||
<div nz-col [nzSpan]="24">
|
||||
<nz-descriptions nzBordered [nzColumn]="{ xxl: 2, xl: 2, lg: 2, md: 1, sm: 1, xs: 1 }">
|
||||
<nz-descriptions-item [nzTitle]="'ID'">{{ monitorId }}</nz-descriptions-item>
|
||||
<nz-descriptions-item [nzTitle]="'HOST'">{{ monitor.host }}</nz-descriptions-item>
|
||||
<nz-descriptions-item [nzTitle]="'monitor.detail.port' | i18n">{{ port }}</nz-descriptions-item>
|
||||
<nz-descriptions-item [nzTitle]="'monitor.intervals' | i18n">{{ monitor.intervals }}s</nz-descriptions-item>
|
||||
<nz-descriptions-item [nzTitle]="'label' | i18n" [nzSpan]="2">
|
||||
<div class="tags-container">
|
||||
<ng-container *ngFor="let label of getObjectEntries(monitor.labels)">
|
||||
<nz-tag>{{ label[0] }}: {{ label[1] }}</nz-tag>
|
||||
</ng-container>
|
||||
</div>
|
||||
</nz-descriptions-item>
|
||||
<nz-descriptions-item [nzTitle]="'monitor.detail.description' | i18n" [nzSpan]="2">
|
||||
{{ monitor.description }}
|
||||
</nz-descriptions-item>
|
||||
<nz-descriptions-item [nzTitle]="'common.new-time' | i18n">
|
||||
{{ monitor.gmtCreate | date : 'YYYY-MM-dd HH:mm:ss' }}
|
||||
</nz-descriptions-item>
|
||||
<nz-descriptions-item [nzTitle]="'common.edit-time' | i18n">
|
||||
{{ monitor.gmtUpdate | date : 'YYYY-MM-dd HH:mm:ss' }}
|
||||
</nz-descriptions-item>
|
||||
</nz-descriptions>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="monitor-annotations" *ngIf="monitor.annotations && getObjectLength(monitor.annotations) > 0">
|
||||
<h3 class="section-title">{{ 'annotation' | i18n }}</h3>
|
||||
<nz-descriptions nzBordered [nzColumn]="1" [nzSize]="'small'">
|
||||
<nz-descriptions-item *ngFor="let annotation of getObjectEntries(monitor.annotations)" [nzTitle]="annotation[0]">
|
||||
{{ annotation[1] }}
|
||||
</nz-descriptions-item>
|
||||
</nz-descriptions>
|
||||
<div nz-row nzGutter="16">
|
||||
<div nz-col nzSpan="8"
|
||||
><p style="text-align: right">{{ 'monitor.intervals' | i18n }}</p></div
|
||||
>
|
||||
<div nz-col nzSpan="16"
|
||||
><p style="text-align: left">{{ monitor.intervals }}s</p></div
|
||||
>
|
||||
</div>
|
||||
<div nz-row nzGutter="16">
|
||||
<div nz-col nzSpan="8"
|
||||
><p style="text-align: right">{{ 'common.new-time' | i18n }}</p></div
|
||||
>
|
||||
<div nz-col nzSpan="16"
|
||||
><p style="text-align: left">{{ monitor.gmtCreate | date : 'YYYY-MM-dd HH:mm:ss' }}</p></div
|
||||
>
|
||||
</div>
|
||||
<div nz-row nzGutter="16">
|
||||
<div nz-col nzSpan="8"
|
||||
><p style="text-align: right">{{ 'common.edit-time' | i18n }}</p></div
|
||||
>
|
||||
<div nz-col nzSpan="16"
|
||||
><p style="text-align: left">{{ monitor.gmtUpdate | date : 'YYYY-MM-dd HH:mm:ss' }}</p></div
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<nz-table
|
||||
@@ -98,7 +124,6 @@
|
||||
<tr>
|
||||
<th style="text-align: center" *ngFor="let field of fields" nzWidth="100px">
|
||||
{{ 'monitor.app.' + app + '.metrics.' + metrics + '.metric.' + field.name | i18nElse : field.name }}
|
||||
<nz-tag *ngIf="field.unit" [nzBordered]="false">{{ field.unit }}</nz-tag>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -108,7 +133,8 @@
|
||||
<ng-container *ngTemplateOutlet="contentTemplate"></ng-container>
|
||||
<ng-template #contentTemplate>
|
||||
{{ value.origin }}
|
||||
<nz-tag *ngIf="value.origin == null">{{ 'monitor.detail.value.null' | i18n }}</nz-tag>
|
||||
<nz-tag *ngIf="value.origin == null" nzColor="warning">{{ 'monitor.detail.value.null' | i18n }}</nz-tag>
|
||||
<nz-tag *ngIf="fields[i].unit" nzColor="success">{{ fields[i].unit }}</nz-tag>
|
||||
</ng-template>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -133,11 +159,11 @@
|
||||
<tr *ngFor="let field of fields; let i = index">
|
||||
<td>
|
||||
{{ 'monitor.app.' + app + '.metrics.' + metrics + '.metric.' + field.name | i18nElse : field.name }}
|
||||
<nz-tag *ngIf="field.unit" [nzBordered]="false">{{ field.unit }}</nz-tag>
|
||||
</td>
|
||||
<td
|
||||
>{{ rowValues[i].origin }}
|
||||
<nz-tag *ngIf="rowValues[i].origin == null">{{ 'monitor.detail.value.null' | i18n }}</nz-tag>
|
||||
<nz-tag *ngIf="rowValues[i].origin == null" nzColor="warning">{{ 'monitor.detail.value.null' | i18n }}</nz-tag>
|
||||
<nz-tag *ngIf="field.unit" nzColor="success">{{ field.unit }}</nz-tag>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user