Compare commits

..
Author SHA1 Message Date
tomsun28 bf21538062 [improve] common metric data query design
Signed-off-by: tomsun28 <tomsun28@outlook.com>
2025-02-28 16:36:19 +08:00
215 changed files with 1641 additions and 7000 deletions
-63
View File
@@ -2298,69 +2298,6 @@
"contributions": [
"code"
]
},
{
"login": "yasminvo",
"name": "yasminvo",
"avatar_url": "https://avatars.githubusercontent.com/u/107528848?v=4",
"profile": "https://github.com/yasminvo",
"contributions": [
"code"
]
},
{
"login": "notbugggg",
"name": "不关银渐层的事哦",
"avatar_url": "https://avatars.githubusercontent.com/u/147966331?v=4",
"profile": "https://github.com/notbugggg",
"contributions": [
"code"
]
},
{
"login": "yyahang",
"name": "yyahang",
"avatar_url": "https://avatars.githubusercontent.com/u/90464876?v=4",
"profile": "https://github.com/yyahang",
"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,
-2
View File
@@ -31,8 +31,6 @@ name: "CodeQL"
on:
schedule:
- cron: '21 13 * * 4'
push:
branches: [ action* ]
jobs:
analyze:
+1 -1
View File
@@ -19,7 +19,7 @@ name: DOC CI
on:
push:
branches: [ master, dev, action* ]
branches: [ master, dev ]
paths:
- 'home/**'
pull_request:
+1 -2
View File
@@ -17,8 +17,7 @@
name: 'HertzBeat Doc Pdf Builder'
on:
push:
branches: [ page_build* ]
page_build
jobs:
build:
+1 -1
View File
@@ -22,7 +22,7 @@ name: Frontend CI
on:
push:
branches: [ master, dev, action* ]
branches: [ master, dev ]
paths:
- 'web-app/**'
pull_request:
+1 -1
View File
@@ -22,7 +22,7 @@ name: License Checker
on:
push:
branches: [ master, dev, action* ]
branches: [ master, dev ]
pull_request:
branches: [ master, dev ]
+1 -1
View File
@@ -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
-3
View File
@@ -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
-7
View File
@@ -1,7 +0,0 @@
FROM gitpod/workspace-full
USER gitpod
RUN bash -c ". /home/gitpod/.sdkman/bin/sdkman-init.sh && \
sdk install java 17.0.3-ms && \
sdk default java 17.0.3-ms"
+2 -3
View File
@@ -1,6 +1,3 @@
image:
file: .gitpod.Dockerfile
tasks:
- name: Run backend
@@ -18,6 +15,8 @@ tasks:
- name: Setup backend
init: |
sdk install java 17.0.11.fx-zulu < /dev/null
sdk default java 17.0.11.fx-zulu < /dev/null
mvn clean install -DskipTests
command: |
gp sync-done setup-backend
+2 -11
View File
@@ -12,7 +12,7 @@
[![Discord](https://img.shields.io/badge/Chat-Discord-7289DA?logo=discord)](https://discord.gg/Fb6M73htGr)
[![Reddit](https://img.shields.io/badge/Reddit-Community-7289DA?logo=reddit)](https://www.reddit.com/r/hertzbeat/)
[![Twitter](https://img.shields.io/twitter/follow/hertzbeat1024?logo=twitter)](https://x.com/hertzbeat1024)
[![Twitter](https://img.shields.io/twitter/follow/hertzbeat1024?logo=twitter)](https://twitter.com/hertzbeat1024)
[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/8139/badge)](https://www.bestpractices.dev/projects/8139)
[![codecov](https://codecov.io/gh/apache/HertzBeat/branch/master/graph/badge.svg)](https://app.codecov.io/gh/apache/hertzbeat)
[![Docker Pulls](https://img.shields.io/docker/pulls/apache/hertzbeat?style=%20for-the-badge&logo=docker&label=DockerHub%20Download)](https://hub.docker.com/r/apache/hertzbeat)
@@ -507,15 +507,6 @@ Thanks to these wonderful people, welcome to join us:
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/myangle1120"><img src="https://avatars.githubusercontent.com/u/19237013?v=4?s=100" width="100px;" alt="myangle1120"/><br /><sub><b>myangle1120</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=myangle1120" title="Code">💻</a></td>
<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>
@@ -543,7 +534,7 @@ WeChat Public : Search ID `usthecom`.
[Reddit Community](https://www.reddit.com/r/hertzbeat/)
[Follow Us Twitter](https://x.com/hertzbeat1024)
[Follow Us Twitter](https://twitter.com/hertzbeat1024)
[Subscribe YouTube](https://www.youtube.com/channel/UCri75zfWX0GHqJFPENEbLow)
+2 -11
View File
@@ -12,7 +12,7 @@
[![Discord](https://img.shields.io/badge/Chat-Discord-7289DA?logo=discord)](https://discord.gg/Fb6M73htGr)
[![Reddit](https://img.shields.io/badge/Reddit-Community-7289DA?logo=reddit)](https://www.reddit.com/r/hertzbeat/)
[![Twitter](https://img.shields.io/twitter/follow/hertzbeat1024?logo=twitter)](https://x.com/hertzbeat1024)
[![Twitter](https://img.shields.io/twitter/follow/hertzbeat1024?logo=twitter)](https://twitter.com/hertzbeat1024)
[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/8139/badge)](https://www.bestpractices.dev/projects/8139)
[![codecov](https://codecov.io/gh/apache/HertzBeat/branch/master/graph/badge.svg)](https://app.codecov.io/gh/apache/hertzbeat)
[![Docker Pulls](https://img.shields.io/docker/pulls/apache/hertzbeat?style=%20for-the-badge&logo=docker&label=DockerHub%20Download)](https://hub.docker.com/r/apache/hertzbeat)
@@ -506,15 +506,6 @@ Thanks these wonderful people, welcome to join us:
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/myangle1120"><img src="https://avatars.githubusercontent.com/u/19237013?v=4?s=100" width="100px;" alt="myangle1120"/><br /><sub><b>myangle1120</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=myangle1120" title="Code">💻</a></td>
<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>
@@ -542,7 +533,7 @@ Thanks these wonderful people, welcome to join us:
[Reddit Community](https://www.reddit.com/r/hertzbeat/)
[Follow Us Twitter](https://x.com/hertzbeat1024)
[Follow Us Twitter](https://twitter.com/hertzbeat1024)
[Subscribe YouTube](https://www.youtube.com/channel/UCri75zfWX0GHqJFPENEbLow)
-5
View File
@@ -73,11 +73,6 @@
"field": "successCode",
"type": 4,
"paramValue": "200, 201"
},
{
"field": "enableUrlEncoding",
"type": 1,
"paramValue": true
}
]
}
@@ -55,8 +55,6 @@ public class RealTimeAlertCalculator {
private static final int CALCULATE_THREADS = 3;
private static final String KEY_INSTANCE = "__instance__";
private static final String KEY_INSTANCE_NAME = "__instancename__";
private static final String KEY_INSTANCE_HOST = "__instancehost__";
private static final String KEY_APP = "__app__";
private static final String KEY_METRICS = "__metrics__";
private static final String KEY_PRIORITY = "__priority__";
@@ -127,14 +125,10 @@ public class RealTimeAlertCalculator {
private void calculate(CollectRep.MetricsData metricsData) {
long currentTimeMilli = System.currentTimeMillis();
String instance = String.valueOf(metricsData.getId());
String instanceName = metricsData.getInstanceName();
String instanceHost = metricsData.getInstanceHost();
String app = metricsData.getApp();
String metrics = metricsData.getMetrics();
int priority = metricsData.getPriority();
int code = metricsData.getCode().getNumber();
Map<String, String> labels = metricsData.getLabels();
Map<String, String> annotations = metricsData.getAnnotations();
List<AlertDefine> thresholds = this.alertDefineService.getRealTimeAlertDefines();
// Filter thresholds by app, metrics and instance
thresholds = filterThresholdsByAppAndMetrics(thresholds, app, metrics, instance, priority);
@@ -143,8 +137,6 @@ public class RealTimeAlertCalculator {
}
Map<String, Object> commonContext = new HashMap<>(8);
commonContext.put(KEY_INSTANCE, instance);
commonContext.put(KEY_INSTANCE_NAME, instanceName);
commonContext.put(KEY_INSTANCE_HOST, instanceHost);
commonContext.put(KEY_APP, app);
commonContext.put(KEY_PRIORITY, priority);
commonContext.put(KEY_CODE, code);
@@ -152,9 +144,6 @@ public class RealTimeAlertCalculator {
if (priority == 0) {
commonContext.put(KEY_AVAILABLE, metricsData.getCode() == CollectRep.Code.SUCCESS ? UP : DOWN);
}
if (labels != null) {
commonContext.putAll(labels);
}
List<CollectRep.Field> fields = metricsData.getFields();
Map<String, Object> fieldValueMap = new HashMap<>(8);
int valueRowCount = metricsData.getValuesCount();
@@ -171,26 +160,21 @@ public class RealTimeAlertCalculator {
if (StringUtils.isBlank(expr)) {
continue;
}
Map<String, String> commonFingerPrints = new HashMap<>(8);
commonFingerPrints.put(CommonConstants.LABEL_INSTANCE, instance);
// here use the alert name as finger, not care the alert name may be changed
commonFingerPrints.put(CommonConstants.LABEL_ALERT_NAME, define.getName());
commonFingerPrints.put(CommonConstants.LABEL_INSTANCE_NAME, instanceName);
commonFingerPrints.put(CommonConstants.LABEL_INSTANCE_HOST, instanceHost);
commonFingerPrints.putAll(define.getLabels());
if (labels != null) {
commonFingerPrints.putAll(labels);
}
{
// trigger the expr before the metrics data, due the available up down or others
try {
boolean match = execAlertExpression(fieldValueMap, expr, true);
try {
Map<String, String> fingerPrints = new HashMap<>(8);
fingerPrints.put(CommonConstants.LABEL_INSTANCE, instance);
// here use the alert name as finger, not care the alert name may be changed
fingerPrints.put(CommonConstants.LABEL_ALERT_NAME, define.getName());
fingerPrints.putAll(define.getLabels());
if (match) {
// If the threshold rule matches, the number of times the threshold has been triggered is determined and an alarm is triggered
afterThresholdRuleMatch(currentTimeMilli, commonFingerPrints, fieldValueMap, define, annotations);
afterThresholdRuleMatch(currentTimeMilli, fingerPrints, fieldValueMap, define);
} else {
handleRecoveredAlert(commonFingerPrints);
handleRecoveredAlert(fingerPrints);
}
// if this threshold pre compile success, ignore blew
continue;
@@ -208,7 +192,9 @@ public class RealTimeAlertCalculator {
fieldValueMap.put(KEY_ROW, valueRowCount);
fieldValueMap.putAll(commonContext);
fingerPrints.clear();
fingerPrints.putAll(commonFingerPrints);
fingerPrints.put(CommonConstants.LABEL_INSTANCE, instance);
fingerPrints.put(CommonConstants.LABEL_ALERT_NAME, define.getName());
fingerPrints.putAll(define.getLabels());
for (int index = 0; index < valueRow.getColumnsList().size(); index++) {
String valueStr = valueRow.getColumns(index);
if (CommonConstants.NULL_VALUE.equals(valueStr)) {
@@ -242,7 +228,7 @@ public class RealTimeAlertCalculator {
boolean match = execAlertExpression(fieldValueMap, expr, false);
try {
if (match) {
afterThresholdRuleMatch(currentTimeMilli, fingerPrints, fieldValueMap, define, annotations);
afterThresholdRuleMatch(currentTimeMilli, fingerPrints, fieldValueMap, define);
} else {
handleRecoveredAlert(fingerPrints);
}
@@ -325,31 +311,20 @@ public class RealTimeAlertCalculator {
pendingAlertMap.remove(fingerprint);
}
private void afterThresholdRuleMatch(long currentTimeMilli, Map<String, String> fingerPrints,
Map<String, Object> fieldValueMap, AlertDefine define, Map<String, String> annotations) {
private void afterThresholdRuleMatch(long currentTimeMilli, Map<String, String> fingerPrints,
Map<String, Object> fieldValueMap, AlertDefine define) {
String fingerprint = calculateFingerprint(fingerPrints);
SingleAlert existingAlert = pendingAlertMap.get(fingerprint);
Map<String, String> labels = new HashMap<>(8);
fieldValueMap.putAll(define.getLabels());
labels.putAll(fingerPrints);
int requiredTimes = define.getTimes() == null ? 1 : define.getTimes();
if (existingAlert == null) {
// First time triggering alert, create new alert and set to pending status
Map<String, String> alertLabels = new HashMap<>(8);
alertLabels.putAll(fingerPrints);
Map<String, String> alertAnnotations = new HashMap<>(8);
if (annotations != null) {
alertAnnotations.putAll(annotations);
}
if (define.getAnnotations() != null) {
alertAnnotations.putAll(define.getAnnotations());
}
// render var content in annotations
for (Map.Entry<String, String> entry : alertAnnotations.entrySet()) {
entry.setValue(AlertTemplateUtil.render(entry.getValue(), fieldValueMap));
}
SingleAlert newAlert = SingleAlert.builder()
.labels(alertLabels)
.annotations(alertAnnotations)
// render var content in content
.labels(labels)
// todo render var content in annotations
.annotations(define.getAnnotations())
.content(AlertTemplateUtil.render(define.getTemplate(), fieldValueMap))
.status(CommonConstants.ALERT_STATUS_PENDING)
.triggerTimes(1)
@@ -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;
}
@@ -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;
/**
@@ -60,18 +54,4 @@ public class SmsConfig {
*/
private UniSmsProperties unisms;
/**
* Aws configuration
*/
private AwsSmsProperties aws;
/**
* Twilio SMS configuration
*/
private TwilioSmsProperties twilio;
/**
* Smslocal SMS configuration
*/
private SmslocalSmsProperties smslocal;
}
@@ -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;
}
@@ -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";
}
@@ -1,66 +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.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* SkyWalking Alert Content Entity
* @see <a href="https://skywalking.apache.org/docs/main/latest/en/setup/backend/backend-alarm/">backend-alarm</a>
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class SkyWalkingExternAlert {
private Long scopeId;
private String scope;
private String name;
private String id0;
private String id1;
private String ruleName;
private String alarmMessage;
private Long startTime;
private List<Tag> tags;
/**
* SkyWalking Tag Entity
*/
@Data
public static class Tag {
private String key;
private String value;
}
}
@@ -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";
}
@@ -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
@@ -20,10 +20,7 @@ package org.apache.hertzbeat.alert.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
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;
@@ -34,11 +31,8 @@ import org.springframework.context.event.EventListener;
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;
/**
* SMS client factory
@@ -55,7 +49,9 @@ public class SmsClientFactory {
private volatile SmsClient currentSmsClient;
public SmsClientFactory(GeneralConfigDao generalConfigDao, ObjectMapper objectMapper, SmsConfig yamlSmsConfig) {
public SmsClientFactory(GeneralConfigDao generalConfigDao,
ObjectMapper objectMapper,
SmsConfig yamlSmsConfig) {
this.generalConfigDao = generalConfigDao;
this.objectMapper = objectMapper;
this.yamlSmsConfig = yamlSmsConfig;
@@ -137,18 +133,9 @@ public class SmsClientFactory {
case ALIBABA:
currentSmsClient = new AlibabaSmsClientImpl(smsConfig.getAlibaba());
break;
case SMSLOCAL:
currentSmsClient = new SmsLocalSmsClientImpl(smsConfig.getSmslocal());
break;
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;
}
}
}
}
@@ -1,287 +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 com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.alert.config.AwsSmsProperties;
import org.apache.hertzbeat.alert.service.SmsClient;
import org.apache.hertzbeat.alert.util.CryptoUtils;
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.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;
import static org.apache.hertzbeat.common.constants.SmsConstants.AWS;
/**
* AWS Cloud SMS Client Implementation<br>
* API doc:<a href="https://docs.aws.amazon.com/pinpoint/latest/apireference_smsvoicev2/API_SendTextMessage.html">https://docs.aws.amazon.com/pinpoint/latest/apireference_smsvoicev2/API_SendTextMessage.html</a><br>
* Signature doc:<a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv-create-signed-request.html"</a>https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv-create-signed-request.html</a>
*/
@Slf4j
public class AwsSmsClientImpl implements SmsClient {
private static final String SERVICE = "sms-voice";
private static final String MESSAGE_TEMPLATE = "Instance: %s, Priority: %s, Content: %s";
private final String accessKey;
private final String secretKey;
private final String region;
public AwsSmsClientImpl(AwsSmsProperties config) {
if (config != null) {
this.accessKey = config.getAccessKeyId();
this.secretKey = config.getAccessKeySecret();
this.region = config.getRegion();
} else {
this.accessKey = "";
this.secretKey = "";
this.region = "";
}
}
@Override
public void sendMessage(NoticeReceiver receiver, NoticeTemplate noticeTemplate, GroupAlert alert) {
// Extract alert info
String instance = null;
String priority = null;
String content = null;
if (alert.getCommonLabels() != null) {
instance = alert.getCommonLabels().get("instance") == 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) {
Map<String, Object> payload = new HashMap<>();
payload.put("MessageBody", message);
payload.put("DestinationPhoneNumber", phoneNumber);
payload.put("MessageType", "TRANSACTIONAL");
Instant now = Instant.now();
String amzDate = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'").withZone(ZoneOffset.UTC).format(now);
String endpoint = "https://" + SERVICE + "." + region + ".amazonaws.com";
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
String payloadInString = new ObjectMapper().writeValueAsString(payload);
URI requestUri = new URI(endpoint);
HttpPost httpPost = createHttpPost(requestUri, amzDate, payloadInString);
log.info("Sending AWS SMS request to {}", requestUri + "," + "headers: " + Arrays.toString(httpPost.getAllHeaders()));
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 amzDate, String payloadInString) throws Exception {
// Define headers once to avoid repetition (Order of headers must be maintained)
Map<String, String> headers = new LinkedHashMap<>();
headers.put("content-type", "application/x-amz-json-1.0");
headers.put("host", SERVICE + "." + this.region + ".amazonaws.com");
headers.put("x-amz-date", amzDate);
headers.put("x-amz-target", "PinpointSMSVoiceV2.SendTextMessage");
// Build authorization header using the same headers
AwsAuthenticationBuilder authBuilder = new AwsAuthenticationBuilder()
.credential(this.accessKey, this.secretKey)
.region(this.region);
headers.forEach(authBuilder::header);
String authorizationHeader = authBuilder.build(requestUri, "POST", SERVICE, payloadInString);
// Create HTTP post and set all headers
HttpPost httpPost = new HttpPost(requestUri);
httpPost.setHeader("Authorization", authorizationHeader);
headers.forEach(httpPost::setHeader);
httpPost.setEntity(new StringEntity(payloadInString, ContentType.APPLICATION_JSON));
return httpPost;
}
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) {
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 responseNode = jsonResponse.get("MessageId");
if (responseNode == null) {
throw new SendMessageException(statusCode + ":" + responseBody);
}
String messageId = responseNode.asText();
log.info("Successfully sent SMS to phone: {}, messageId: {}", phoneNumber, messageId);
}
}
@Override
public String getType() {
return AWS;
}
@Override
public boolean checkConfig() {
return !(accessKey.isBlank() || secretKey.isBlank() || region.isBlank());
}
private static class AwsAuthenticationBuilder {
private String accessKey;
private String secretKey;
private String region;
private String service;
private URI requestUri;
private String method;
private String payload;
private final Map<String, String> headers = new LinkedHashMap<>();
public AwsAuthenticationBuilder region(String region) {
this.region = region;
return this;
}
public AwsAuthenticationBuilder credential(String accessKey, String secretKey) {
this.accessKey = accessKey;
this.secretKey = secretKey;
return this;
}
public AwsAuthenticationBuilder header(String header, String value) {
this.headers.put(header, value);
return this;
}
public String build(URI requestUri, String method, String service, String payload) throws Exception {
this.requestUri = requestUri;
this.method = method;
this.service = service;
this.payload = payload;
return "%s Credential=%s/%s, SignedHeaders=%s, Signature=%s".formatted(
getAlgorithm(),
this.accessKey,
getCredentialScope(),
getSignedHeaders(),
getSignature()
);
}
private String getCredentialScope() {
return getDateStamp() + "/" + region + "/" + service + "/aws4_request";
}
private String getSignedHeaders() {
return String.join(";", headers.keySet());
}
private String getDateTime() {
return headers.get("x-amz-date");
}
private String getDateStamp() {
return getDateTime().substring(0, 8);
}
private String getSignature() {
String canonicalRequest = getCanonicalRequest();
String stringToSign = String.join("\n",
getAlgorithm(),
getDateTime(),
getCredentialScope(),
CryptoUtils.sha256Hex(canonicalRequest));
byte[] signingKey = getSignatureKey(secretKey, getDateStamp(), region, service);
return CryptoUtils.hmacSha256Hex(signingKey, stringToSign);
}
private String getCanonicalRequest() {
return String.join("\n",
method,
requestUri.getPath().isEmpty() ? "/" : requestUri.getPath(),
requestUri.getQuery() != null ? requestUri.getQuery() : "",
getCanonicalHeaders(),
getSignedHeaders(),
CryptoUtils.sha256Hex(payload)
);
}
private String getCanonicalHeaders() {
return headers.entrySet().stream()
.map(entry -> entry.getKey() + ":" + entry.getValue())
.collect(Collectors.joining("\n")) + "\n";
}
private String getAlgorithm() {
return "AWS4-HMAC-SHA256";
}
private byte[] getSignatureKey(String key, String dateStamp, String regionName, String serviceName) {
byte[] secret = ("AWS4" + key).getBytes(StandardCharsets.UTF_8);
byte[] date = CryptoUtils.hmac256(secret, dateStamp);
byte[] region = CryptoUtils.hmac256(date, regionName);
byte[] service = CryptoUtils.hmac256(region, serviceName);
return CryptoUtils.hmac256(service, "aws4_request");
}
}
}
@@ -305,7 +305,7 @@ public class NoticeConfigServiceImpl implements NoticeConfigService, CommandLine
Map<String, String> labels = new HashMap<>(8);
labels.put(CommonConstants.LABEL_INSTANCE, "1000000");
labels.put(CommonConstants.LABEL_ALERT_NAME, "CPU Usage Alert");
labels.put(CommonConstants.LABEL_INSTANCE_HOST, "127.0.0.1");
labels.put(CommonConstants.LABEL_HOST, "127.0.0.1");
Map<String, String> annotations = new HashMap<>(8);
annotations.put("suggest", "Please check the CPU usage of the server");
SingleAlert singleAlert1 = SingleAlert.builder()
@@ -1,95 +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.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.alert.dto.SkyWalkingExternAlert;
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.time.Instant;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* SkyWalking external alarm service impl
*/
@Slf4j
@Service
public class SkyWalkingExternAlertService implements ExternAlertService {
@Autowired
private AlarmCommonReduce alarmCommonReduce;
@Override
public void addExternAlert(String content) {
TypeReference<List<SkyWalkingExternAlert>> typeReference = new TypeReference<>() {};
List<SkyWalkingExternAlert> alerts = JsonUtil.fromJson(content, typeReference);
if (alerts == null || alerts.isEmpty()) {
log.warn("Parse SkyWalking extern alert content failed! content: {}", content);
return;
}
for (SkyWalkingExternAlert alert : alerts) {
SingleAlert singleAlert = SingleAlert.builder()
.content(alert.getAlarmMessage())
.status(CommonConstants.ALERT_STATUS_FIRING)
.activeAt(Instant.now().toEpochMilli())
.startAt(alert.getStartTime() != null ? alert.getStartTime() : Instant.now().toEpochMilli())
.labels(acquireAlertLabels(alert))
.annotations(acquireAlertAnnotations(alert))
.triggerTimes(1)
.build();
alarmCommonReduce.reduceAndSendAlarm(singleAlert);
}
}
@Override
public String supportSource() {
return "skywalking";
}
private Map<String, String> acquireAlertLabels(SkyWalkingExternAlert externAlert){
Map<String, String> labels = new HashMap<>(8);
labels.put("__source__", "skywalking");
List<SkyWalkingExternAlert.Tag> tags = externAlert.getTags();
if (tags == null || tags.isEmpty()){
return labels;
}
tags.forEach(tag -> labels.put(tag.getKey(), tag.getValue()));
return labels;
}
private Map<String, String> acquireAlertAnnotations(SkyWalkingExternAlert externAlert){
Map<String, String> annotations = new HashMap<>(8);
annotations.putIfAbsent("scope", externAlert.getScope());
annotations.putIfAbsent("name", externAlert.getName());
annotations.putIfAbsent("id0", externAlert.getId0());
annotations.putIfAbsent("id1", externAlert.getId1());
annotations.putIfAbsent("ruleName", externAlert.getRuleName());
return annotations;
}
}
@@ -1,146 +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.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.alert.config.SmslocalSmsProperties;
import org.apache.hertzbeat.alert.service.SmsClient;
import org.apache.hertzbeat.common.constants.SmsConstants;
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.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
/**
* Smslocal SMS Client Implement
*/
@Slf4j
public class SmsLocalSmsClientImpl implements SmsClient {
private static final String HOST = "secure.smslocal.com";
private static final String PATH = "/api/service/enterprise-service/external/sms";
private static final String FROM = "Hertzbeat";
private static final String SUCCESS_CODE = "200";
private final SmslocalSmsProperties config;
public SmsLocalSmsClientImpl(SmslocalSmsProperties smslocalSmsProperties) {
this.config = smslocalSmsProperties;
}
@Override
public void sendMessage(NoticeReceiver receiver, NoticeTemplate noticeTemplate, GroupAlert alert) {
if (Objects.isNull(receiver) || Objects.isNull(alert)) {
log.warn("receiver and alert can not be null! receiver: {}, alert:{}", receiver, alert);
return;
}
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
String content = alert.getCommonAnnotations().get("summary");
if (Objects.isNull(content) || Objects.isNull(alert.getCommonAnnotations().get("description"))) {
content = alert.getAlerts().get(0).getContent();
}
SmsMessage smsMessage = new SmsMessage(FROM, receiver.getPhone(), content);
String payload = JsonUtil.toJson(smsMessage);
HttpPost httpPost = new HttpPost("https://" + HOST + PATH);
httpPost.setHeader("Content-Type", "application/json; charset=utf-8");
httpPost.setHeader("Token", config.getApiKey());
httpPost.setEntity(new StringEntity(payload, StandardCharsets.UTF_8));
log.debug("Sending SMS request to {}, payload: {}", httpPost.getURI(), payload);
// send http request and handle response
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
int statusCode = response.getStatusLine().getStatusCode();
String responseBody = EntityUtils.toString(response.getEntity());
log.debug("SMS response status: {}, body: {}", statusCode, responseBody);
if (statusCode != 200) {
throw new SendMessageException("HTTP request failed with status code: " + statusCode);
}
JsonNode jsonResponse = JsonUtil.fromJson(responseBody);
JsonNode jsonNode = jsonResponse.get(0);
if (Objects.isNull(jsonNode)) {
log.warn("jsonResponse parse errorCode failed: {}", jsonResponse);
return;
}
String errorCode = jsonNode.get("errorCode").asText();
if (!SUCCESS_CODE.equals(errorCode)) {
String msgid = jsonNode.get("id").asText();
throw new SendMessageException(errorCode + ":" + msgid);
}
log.info("Successfully sent SMS to phone: {}", receiver.getPhone());
}
} catch (Exception e) {
log.error("Failed to send SMS: {}", e.getMessage());
throw new SendMessageException(e.getMessage());
}
}
@Override
public String getType() {
return SmsConstants.SMSLOCAL;
}
@Override
public boolean checkConfig() {
if (Objects.isNull(config) || Objects.isNull(config.getApiKey()) || config.getApiKey().isBlank()) {
log.warn("smslocal properties can not be null: {}", config);
return false;
}
return true;
}
@Getter
@Setter
private static class SmsMessage {
String from;
String to;
String content;
final int datacoding = 0;
final String direction = "mt";
public SmsMessage(String from, String to, String content) {
this.from = from;
this.to = to;
this.content = content;
}
}
}
@@ -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,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());
}
}
@@ -89,18 +89,7 @@ public class CryptoUtils {
* @return lowercase hexadecimal string
*/
public static String hmacSha256Hex(String key, String data) {
return hmacSha256Hex(hmac256(key.getBytes(UTF8), data), data);
}
/**
* Calculate HMAC-SHA256 signature and convert to lowercase hexadecimal string
* Note: This is necessary as, converting a String to byte[] and back may yield different results due to encoding differences or data loss.
* @param key secret key in byte array
* @param data data to be signed
* @return lowercase hexadecimal string
*/
public static String hmacSha256Hex(byte[] key, String data) {
byte[] hmacResult = hmac256(key, data);
byte[] hmacResult = hmac256(key.getBytes(UTF8), data);
return DatatypeConverter.printHexBinary(hmacResult).toLowerCase();
}
}
@@ -1,69 +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.AwsSmsProperties;
import org.apache.hertzbeat.alert.service.impl.AwsSmsClientImpl;
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 AwsSmsClientImpl}
*/
class AwsSmsClientImplTest {
@Test
void getType() {
AwsSmsProperties awsSmsProperties = new AwsSmsProperties();
awsSmsProperties.setAccessKeyId("accessKeyId");
awsSmsProperties.setAccessKeySecret("accessKeySecret");
awsSmsProperties.setRegion("region");
AwsSmsClientImpl awsSmsClient = new AwsSmsClientImpl(awsSmsProperties);
assertEquals("aws", awsSmsClient.getType());
}
@ParameterizedTest
@CsvSource({
"accessKeyId, accessKeySecret, region, true",
"accessKeyId, accessKeySecret, '', false",
"accessKeyId, '', region, false",
"accessKeyId, accessKeySecret, '', false",
"accessKeyId, '', '', false",
"'', accessKeySecret, region, false",
"'', accessKeySecret, '', false",
"'', '', region, false",
"'', accessKeySecret, '', false",
})
void checkConfig(String accessKeyId, String accessKeySecret, String region, boolean expected) {
AwsSmsProperties awsSmsProperties = new AwsSmsProperties();
awsSmsProperties.setAccessKeyId(accessKeyId);
awsSmsProperties.setAccessKeySecret(accessKeySecret);
awsSmsProperties.setRegion(region);
AwsSmsClientImpl awsSmsClient = new AwsSmsClientImpl(awsSmsProperties);
assertEquals(expected, awsSmsClient.checkConfig());
}
}
@@ -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());
}
}
@@ -88,7 +88,6 @@ public class JdbcCommonCollect extends AbstractCollect {
SshTunnel sshTunnel = jdbcProtocol.getSshTunnel();
int timeout = CollectUtil.getTimeout(jdbcProtocol.getTimeout());
boolean reuseConnection = Boolean.parseBoolean(jdbcProtocol.getReuseConnection());
Statement statement = null;
String databaseUrl;
try {
@@ -100,7 +99,7 @@ public class JdbcCommonCollect extends AbstractCollect {
}
statement = getConnection(jdbcProtocol.getUsername(),
jdbcProtocol.getPassword(), databaseUrl, timeout, reuseConnection);
jdbcProtocol.getPassword(), databaseUrl, timeout);
switch (jdbcProtocol.getQueryType()) {
case QUERY_TYPE_ONE_ROW -> queryOneRow(statement, jdbcProtocol.getSql(), metrics.getAliasFields(), builder, startTime);
case QUERY_TYPE_MULTI_ROW -> queryMultiRow(statement, jdbcProtocol.getSql(), metrics.getAliasFields(), builder, startTime);
@@ -143,20 +142,11 @@ public class JdbcCommonCollect extends AbstractCollect {
builder.setMsg("Query Error: " + errorMessage);
} finally {
if (statement != null) {
Connection connection = null;
try {
connection = statement.getConnection();
statement.close();
} catch (Exception e) {
log.error("Jdbc close statement error: {}", e.getMessage());
}
try {
if (!reuseConnection && connection != null) {
connection.close();
}
} catch (Exception e) {
log.error("Jdbc close connection error: {}", e.getMessage());
}
}
}
}
@@ -167,40 +157,38 @@ public class JdbcCommonCollect extends AbstractCollect {
}
private Statement getConnection(String username, String password, String url, Integer timeout, boolean reuseConnection) throws Exception {
private Statement getConnection(String username, String password, String url, Integer timeout) throws Exception {
CacheIdentifier identifier = CacheIdentifier.builder()
.ip(url)
.username(username).password(password).build();
Optional<AbstractConnection<?>> cacheOption = connectionCommonCache.getCache(identifier, true);
Statement statement = null;
if (reuseConnection) {
Optional<AbstractConnection<?>> cacheOption = connectionCommonCache.getCache(identifier, true);
if (cacheOption.isPresent()) {
JdbcConnect jdbcConnect = (JdbcConnect) cacheOption.get();
if (cacheOption.isPresent()) {
JdbcConnect jdbcConnect = (JdbcConnect) cacheOption.get();
try {
statement = jdbcConnect.getConnection().createStatement();
// set query timeout
int timeoutSecond = timeout / 1000;
timeoutSecond = timeoutSecond <= 0 ? 1 : timeoutSecond;
statement.setQueryTimeout(timeoutSecond);
// set query max row number
statement.setMaxRows(1000);
} catch (Exception e) {
log.info("The jdbc connect from cache, create statement error: {}", e.getMessage());
try {
statement = jdbcConnect.getConnection().createStatement();
// set query timeout
int timeoutSecond = timeout / 1000;
timeoutSecond = timeoutSecond <= 0 ? 1 : timeoutSecond;
statement.setQueryTimeout(timeoutSecond);
// set query max row number
statement.setMaxRows(1000);
} catch (Exception e) {
log.info("The jdbc connect from cache, create statement error: {}", e.getMessage());
try {
if (statement != null) {
statement.close();
}
jdbcConnect.close();
} catch (Exception e2) {
log.error(e2.getMessage());
if (statement != null) {
statement.close();
}
statement = null;
connectionCommonCache.removeCache(identifier);
jdbcConnect.close();
} catch (Exception e2) {
log.error(e2.getMessage());
}
statement = null;
connectionCommonCache.removeCache(identifier);
}
if (statement != null) {
return statement;
}
}
if (statement != null) {
return statement;
}
// renew connection when failed
Connection connection = DriverManager.getConnection(url, username, password);
@@ -210,10 +198,8 @@ public class JdbcCommonCollect extends AbstractCollect {
timeoutSecond = timeoutSecond <= 0 ? 1 : timeoutSecond;
statement.setQueryTimeout(timeoutSecond);
statement.setMaxRows(1000);
if (reuseConnection) {
JdbcConnect jdbcConnect = new JdbcConnect(connection);
connectionCommonCache.addCache(identifier, jdbcConnect);
}
JdbcConnect jdbcConnect = new JdbcConnect(connection);
connectionCommonCache.addCache(identifier, jdbcConnect);
return statement;
}
@@ -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);
@@ -173,6 +173,7 @@ public class PrometheusAutoCollectImpl {
Map<String, MetricFamily> metricFamilyMap = TextParser.textToMetricFamilies(resp);
List<CollectRep.MetricsData> metricsDataList = new LinkedList<>();
for (Map.Entry<String, MetricFamily> entry : metricFamilyMap.entrySet()) {
builder.clearMetrics();
builder.clearFields();
builder.clearValues();
String metricsName = entry.getKey();
@@ -84,8 +84,6 @@ public class SnmpCollectImpl extends AbstractCollect {
+ "{1,choice,0#|1#1 hour, |1<{1,number,integer} hours, }"
+ "{2,choice,0#|1#1 minute, |1<{2,number,integer} minutes, }"
+ "{3,choice,0#|1#1 second, |1<{3,number,integer} seconds }";
private static final String DATE_AND_TIME_PATTERN = "%04d-%02d-%02d,%02d:%02d:%02d.%d";
private static final String TIME_ZONE_PATTERN = "%c%02d:%02d";
private final Map<Integer, Snmp> versionSnmpService = new ConcurrentHashMap<>(3);
@@ -307,9 +305,6 @@ public class SnmpCollectImpl extends AbstractCollect {
CharBuffer res = decoder.decode(ByteBuffer.wrap(bytes));
return res.toString();
} catch (Exception e) {
if (isDateAndTimeOctetString(binding)) {
return parseDateAndTime(clearHexStr);
}
return new String(bytes);
}
} catch (Exception e) {
@@ -320,68 +315,6 @@ public class SnmpCollectImpl extends AbstractCollect {
}
}
private static boolean isDateAndTimeOctetString(VariableBinding binding) {
if (!(binding.getVariable() instanceof OctetString)) {
return false;
}
byte[] bytes = HexFormat.of().parseHex(binding.toValueString().replaceAll(HEX_SPLIT, ""));
if (bytes.length != 8 && bytes.length != 11) return false;
int year = ((bytes[0] & 0xFF) << 8) | (bytes[1] & 0xFF);
if (year < 1970 || year > 3000) return false;
int month = bytes[2] & 0xFF;
if (month < 1 || month > 12) return false;
int day = bytes[3] & 0xFF;
if (day < 1 || day > 31) return false;
int hour = bytes[4] & 0xFF;
if (hour > 23) return false;
int minute = bytes[5] & 0xFF;
if (minute > 59) return false;
int second = bytes[6] & 0xFF;
if (second > 59) return false;
int deciSecond = bytes[7] & 0xFF;
if (deciSecond > 99) return false;
if (bytes.length == 11) {
int tzSign = bytes[8] & 0xFF;
if (tzSign != 0x2B && tzSign != 0x2D) return false;
int tzHour = bytes[9] & 0xFF;
if (tzHour > 23) return false;
int tzMinute = bytes[10] & 0xFF;
if (tzMinute > 59) return false;
}
return true;
}
private static String parseDateAndTime(String hexString) {
byte[] bytes = HexFormat.of().parseHex(hexString);
int year = ((bytes[0] & 0xFF) << 8) | (bytes[1] & 0xFF);
int month = bytes[2] & 0xFF;
int day = bytes[3] & 0xFF;
int hour = bytes[4] & 0xFF;
int minute = bytes[5] & 0xFF;
int second = bytes[6] & 0xFF;
int deciSeconds = bytes[7] & 0xFF;
String dateTime = String.format(DATE_AND_TIME_PATTERN,
year, month, day, hour, minute, second, deciSeconds);
if (bytes.length == 11) {
char sign = (char) bytes[8];
int tzHour = bytes[9] & 0xFF;
int tzMinute = bytes[10] & 0xFF;
dateTime += String.format(" " + TIME_ZONE_PATTERN, sign, tzHour, tzMinute);
}
return dateTime;
}
private void snmpClose(Snmp snmp, int version) throws IOException {
snmp.close();
versionSnmpService.remove(version);
@@ -79,12 +79,11 @@ public class SshCollectImpl extends AbstractCollect {
long startTime = System.currentTimeMillis();
SshProtocol sshProtocol = metrics.getSsh();
boolean reuseConnection = Boolean.parseBoolean(sshProtocol.getReuseConnection());
boolean useProxy = Boolean.parseBoolean(sshProtocol.getUseProxy());
int timeout = CollectUtil.getTimeout(sshProtocol.getTimeout(), DEFAULT_TIMEOUT);
ClientChannel channel = null;
ClientSession clientSession = null;
try {
clientSession = getConnectSession(sshProtocol, timeout, reuseConnection, useProxy);
clientSession = getConnectSession(sshProtocol, timeout, reuseConnection);
if (CommonSshBlacklist.isCommandBlacklisted(sshProtocol.getScript())) {
builder.setCode(CollectRep.Code.FAIL);
builder.setMsg("The command is blacklisted: " + sshProtocol.getScript());
@@ -157,7 +156,7 @@ public class SshCollectImpl extends AbstractCollect {
log.error(e.getMessage(), e);
}
}
if (clientSession != null && !reuseConnection && !useProxy) {
if (clientSession != null && !reuseConnection) {
try {
clientSession.close();
} catch (Exception e) {
@@ -281,8 +280,11 @@ public class SshCollectImpl extends AbstractCollect {
connectionCommonCache.removeCache(identifier);
}
private ClientSession getConnectSession(SshProtocol sshProtocol, int timeout, boolean reuseConnection, boolean useProxy)
private ClientSession getConnectSession(SshProtocol sshProtocol, int timeout, boolean reuseConnection)
throws IOException, GeneralSecurityException {
return SshHelper.getConnectSession(sshProtocol, timeout, reuseConnection, useProxy);
return SshHelper.getConnectSession(
sshProtocol.getHost(), sshProtocol.getPort(), sshProtocol.getUsername(), sshProtocol.getPassword(),
sshProtocol.getPrivateKey(), sshProtocol.getPrivateKeyPassphrase(), timeout, reuseConnection
);
}
}
@@ -183,18 +183,21 @@ public class CommonDispatcher implements MetricsTaskDispatch, CollectDataDispatc
Job job = timerTask.getJob();
job.constructPriorMetrics();
Set<Metrics> metricsSet = job.getNextCollectMetrics(null, true);
metricsSet.forEach(metrics -> {
MetricsCollect metricsCollect = new MetricsCollect(metrics, timeout, this,
collectorIdentity, unitConvertList);
jobRequestQueue.addJob(metricsCollect);
if (metrics.getPrometheus() != null) {
metricsTimeoutMonitorMap.put(String.valueOf(job.getId()),
new MetricsTime(System.currentTimeMillis(), metrics, timeout));
} else {
metricsTimeoutMonitorMap.put(job.getId() + "-" + metrics.getName(),
new MetricsTime(System.currentTimeMillis(), metrics, timeout));
}
});
// Avoid NullPointerException
if (null != metricsSet){
metricsSet.forEach(metrics -> {
MetricsCollect metricsCollect = new MetricsCollect(metrics, timeout, this,
collectorIdentity, unitConvertList);
jobRequestQueue.addJob(metricsCollect);
if (metrics.getPrometheus() != null) {
metricsTimeoutMonitorMap.put(String.valueOf(job.getId()),
new MetricsTime(System.currentTimeMillis(), metrics, timeout));
} else {
metricsTimeoutMonitorMap.put(job.getId() + "-" + metrics.getName(),
new MetricsTime(System.currentTimeMillis(), metrics, timeout));
}
});
}
}
@Override
@@ -234,6 +237,8 @@ public class CommonDispatcher implements MetricsTaskDispatch, CollectDataDispatc
long spendTime = System.currentTimeMillis() - job.getDispatchTime();
long interval = job.getInterval() - spendTime / 1000;
interval = interval <= 0 ? 0 : interval;
// Reset Construction Execution Metrics Task View
job.constructPriorMetrics();
timerDispatch.cyclicJob(timerJob, interval, TimeUnit.SECONDS);
}
} else if (!metricsSet.isEmpty()) {
@@ -330,6 +335,8 @@ public class CommonDispatcher implements MetricsTaskDispatch, CollectDataDispatc
long spendTime = System.currentTimeMillis() - job.getDispatchTime();
long interval = job.getInterval() - spendTime / 1000;
interval = interval <= 0 ? 0 : interval;
// Reset Construction Execution Metrics Task View
job.constructPriorMetrics();
timerDispatch.cyclicJob(timerJob, interval, TimeUnit.SECONDS);
}
// it is an asynchronous periodic cyclic task, directly response the collected data
@@ -75,18 +75,6 @@ public class MetricsCollect implements Runnable, Comparable<MetricsCollect> {
* metrics configuration
*/
protected Metrics metrics;
/**
* metadata
*/
protected Map<String, String> metadata;
/**
* labels
*/
protected Map<String, String> labels;
/**
* annotations
*/
protected Map<String, String> annotations;
/**
* time wheel timeout
*/
@@ -131,9 +119,6 @@ public class MetricsCollect implements Runnable, Comparable<MetricsCollect> {
this.id = job.getMonitorId();
this.tenantId = job.getTenantId();
this.app = job.getApp();
this.metadata = job.getMetadata();
this.labels = job.getLabels();
this.annotations = job.getAnnotations();
this.collectDataDispatch = collectDataDispatch;
this.isCyclic = job.isCyclic();
this.isSd = job.isSd();
@@ -151,8 +136,9 @@ public class MetricsCollect implements Runnable, Comparable<MetricsCollect> {
this.startTime = System.currentTimeMillis();
setNewThreadName(id, app, startTime, metrics);
CollectRep.MetricsData.Builder response = CollectRep.MetricsData.newBuilder();
response.setApp(app).setId(id).setTenantId(tenantId)
.setLabels(labels).setAnnotations(annotations).addMetadataAll(metadata);
response.setApp(app);
response.setId(id);
response.setTenantId(tenantId);
// for prometheus auto
if (DispatchConstants.PROTOCOL_PROMETHEUS.equalsIgnoreCase(metrics.getProtocol())) {
List<CollectRep.MetricsData> metricsData = PrometheusAutoCollectImpl
@@ -39,7 +39,7 @@ spring:
collector:
info:
version: ${COLLECTOR_VERSION:1.7.0}
version: ${COLLECTOR_VERSION:1.6.1}
ip: ${COLLECTOR_IP:}
dispatch:
entrance:
@@ -17,18 +17,13 @@
package org.apache.hertzbeat.collector.collect.common.ssh;
import java.io.InputStream;
import java.security.KeyPair;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.collector.collect.common.cache.AbstractConnection;
import org.apache.hertzbeat.collector.collect.common.cache.CacheIdentifier;
import org.apache.hertzbeat.collector.collect.common.cache.GlobalConnectionCache;
import org.apache.hertzbeat.collector.collect.common.cache.SshConnect;
import org.apache.hertzbeat.collector.util.PrivateKeyUtils;
import org.apache.hertzbeat.common.entity.job.protocol.SshProtocol;
import org.apache.sshd.client.SshClient;
import org.apache.sshd.client.config.hosts.HostConfigEntry;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.config.keys.FilePasswordProvider;
import org.apache.sshd.common.util.security.SecurityUtils;
@@ -106,101 +101,4 @@ public class SshHelper {
return clientSession;
}
public static ClientSession getConnectSession(SshProtocol sshProtocol, int timeout, boolean reuseConnection, boolean useProxy)
throws IOException, GeneralSecurityException {
CacheIdentifier identifier = CacheIdentifier.builder()
.ip(sshProtocol.getHost()).port(sshProtocol.getPort())
.username(sshProtocol.getUsername()).password(sshProtocol.getPassword())
.build();
ClientSession clientSession = null;
// When using ProxyJump, force connection reuse:
// Apache MINA SSHD will pass the proxy password error to the target host in proxy scenarios, causing the first connection to fail.
// Reusing connections can skip duplicate authentication and avoid this problem.
if (reuseConnection || useProxy) {
Optional<AbstractConnection<?>> cacheOption = CONNECTION_COMMON_CACHE.getCache(identifier, true);
if (cacheOption.isPresent()) {
SshConnect sshConnect = (SshConnect) cacheOption.get();
clientSession = sshConnect.getConnection();
try {
if (clientSession == null || clientSession.isClosed() || clientSession.isClosing()) {
clientSession = null;
CONNECTION_COMMON_CACHE.removeCache(identifier);
}
} catch (Exception e) {
log.warn(e.getMessage());
clientSession = null;
CONNECTION_COMMON_CACHE.removeCache(identifier);
}
}
if (clientSession != null) {
return clientSession;
}
}
SshClient sshClient = CommonSshClient.getSshClient();
HostConfigEntry proxyConfig = new HostConfigEntry();
if (useProxy && StringUtils.hasText(sshProtocol.getProxyHost())) {
String proxySpec = String.format("%s@%s:%d", sshProtocol.getProxyUsername(), sshProtocol.getProxyHost(), Integer.parseInt(sshProtocol.getProxyPort()));
proxyConfig.setHostName(sshProtocol.getHost());
proxyConfig.setHost(sshProtocol.getHost());
proxyConfig.setPort(Integer.parseInt(sshProtocol.getPort()));
proxyConfig.setUsername(sshProtocol.getUsername());
proxyConfig.setProxyJump(proxySpec);
// Apache SSHD requires the password for the proxy to be preloaded into the sshClient instance before connecting
if (StringUtils.hasText(sshProtocol.getProxyPassword())) {
sshClient.addPasswordIdentity(sshProtocol.getProxyPassword());
log.debug("Loaded proxy server password authentication: {}@{}", sshProtocol.getProxyUsername(), sshProtocol.getProxyHost());
}
if (StringUtils.hasText(sshProtocol.getProxyPrivateKey())) {
proxyConfig.setIdentities(List.of(sshProtocol.getProxyPrivateKey()));
log.debug("Proxy private key loaded into HostConfigEntry");
}
}
if (useProxy && StringUtils.hasText(sshProtocol.getProxyHost())) {
try {
clientSession = sshClient.connect(proxyConfig)
.verify(timeout, TimeUnit.MILLISECONDS).getSession();
}
finally {
sshClient.removePasswordIdentity(sshProtocol.getProxyPassword());
}
} else {
clientSession = sshClient.connect(sshProtocol.getUsername(), sshProtocol.getHost(), Integer.parseInt(sshProtocol.getPort()))
.verify(timeout, TimeUnit.MILLISECONDS).getSession();
}
if (StringUtils.hasText(sshProtocol.getPassword())) {
clientSession.addPasswordIdentity(sshProtocol.getPassword());
} else if (StringUtils.hasText(sshProtocol.getPrivateKey())) {
var resourceKey = PrivateKeyUtils.writePrivateKey(sshProtocol.getHost(), sshProtocol.getPrivateKey());
try (InputStream keyStream = new FileInputStream(resourceKey)) {
FilePasswordProvider passwordProvider = (session, resource, index) -> {
if (StringUtils.hasText(sshProtocol.getPrivateKeyPassphrase())) {
return sshProtocol.getPrivateKeyPassphrase();
}
return null;
};
Iterable<KeyPair> keyPairs = SecurityUtils.loadKeyPairIdentities(null, () -> resourceKey, keyStream, passwordProvider);
if (keyPairs != null) {
keyPairs.forEach(clientSession::addPublicKeyIdentity);
} else {
log.error("Failed to load private key pairs from: {}", resourceKey);
}
} catch (IOException e) {
log.error("Error reading private key file: {}", e.getMessage());
}
} // else auth with localhost private public key certificates
// auth
if (!clientSession.auth().verify(timeout, TimeUnit.MILLISECONDS).isSuccess()) {
clientSession.close();
throw new IllegalArgumentException("ssh auth failed.");
}
if (reuseConnection || useProxy) {
SshConnect sshConnect = new SshConnect(clientSession);
CONNECTION_COMMON_CACHE.addCache(identifier, sshConnect);
}
return clientSession;
}
}
@@ -93,14 +93,9 @@ public interface CommonConstants {
String LABEL_ALERT_NAME = "alertname";
/**
* label key: instance host
* label key: host
*/
String LABEL_INSTANCE_HOST = "instancehost";
/**
* label key: instance name
*/
String LABEL_INSTANCE_NAME = "instancename";
String LABEL_HOST = "host";
/**
* Alarm severity label key
@@ -1,30 +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.common.constants;
/**
* Import/Export task constants
*/
public interface ImExportTaskConstant {
/**
* If the number of tasks exceeds 100, progress information will broadcast
*/
Integer IMPORT_TASK_PROCESS_THRESHOLD = 100;
}
@@ -1,39 +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.common.constants;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;
/**
* Manager Event Type Enum
*/
@Getter
@AllArgsConstructor
@ToString
public enum ManagerEventTypeEnum {
/**
* IMPORT_TASK_EVENT
*/
IMPORT_TASK_EVENT("IMPORT_TASK_EVENT");
private final String value;
}
@@ -27,16 +27,12 @@ public interface MetricDataConstants {
String UNIT = "unit";
// key in Schema metadata
String ID = "id";
String MONITOR_ID = "id";
String TENANT_ID = "tenantId";
String APP = "app";
String METRICS = "metrics";
String LABELS = "labels";
String ANNOTATIONS = "annotations";
String PRIORITY = "priority";
String TIME = "time";
String CODE = "code";
String MSG = "msg";
String INSTANCE_NAME = "instancename";
String INSTANCE_HOST = "instancehost";
}
@@ -1,40 +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.common.constants;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;
/**
* Notify Level Enum
*/
@Getter
@AllArgsConstructor
@ToString
public enum NotifyLevelEnum {
SUCCESS("SUCCESS"),
ERROR("ERROR"),
INFO("INFO"),
WARNING("WARNING"),
BLANK("BLANK");
private final String value;
}
@@ -23,19 +23,10 @@ package org.apache.hertzbeat.common.constants;
public interface SmsConstants {
// Tencent cloud SMS
String TENCENT = "tencent";
// Alibaba Cloud SMS
String ALIBABA = "alibaba";
// UniSMS
String UNISMS = "unisms";
// Smslocal SMS
String SMSLOCAL = "smslocal";
// Aws cloud SMS
String AWS = "aws";
// Twilio SMS
String TWILIO = "twilio";
}
@@ -63,7 +63,6 @@ public class GroupAlert {
private Long id;
@Schema(title = "Group Key", example = "HighCPUUsage{alertname=\"HighCPUUsage\", instance=\"server1\"}")
@Column(length = 2048)
private String groupKey;
@Schema(title = "Status", example = "resolved")
@@ -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)
@@ -59,9 +59,8 @@ public class SingleAlert {
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Schema(title = "Threshold Id", example = "87584674384", accessMode = READ_ONLY)
private Long id;
@Schema(title = "Fingerprint", example = "alertname:demo")
@Column(length = 2048)
@Schema(title = "Fingerprint", example = "dxsdfdsf")
private String fingerprint;
@Schema(title = "Labels", example = "{\"alertname\": \"HighCPUUsage\", \"priority\": \"critical\", \"instance\": \"343483943\"}")
@@ -75,7 +74,6 @@ public class SingleAlert {
private Map<String, String> annotations;
@Schema(title = "Content", example = "CPU usage is above 80% for the last 5 minutes on instance server1.example.com.")
@Column(length = 4096)
private String content;
@Schema(title = "Status", example = "firing|resolved")
@@ -1,79 +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.common.entity.dto;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.hertzbeat.common.constants.ImportTaskStatusEnum;
import org.apache.hertzbeat.common.constants.ManagerEventTypeEnum;
import org.apache.hertzbeat.common.constants.NotifyLevelEnum;
import org.springframework.lang.Nullable;
/**
* Import task message
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class ImportTaskMessage extends ManagerMessage {
/**
* Task name
*/
@NotNull
private String taskName;
/**
* Progress, expressed as a percentage
*/
@Nullable
private Integer progress;
/**
* Task Status,
* @see ImportTaskStatusEnum
*/
@NotNull
private String status;
/**
* If Fail, the error message
*/
@Nullable
private String errMsg;
public ImportTaskMessage(String notifyLevel, String managerEventType, String taskName, @Nullable Integer progress, String status, @Nullable String errMsg){
super(notifyLevel, managerEventType);
this.taskName = taskName;
this.progress = progress;
this.status = status;
this.errMsg = errMsg;
}
public static ManagerMessage createInProgressMessage(String taskName, Integer process){
return new ImportTaskMessage(NotifyLevelEnum.INFO.getValue(), ManagerEventTypeEnum.IMPORT_TASK_EVENT.getValue(), taskName, process, ImportTaskStatusEnum.IN_PROGRESS.getValue(), null);
}
public static ManagerMessage createCompletedMessage(String taskName){
return new ImportTaskMessage(NotifyLevelEnum.SUCCESS.getValue(), ManagerEventTypeEnum.IMPORT_TASK_EVENT.getValue(), taskName, null, ImportTaskStatusEnum.COMPLETED.getValue(), null);
}
public static ManagerMessage createFailedMessage(String taskName, String errMsg){
return new ImportTaskMessage(NotifyLevelEnum.ERROR.getValue(), ManagerEventTypeEnum.IMPORT_TASK_EVENT.getValue(), taskName, null, ImportTaskStatusEnum.FAILED.getValue(), errMsg);
}
}
@@ -1,42 +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.common.entity.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* Manager Message Entity
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ManagerMessage {
/**
* Notify Level
* @see org.apache.hertzbeat.common.constants.NotifyLevelEnum
*/
private String notifyLevel;
/**
* Manager Event Type
* @see org.apache.hertzbeat.common.constants.ManagerEventTypeEnum
*/
private String managerEventType;
}
@@ -0,0 +1,81 @@
/*
* 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.common.entity.dto.query;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* Metric History Range Query Data
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Schema(description = "Metric Query Data")
public class MetricQueryData {
@Schema(title = "Metric Schema")
private MetricSchema schema;
@Schema(title = "metrics row values, first is the timestamp-ts", example = "[[29,32,44],[32,34,true]]")
private List<List<Object>> values;
/**
* Metric Schema
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public static final class MetricSchema {
@Schema(title = "Metrics Field")
private List<MetricField> fields;
@Schema(title = "Meta Information")
private Map<String, String> meta;
}
/**
* Metric Field
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public static final class MetricField {
@Schema(title = "Metric Field Name")
private String name;
@Schema(title = "Field Type: number, string, time, bool")
private String type;
@Schema(title = "Field Unit: %, Mb, Kbps etc.")
private String unit;
@Schema(title = "Whether is a label")
private Boolean label;
}
}
@@ -61,19 +61,6 @@ public class Job {
* Monitoring Task ID
*/
private long monitorId;
/**
* metadata info bind with this job
* eg: instancename, instancehost
*/
private Map<String, String> metadata;
/**
* bind labels
*/
private Map<String, String> labels;
/**
* bind annotations
*/
private Map<String, String> annotations;
/**
* Is hide this app in main menus layout, only for app type, default true.
*/
@@ -172,36 +159,23 @@ public class Job {
* collector use - construct to initialize metrics execution view
*/
public synchronized void constructPriorMetrics() {
long now = System.currentTimeMillis();
Map<Byte, List<Metrics>> currentCollectMetrics = metrics.stream()
.filter(metrics -> (now >= metrics.getCollectTime() + metrics.getInterval() * 1000))
.peek(metric -> {
metric.setCollectTime(now);
// Determine whether to configure aliasFields If not, configure the default
if ((metric.getAliasFields() == null || metric.getAliasFields().isEmpty()) && metric.getFields() != null) {
metric.setAliasFields(metric.getFields().stream().map(Metrics.Field::getField).collect(Collectors.toList()));
}
// Set the default metrics execution priority, if not filled, the default last priority
if (metric.getPriority() == null) {
metric.setPriority(Byte.MAX_VALUE);
}
})
.collect(Collectors.groupingBy(Metrics::getPriority));
// the current collect metrics can not empty, if empty, add a default availability metrics
// due the metric collect is trigger by the previous metric collect
if (currentCollectMetrics.isEmpty()) {
Optional<Metrics> defaultMetricOption = metrics.stream().filter(metric -> metric.getPriority() == 0).findFirst();
if (defaultMetricOption.isPresent()) {
Metrics defaultMetric = defaultMetricOption.get();
defaultMetric.setCollectTime(now);
currentCollectMetrics.put((byte) 0, Collections.singletonList(defaultMetric));
} else {
log.error("metrics must has one priority 0 metrics at least.");
}
}
Map<Byte, List<Metrics>> map = metrics.stream()
.filter(metrics -> (System.currentTimeMillis() >= metrics.getCollectTime() + metrics.getInterval() * 1000))
.peek(metric -> {
metric.setCollectTime(System.currentTimeMillis());
// Determine whether to configure aliasFields If not, configure the default
if ((metric.getAliasFields() == null || metric.getAliasFields().isEmpty()) && metric.getFields() != null) {
metric.setAliasFields(metric.getFields().stream().map(Metrics.Field::getField).collect(Collectors.toList()));
}
// Set the default metrics execution priority, if not filled, the default last priority
if (metric.getPriority() == null) {
metric.setPriority(Byte.MAX_VALUE);
}
})
.collect(Collectors.groupingBy(Metrics::getPriority));
// Construct a linked list of task execution order of the metrics
priorMetrics = new LinkedList<>();
currentCollectMetrics.values().forEach(metric -> {
map.values().forEach(metric -> {
Set<Metrics> metricsSet = Collections.synchronizedSet(new HashSet<>(metric));
priorMetrics.add(metricsSet);
});
@@ -286,7 +260,7 @@ public class Job {
public void initIntervals() {
List<Long> metricsIntervals = new LinkedList<>();
for (Metrics metrics: getMetrics()) {
metrics.setCollectTime(0L);
metrics.setCollectTime(System.currentTimeMillis());
if (metrics.getInterval() <= 0) {
metrics.setInterval(defaultInterval);
}
@@ -313,10 +287,10 @@ public class Job {
* The least common multiple
*/
public static long lcm(List<Long> array) {
if (array != null && !array.isEmpty()) {
if (array != null) {
long result = array.get(0);
for (int i = 1; i < array.size(); i++) {
result = result / gcd(result, array.get(i)) * array.get(i);
result = (result * array.get(i)) / gcd(result, array.get(i));
}
return result;
}
@@ -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
*/
@@ -71,10 +71,7 @@ public class JdbcProtocol implements CommonRequestProtocol, Protocol {
* DATABASE LINK URL eg: jdbc:mysql://localhost:3306/usthe
*/
private String url;
/**
* reuse connection session
*/
private String reuseConnection = "true";
/**
* ssh tunnel
*/
@@ -80,34 +80,4 @@ public class SshProtocol implements CommonRequestProtocol, Protocol {
* Response data parsing modeoneRow, multiRow
*/
private String parseType;
/**
* IP ADDRESS OR DOMAIN NAME OF THE PEER PROXY HOST
*/
private String proxyHost;
/**
* Peer proxy host port
*/
private String proxyPort;
/**
* Proxy UserName
*/
private String proxyUsername;
/**
* Proxy Password (optional)
*/
private String proxyPassword;
/**
* flag of use proxy
*/
private String useProxy = "false";
/**
* Proxy private key (optional)
*/
private String proxyPrivateKey;
}
@@ -43,7 +43,6 @@ import org.apache.arrow.vector.types.pojo.FieldType;
import org.apache.arrow.vector.types.pojo.Schema;
import org.apache.hertzbeat.common.constants.MetricDataConstants;
import org.apache.hertzbeat.common.entity.arrow.RowWrapper;
import org.apache.hertzbeat.common.util.JsonUtil;
@SuppressWarnings("all")
@Slf4j
@@ -139,7 +138,17 @@ public final class CollectRep {
public static Builder newBuilder(MetricsData metricsData) {
Builder builder = new Builder();
builder.addMetadataAll(metricsData.getMetadata());
// get metadata from metricsData
Map<String, String> metadata = metricsData.getMetadata();
builder.setId(Long.parseLong(metadata.getOrDefault(MetricDataConstants.MONITOR_ID, "0")))
.setTenantId(Long.parseLong(metadata.getOrDefault(MetricDataConstants.TENANT_ID, "0")))
.setApp(metadata.getOrDefault(MetricDataConstants.APP, ""))
.setMetrics(metadata.getOrDefault(MetricDataConstants.METRICS, ""))
.setPriority(Integer.parseInt(metadata.getOrDefault(MetricDataConstants.PRIORITY, "0")))
.setTime(Long.parseLong(metadata.getOrDefault(MetricDataConstants.TIME, "0")))
.setCode(Code.forNumber(Integer.parseInt(metadata.getOrDefault(MetricDataConstants.CODE, "0"))))
.setMsg(metadata.getOrDefault(MetricDataConstants.MSG, ""));
metricsData.getFields().forEach(builder::addField);
metricsData.getValues().forEach(builder::addValueRow);
return builder;
@@ -182,70 +191,42 @@ public final class CollectRep {
public long getId() {
Map<String, String> metadata = getMetadata();
return Long.parseLong(metadata.getOrDefault(MetricDataConstants.ID, "0"));
return Long.parseLong(metadata.getOrDefault("id", "0"));
}
public long getTenantId() {
Map<String, String> metadata = getMetadata();
return Long.parseLong(metadata.getOrDefault(MetricDataConstants.TENANT_ID, "0"));
return Long.parseLong(metadata.getOrDefault("tenantId", "0"));
}
public String getApp() {
Map<String, String> metadata = getMetadata();
return metadata.getOrDefault(MetricDataConstants.APP, "");
return metadata.getOrDefault("app", "");
}
public String getMetrics() {
Map<String, String> metadata = getMetadata();
return metadata.getOrDefault(MetricDataConstants.METRICS, "");
return metadata.getOrDefault("metrics", "");
}
public int getPriority() {
Map<String, String> metadata = getMetadata();
return Integer.parseInt(metadata.getOrDefault(MetricDataConstants.PRIORITY, "0"));
return Integer.parseInt(metadata.getOrDefault("priority", "0"));
}
public long getTime() {
Map<String, String> metadata = getMetadata();
return Long.parseLong(metadata.getOrDefault(MetricDataConstants.TIME, "0"));
return Long.parseLong(metadata.getOrDefault("time", "0"));
}
public Code getCode() {
Map<String, String> metadata = getMetadata();
return Code.forNumber(Integer.parseInt(metadata.getOrDefault(MetricDataConstants.CODE, "0")));
return Code.forNumber(Integer.parseInt(metadata.getOrDefault("code", "0")));
}
public String getMsg() {
Map<String, String> metadata = getMetadata();
return metadata.getOrDefault(MetricDataConstants.MSG, "");
}
public String getInstanceName() {
Map<String, String> metadata = getMetadata();
return metadata.getOrDefault(MetricDataConstants.INSTANCE_NAME, null);
}
public String getInstanceHost() {
Map<String, String> metadata = getMetadata();
return metadata.getOrDefault(MetricDataConstants.INSTANCE_HOST, null);
}
public Map<String, String> getLabels() {
Map<String, String> metadata = getMetadata();
String labelStr = metadata.getOrDefault(MetricDataConstants.LABELS, "");
if (labelStr == null || "".equals(labelStr)) {
return null;
}
return JsonUtil.fromJson(labelStr, Map.class);
}
public Map<String, String> getAnnotations() {
Map<String, String> metadata = getMetadata();
String annotationStr = metadata.getOrDefault(MetricDataConstants.ANNOTATIONS, "");
if (annotationStr == null || "".equals(annotationStr)) {
return null;
}
return JsonUtil.fromJson(annotationStr, Map.class);
return metadata.getOrDefault("msg", "");
}
private Map<String, String> getMetadata() {
@@ -317,82 +298,54 @@ public final class CollectRep {
// Builder remains mostly the same, but build() method changes
public static class Builder {
private Map<String, String> metadata = new HashMap<>();
private long id;
private long tenantId;
private String app = "";
private String metrics = "";
private int priority;
private long time;
private Code code = Code.SUCCESS;
private String msg = "";
private List<Field> fields = new ArrayList<>();
private List<ValueRow> values = new ArrayList<>();
public Builder setId(long id) {
metadata.put(MetricDataConstants.ID, String.valueOf(id));
this.id = id;
return this;
}
public Builder setTenantId(long tenantId) {
metadata.put(MetricDataConstants.TENANT_ID, String.valueOf(tenantId));
this.tenantId = tenantId;
return this;
}
public Builder setApp(String app) {
metadata.put(MetricDataConstants.APP, app != null ? app : "");
this.app = app;
return this;
}
public Builder setMetrics(String metrics) {
metadata.put(MetricDataConstants.METRICS, metrics != null ? metrics : "");
return this;
}
public Builder setLabels(Map<String, String> labels) {
if (labels == null || labels.isEmpty()) {
return this;
}
String labelStr = JsonUtil.toJson(labels);
metadata.put(MetricDataConstants.LABELS, labelStr);
return this;
}
public Builder setAnnotations(Map<String, String> annotations) {
if (annotations == null || annotations.isEmpty()) {
return this;
}
String annotationStr = JsonUtil.toJson(annotations);
metadata.put(MetricDataConstants.ANNOTATIONS, annotationStr);
this.metrics = metrics;
return this;
}
public Builder setPriority(int priority) {
metadata.put(MetricDataConstants.PRIORITY, String.valueOf(priority));
this.priority = priority;
return this;
}
public Builder setTime(long time) {
metadata.put(MetricDataConstants.TIME, String.valueOf(time));
this.time = time;
return this;
}
public Builder setCode(Code code) {
metadata.put(MetricDataConstants.CODE, String.valueOf(code != null ? code.value : 0));
this.code = code;
return this;
}
public Builder setMsg(String msg) {
metadata.put(MetricDataConstants.MSG, msg != null ? msg : "");
return this;
}
public Builder addMetadata(String key, String value) {
if (key == null || "".equals(key)) {
return this;
}
metadata.put(key, value);
return this;
}
public Builder addMetadataAll(Map<String, String> meta) {
if (meta == null || meta.isEmpty()) {
return this;
}
this.metadata.putAll(meta);
this.msg = msg;
return this;
}
@@ -407,6 +360,17 @@ public final class CollectRep {
}
public MetricsData build() {
// Create metadata
Map<String, String> metadata = new HashMap<>();
metadata.put(MetricDataConstants.MONITOR_ID, String.valueOf(id));
metadata.put(MetricDataConstants.TENANT_ID, String.valueOf(tenantId));
metadata.put(MetricDataConstants.APP, app != null ? app : "");
metadata.put(MetricDataConstants.METRICS, metrics != null ? metrics : "");
metadata.put(MetricDataConstants.PRIORITY, String.valueOf(priority));
metadata.put(MetricDataConstants.TIME, String.valueOf(time));
metadata.put(MetricDataConstants.CODE, String.valueOf(code != null ? code.value : 0));
metadata.put(MetricDataConstants.MSG, msg != null ? msg : "");
BufferAllocator allocator = new RootAllocator();
try {
// Create Arrow fields with metadata
@@ -443,17 +407,7 @@ public final class CollectRep {
fieldIndex < row.getColumnsList().size()) {
String value = row.getColumns(fieldIndex);
if (value != null) {
// Check byte array size, Arrow buffer size is 32768 bytes
byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
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);
}
vector.set(rowIndex, value.getBytes(StandardCharsets.UTF_8));
}
}
}
@@ -471,65 +425,38 @@ public final class CollectRep {
throw e;
}
}
// Add getter methods
public long getId() {
return Long.parseLong(metadata.getOrDefault(MetricDataConstants.ID, "0"));
return id;
}
public long getTenantId() {
return Long.parseLong(metadata.getOrDefault(MetricDataConstants.TENANT_ID, "0"));
return tenantId;
}
public String getApp() {
return metadata.getOrDefault(MetricDataConstants.APP, "");
return app;
}
public String getMetrics() {
return metadata.getOrDefault(MetricDataConstants.METRICS, "");
return metrics;
}
public int getPriority() {
return Integer.parseInt(metadata.getOrDefault(MetricDataConstants.PRIORITY, "0"));
return priority;
}
public long getTime() {
return Integer.parseInt(metadata.getOrDefault(MetricDataConstants.TIME, "0"));
return time;
}
public Code getCode() {
return Code.forNumber(Integer.parseInt(metadata.getOrDefault(MetricDataConstants.CODE, "0")));
return code;
}
public String getMsg() {
return metadata.getOrDefault(MetricDataConstants.MSG, "");
}
public String getInstanceName() {
return metadata.getOrDefault(MetricDataConstants.INSTANCE_NAME, null);
}
public String getInstanceHost() {
return metadata.getOrDefault(MetricDataConstants.INSTANCE_HOST, null);
}
public Map<String, String> getLabels() {
String labelStr = metadata.getOrDefault(MetricDataConstants.LABELS, "");
if (labelStr == null || "".equals(labelStr)) {
return null;
}
return JsonUtil.fromJson(labelStr, Map.class);
}
public Map<String, String> getAnnotations() {
String annotationStr = metadata.getOrDefault(MetricDataConstants.ANNOTATIONS, "");
if (annotationStr == null || "".equals(annotationStr)) {
return null;
}
return JsonUtil.fromJson(annotationStr, Map.class);
}
public Map<String, String> getMetadata() {
return metadata;
return msg;
}
public List<Field> getFieldsList() {
@@ -564,6 +491,10 @@ public final class CollectRep {
values = new LinkedList<>();
}
public void clearMetrics() {
metrics = null;
}
public void clearFields() {
fields = new LinkedList<>();
}
@@ -636,13 +567,6 @@ public final class CollectRep {
return new Builder();
}
public boolean equals(Object o) {
if(!(o instanceof Field))
return false;
Field other = (Field)o;
return other.name.equals(this.name);
}
public static class Builder {
private final Field instance;
@@ -1,46 +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.common.entity.message;
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 CollectRep}
*/
public class CollectRepTest {
@ParameterizedTest
@CsvSource(value = {
"name, name, true",
"name1, name3, false",
})
void testFieldEquals(String name1, String name2, boolean result) {
CollectRep.Field field1 = new CollectRep.Field();
field1.setName(name1);
CollectRep.Field field2 = new CollectRep.Field();
field2.setName(name2);
assertEquals(field1.equals(field2), result);
}
}
@@ -72,7 +72,7 @@ public abstract class AbstractCollectE2eTest {
metricsCollect = new MetricsCollect(mock(Metrics.class), timeout, mock(CollectDataDispatch.class), null, List.of());
// Initialize services and components
appService.afterPropertiesSet();
appService.run();
metrics = new Metrics();
}
@@ -1,88 +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.manager.config;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.common.constants.ManagerEventTypeEnum;
import org.apache.hertzbeat.common.entity.dto.ImportTaskMessage;
import org.apache.hertzbeat.common.entity.dto.ManagerMessage;
import org.apache.hertzbeat.common.util.JsonUtil;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Manager SSE
*/
@Slf4j
@Component
public class ManagerSseManager {
private final Map<Long, SseEmitter> emitters = new ConcurrentHashMap<>();
public SseEmitter createEmitter(Long clientId) {
SseEmitter emitter = new SseEmitter(Long.MAX_VALUE);
emitter.onCompletion(() -> removeEmitter(clientId));
emitter.onTimeout(() -> removeEmitter(clientId));
emitters.put(clientId, emitter);
return emitter;
}
@Async
public void broadcast(String eventName, String data) {
emitters.forEach((clientId, emitter) -> {
try {
emitter.send(SseEmitter.event()
.id(String.valueOf(System.currentTimeMillis()))
.name(eventName)
.data(data));
} catch (IOException | IllegalStateException e) {
emitter.complete();
removeEmitter(clientId);
} catch (Exception exception) {
log.error("Failed to broadcast manager message data to client: {}", exception.getMessage());
emitter.complete();
removeEmitter(clientId);
}
});
}
public void broadcastImportTaskInProgress(String taskName, Integer progress){
ManagerMessage managerMessage = ImportTaskMessage.createInProgressMessage(taskName, progress);
broadcast(ManagerEventTypeEnum.IMPORT_TASK_EVENT.getValue(), JsonUtil.toJson(managerMessage));
}
public void broadcastImportTaskSuccess(String taskName){
ManagerMessage managerMessage = ImportTaskMessage.createCompletedMessage(taskName);
broadcast(ManagerEventTypeEnum.IMPORT_TASK_EVENT.getValue(), JsonUtil.toJson(managerMessage));
}
public void broadcastImportTaskFail(String taskName, String errMsg){
ManagerMessage managerMessage = ImportTaskMessage.createFailedMessage(taskName, errMsg);
broadcast(ManagerEventTypeEnum.IMPORT_TASK_EVENT.getValue(), JsonUtil.toJson(managerMessage));
}
private void removeEmitter(Long clientId) {
emitters.remove(clientId);
}
}
@@ -1,50 +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.manager.controller;
import org.apache.hertzbeat.common.util.SnowFlakeIdGenerator;
import org.apache.hertzbeat.manager.config.ManagerSseManager;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import static org.springframework.http.MediaType.TEXT_EVENT_STREAM_VALUE;
/**
* SSE controller for manager
*/
@RestController
@RequestMapping(path = "/api/manager/sse", produces = {TEXT_EVENT_STREAM_VALUE})
public class ManagerSseController {
private final ManagerSseManager emitterManager;
public ManagerSseController(ManagerSseManager emitterManager) {
this.emitterManager = emitterManager;
}
@GetMapping(path = "/subscribe")
public SseEmitter subscribe() {
Long clientId = SnowFlakeIdGenerator.generateId();
return emitterManager.createEmitter(clientId);
}
}
@@ -15,32 +15,26 @@
* limitations under the License.
*/
package org.apache.hertzbeat.alert.config;
package org.apache.hertzbeat.manager.pojo.dto;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
/**
* AWS Cloud SMS configuration properties
* Alibaba Sms Sender configuration dto
*/
@Data
public class AwsSmsProperties {
/**
* AWS Cloud access key id
*/
public class SmsAlibabaConfig {
@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;
@NotBlank(message = "SignName cannot be empty")
private String signName;
@NotBlank(message = "TemplateCode cannot be null")
private String templateCode;
}
@@ -15,23 +15,29 @@
* 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;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* Smslocal SMS Properties
* Sms Sender configuration dto
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SmslocalSmsProperties {
/**
* SmsLocal account api key
*/
private String apiKey;
public class SmsNoticeSender {
@NotBlank(message = "Type cannot be empty")
private String type;
private SmsTencentConfig tencent;
private SmsAlibabaConfig alibaba;
private SmsUniSmsConfig unisms;
private boolean enable = true;
}
@@ -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,26 @@ import lombok.Data;
import lombok.NoArgsConstructor;
/**
* Twilio SMS configuration properties
* Tencent 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 SmsTencentConfig {
@NotBlank(message = "SecretId cannot be empty")
private String secretId;
/**
* Twilio Auth Token
*/
@NotBlank(message = "Auth Token cannot be empty")
private String authToken;
@NotBlank(message = "SecretKey cannot be empty")
private String secretKey;
/**
* Twilio Issued Phone Number
*/
@NotBlank(message = "Twilio Phone Number cannot be empty")
private String twilioPhoneNumber;
}
@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;
}
@@ -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";
}
@@ -120,11 +120,7 @@ public class SchedulerInit implements CommandLineRunner {
appDefine.setDefaultInterval(monitor.getIntervals());
appDefine.setCyclic(true);
appDefine.setTimestamp(System.currentTimeMillis());
Map<String, String> metadata = Map.of(CommonConstants.LABEL_INSTANCE_NAME, monitor.getName(),
CommonConstants.LABEL_INSTANCE_HOST, monitor.getHost());
appDefine.setMetadata(metadata);
appDefine.setLabels(monitor.getLabels());
appDefine.setAnnotations(monitor.getAnnotations());
List<Configmap> configmaps = params.stream()
.map(param -> new Configmap(param.getField(), param.getParamValue(),
param.getType())).collect(Collectors.toList());
@@ -29,10 +29,9 @@ public interface ImExportService {
/**
* Import Configuration
* @param taskName task name
* @param is input stream
*/
void importConfig(String taskName, InputStream is);
void importConfig(InputStream is);
/**
* Export Configuration
@@ -22,20 +22,6 @@ import cn.afterturn.easypoi.excel.annotation.ExcelTarget;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import jakarta.annotation.Resource;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.common.constants.ImExportTaskConstant;
import org.apache.hertzbeat.common.entity.manager.Monitor;
import org.apache.hertzbeat.common.entity.manager.Param;
import org.apache.hertzbeat.manager.config.ManagerSseManager;
import org.apache.hertzbeat.manager.pojo.dto.MonitorDto;
import org.apache.hertzbeat.manager.service.ImExportService;
import org.apache.hertzbeat.manager.service.MonitorService;
import org.apache.hertzbeat.manager.service.TagService;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.util.CollectionUtils;
import java.io.InputStream;
import java.io.OutputStream;
import java.time.LocalDate;
@@ -43,6 +29,17 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.common.entity.manager.Monitor;
import org.apache.hertzbeat.common.entity.manager.Param;
import org.apache.hertzbeat.manager.pojo.dto.MonitorDto;
import org.apache.hertzbeat.manager.service.ImExportService;
import org.apache.hertzbeat.manager.service.MonitorService;
import org.apache.hertzbeat.manager.service.TagService;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.util.CollectionUtils;
/**
* class AbstractImExportServiceImpl
@@ -57,30 +54,27 @@ public abstract class AbstractImExportServiceImpl implements ImExportService {
@Resource
private TagService tagService;
@Resource
private ManagerSseManager managerSseManager;
@Override
public void importConfig(String taskName, InputStream is) {
var formList = parseImport(is).stream().map(this::convert).toList();
public void importConfig(InputStream is) {
var formList = parseImport(is)
.stream()
.map(this::convert)
.toList();
if (!CollectionUtils.isEmpty(formList)) {
int totalElements = formList.size();
int progressInterval = Math.max(1, totalElements / 10);
for (int i = 0; i < totalElements; i++) {
MonitorDto monitorDto = formList.get(i);
formList.forEach(monitorDto -> {
monitorService.validate(monitorDto, false);
monitorService.addMonitor(monitorDto.getMonitor(), monitorDto.getParams(), monitorDto.getCollector(), monitorDto.getGrafanaDashboard());
if (totalElements >= ImExportTaskConstant.IMPORT_TASK_PROCESS_THRESHOLD && ((i + 1) % progressInterval == 0) && (i + 1 < totalElements)) {
managerSseManager.broadcastImportTaskInProgress(taskName, (int) ((i + 1) * 100.0 / totalElements));
}
}
managerSseManager.broadcastImportTaskSuccess(taskName);
});
}
}
@Override
public void exportConfig(OutputStream os, List<Long> configList) {
var monitorList = configList.stream().map(it -> monitorService.getMonitorDto(it)).filter(Objects::nonNull).map(this::convert).toList();
var monitorList = configList.stream()
.map(it -> monitorService.getMonitorDto(it))
.filter(Objects::nonNull)
.map(this::convert)
.toList();
writeOs(monitorList, os);
}
@@ -105,13 +99,15 @@ public abstract class AbstractImExportServiceImpl implements ImExportService {
var monitor = new MonitorDTO();
BeanUtils.copyProperties(dto.getMonitor(), monitor);
exportMonitor.setMonitor(monitor);
exportMonitor.setParams(dto.getParams().stream().map(it -> {
var param = new ParamDTO();
param.setField(it.getField());
param.setType(it.getType());
param.setValue(it.getParamValue());
return param;
}).toList());
exportMonitor.setParams(dto.getParams().stream()
.map(it -> {
var param = new ParamDTO();
param.setField(it.getField());
param.setType(it.getType());
param.setValue(it.getParamValue());
return param;
})
.toList());
exportMonitor.getMonitor().setCollector(dto.getCollector());
return exportMonitor;
}
@@ -124,7 +120,7 @@ public abstract class AbstractImExportServiceImpl implements ImExportService {
var monitorDto = new MonitorDto();
var monitor = new Monitor();
log.debug("exportMonitor.monitor{}", exportMonitor.monitor);
if (exportMonitor.monitor != null) {
if (exportMonitor.monitor != null) {
// Add one more null check
BeanUtils.copyProperties(exportMonitor.monitor, monitor);
}
@@ -133,13 +129,15 @@ public abstract class AbstractImExportServiceImpl implements ImExportService {
monitorDto.setCollector(exportMonitor.getMonitor().getCollector());
}
if (exportMonitor.params != null) {
monitorDto.setParams(exportMonitor.params.stream().map(it -> {
var param = new Param();
param.setField(it.field);
param.setType(it.type);
param.setParamValue(it.value);
return param;
}).toList());
monitorDto.setParams(exportMonitor.params.stream()
.map(it -> {
var param = new Param();
param.setField(it.field);
param.setType(it.type);
param.setParamValue(it.value);
return param;
})
.toList());
} else {
monitorDto.setParams(Collections.emptyList());
}
@@ -205,4 +203,5 @@ public abstract class AbstractImExportServiceImpl implements ImExportService {
@Excel(name = "Value")
private String value;
}
}
@@ -63,7 +63,7 @@ import org.apache.hertzbeat.manager.service.AppService;
import org.apache.hertzbeat.manager.service.MonitorService;
import org.apache.hertzbeat.manager.service.ObjectStoreService;
import org.apache.hertzbeat.warehouse.service.WarehouseService;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.event.EventListener;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
@@ -75,13 +75,12 @@ 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)
@Slf4j
public class AppServiceImpl implements AppService, InitializingBean {
public class AppServiceImpl implements AppService, CommandLineRunner {
private static final String PUSH_PROTOCOL_METRICS_NAME = "metrics";
@@ -501,7 +500,7 @@ public class AppServiceImpl implements AppService, InitializingBean {
}
@Override
public void afterPropertiesSet() throws Exception {
public void run(String... args) throws Exception {
var objectStoreConfig = objectStoreConfigService.getConfig();
refreshStore(objectStoreConfig);
}
@@ -42,6 +42,7 @@ import org.apache.hertzbeat.common.entity.manager.MonitorBind;
import org.apache.hertzbeat.common.entity.manager.Param;
import org.apache.hertzbeat.common.entity.manager.ParamDefine;
import org.apache.hertzbeat.common.entity.manager.SdMonitorParam;
import org.apache.hertzbeat.common.entity.manager.Tag;
import org.apache.hertzbeat.common.entity.message.CollectRep;
import org.apache.hertzbeat.common.entity.sd.ServiceDiscoveryProtocol;
import org.apache.hertzbeat.common.support.event.MonitorDeletedEvent;
@@ -53,7 +54,6 @@ import org.apache.hertzbeat.common.util.JsonUtil;
import org.apache.hertzbeat.common.util.SdMonitorOperator;
import org.apache.hertzbeat.common.util.SnowFlakeIdGenerator;
import org.apache.hertzbeat.grafana.service.DashboardService;
import org.apache.hertzbeat.manager.config.ManagerSseManager;
import org.apache.hertzbeat.manager.dao.CollectorDao;
import org.apache.hertzbeat.manager.dao.CollectorMonitorBindDao;
import org.apache.hertzbeat.manager.dao.MonitorBindDao;
@@ -90,6 +90,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -137,8 +138,6 @@ public class MonitorServiceImpl implements MonitorService {
private WarehouseService warehouseService;
@Autowired
private DashboardService dashboardService;
@Autowired
private ManagerSseManager managerSseManager;
public MonitorServiceImpl(List<ImExportService> imExportServiceList) {
imExportServiceList.forEach(it -> imExportServiceMap.put(it.type(), it));
@@ -184,21 +183,17 @@ public class MonitorServiceImpl implements MonitorService {
@Override
public void importConfig(MultipartFile file) throws Exception {
var fileName = FileUtil.getFileName(file);
var type = FileUtil.getFileType(file);
try {
if (!imExportServiceMap.containsKey(type)) {
String errMsg = ExportFileConstants.FILE + " " + fileName + " is not supported.";
throw new RuntimeException(errMsg);
}
var imExportService = imExportServiceMap.get(type);
imExportService.importConfig(fileName, file.getInputStream());
} catch (Exception e){
managerSseManager.broadcastImportTaskFail(fileName, e.getMessage());
throw e;
if (!imExportServiceMap.containsKey(type)) {
throw new RuntimeException(ExportFileConstants.FILE + " " + fileName + " is not supported.");
}
var imExportService = imExportServiceMap.get(type);
imExportService.importConfig(file.getInputStream());
}
@Override
@Transactional(readOnly = true)
public void validate(MonitorDto monitorDto, Boolean isModify) throws IllegalArgumentException {
@@ -431,11 +426,6 @@ public class MonitorServiceImpl implements MonitorService {
appDefine.setDefaultInterval(monitor.getIntervals());
appDefine.setCyclic(true);
appDefine.setTimestamp(System.currentTimeMillis());
Map<String, String> metadata = Map.of(CommonConstants.LABEL_INSTANCE_NAME, monitor.getName(),
CommonConstants.LABEL_INSTANCE_HOST, monitor.getHost());
appDefine.setMetadata(metadata);
appDefine.setLabels(monitor.getLabels());
appDefine.setAnnotations(monitor.getAnnotations());
List<Configmap> configmaps = params.stream().map(param ->
new Configmap(param.getField(), param.getParamValue(), param.getType())).collect(Collectors.toList());
appDefine.setConfigmap(configmaps);
@@ -683,11 +673,6 @@ public class MonitorServiceImpl implements MonitorService {
appDefine.setDefaultInterval(monitor.getIntervals());
appDefine.setCyclic(true);
appDefine.setTimestamp(System.currentTimeMillis());
Map<String, String> metadata = Map.of(CommonConstants.LABEL_INSTANCE_NAME, monitor.getName(),
CommonConstants.LABEL_INSTANCE_HOST, monitor.getHost());
appDefine.setMetadata(metadata);
appDefine.setLabels(monitor.getLabels());
appDefine.setAnnotations(monitor.getAnnotations());
List<Configmap> configmaps = params.stream().map(param ->
new Configmap(param.getField(), param.getParamValue(), param.getType())).collect(Collectors.toList());
List<ParamDefine> paramDefaultValue = appDefine.getParams().stream()
@@ -798,11 +783,6 @@ public class MonitorServiceImpl implements MonitorService {
appDefine.setDefaultInterval(monitor.getIntervals());
appDefine.setCyclic(true);
appDefine.setTimestamp(System.currentTimeMillis());
Map<String, String> metadata = Map.of(CommonConstants.LABEL_INSTANCE_NAME, monitor.getName(),
CommonConstants.LABEL_INSTANCE_HOST, monitor.getHost());
appDefine.setMetadata(metadata);
appDefine.setLabels(monitor.getLabels());
appDefine.setAnnotations(monitor.getAnnotations());
List<Param> params = paramDao.findParamsByMonitorId(monitor.getId());
List<Configmap> configmaps = params.stream().map(param -> new Configmap(param.getField(),
param.getParamValue(), param.getType())).collect(Collectors.toList());
@@ -854,11 +834,6 @@ public class MonitorServiceImpl implements MonitorService {
appDefine.setDefaultInterval(monitor.getIntervals());
appDefine.setCyclic(true);
appDefine.setTimestamp(System.currentTimeMillis());
Map<String, String> metadata = Map.of(CommonConstants.LABEL_INSTANCE_NAME, monitor.getName(),
CommonConstants.LABEL_INSTANCE_HOST, monitor.getHost());
appDefine.setMetadata(metadata);
appDefine.setLabels(monitor.getLabels());
appDefine.setAnnotations(monitor.getAnnotations());
resetMetricsCommonField(monitor, appDefine, sdMonitorParam);
List<Configmap> configmaps = params.stream().map(param -> {
@@ -969,11 +944,6 @@ public class MonitorServiceImpl implements MonitorService {
appDefine.setMonitorId(monitorId);
appDefine.setCyclic(false);
appDefine.setTimestamp(System.currentTimeMillis());
Map<String, String> metadata = Map.of(CommonConstants.LABEL_INSTANCE_NAME, monitor.getName(),
CommonConstants.LABEL_INSTANCE_HOST, monitor.getHost());
appDefine.setMetadata(metadata);
appDefine.setLabels(monitor.getLabels());
appDefine.setAnnotations(monitor.getAnnotations());
final Job sdJob = SdMonitorOperator.constructSdJob(appDefine, sdParam);
List<CollectRep.MetricsData> collectRep;
if (collector != null) {
@@ -1007,11 +977,6 @@ public class MonitorServiceImpl implements MonitorService {
appDefine.setMonitorId(monitorId);
appDefine.setCyclic(false);
appDefine.setTimestamp(System.currentTimeMillis());
Map<String, String> metadata = Map.of(CommonConstants.LABEL_INSTANCE_NAME, monitor.getName(),
CommonConstants.LABEL_INSTANCE_HOST, monitor.getHost());
appDefine.setMetadata(metadata);
appDefine.setLabels(monitor.getLabels());
appDefine.setAnnotations(monitor.getAnnotations());
List<Configmap> configmaps = params.stream().map(param ->
new Configmap(param.getField(), param.getParamValue(), param.getType())).collect(Collectors.toList());
appDefine.setConfigmap(configmaps);
@@ -1039,6 +1004,15 @@ public class MonitorServiceImpl implements MonitorService {
collectRep.forEach(CollectRep.MetricsData::close);
}
private List<Tag> filterTags(List<Tag> tags) {
if (tags == null || tags.isEmpty()) {
return new LinkedList<>();
}
return tags.stream()
.filter(tag -> !(tag.getName().equals(CommonConstants.TAG_MONITOR_ID) || tag.getName().equals(CommonConstants.TAG_MONITOR_NAME)))
.collect(Collectors.toList());
}
@Override
@Transactional(rollbackFor = Exception.class)
public void copyMonitor(Long id) {
@@ -1096,11 +1070,6 @@ public class MonitorServiceImpl implements MonitorService {
appDefine.setDefaultInterval(newMonitor.getIntervals());
appDefine.setCyclic(true);
appDefine.setTimestamp(System.currentTimeMillis());
Map<String, String> metadata = Map.of(CommonConstants.LABEL_INSTANCE_NAME, newMonitor.getName(),
CommonConstants.LABEL_INSTANCE_HOST, newMonitor.getHost());
appDefine.setMetadata(metadata);
appDefine.setLabels(newMonitor.getLabels());
appDefine.setAnnotations(newMonitor.getAnnotations());
List<Configmap> configmaps = sourceParams.stream()
.map(param -> new Configmap(param.getField(), param.getParamValue(), param.getType()))
.collect(Collectors.toList());
@@ -285,8 +285,11 @@ public class PluginServiceImpl implements PluginService {
String jarPath = new File(this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath()).getAbsolutePath();
Path extLibPath = Paths.get(new File(jarPath).getParent(), "plugin-lib");
File extLibDir = extLibPath.toFile();
String fileName = pluginUpload.getJarFile().getOriginalFilename();
validateFileName(fileName);
if (fileName == null) {
throw new CommonException("Failed to upload plugin");
}
fileName = UUID.randomUUID().toString().replace("-", "") + "_" + fileName;
File destFile = new File(extLibDir, fileName);
FileUtils.createParentDirectories(destFile);
@@ -318,20 +321,6 @@ public class PluginServiceImpl implements PluginService {
syncPluginStatus();
}
/**
* validate file name if file name is invalid, throw exception
*
* @param fileName file name
*/
private void validateFileName(String fileName) {
if (fileName == null) {
throw new CommonException("Failed to upload plugin");
}
if (fileName.matches(".*(\\.\\.|[\n\t\r/\\\\]).*")) {
throw new CommonException("Invalid plugin file name: " + fileName);
}
}
@Override
public boolean pluginIsEnable(Class<?> clazz) {
return Boolean.TRUE.equals(PLUGIN_ENABLE_STATUS.get(clazz.getName()));
@@ -380,7 +369,7 @@ public class PluginServiceImpl implements PluginService {
}
private void syncSinglePluginStatus(PluginMetadata plugin) {
if (plugin == null || CollectionUtils.isEmpty(plugin.getItems())) {
if (plugin == null || CollectionUtils.isEmpty(plugin.getItems())){
return;
}
for (PluginItem item : plugin.getItems()) {
@@ -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:
@@ -225,16 +225,7 @@ alerter:
access-key-secret: YOUR_ACCESS_KEY_SECRET
signature: YOUR_SMS_SIGNATURE
template-id: YOUR_TEMPLATE_ID
smslocal:
api-key: YOUR_API_KEY_HERE
aws:
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;
@@ -81,17 +81,6 @@ params:
required: true
defaultValue: true
# field-param field key
- field: useProxy
# name-param field display i18n name
name:
zh-CN: 使用代理
en-US: Use Proxy Connection
# type-param field type(most mapping the html input type)
type: boolean
# required-true or false
required: true
defaultValue: false
# field-param field key
- field: username
# name-param field display i18n name
name:
@@ -138,72 +127,6 @@ params:
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyHost
# name-param field display i18n name
name:
zh-CN: 代理主机
en-US: Proxy Host
# type-param field type(most mapping the html input type)
type: text
# required-true or false
required: false
# hide param-true or false
hide: true
- field: proxyPort
# name-param field display i18n name
name:
zh-CN: 代理端口
en-US: Proxy Port
# type-param field type(most mapping the html input type)
type: number
# when type is number, range is required
range: '[0,65535]'
# required-true or false
required: false
# hide param-true or false
hide: true
# default value
defaultValue: 22
# field-param field key
- field: proxyUsername
# name-param field display i18n name
name:
zh-CN: 代理用户名
en-US: Proxy Username
# type-param field type(most mapping the html input type)
type: text
# when type is text, use limit to limit string length
limit: 50
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyPassword
# name-param field display i18n name
name:
zh-CN: 代理密码
en-US: Proxy Password
# type-param field type(most mapping the html input tag)
type: password
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyPrivateKey
# name-param field display i18n name
name:
zh-CN: 代理主机私钥
en-US: proxyPrivateKey
# type-param field type(most mapping the html input type)
type: textarea
placeholder: -----BEGIN RSA PRIVATE KEY-----
# required-true or false
required: false
# hide param-true or false
hide: true
# collect metrics config list
metrics:
# metrics - basic, inner monitoring metrics (responseTime - response time)
@@ -251,18 +174,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
# ssh run collect script
script: (uname -r ; hostname ; uptime | awk -F "," '{print $1}' | sed "s/ //g") | sed ":a;N;s/\n/^/g;ta" | awk -F '^' 'BEGIN{print "version hostname uptime"} {print $1, $2, $3}'
# ssh response data parse type: oneRow, multiRow
@@ -332,18 +243,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: "LANG=C lscpu | awk -F: '$1==\"Model name\" {print $2}';awk '/processor/{core++} END{print core}' /proc/cpuinfo;uptime | sed 's/,/ /g' | awk '{for(i=NF-2;i<=NF;i++)print $i }' | xargs;vmstat 1 1 | awk 'NR==3{print $11}';vmstat 1 1 | awk 'NR==3{print $12}';vmstat 1 2 | awk 'NR==4{print $15}'"
parseType: oneRow
@@ -412,18 +311,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: free -m | awk 'BEGIN{print "total used free buff_cache available"} NR==2{print $2,$3,$4,$6,$7}'
parseType: multiRow
@@ -469,18 +356,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: vmstat -D | awk 'NR==1{print $1}';vmstat -D | awk 'NR==2{print $1}';vmstat 1 1 | awk 'NR==3{print $10}';vmstat 1 1 | awk 'NR==3{print $9}';vmstat 1 1 | awk 'NR==3{print $16}'
parseType: oneRow
@@ -521,18 +396,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: cat /proc/net/dev | tail -n +3 | awk 'BEGIN{ print "interface_name receive_bytes transmit_bytes"} {print $1,$2,$10}'
parseType: multiRow
@@ -581,18 +444,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: df -mP | tail -n +2 | awk 'BEGIN{ print "filesystem used available usage mounted"} {print $1,$3,$4,$5,$6}'
parseType: multiRow
@@ -635,18 +486,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: ps aux | sort -k3nr | awk 'BEGIN{ print "pid cpu_usage mem_usage command" } {printf "%s %s %s ", $2, $3, $4; for (i=11; i<=NF; i++) { printf "%s", $i; if (i < NF) printf ""; } print ""}' | head -n 11
parseType: multiRow
@@ -689,17 +528,5 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: ps aux | sort -k4nr | awk 'BEGIN{ print "pid cpu_usage mem_usage command" } {printf "%s %s %s ", $2, $3, $4; for (i=11; i<=NF; i++) { printf "%s", $i; if (i < NF) printf ""; } print ""}' | head -n 11
parseType: multiRow
@@ -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^_^
@@ -82,17 +82,6 @@ params:
required: true
defaultValue: true
# field-param field key
- field: useProxy
# name-param field display i18n name
name:
zh-CN: 使用代理
en-US: Use Proxy Connection
# type-param field type(most mapping the html input type)
type: boolean
# required-true or false
required: true
defaultValue: false
# field-param field key
- field: username
# name-param field display i18n name
name:
@@ -139,72 +128,6 @@ params:
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyHost
# name-param field display i18n name
name:
zh-CN: 代理主机
en-US: Proxy Host
# type-param field type(most mapping the html input type)
type: text
# required-true or false
required: false
# hide param-true or false
hide: true
- field: proxyPort
# name-param field display i18n name
name:
zh-CN: 代理端口
en-US: Proxy Port
# type-param field type(most mapping the html input type)
type: number
# when type is number, range is required
range: '[0,65535]'
# required-true or false
required: false
# hide param-true or false
hide: true
# default value
defaultValue: 22
# field-param field key
- field: proxyUsername
# name-param field display i18n name
name:
zh-CN: 代理用户名
en-US: Proxy Username
# type-param field type(most mapping the html input type)
type: text
# when type is text, use limit to limit string length
limit: 50
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyPassword
# name-param field display i18n name
name:
zh-CN: 代理密码
en-US: Proxy Password
# type-param field type(most mapping the html input tag)
type: password
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyPrivateKey
# name-param field display i18n name
name:
zh-CN: 代理主机私钥
en-US: proxyPrivateKey
# type-param field type(most mapping the html input type)
type: textarea
placeholder: -----BEGIN RSA PRIVATE KEY-----
# required-true or false
required: false
# hide param-true or false
hide: true
# collect metrics config list
metrics:
# metrics - basic, inner monitoring metrics (responseTime - response time)
@@ -252,18 +175,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
# ssh run collect script
script: (uname -r ; hostname ; uptime | awk -F "," '{print $1}' | sed "s/ //g") | sed ":a;N;s/\n/^/g;ta" | awk -F '^' 'BEGIN{print "version hostname uptime"} {print $1, $2, $3}'
# ssh response data parse type: oneRow, multiRow
@@ -333,18 +244,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: "LANG=C lscpu | awk -F: '$1==\"Model name\" {print $2}';awk '/processor/{core++} END{print core}' /proc/cpuinfo;uptime | sed 's/,/ /g' | awk '{for(i=NF-2;i<=NF;i++)print $i }' | xargs;vmstat 1 1 | awk 'NR==3{print $11}';vmstat 1 1 | awk 'NR==3{print $12}';vmstat 1 2 | awk 'NR==4{print $15}'"
parseType: oneRow
@@ -413,18 +312,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: free -m | awk 'BEGIN{print "total used free buff_cache available"} NR==2{print $2,$3,$4,$6,$7}'
parseType: multiRow
@@ -470,18 +357,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: vmstat -D | awk 'NR==1{print $1}';vmstat -D | awk 'NR==2{print $1}';vmstat 1 1 | awk 'NR==3{print $10}';vmstat 1 1 | awk 'NR==3{print $9}';vmstat 1 1 | awk 'NR==3{print $16}'
parseType: oneRow
@@ -522,18 +397,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: cat /proc/net/dev | tail -n +3 | awk 'BEGIN{ print "interface_name receive_bytes transmit_bytes"} {gsub(":", "", $1); print $1,$2,$10}'
parseType: multiRow
@@ -582,18 +445,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: df -mP | tail -n +2 | awk 'BEGIN{ print "filesystem used available usage mounted"} {print $1,$3,$4,$5,$6}'
parseType: multiRow
@@ -636,18 +487,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: ps aux | sort -k3nr | awk 'BEGIN{ print "pid cpu_usage mem_usage command" } {printf "%s %s %s ", $2, $3, $4; for (i=11; i<=NF; i++) { printf "%s", $i; if (i < NF) printf ""; } print ""}' | head -n 11
parseType: multiRow
@@ -690,18 +529,5 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: ps aux | sort -k4nr | awk 'BEGIN{ print "pid cpu_usage mem_usage command" } {printf "%s %s %s ", $2, $3, $4; for (i=11; i<=NF; i++) { printf "%s", $i; if (i < NF) printf ""; } print ""}' | head -n 11
parseType: multiRow
@@ -81,17 +81,6 @@ params:
required: true
defaultValue: true
# field-param field key
- field: useProxy
# name-param field display i18n name
name:
zh-CN: 使用代理
en-US: Use Proxy Connection
# type-param field type(most mapping the html input type)
type: boolean
# required-true or false
required: true
defaultValue: false
# field-param field key
- field: username
# name-param field display i18n name
name:
@@ -138,72 +127,6 @@ params:
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyHost
# name-param field display i18n name
name:
zh-CN: 代理主机
en-US: Proxy Host
# type-param field type(most mapping the html input type)
type: text
# required-true or false
required: false
# hide param-true or false
hide: true
- field: proxyPort
# name-param field display i18n name
name:
zh-CN: 代理端口
en-US: Proxy Port
# type-param field type(most mapping the html input type)
type: number
# when type is number, range is required
range: '[0,65535]'
# required-true or false
required: false
# hide param-true or false
hide: true
# default value
defaultValue: 22
# field-param field key
- field: proxyUsername
# name-param field display i18n name
name:
zh-CN: 代理用户名
en-US: Proxy Username
# type-param field type(most mapping the html input type)
type: text
# when type is text, use limit to limit string length
limit: 50
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyPassword
# name-param field display i18n name
name:
zh-CN: 代理密码
en-US: Proxy Password
# type-param field type(most mapping the html input tag)
type: password
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyPrivateKey
# name-param field display i18n name
name:
zh-CN: 代理主机私钥
en-US: proxyPrivateKey
# type-param field type(most mapping the html input type)
type: textarea
placeholder: -----BEGIN RSA PRIVATE KEY-----
# required-true or false
required: false
# hide param-true or false
hide: true
# collect metrics config list
metrics:
# metrics - basic, inner monitoring metrics (responseTime - response time)
@@ -251,18 +174,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
# ssh run collect script
script: (uname -r ; hostname ; uptime | awk -F "," '{print $1}' | sed "s/ //g") | sed ":a;N;s/\n/^/g;ta" | awk -F '^' 'BEGIN{print "version hostname uptime"} {print $1, $2, $3}'
# ssh response data parse type: oneRow, multiRow
@@ -332,18 +243,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: "LANG=C lscpu | awk -F: '$1==\"Model name\" {print $2}';awk '/processor/{core++} END{print core}' /proc/cpuinfo;uptime | sed 's/,/ /g' | awk '{for(i=NF-2;i<=NF;i++)print $i }' | xargs;vmstat 1 1 | awk 'NR==3{print $11}';vmstat 1 1 | awk 'NR==3{print $12}';vmstat 1 2 | awk 'NR==4{print $15}'"
parseType: oneRow
@@ -412,18 +311,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: free -m | awk 'BEGIN{print "total used free buff_cache available"} NR==2{print $2,$3,$4,$6,$7}'
parseType: multiRow
@@ -469,18 +356,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: vmstat -D | awk 'NR==1{print $1}';vmstat -D | awk 'NR==2{print $1}';vmstat 1 1 | awk 'NR==3{print $10}';vmstat 1 1 | awk 'NR==3{print $9}';vmstat 1 1 | awk 'NR==3{print $16}'
parseType: oneRow
@@ -521,18 +396,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: cat /proc/net/dev | tail -n +3 | awk 'BEGIN{ print "interface_name receive_bytes transmit_bytes"} {print $1,$2,$10}'
parseType: multiRow
@@ -581,18 +444,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: df -mP | tail -n +2 | awk 'BEGIN{ print "filesystem used available usage mounted"} {print $1,$3,$4,$5,$6}'
parseType: multiRow
@@ -635,18 +486,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: ps aux | sort -k3nr | awk 'BEGIN{ print "pid cpu_usage mem_usage command" } {printf "%s %s %s ", $2, $3, $4; for (i=11; i<=NF; i++) { printf "%s", $i; if (i < NF) printf ""; } print ""}' | head -n 11
parseType: multiRow
@@ -689,17 +528,5 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: ps aux | sort -k4nr | awk 'BEGIN{ print "pid cpu_usage mem_usage command" } {printf "%s %s %s ", $2, $3, $4; for (i=11; i<=NF; i++) { printf "%s", $i; if (i < NF) printf ""; } print ""}' | head -n 11
parseType: multiRow
@@ -81,17 +81,6 @@ params:
required: true
defaultValue: true
# field-param field key
- field: useProxy
# name-param field display i18n name
name:
zh-CN: 使用代理
en-US: Use Proxy Connection
# type-param field type(most mapping the html input type)
type: boolean
# required-true or false
required: true
defaultValue: false
# field-param field key
- field: username
# name-param field display i18n name
name:
@@ -137,72 +126,6 @@ params:
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyHost
# name-param field display i18n name
name:
zh-CN: 代理主机
en-US: Proxy Host
# type-param field type(most mapping the html input type)
type: text
# required-true or false
required: false
# hide param-true or false
hide: true
- field: proxyPort
# name-param field display i18n name
name:
zh-CN: 代理端口
en-US: Proxy Port
# type-param field type(most mapping the html input type)
type: number
# when type is number, range is required
range: '[0,65535]'
# required-true or false
required: false
# hide param-true or false
hide: true
# default value
defaultValue: 22
# field-param field key
- field: proxyUsername
# name-param field display i18n name
name:
zh-CN: 代理用户名
en-US: Proxy Username
# type-param field type(most mapping the html input type)
type: text
# when type is text, use limit to limit string length
limit: 50
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyPassword
# name-param field display i18n name
name:
zh-CN: 代理密码
en-US: Proxy Password
# type-param field type(most mapping the html input tag)
type: password
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyPrivateKey
# name-param field display i18n name
name:
zh-CN: 代理主机私钥
en-US: proxyPrivateKey
# type-param field type(most mapping the html input type)
type: textarea
placeholder: -----BEGIN RSA PRIVATE KEY-----
# required-true or false
required: false
# hide param-true or false
hide: true
# collect metrics config list
metrics:
# metrics - basic, inner monitoring metrics (responseTime - response time)
@@ -250,18 +173,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
# ssh run collect script
script: (uname -r ; hostname ; uptime | awk -F "," '{print $1}' | sed "s/ //g") | sed ":a;N;s/\n/^/g;ta" | awk -F '^' 'BEGIN{print "version hostname uptime"} {print $1, $2, $3}'
# ssh response data parse type: oneRow, multiRow
@@ -331,18 +242,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: "LANG=C lscpu | awk -F: '$1==\"Model name\" {print $2}';awk '/processor/{core++} END{print core}' /proc/cpuinfo;uptime | sed 's/,/ /g' | awk '{for(i=NF-2;i<=NF;i++)print $i }' | xargs;vmstat 1 1 | awk 'NR==3{print $11}';vmstat 1 1 | awk 'NR==3{print $12}';vmstat 1 2 | awk 'NR==4{print $15}'"
parseType: oneRow
@@ -411,18 +310,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: free -m | awk 'BEGIN{print "total used free buff_cache available"} NR==2{print $2,$3,$4,$6,$7}'
parseType: multiRow
@@ -468,18 +355,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: vmstat -D | awk 'NR==1{print $1}';vmstat -D | awk 'NR==2{print $1}';vmstat 1 1 | awk 'NR==3{print $10}';vmstat 1 1 | awk 'NR==3{print $9}';vmstat 1 1 | awk 'NR==3{print $16}'
parseType: oneRow
@@ -520,18 +395,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: cat /proc/net/dev | tail -n +3 | awk 'BEGIN{ print "interface_name receive_bytes transmit_bytes"} {print $1,$2,$10}'
parseType: multiRow
@@ -580,18 +443,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: df -mP | tail -n +2 | awk 'BEGIN{ print "filesystem used available usage mounted"} {print $1,$3,$4,$5,$6}'
parseType: multiRow
@@ -634,18 +485,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: ps --no-headers -eo pid,%cpu,%mem,cmd --sort=-%cpu | head -n 10 | awk 'BEGIN {print "pid cpu_usage mem_usage command"} {print $1, $2, $3, $4}'
parseType: multiRow
@@ -688,17 +527,5 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: ps --no-headers -eo pid,%cpu,%mem,cmd --sort=-%mem | head -n 10 | awk 'BEGIN {print "pid cpu_usage mem_usage command"} {print $1, $2, $3, $4}'
parseType: multiRow
@@ -81,17 +81,6 @@ params:
required: true
defaultValue: true
# field-param field key
- field: useProxy
# name-param field display i18n name
name:
zh-CN: 使用代理
en-US: Use Proxy Connection
# type-param field type(most mapping the html input type)
type: boolean
# required-true or false
required: true
defaultValue: false
# field-param field key
- field: username
# name-param field display i18n name
name:
@@ -138,72 +127,6 @@ params:
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyHost
# name-param field display i18n name
name:
zh-CN: 代理主机
en-US: Proxy Host
# type-param field type(most mapping the html input type)
type: text
# required-true or false
required: false
# hide param-true or false
hide: true
- field: proxyPort
# name-param field display i18n name
name:
zh-CN: 代理端口
en-US: Proxy Port
# type-param field type(most mapping the html input type)
type: number
# when type is number, range is required
range: '[0,65535]'
# required-true or false
required: false
# hide param-true or false
hide: true
# default value
defaultValue: 22
# field-param field key
- field: proxyUsername
# name-param field display i18n name
name:
zh-CN: 代理用户名
en-US: Proxy Username
# type-param field type(most mapping the html input type)
type: text
# when type is text, use limit to limit string length
limit: 50
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyPassword
# name-param field display i18n name
name:
zh-CN: 代理密码
en-US: Proxy Password
# type-param field type(most mapping the html input tag)
type: password
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyPrivateKey
# name-param field display i18n name
name:
zh-CN: 代理主机私钥
en-US: proxyPrivateKey
# type-param field type(most mapping the html input type)
type: textarea
placeholder: -----BEGIN RSA PRIVATE KEY-----
# required-true or false
required: false
# hide param-true or false
hide: true
# collect metrics config list
metrics:
# metrics - basic, inner monitoring metrics (responseTime - response time)
@@ -251,18 +174,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
# ssh run collect script
script: (uname -r ; hostname ; uptime | awk -F "," '{print $1}' | sed "s/ //g") | sed ":a;N;s/\n/^/g;ta" | awk -F '^' 'BEGIN{print "version hostname uptime"} {print $1, $2, $3}'
# ssh response data parse type: oneRow, multiRow
@@ -332,18 +243,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: "LANG=C lscpu | awk -F: '$1==\"Model name\" {print $2}';awk '/processor/{core++} END{print core}' /proc/cpuinfo;uptime | sed 's/,/ /g' | awk '{for(i=NF-2;i<=NF;i++)print $i }' | xargs;vmstat 1 1 | awk 'NR==3{print $11}';vmstat 1 1 | awk 'NR==3{print $12}';vmstat 1 2 | awk 'NR==4{print $15}'"
parseType: oneRow
@@ -412,18 +311,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: free -m | awk 'BEGIN{print "total used free buff_cache available"} NR==2{print $2,$3,$4,$6,$7}'
parseType: multiRow
@@ -469,18 +356,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: vmstat -D | awk 'NR==1{print $1}';vmstat -D | awk 'NR==2{print $1}';vmstat 1 1 | awk 'NR==3{print $10}';vmstat 1 1 | awk 'NR==3{print $9}';vmstat 1 1 | awk 'NR==3{print $16}'
parseType: oneRow
@@ -521,18 +396,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: cat /proc/net/dev | tail -n +3 | awk 'BEGIN{ print "interface_name receive_bytes transmit_bytes"} {print $1,$2,$10}'
parseType: multiRow
@@ -581,18 +444,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: df -mP | tail -n +2 | awk 'BEGIN{ print "filesystem used available usage mounted"} {print $1,$3,$4,$5,$6}'
parseType: multiRow
@@ -635,18 +486,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: ps aux | sort -k3nr | awk 'BEGIN{ print "pid cpu_usage mem_usage command" } {printf "%s %s %s ", $2, $3, $4; for (i=11; i<=NF; i++) { printf "%s", $i; if (i < NF) printf ""; } print ""}' | head -n 11
parseType: multiRow
@@ -689,17 +528,5 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: ps aux | sort -k4nr | awk 'BEGIN{ print "pid cpu_usage mem_usage command" } {printf "%s %s %s ", $2, $3, $4; for (i=11; i<=NF; i++) { printf "%s", $i; if (i < NF) printf ""; } print ""}' | head -n 11
parseType: multiRow
@@ -81,17 +81,6 @@ params:
required: true
defaultValue: true
# field-param field key
- field: useProxy
# name-param field display i18n name
name:
zh-CN: 使用代理
en-US: Use Proxy Connection
# type-param field type(most mapping the html input type)
type: boolean
# required-true or false
required: true
defaultValue: false
# field-param field key
- field: username
# name-param field display i18n name
name:
@@ -138,72 +127,6 @@ params:
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyHost
# name-param field display i18n name
name:
zh-CN: 代理主机
en-US: Proxy Host
# type-param field type(most mapping the html input type)
type: text
# required-true or false
required: false
# hide param-true or false
hide: true
- field: proxyPort
# name-param field display i18n name
name:
zh-CN: 代理端口
en-US: Proxy Port
# type-param field type(most mapping the html input type)
type: number
# when type is number, range is required
range: '[0,65535]'
# required-true or false
required: false
# hide param-true or false
hide: true
# default value
defaultValue: 22
# field-param field key
- field: proxyUsername
# name-param field display i18n name
name:
zh-CN: 代理用户名
en-US: Proxy Username
# type-param field type(most mapping the html input type)
type: text
# when type is text, use limit to limit string length
limit: 50
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyPassword
# name-param field display i18n name
name:
zh-CN: 代理密码
en-US: Proxy Password
# type-param field type(most mapping the html input tag)
type: password
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyPrivateKey
# name-param field display i18n name
name:
zh-CN: 代理主机私钥
en-US: proxyPrivateKey
# type-param field type(most mapping the html input type)
type: textarea
placeholder: -----BEGIN RSA PRIVATE KEY-----
# required-true or false
required: false
# hide param-true or false
hide: true
# collect metrics config list
metrics:
# metrics - basic, inner monitoring metrics (responseTime - response time)
@@ -251,18 +174,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
# ssh run collect script
script: uname -r ; hostname ; uptime | awk -F "," '{print $1}' | sed "s/ //g"
# ssh response data parse type: oneRow, multiRow
@@ -333,18 +244,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: "dmesg | grep -i cpu | awk 'NR==1';sysctl hw.ncpu | awk '{print $2}';uptime | sed 's/,/ /g' | awk '{for(i=NF-2;i<=NF;i++)print $i }' | xargs;vmstat 1 1 | awk 'NR==3{print $11}';vmstat 1 1 | awk 'NR==3{print $12}';vmstat 1 2 | awk 'NR==4{print $15}'"
parseType: oneRow
@@ -410,18 +309,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: sysctl hw | egrep 'hw.(phys|user|real)' | awk '{print $2}';dmesg | grep memory | grep avail | awk '{print $4}';
parseType: oneRow
@@ -470,18 +357,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: df -m | tail -n +2 | awk 'BEGIN{ print "filesystem used available usage mounted"} {print $1,$3,$4,$5,$6}'
parseType: multiRow
@@ -524,18 +399,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: ps aux | sort -k3nr | awk 'BEGIN{ print "pid cpu_usage mem_usage command" } {printf "%s %s %s ", $2, $3, $4; for (i=11; i<=NF; i++) { printf "%s", $i; if (i < NF) printf ""; } print ""}' | head -n 11
parseType: multiRow
@@ -578,17 +441,5 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: ps aux | sort -k4nr | awk 'BEGIN{ print "pid cpu_usage mem_usage command" } {printf "%s %s %s ", $2, $3, $4; for (i=11; i<=NF; i++) { printf "%s", $i; if (i < NF) printf ""; } print ""}' | head -n 11
parseType: multiRow
@@ -81,17 +81,6 @@ params:
required: true
defaultValue: true
# field-param field key
- field: useProxy
# name-param field display i18n name
name:
zh-CN: 使用代理
en-US: Use Proxy Connection
# type-param field type(most mapping the html input type)
type: boolean
# required-true or false
required: true
defaultValue: false
# field-param field key
- field: username
# name-param field display i18n name
name:
@@ -137,72 +126,6 @@ params:
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyHost
# name-param field display i18n name
name:
zh-CN: 代理主机
en-US: Proxy Host
# type-param field type(most mapping the html input type)
type: text
# required-true or false
required: false
# hide param-true or false
hide: true
- field: proxyPort
# name-param field display i18n name
name:
zh-CN: 代理端口
en-US: Proxy Port
# type-param field type(most mapping the html input type)
type: number
# when type is number, range is required
range: '[0,65535]'
# required-true or false
required: false
# hide param-true or false
hide: true
# default value
defaultValue: 22
# field-param field key
- field: proxyUsername
# name-param field display i18n name
name:
zh-CN: 代理用户名
en-US: Proxy Username
# type-param field type(most mapping the html input type)
type: text
# when type is text, use limit to limit string length
limit: 50
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyPassword
# name-param field display i18n name
name:
zh-CN: 代理密码
en-US: Proxy Password
# type-param field type(most mapping the html input tag)
type: password
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyPrivateKey
# name-param field display i18n name
name:
zh-CN: 代理主机私钥
en-US: proxyPrivateKey
# type-param field type(most mapping the html input type)
type: textarea
placeholder: -----BEGIN RSA PRIVATE KEY-----
# required-true or false
required: false
# hide param-true or false
hide: true
# collect metrics config list
metrics:
# metrics - basic, inner monitoring metrics (responseTime - response time)
@@ -250,18 +173,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
# ssh run collect script
script: (uname -r ; hostname ; uptime | awk -F "," '{print $1}' | sed "s/ //g") | sed ":a;N;s/\n/^/g;ta" | awk -F '^' 'BEGIN{print "version hostname uptime"} {print $1, $2, $3}'
# ssh response data parse type: oneRow, multiRow
@@ -331,18 +242,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: "LANG=C lscpu | awk -F: '$1==\"Model name\" {print $2}';awk '/processor/{core++} END{print core}' /proc/cpuinfo;uptime | sed 's/,/ /g' | awk '{for(i=NF-2;i<=NF;i++)print $i }' | xargs;vmstat 1 1 | awk 'NR==3{print $11}';vmstat 1 1 | awk 'NR==3{print $12}';vmstat 1 2 | awk 'NR==4{print $15}'"
parseType: oneRow
@@ -411,18 +310,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: free -m | awk 'BEGIN{print "total used free buff_cache available"} NR==2{print $2,$3,$4,$6,$7}'
parseType: multiRow
@@ -468,18 +355,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: vmstat -D | awk 'NR==1{print $1}';vmstat -D | awk 'NR==2{print $1}';vmstat 1 1 | awk 'NR==3{print $10}';vmstat 1 1 | awk 'NR==3{print $9}';vmstat 1 1 | awk 'NR==3{print $16}'
parseType: oneRow
@@ -520,18 +395,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: cat /proc/net/dev | tail -n +3 | awk 'BEGIN{ print "interface_name receive_bytes transmit_bytes"} {print $1,$2,$10}'
parseType: multiRow
@@ -580,18 +443,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: df -mP | tail -n +2 | awk 'BEGIN{ print "filesystem used available usage mounted"} {print $1,$3,$4,$5,$6}'
parseType: multiRow
@@ -634,18 +485,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: ps aux | sort -k3nr | awk 'BEGIN{ print "pid cpu_usage mem_usage command" } {printf "%s %s %s ", $2, $3, $4; for (i=11; i<=NF; i++) { printf "%s", $i; if (i < NF) printf ""; } print ""}' | head -n 11
parseType: multiRow
@@ -688,17 +527,5 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: ps aux | sort -k4nr | awk 'BEGIN{ print "pid cpu_usage mem_usage command" } {printf "%s %s %s ", $2, $3, $4; for (i=11; i<=NF; i++) { printf "%s", $i; if (i < NF) printf ""; } print ""}' | head -n 11
parseType: multiRow
@@ -82,17 +82,6 @@ params:
required: true
defaultValue: true
# field-param field key
- field: useProxy
# name-param field display i18n name
name:
zh-CN: 使用代理
en-US: Use Proxy Connection
# type-param field type(most mapping the html input type)
type: boolean
# required-true or false
required: true
defaultValue: false
# field-param field key
- field: username
# name-param field display i18n name
name:
@@ -127,139 +116,6 @@ params:
required: false
# hide param-true or false
hide: true
# collect metrics config list
# field-param field key
- field: proxyHost
# name-param field display i18n name
name:
zh-CN: 代理主机
en-US: Proxy Host
# type-param field type(most mapping the html input type)
type: text
# required-true or false
required: false
# hide param-true or false
hide: true
- field: proxyPort
# name-param field display i18n name
name:
zh-CN: 代理端口
en-US: Proxy Port
# type-param field type(most mapping the html input type)
type: number
# when type is number, range is required
range: '[0,65535]'
# required-true or false
required: false
# hide param-true or false
hide: true
# default value
defaultValue: 22
# field-param field key
- field: proxyUsername
# name-param field display i18n name
name:
zh-CN: 代理用户名
en-US: Proxy Username
# type-param field type(most mapping the html input type)
type: text
# when type is text, use limit to limit string length
limit: 50
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyPassword
# name-param field display i18n name
name:
zh-CN: 代理密码
en-US: Proxy Password
# type-param field type(most mapping the html input tag)
type: password
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyPrivateKey
# name-param field display i18n name
name:
zh-CN: 代理主机私钥
en-US: proxyPrivateKey
# type-param field type(most mapping the html input type)
type: textarea
placeholder: -----BEGIN RSA PRIVATE KEY-----
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyHost
# name-param field display i18n name
name:
zh-CN: 代理主机
en-US: Proxy Host
# type-param field type(most mapping the html input type)
type: text
# required-true or false
required: false
# hide param-true or false
hide: true
- field: proxyPort
# name-param field display i18n name
name:
zh-CN: 代理端口
en-US: Proxy Port
# type-param field type(most mapping the html input type)
type: number
# when type is number, range is required
range: '[0,65535]'
# required-true or false
required: false
# hide param-true or false
hide: true
# default value
defaultValue: 22
# field-param field key
- field: proxyUsername
# name-param field display i18n name
name:
zh-CN: 代理用户名
en-US: Proxy Username
# type-param field type(most mapping the html input type)
type: text
# when type is text, use limit to limit string length
limit: 50
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyPassword
# name-param field display i18n name
name:
zh-CN: 代理密码
en-US: Proxy Password
# type-param field type(most mapping the html input tag)
type: password
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyPrivateKey
# name-param field display i18n name
name:
zh-CN: 代理主机私钥
en-US: proxyPrivateKey
# type-param field type(most mapping the html input type)
type: textarea
placeholder: -----BEGIN RSA PRIVATE KEY-----
# required-true or false
required: false
# hide param-true or false
hide: true
# collect metrics config list
metrics:
# metrics - basic, inner monitoring metrics (responseTime - response time)
@@ -336,18 +192,6 @@ metrics:
privateKey: ^_^privateKey^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
# ssh run collect script
script: nvidia-smi --query-gpu=index,name,utilization.gpu,utilization.memory,memory.total,memory.used,memory.free,temperature.gpu --format=csv,nounits | sed 's/ *, */,/g' | sed 's/ //g' | sed 's/,/ /g'
# ssh response data parse type: oneRow, multiRow
@@ -81,17 +81,6 @@ params:
required: true
defaultValue: true
# field-param field key
- field: useProxy
# name-param field display i18n name
name:
zh-CN: 使用代理
en-US: Use Proxy Connection
# type-param field type(most mapping the html input type)
type: boolean
# required-true or false
required: true
defaultValue: false
# field-param field key
- field: username
# name-param field display i18n name
name:
@@ -137,72 +126,6 @@ params:
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyHost
# name-param field display i18n name
name:
zh-CN: 代理主机
en-US: Proxy Host
# type-param field type(most mapping the html input type)
type: text
# required-true or false
required: false
# hide param-true or false
hide: true
- field: proxyPort
# name-param field display i18n name
name:
zh-CN: 代理端口
en-US: Proxy Port
# type-param field type(most mapping the html input type)
type: number
# when type is number, range is required
range: '[0,65535]'
# required-true or false
required: false
# hide param-true or false
hide: true
# default value
defaultValue: 22
# field-param field key
- field: proxyUsername
# name-param field display i18n name
name:
zh-CN: 代理用户名
en-US: Proxy Username
# type-param field type(most mapping the html input type)
type: text
# when type is text, use limit to limit string length
limit: 50
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyPassword
# name-param field display i18n name
name:
zh-CN: 代理密码
en-US: Proxy Password
# type-param field type(most mapping the html input tag)
type: password
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyPrivateKey
# name-param field display i18n name
name:
zh-CN: 代理主机私钥
en-US: proxyPrivateKey
# type-param field type(most mapping the html input type)
type: textarea
placeholder: -----BEGIN RSA PRIVATE KEY-----
# required-true or false
required: false
# hide param-true or false
hide: true
# collect metrics config list
metrics:
# metrics - basic, inner monitoring metrics (responseTime - response time)
@@ -250,18 +173,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
# ssh run collect script
script: (uname -r ; hostname ; uptime | awk -F "," '{print $1}' | sed "s/ //g") | sed ":a;N;s/\n/^/g;ta" | awk -F '^' 'BEGIN{print "version hostname uptime"} {print $1, $2, $3}'
# ssh response data parse type: oneRow, multiRow
@@ -331,18 +242,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: "LANG=C lscpu | awk -F: '$1==\"Model name\" {print $2}';awk '/processor/{core++} END{print core}' /proc/cpuinfo;uptime | sed 's/,/ /g' | awk '{for(i=NF-2;i<=NF;i++)print $i }' | xargs;vmstat 1 1 | awk 'NR==3{print $11}';vmstat 1 1 | awk 'NR==3{print $12}';vmstat 1 2 | awk 'NR==4{print $15}'"
parseType: oneRow
@@ -411,18 +310,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: free -m | awk 'BEGIN{print "total used free buff_cache available"} NR==2{print $2,$3,$4,$6,$7}'
parseType: multiRow
@@ -468,18 +355,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: vmstat -D | awk 'NR==1{print $1}';vmstat -D | awk 'NR==2{print $1}';vmstat 1 1 | awk 'NR==3{print $10}';vmstat 1 1 | awk 'NR==3{print $9}';vmstat 1 1 | awk 'NR==3{print $16}'
parseType: oneRow
@@ -520,18 +395,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: cat /proc/net/dev | tail -n +3 | awk 'BEGIN{ print "interface_name receive_bytes transmit_bytes"} {print $1,$2,$10}'
parseType: multiRow
@@ -580,18 +443,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: df -m | tail -n +2 | awk 'BEGIN{ print "filesystem used available usage mounted"} {print $1,$3,$4,$5,$6}'
parseType: multiRow
@@ -634,18 +485,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: ps aux | sort -k3nr | awk 'BEGIN{ print "pid cpu_usage mem_usage command" } {printf "%s %s %s ", $2, $3, $4; for (i=11; i<=NF; i++) { printf "%s", $i; if (i < NF) printf ""; } print ""}' | head -n 11
parseType: multiRow
@@ -688,17 +527,5 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: ps aux | sort -k4nr | awk 'BEGIN{ print "pid cpu_usage mem_usage command" } {printf "%s %s %s ", $2, $3, $4; for (i=11; i<=NF; i++) { printf "%s", $i; if (i < NF) printf ""; } print ""}' | head -n 11
parseType: multiRow
@@ -64,13 +64,6 @@ params:
required: false
hide: true
defaultValue: 6000
- field: reuseConnection
name:
zh-CN: 复用连接
en-US: Reuse Connection
type: boolean
required: false
defaultValue: true
- field: database
name:
zh-CN: 服务名
@@ -165,7 +158,6 @@ metrics:
password: ^_^password^_^
database: ^_^database^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# SQL Query MethodoneRow, multiRow, columns
queryType: oneRow
# sql
@@ -221,8 +213,8 @@ metrics:
password: ^_^password^_^
database: ^_^database^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
queryType: multiRow
sql: select file_id, file_name, tablespace_name, status, bytes / 1024 / 1024 as bytes, blocks from dba_data_files
url: ^_^url^_^
@@ -246,7 +238,6 @@ metrics:
password: ^_^password^_^
database: ^_^database^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
queryType: oneRow
sql: select count(*) as count from v$session
url: ^_^url^_^
@@ -271,7 +262,6 @@ metrics:
password: ^_^password^_^
database: ^_^database^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
queryType: oneRow
sql: select count(*) as count from v$session where username is not null and status = 'ACTIVE'
url: ^_^url^_^
@@ -296,7 +286,6 @@ metrics:
password: ^_^password^_^
database: ^_^database^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
queryType: oneRow
sql: select count(*) as count from v$session where username is null
url: ^_^url^_^
@@ -327,7 +316,6 @@ metrics:
password: ^_^password^_^
database: ^_^database^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
queryType: oneRow
sql: SELECT username, count( username ) as count FROM v$session WHERE username IS NOT NULL GROUP BY username
url: ^_^url^_^
@@ -373,7 +361,6 @@ metrics:
password: ^_^password^_^
database: ^_^database^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
queryType: columns
sql: select metric_name, value from gv$sysmetric where metric_name = 'I/O Megabytes per Second' or metric_name = 'User Transaction Per Sec' or metric_name = 'I/O Requests per Second'
url: ^_^url^_^
@@ -427,7 +414,6 @@ metrics:
password: ^_^password^_^
database: ^_^database^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
queryType: multiRow
# DBA_TABLESPACE_USAGE_METRICS可以查出表空间used_max值,它的大小计算单位是block1kb=8block,把block*8/1024转化为MB单位
sql: "SELECT tablespace_name,ROUND ( (TABLESPACE_SIZE * 8 / 1024), 0) AS total,ROUND ( (USED_SPACE * 8 / 1024), 0) AS used,ROUND ( ( (TABLESPACE_SIZE * 8 / 1024) - (USED_SPACE * 8 / 1024)), 0) AS free,ROUND ( (USED_PERCENT), 0) AS used_percentage,100 - ROUND ( (USED_PERCENT), 0) AS free_percentage FROM sys.dba_tablespace_usage_metrics ORDER BY used_percent DESC"
@@ -453,7 +439,6 @@ metrics:
password: ^_^password^_^
database: ^_^database^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
queryType: oneRow
sql: select count(*) as process_count from v$process
url: ^_^url^_^
@@ -491,7 +476,6 @@ metrics:
password: ^_^password^_^
database: ^_^database^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
queryType: columns
sql: select metric_name, value from gv$sysmetric where metric_name = 'User Commits Per Sec' or metric_name = 'User Rollbacks Per Sec'
url: ^_^url^_^
@@ -577,7 +561,6 @@ metrics:
password: ^_^password^_^
database: ^_^database^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
queryType: columns
sql: select wait_class, sum(time_waited) total_wait_time from v$active_session_history where session_state = 'WAITING' GROUP BY wait_class ORDER BY total_wait_time DESC
url: ^_^url^_^
@@ -608,7 +591,6 @@ metrics:
password: ^_^password^_^
database: ^_^database^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
queryType: multiRow
sql: select stat_name as type, value as num from v$osstat where stat_name like '%CPU%' or stat_name like '%TIME'
url: ^_^url^_^
@@ -639,7 +621,6 @@ metrics:
password: ^_^password^_^
database: ^_^database^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
queryType: multiRow
sql: select stat_name as type, value as num from v$osstat where stat_name like '%BYTES'
url: ^_^url^_^
@@ -675,7 +656,6 @@ metrics:
password: ^_^password^_^
database: ^_^database^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
queryType: columns
sql: select metric_name, value from gv$sysmetric where metric_name like '%Cache Hit Ratio' order by end_time asc
url: ^_^url^_^
@@ -753,7 +733,6 @@ metrics:
password: ^_^password^_^
database: ^_^database^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
queryType: multiRow
sql: SELECT * FROM (SELECT sql_id, child_number, executions, ROUND(CASE WHEN executions = 0 THEN NULL ELSE elapsed_time / (executions*1000000) END,4) AS per_secs, cpu_time / 1000000 AS cpu_secs, buffer_gets, disk_reads, fetches, parse_calls, optimizer_cost, sql_text FROM v$sql ) where rownum <= 10 ORDER BY per_secs DESC
url: ^_^url^_^
@@ -82,17 +82,6 @@ params:
required: true
defaultValue: true
# field-param field key
- field: useProxy
# name-param field display i18n name
name:
zh-CN: 使用代理
en-US: Use Proxy Connection
# type-param field type(most mapping the html input type)
type: boolean
# required-true or false
required: true
defaultValue: false
# field-param field key
- field: username
# name-param field display i18n name
name:
@@ -138,72 +127,6 @@ params:
limit: 100
# required-true or false
required: true
# field-param field key
- field: proxyHost
# name-param field display i18n name
name:
zh-CN: 代理主机
en-US: Proxy Host
# type-param field type(most mapping the html input type)
type: text
# required-true or false
required: false
# hide param-true or false
hide: true
- field: proxyPort
# name-param field display i18n name
name:
zh-CN: 代理端口
en-US: Proxy Port
# type-param field type(most mapping the html input type)
type: number
# when type is number, range is required
range: '[0,65535]'
# required-true or false
required: false
# hide param-true or false
hide: true
# default value
defaultValue: 22
# field-param field key
- field: proxyUsername
# name-param field display i18n name
name:
zh-CN: 代理用户名
en-US: Proxy Username
# type-param field type(most mapping the html input type)
type: text
# when type is text, use limit to limit string length
limit: 50
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyPassword
# name-param field display i18n name
name:
zh-CN: 代理密码
en-US: Proxy Password
# type-param field type(most mapping the html input tag)
type: password
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyPrivateKey
# name-param field display i18n name
name:
zh-CN: 代理主机私钥
en-US: proxyPrivateKey
# type-param field type(most mapping the html input type)
type: textarea
placeholder: -----BEGIN RSA PRIVATE KEY-----
# required-true or false
required: false
# hide param-true or false
hide: true
# collect metrics config list
metrics:
# metrics - basic, inner monitoring metrics (responseTime - response time)
@@ -269,18 +192,6 @@ metrics:
privateKey: ^_^privateKey^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
# ssh run collect script
# ssh response data parse type: oneRow, multiRow
script: output=$(ps -ef|grep '^_^process_name^_^'|grep -v grep); [ -n "$output" ] && ps -eo pid,user,%cpu,%mem,rss,cmd | grep -v grep | grep '^_^process_name^_^' | awk 'BEGIN {print "pid user cpu mem rss cmd"} {cmd=substr($0, index($0, $6)); gsub(/ /, "", cmd); print $1, $2, $3, $4, $5, cmd}'
@@ -406,18 +317,6 @@ metrics:
privateKey: ^_^privateKey^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
# ssh run collect script
# ssh response data parse type: oneRow, multiRow
script: echo -e "pid VmPeak VmSize VmLck VmPin VmHWM VmRSS VmData VmStk VmExe VmLib VmPTE VmSwap";ps -eo pid,cmd | grep -v grep | grep '^_^process_name^_^' | awk '{ cmd=substr($0, index($0, $3)); sub(/ /, "", cmd); print $1, cmd }' | while read pid _; do echo -n "$pid ";cat /proc/$pid/status | grep Vm | awk -F ':\t' '{gsub(/^ +| +$/, "", $2); print $2}' | paste -d' ' -s - | sed 's/[[:space:]]*[kKMmGg]*B//g';done
@@ -470,18 +369,6 @@ metrics:
privateKey: ^_^privateKey^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
# ssh run collect script
# ssh response data parse type: oneRow, multiRow
script: echo "pid path date fd_count" ; ps -eo pid,cmd | grep -v grep | grep '^_^process_name^_^' | awk '{cmd=substr($0, index($0, $3)); gsub(/ /, "", cmd); print $1, cmd}' | while read pid _; do cwd=$(readlink -f "/proc/$pid/cwd"); start_time=$(ps -p $pid -o lstart | tail -n 1 | sed 's/ //g'); fd_count=$(ls -l /proc/$pid/fd/ 2>/dev/null | wc -l); echo "$pid $cwd $start_time $fd_count"; done
@@ -554,18 +441,6 @@ metrics:
privateKey: ^_^privateKey^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
# ssh run collect script
# ssh response data parse type: oneRow, multiRow
script: echo -e "pid rchar wchar syscr syscw read_bytes write_bytes cancelled_write_bytes";ps -eo pid,cmd | grep -v grep | grep '^_^process_name^_^' | awk '{ cmd=substr($0, index($0, $3)); gsub(/ /, "", cmd); print $1, cmd }' | while read pid _; do echo -n "$pid ";cat /proc/$pid/io | awk -F ':' '{gsub(/^ +| +$/, "", $2); print $2}' | paste -d' ' -s -;done
@@ -81,17 +81,6 @@ params:
required: true
defaultValue: true
# field-param field key
- field: useProxy
# name-param field display i18n name
name:
zh-CN: 使用代理
en-US: Use Proxy Connection
# type-param field type(most mapping the html input type)
type: boolean
# required-true or false
required: true
defaultValue: false
# field-param field key
- field: username
# name-param field display i18n name
name:
@@ -138,72 +127,6 @@ params:
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyHost
# name-param field display i18n name
name:
zh-CN: 代理主机
en-US: Proxy Host
# type-param field type(most mapping the html input type)
type: text
# required-true or false
required: false
# hide param-true or false
hide: true
- field: proxyPort
# name-param field display i18n name
name:
zh-CN: 代理端口
en-US: Proxy Port
# type-param field type(most mapping the html input type)
type: number
# when type is number, range is required
range: '[0,65535]'
# required-true or false
required: false
# hide param-true or false
hide: true
# default value
defaultValue: 22
# field-param field key
- field: proxyUsername
# name-param field display i18n name
name:
zh-CN: 代理用户名
en-US: Proxy Username
# type-param field type(most mapping the html input type)
type: text
# when type is text, use limit to limit string length
limit: 50
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyPassword
# name-param field display i18n name
name:
zh-CN: 代理密码
en-US: Proxy Password
# type-param field type(most mapping the html input tag)
type: password
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyPrivateKey
# name-param field display i18n name
name:
zh-CN: 代理主机私钥
en-US: proxyPrivateKey
# type-param field type(most mapping the html input type)
type: textarea
placeholder: -----BEGIN RSA PRIVATE KEY-----
# required-true or false
required: false
# hide param-true or false
hide: true
# collect metrics config list
metrics:
# metrics - basic, inner monitoring metrics (responseTime - response time)
@@ -251,18 +174,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
# ssh run collect script
script: (uname -r ; hostname ; uptime | awk -F "," '{print $1}' | sed "s/ //g") | sed ":a;N;s/\n/^/g;ta" | awk -F '^' 'BEGIN{print "version hostname uptime"} {print $1, $2, $3}'
# ssh response data parse type: oneRow, multiRow
@@ -332,18 +243,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: "LANG=C lscpu | awk -F: '$1==\"Model name\" {print $2}';awk '/processor/{core++} END{print core}' /proc/cpuinfo;uptime | sed 's/,/ /g' | awk '{for(i=NF-2;i<=NF;i++)print $i }' | xargs;vmstat 1 1 | awk 'NR==3{print $11}';vmstat 1 1 | awk 'NR==3{print $12}';vmstat 1 2 | awk 'NR==4{print $15}'"
parseType: oneRow
@@ -412,18 +311,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: free -m | awk 'BEGIN{print "total used free buff_cache available"} NR==2{print $2,$3,$4,$6,$7}'
parseType: multiRow
@@ -469,18 +356,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: vmstat -D | awk 'NR==1{print $1}';vmstat -D | awk 'NR==2{print $1}';vmstat 1 1 | awk 'NR==3{print $10}';vmstat 1 1 | awk 'NR==3{print $9}';vmstat 1 1 | awk 'NR==3{print $16}'
parseType: oneRow
@@ -521,18 +396,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: cat /proc/net/dev | tail -n +3 | awk 'BEGIN{ print "interface_name receive_bytes transmit_bytes"} {print $1,$2,$10}'
parseType: multiRow
@@ -581,18 +444,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: df -mP | tail -n +2 | awk 'BEGIN{ print "filesystem used available usage mounted"} {print $1,$3,$4,$5,$6}'
parseType: multiRow
@@ -635,18 +486,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: ps aux | sort -k3nr | awk 'BEGIN{ print "pid cpu_usage mem_usage command" } {printf "%s %s %s ", $2, $3, $4; for (i=11; i<=NF; i++) { printf "%s", $i; if (i < NF) printf ""; } print ""}' | head -n 11
parseType: multiRow
@@ -689,17 +528,5 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: ps aux | sort -k4nr | awk 'BEGIN{ print "pid cpu_usage mem_usage command" } {printf "%s %s %s ", $2, $3, $4; for (i=11; i<=NF; i++) { printf "%s", $i; if (i < NF) printf ""; } print ""}' | head -n 11
parseType: multiRow
@@ -81,17 +81,6 @@ params:
required: true
defaultValue: true
# field-param field key
- field: useProxy
# name-param field display i18n name
name:
zh-CN: 使用代理
en-US: Use Proxy Connection
# type-param field type(most mapping the html input type)
type: boolean
# required-true or false
required: true
defaultValue: false
# field-param field key
- field: username
# name-param field display i18n name
name:
@@ -138,72 +127,6 @@ params:
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyHost
# name-param field display i18n name
name:
zh-CN: 代理主机
en-US: Proxy Host
# type-param field type(most mapping the html input type)
type: text
# required-true or false
required: false
# hide param-true or false
hide: true
- field: proxyPort
# name-param field display i18n name
name:
zh-CN: 代理端口
en-US: Proxy Port
# type-param field type(most mapping the html input type)
type: number
# when type is number, range is required
range: '[0,65535]'
# required-true or false
required: false
# hide param-true or false
hide: true
# default value
defaultValue: 22
# field-param field key
- field: proxyUsername
# name-param field display i18n name
name:
zh-CN: 代理用户名
en-US: Proxy Username
# type-param field type(most mapping the html input type)
type: text
# when type is text, use limit to limit string length
limit: 50
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyPassword
# name-param field display i18n name
name:
zh-CN: 代理密码
en-US: Proxy Password
# type-param field type(most mapping the html input tag)
type: password
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyPrivateKey
# name-param field display i18n name
name:
zh-CN: 代理主机私钥
en-US: proxyPrivateKey
# type-param field type(most mapping the html input type)
type: textarea
placeholder: -----BEGIN RSA PRIVATE KEY-----
# required-true or false
required: false
# hide param-true or false
hide: true
# collect metrics config list
metrics:
# metrics - basic, inner monitoring metrics (responseTime - response time)
@@ -251,18 +174,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
# ssh run collect script
script: (uname -r ; hostname ; uptime | awk -F "," '{print $1}' | sed "s/ //g") | sed ":a;N;s/\n/^/g;ta" | awk -F '^' 'BEGIN{print "version hostname uptime"} {print $1, $2, $3}'
# ssh response data parse type: oneRow, multiRow
@@ -332,18 +243,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: "LANG=C lscpu | awk -F: '/Model name/ {print $2}' | awk 'NR==1';awk '/processor/{core++} END{print core}' /proc/cpuinfo;uptime | sed 's/,/ /g' | awk '{for(i=NF-2;i<=NF;i++)print $i }' | xargs;vmstat 1 1 | awk 'NR==3{print $11}';vmstat 1 1 | awk 'NR==3{print $12}';vmstat 1 2 | awk 'NR==4{print $15}'"
parseType: oneRow
@@ -412,18 +311,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: free -m | awk 'BEGIN{print "total used free buff_cache available"} NR==2{print $2,$3,$4,$6,$7}'
parseType: multiRow
@@ -469,18 +356,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: vmstat -D | awk 'NR==1{print $1}';vmstat -D | awk 'NR==2{print $1}';vmstat 1 1 | awk 'NR==3{print $10}';vmstat 1 1 | awk 'NR==3{print $9}';vmstat 1 1 | awk 'NR==3{print $16}'
parseType: oneRow
@@ -521,18 +396,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: cat /proc/net/dev | tail -n +3 | awk 'BEGIN{ print "interface_name receive_bytes transmit_bytes"} {print $1,$2,$10}'
parseType: multiRow
@@ -581,18 +444,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: df -m | tail -n +2 | awk 'BEGIN{ print "filesystem used available usage mounted"} {print $1,$3,$4,$5,$6}'
parseType: multiRow
@@ -635,18 +486,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: ps aux | sort -k3nr | awk 'BEGIN{ print "pid cpu_usage mem_usage command" } {printf "%s %s %s ", $2, $3, $4; for (i=11; i<=NF; i++) { printf "%s", $i; if (i < NF) printf ""; } print ""}' | head -n 11
parseType: multiRow
@@ -689,17 +528,5 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: ps aux | sort -k4nr | awk 'BEGIN{ print "pid cpu_usage mem_usage command" } {printf "%s %s %s ", $2, $3, $4; for (i=11; i<=NF; i++) { printf "%s", $i; if (i < NF) printf ""; } print ""}' | head -n 11
parseType: multiRow
@@ -81,17 +81,6 @@ params:
required: true
defaultValue: true
# field-param field key
- field: useProxy
# name-param field display i18n name
name:
zh-CN: 使用代理
en-US: Use Proxy Connection
# type-param field type(most mapping the html input type)
type: boolean
# required-true or false
required: true
defaultValue: false
# field-param field key
- field: username
# name-param field display i18n name
name:
@@ -138,72 +127,6 @@ params:
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyHost
# name-param field display i18n name
name:
zh-CN: 代理主机
en-US: Proxy Host
# type-param field type(most mapping the html input type)
type: text
# required-true or false
required: false
# hide param-true or false
hide: true
- field: proxyPort
# name-param field display i18n name
name:
zh-CN: 代理端口
en-US: Proxy Port
# type-param field type(most mapping the html input type)
type: number
# when type is number, range is required
range: '[0,65535]'
# required-true or false
required: false
# hide param-true or false
hide: true
# default value
defaultValue: 22
# field-param field key
- field: proxyUsername
# name-param field display i18n name
name:
zh-CN: 代理用户名
en-US: Proxy Username
# type-param field type(most mapping the html input type)
type: text
# when type is text, use limit to limit string length
limit: 50
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyPassword
# name-param field display i18n name
name:
zh-CN: 代理密码
en-US: Proxy Password
# type-param field type(most mapping the html input tag)
type: password
# required-true or false
required: false
# hide param-true or false
hide: true
# field-param field key
- field: proxyPrivateKey
# name-param field display i18n name
name:
zh-CN: 代理主机私钥
en-US: proxyPrivateKey
# type-param field type(most mapping the html input type)
type: textarea
placeholder: -----BEGIN RSA PRIVATE KEY-----
# required-true or false
required: false
# hide param-true or false
hide: true
# collect metrics config list
metrics:
# metrics - basic, inner monitoring metrics (responseTime - response time)
@@ -251,18 +174,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
# ssh run collect script
script: (uname -r ; hostname ; uptime | awk -F "," '{print $1}' | sed "s/ //g") | sed ":a;N;s/\n/^/g;ta" | awk -F '^' 'BEGIN{print "version hostname uptime"} {print $1, $2, $3}'
# ssh response data parse type: oneRow, multiRow
@@ -332,18 +243,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: "LANG=C lscpu | awk -F: '$1==\"Model name\" {print $2}';awk '/processor/{core++} END{print core}' /proc/cpuinfo;uptime | sed 's/,/ /g' | awk '{for(i=NF-2;i<=NF;i++)print $i }' | xargs;vmstat 1 1 | awk 'NR==3{print $11}';vmstat 1 1 | awk 'NR==3{print $12}';vmstat 1 2 | awk 'NR==4{print $15}'"
parseType: oneRow
@@ -412,18 +311,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: free -m | awk 'BEGIN{print "total used free buff_cache available"} NR==2{print $2,$3,$4,$6,$7}'
parseType: multiRow
@@ -469,18 +356,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: vmstat -D | awk 'NR==1{print $1}';vmstat -D | awk 'NR==2{print $1}';vmstat 1 1 | awk 'NR==3{print $10}';vmstat 1 1 | awk 'NR==3{print $9}';vmstat 1 1 | awk 'NR==3{print $16}'
parseType: oneRow
@@ -521,18 +396,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: cat /proc/net/dev | tail -n +3 | awk 'BEGIN{ print "interface_name receive_bytes transmit_bytes"} {print $1,$2,$10}'
parseType: multiRow
@@ -581,18 +444,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: df -mP | tail -n +2 | awk 'BEGIN{ print "filesystem used available usage mounted"} {print $1,$3,$4,$5,$6}'
parseType: multiRow
@@ -635,18 +486,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: ps aux | sort -k3nr | awk 'BEGIN{ print "pid cpu_usage mem_usage command" } {printf "%s %s %s ", $2, $3, $4; for (i=11; i<=NF; i++) { printf "%s", $i; if (i < NF) printf ""; } print ""}' | head -n 11
parseType: multiRow
@@ -689,18 +528,6 @@ metrics:
privateKeyPassphrase: ^_^privateKeyPassphrase^_^
timeout: ^_^timeout^_^
reuseConnection: ^_^reuseConnection^_^
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
script: ps aux | sort -k4nr | awk 'BEGIN{ print "pid cpu_usage mem_usage command" } {printf "%s %s %s ", $2, $3, $4; for (i=11; i<=NF; i++) { printf "%s", $i; if (i < NF) printf ""; } print ""}' | head -n 11
parseType: multiRow
@@ -729,15 +556,3 @@ metrics:
reuseConnection: ^_^reuseConnection^_^
script: sensors | grep "^Core\s[0-9\d+\:]" | awk '{print $3}' | sed "s/°C/\ /g" | awk '{ total += $1; count++ } END { print total/count }'
parseType: oneRow
# whether to use proxy server for ssh connection
useProxy: ^_^useProxy^_^
# ssh proxy host: ipv4 domain
proxyHost: ^_^proxyHost^_^
# ssh proxy port
proxyPort: ^_^proxyPort^_^
# ssh proxy username
proxyUsername: ^_^proxyUsername^_^
# ssh proxy password
proxyPassword: ^_^proxyPassword^_^
# ssh proxy private key
proxyPrivateKey: ^_^proxyPrivateKey^_^
@@ -78,7 +78,6 @@ excludedResource:
- /api/apps/hierarchy===get
- /api/push/**===*
- /api/status/page/public/**===*
- /api/manager/sse/**===*
# web ui resource
- /===get
- /assets/**===get
@@ -55,7 +55,7 @@ class AppServiceTest {
@BeforeEach
void setUp() throws Exception {
appService.afterPropertiesSet();
appService.run();
}
@Test
@@ -135,7 +135,6 @@ class MonitorServiceTest {
.intervals(1)
.name("memory")
.app("demoApp")
.host("localhost")
.build();
Job job = new Job();
job.setMetrics(new ArrayList<>());
@@ -158,7 +157,6 @@ class MonitorServiceTest {
.intervals(1)
.name("memory")
.app("demoApp")
.host("localhost")
.build();
Job job = new Job();
job.setMetrics(new ArrayList<>());
@@ -181,7 +179,6 @@ class MonitorServiceTest {
.intervals(1)
.name("memory")
.app("demoApp")
.host("localhost")
.build();
Job job = new Job();
when(appService.getAppDefine(monitor.getApp())).thenReturn(job);
@@ -197,7 +194,6 @@ class MonitorServiceTest {
Monitor monitor = Monitor.builder()
.intervals(1)
.name("memory")
.host("localhost")
.app("demoApp")
.build();
Job job = new Job();
@@ -737,7 +733,6 @@ class MonitorServiceTest {
.intervals(1)
.name("memory")
.app("demoApp")
.host("localhost")
.build();
Job job = new Job();
when(appService.getAppDefine(monitor.getApp())).thenReturn(job);
@@ -19,7 +19,6 @@ package org.apache.hertzbeat.manager.service;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyLong;
@@ -40,7 +39,6 @@ import org.apache.hertzbeat.common.constants.PluginType;
import org.apache.hertzbeat.common.entity.dto.PluginUpload;
import org.apache.hertzbeat.common.entity.manager.PluginItem;
import org.apache.hertzbeat.common.entity.manager.PluginMetadata;
import org.apache.hertzbeat.common.support.exception.CommonException;
import org.apache.hertzbeat.manager.dao.PluginItemDao;
import org.apache.hertzbeat.manager.dao.PluginMetadataDao;
import org.apache.hertzbeat.manager.dao.PluginParamDao;
@@ -105,23 +103,6 @@ class PluginServiceTest {
}
@Test
void testUploadPluginWithInvalidName() {
MockMultipartFile mockFile = new MockMultipartFile(
"file", "../test-plugin.jar", "application/java-archive",
"plugin-content".getBytes(StandardCharsets.UTF_8));
PluginUpload pluginUpload = new PluginUpload(mockFile, "Test Plugin", true);
assertThrows(CommonException.class, () -> pluginService.savePlugin(pluginUpload));
MockMultipartFile mockWindowsFile = new MockMultipartFile(
"file", "..\\..\\test-plugin.jar", "application/java-archive",
"plugin-content".getBytes(StandardCharsets.UTF_8));
PluginUpload pluginUploadWindows = new PluginUpload(mockWindowsFile, "Test Plugin", true);
assertThrows(CommonException.class, () -> pluginService.savePlugin(pluginUploadWindows));
}
@Test
void testUpdateStatus() {
PluginMetadata plugin = new PluginMetadata();
@@ -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());
}
}
@@ -0,0 +1,72 @@
/*
* 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.warehouse.controller;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import org.apache.hertzbeat.common.entity.dto.Message;
import org.apache.hertzbeat.common.entity.dto.query.MetricQueryData;
import org.apache.hertzbeat.warehouse.service.MetricsDataQueryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* Metrics Data Query API
*/
@RestController
@RequestMapping(produces = {APPLICATION_JSON_VALUE})
@Tag(name = "Metrics Data Query API")
public class MetricsDataQueryController {
@Autowired
private MetricsDataQueryService queryService;
@GetMapping("/api/warehouse/query")
@Operation(summary = "Query Real Time Metrics Data")
public ResponseEntity<Message<List<MetricQueryData>>> queryMetricsData(
@Parameter(description = "Query PromQL expr list", example = "cpu")
@RequestParam List<String> queries,
@Parameter(description = "Query timestamp", example = "1725854804451")
@RequestParam long time) {
return ResponseEntity.ok(Message.success(queryService.query(queries, time)));
}
@GetMapping("/api/warehouse/query/range")
@Operation(summary = "Query Range Metrics Data")
public ResponseEntity<Message<List<MetricQueryData>>> queryMetricsDataRange(
@Parameter(description = "Query PromQL expr list", example = "cpu")
@RequestParam List<String> queries,
@Parameter(description = "Query start timestamp", example = "1725854804451")
@RequestParam long start,
@Parameter(description = "Query end timestamp", example = "1733630804452")
@RequestParam long end,
@Parameter(description = "Query step", example = "4m")
@RequestParam String step
) {
return ResponseEntity.ok(Message.success(queryService.queryRange(queries, start, end, step)));
}
}
@@ -15,35 +15,31 @@
* limitations under the License.
*/
package org.apache.hertzbeat.common.constants;
package org.apache.hertzbeat.warehouse.service;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;
import java.util.List;
import org.apache.hertzbeat.common.entity.dto.query.MetricQueryData;
/**
* Import/Export task status
* metrics data query service
*/
@Getter
@AllArgsConstructor
@ToString
public enum ImportTaskStatusEnum {
public interface MetricsDataQueryService {
/**
* Query metrics data
* @param queries query expr
* @param time time
* @return data
*/
List<MetricQueryData> query(List<String> queries, long time);
/**
* In progress
* Query metrics data range
* @param queries query expr
* @param start start
* @param end end
* @param step step
* @return data
*/
IN_PROGRESS("IN_PROGRESS"),
/**
* Completed
*/
COMPLETED("COMPLETED"),
/**
* Failed
*/
FAILED("FAILED");
private final String value;
List<MetricQueryData> queryRange(List<String> queries, long start, long end, String step);
}
@@ -0,0 +1,282 @@
/*
* 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.warehouse.service.impl.greptime;
import io.greptime.GreptimeDB;
import io.greptime.models.AuthInfo;
import io.greptime.models.DataType;
import io.greptime.models.Err;
import io.greptime.models.Result;
import io.greptime.models.Table;
import io.greptime.models.TableSchema;
import io.greptime.models.WriteOk;
import io.greptime.options.GreptimeOptions;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.Instant;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAmount;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.hertzbeat.common.constants.CommonConstants;
import org.apache.hertzbeat.common.entity.dto.Value;
import org.apache.hertzbeat.common.entity.dto.query.MetricQueryData;
import org.apache.hertzbeat.common.entity.message.CollectRep;
import org.apache.hertzbeat.common.util.JsonUtil;
import org.apache.hertzbeat.common.util.TimePeriodUtil;
import org.apache.hertzbeat.warehouse.service.MetricsDataQueryService;
import org.apache.hertzbeat.warehouse.store.history.greptime.GreptimeProperties;
import org.apache.hertzbeat.warehouse.store.history.vm.PromQlQueryContent;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
/**
* GreptimeDB data storage, only supports GreptimeDB version >= v0.5
*/
@Component
@ConditionalOnProperty(prefix = "warehouse.store.greptime", name = "enabled", havingValue = "true")
@Slf4j
public class GreptimeDbStorage implements MetricsDataQueryService, DisposableBean {
private static final String BASIC = "Basic";
private static final String QUERY_RANGE_PATH = "/v1/prometheus/api/v1/query_range";
private static final String LABEL_KEY_NAME = "__name__";
private static final String LABEL_KEY_FIELD = "__field__";
private static final String LABEL_KEY_INSTANCE = "instance";
private static final String SPILT = "_";
private GreptimeDB greptimeDb;
private final GreptimeProperties greptimeProperties;
private final RestTemplate restTemplate;
public GreptimeDbStorage(GreptimeProperties greptimeProperties, RestTemplate restTemplate) {
if (greptimeProperties == null) {
log.error("init error, please config Warehouse GreptimeDB props in application.yml");
throw new IllegalArgumentException("please config Warehouse GreptimeDB props");
}
this.restTemplate = restTemplate;
this.greptimeProperties = greptimeProperties;
initGreptimeDbClient(greptimeProperties);
}
private void initGreptimeDbClient(GreptimeProperties greptimeProperties) {
String endpoints = greptimeProperties.grpcEndpoints();
GreptimeOptions opts = GreptimeOptions.newBuilder(endpoints.split(","), greptimeProperties.database())
.writeMaxRetries(3)
.authInfo(new AuthInfo(greptimeProperties.username(), greptimeProperties.password()))
.routeTableRefreshPeriodSeconds(30)
.build();
this.greptimeDb = GreptimeDB.create(opts);
}
public void saveData(CollectRep.MetricsData metricsData) {
if (metricsData.getCode() != CollectRep.Code.SUCCESS) {
return;
}
if (metricsData.getValuesList().isEmpty()) {
log.info("[warehouse greptime] flush metrics data {} {} is null, ignore.", metricsData.getId(), metricsData.getMetrics());
return;
}
String monitorId = String.valueOf(metricsData.getId());
String tableName = getTableName(metricsData.getApp(), metricsData.getMetrics());
TableSchema.Builder tableSchemaBuilder = TableSchema.newBuilder(tableName);
tableSchemaBuilder.addTag("instance", DataType.String)
.addTimestamp("ts", DataType.TimestampMillisecond);
List<CollectRep.Field> fieldsList = metricsData.getFieldsList();
for (CollectRep.Field field : fieldsList) {
// handle field type
if (field.getLabel()) {
tableSchemaBuilder.addTag(field.getName(), DataType.String);
} else {
if (field.getType() == CommonConstants.TYPE_NUMBER) {
tableSchemaBuilder.addField(field.getName(), DataType.Float64);
} else if (field.getType() == CommonConstants.TYPE_STRING) {
tableSchemaBuilder.addField(field.getName(), DataType.String);
}
}
}
Table table = Table.from(tableSchemaBuilder.build());
try {
long now = System.currentTimeMillis();
Object[] values = new Object[2 + fieldsList.size()];
values[0] = monitorId;
values[1] = now;
for (CollectRep.ValueRow valueRow : metricsData.getValuesList()) {
for (int i = 0; i < fieldsList.size(); i++) {
if (!CommonConstants.NULL_VALUE.equals(valueRow.getColumns(i))) {
CollectRep.Field field = fieldsList.get(i);
if (field.getLabel()) {
values[2 + i] = valueRow.getColumns(i);
} else {
if (field.getType() == CommonConstants.TYPE_NUMBER) {
values[2 + i] = Double.parseDouble(valueRow.getColumns(i));
} else if (field.getType() == CommonConstants.TYPE_STRING) {
values[2 + i] = valueRow.getColumns(i);
}
}
} else {
values[2 + i] = null;
}
}
table.addRow(values);
}
CompletableFuture<Result<WriteOk, Err>> writeFuture = greptimeDb.write(table);
try {
Result<WriteOk, Err> result = writeFuture.get(10, TimeUnit.SECONDS);
if (result.isOk()) {
log.debug("[warehouse greptime]-Write successful");
} else {
log.warn("[warehouse greptime]--Write failed: {}", result.getErr());
}
} catch (Throwable throwable) {
log.error("[warehouse greptime]--Error occurred: {}", throwable.getMessage());
}
} catch (Exception e) {
log.error("[warehouse greptime]--Error: {}", e.getMessage(), e);
}
}
public Map<String, List<Value>> getHistoryMetricData(Long monitorId, String app, String metrics, String metric,
String label, String history) {
String name = getTableName(app, metrics);
String timeSeriesSelector = LABEL_KEY_NAME + "=\"" + name + "\""
+ "," + LABEL_KEY_INSTANCE + "=\"" + monitorId + "\"";
if (!CommonConstants.PROMETHEUS.equals(app)) {
timeSeriesSelector = timeSeriesSelector + "," + LABEL_KEY_FIELD + "=\"" + metric + "\"";
}
Map<String, List<Value>> instanceValuesMap = new HashMap<>(8);
try {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(List.of(MediaType.APPLICATION_JSON));
if (StringUtils.hasText(greptimeProperties.username())
&& StringUtils.hasText(greptimeProperties.password())) {
String authStr = greptimeProperties.username() + ":" + greptimeProperties.password();
String encodedAuth = new String(Base64.encodeBase64(authStr.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
headers.add(HttpHeaders.AUTHORIZATION, BASIC + " " + encodedAuth);
}
Instant now = Instant.now();
long start;
try {
if (NumberUtils.isParsable(history)) {
start = NumberUtils.toLong(history);
start = (ZonedDateTime.now().toEpochSecond() - start);
} else {
TemporalAmount temporalAmount = TimePeriodUtil.parseTokenTime(history);
assert temporalAmount != null;
Instant dateTime = now.minus(temporalAmount);
start = dateTime.getEpochSecond();
}
} catch (Exception e) {
log.error("history time error: {}. use default: 6h", e.getMessage());
start = now.minus(6, ChronoUnit.HOURS).getEpochSecond();
}
long end = now.getEpochSecond();
String step = "60s";
if (end - start < Duration.ofDays(7).getSeconds() && end - start > Duration.ofDays(1).getSeconds()) {
step = "1h";
} else if (end - start >= Duration.ofDays(7).getSeconds()) {
step = "4h";
}
HttpEntity<Void> httpEntity = new HttpEntity<>(headers);
URI uri = UriComponentsBuilder.fromHttpUrl(greptimeProperties.httpEndpoint() + QUERY_RANGE_PATH)
.queryParam(URLEncoder.encode("query", StandardCharsets.UTF_8), URLEncoder.encode("{" + timeSeriesSelector + "}", StandardCharsets.UTF_8))
.queryParam("start", start)
.queryParam("end", end)
.queryParam("step", step)
.build(true).toUri();
ResponseEntity<PromQlQueryContent> responseEntity = restTemplate.exchange(uri,
HttpMethod.GET, httpEntity, PromQlQueryContent.class);
if (responseEntity.getStatusCode().is2xxSuccessful()) {
log.debug("query metrics data from victoria-metrics success. {}", uri);
if (responseEntity.getBody() != null && responseEntity.getBody().getData() != null
&& responseEntity.getBody().getData().getResult() != null) {
List<PromQlQueryContent.ContentData.Content> contents = responseEntity.getBody().getData().getResult();
for (PromQlQueryContent.ContentData.Content content : contents) {
Map<String, String> labels = content.getMetric();
labels.remove(LABEL_KEY_NAME);
labels.remove(LABEL_KEY_INSTANCE);
String labelStr = JsonUtil.toJson(labels);
if (content.getValues() != null && !content.getValues().isEmpty()) {
List<Value> valueList = instanceValuesMap.computeIfAbsent(labelStr, k -> new LinkedList<>());
for (Object[] valueArr : content.getValues()) {
long timestamp = ((Double) valueArr[0]).longValue();
String value = new BigDecimal(String.valueOf(valueArr[1])).setScale(4, RoundingMode.HALF_UP).stripTrailingZeros().toPlainString();
// read timestamp here is s unit
valueList.add(new Value(value, timestamp * 1000));
}
}
}
}
} else {
log.error("query metrics data from greptime failed. {}", responseEntity);
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return instanceValuesMap;
}
private String getTableName(String app, String metrics) {
return app + SPILT + metrics;
}
@Override
public void destroy() {
if (this.greptimeDb != null) {
this.greptimeDb.shutdownGracefully();
this.greptimeDb = null;
}
}
@Override
public List<MetricQueryData> query(List<String> queries, long time) {
return List.of();
}
@Override
public List<MetricQueryData> queryRange(List<String> queries, long start, long end, String step) {
return List.of();
}
}
@@ -73,13 +73,10 @@ public class DataStorageDispatch {
if (metricsData == null) {
continue;
}
try {
calculateMonitorStatus(metricsData);
historyDataWriter.ifPresent(dataWriter -> dataWriter.saveData(metricsData));
pluginRunner.pluginExecute(PostCollectPlugin.class, ((postCollectPlugin, pluginContext) -> postCollectPlugin.execute(metricsData, pluginContext)));
} finally {
realTimeDataWriter.saveData(metricsData);
}
calculateMonitorStatus(metricsData);
historyDataWriter.ifPresent(dataWriter -> dataWriter.saveData(metricsData));
pluginRunner.pluginExecute(PostCollectPlugin.class, ((postCollectPlugin, pluginContext) -> postCollectPlugin.execute(metricsData, pluginContext)));
realTimeDataWriter.saveData(metricsData);
} catch (InterruptedException interruptedException) {
Thread.currentThread().interrupt();
} catch (Exception e) {
@@ -70,7 +70,6 @@ public class MemoryDataStorage extends AbstractRealTimeDataStorage {
Long monitorId = metricsData.getId();
String metrics = metricsData.getMetrics();
if (metricsData.getCode() != CollectRep.Code.SUCCESS) {
metricsData.close();
return;
}
Map<String, CollectRep.MetricsData> metricsDataMap =

Some files were not shown because too many files have changed in this diff Show More