mirror of
https://github.com/dromara/hertzbeat.git
synced 2026-09-17 18:19:02 +00:00
Compare commits
67
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f991f13ac | ||
|
|
3fe6db1723 | ||
|
|
b46d049158 | ||
|
|
4a8d664c93 | ||
|
|
dc52c88d88 | ||
|
|
df4e947c8a | ||
|
|
a4ec6c1f66 | ||
|
|
a8dd57d009 | ||
|
|
af3eabdd1c | ||
|
|
d6b300d3df | ||
|
|
b5789538e6 | ||
|
|
d6c5b2b8a2 | ||
|
|
3a04647c3c | ||
|
|
d2999c1aa6 | ||
|
|
1f1aafc70e | ||
|
|
ea5b678af5 | ||
|
|
fa24e5000f | ||
|
|
f242ead7a9 | ||
|
|
5402437eac | ||
|
|
ce61c7d456 | ||
|
|
320766a48e | ||
|
|
efb2ac02df | ||
|
|
06c939c810 | ||
|
|
e56823b240 | ||
|
|
3b18d1ddaf | ||
|
|
d44fe43eb0 | ||
|
|
a221ddfba2 | ||
|
|
8e31a3147b | ||
|
|
d2f9a56fe7 | ||
|
|
a0b41dc7bb | ||
|
|
3f572a1ddc | ||
|
|
767deccee5 | ||
|
|
9221e2f6c1 | ||
|
|
0a36b3df90 | ||
|
|
f3202133d8 | ||
|
|
6ee458c521 | ||
|
|
cbc1caf4ac | ||
|
|
86db630fc7 | ||
|
|
145c4d1d5e | ||
|
|
0217cbb7f9 | ||
|
|
9f5df95f29 | ||
|
|
0f955019bf | ||
|
|
129b6282d3 | ||
|
|
36c5d8f518 | ||
|
|
de8a473e24 | ||
|
|
ffc4641dc9 | ||
|
|
d0cb9f8bf3 | ||
|
|
0d4ff33f19 | ||
|
|
86f40e5e15 | ||
|
|
dbbbc045d4 | ||
|
|
b0fdd5e11d | ||
|
|
9c5ea20b15 | ||
|
|
7a74f80906 | ||
|
|
ee32a890eb | ||
|
|
ec1c04194b | ||
|
|
55d8dfdede | ||
|
|
918073dca7 | ||
|
|
2defaecd93 | ||
|
|
641ba47f4c | ||
|
|
ccbc2151ae | ||
|
|
1cb919a301 | ||
|
|
7351a03c81 | ||
|
|
26c3a802d1 | ||
|
|
47dbe2fd2a | ||
|
|
f4943e9d89 | ||
|
|
1f6614d1a1 | ||
|
|
4a96c02b9a |
@@ -48,6 +48,15 @@ jobs:
|
||||
- name: Build with Maven
|
||||
run: mvnd clean -B package -Prelease -Dmaven.test.skip=false --file pom.xml
|
||||
|
||||
- name: Upload test reports
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: test-reports-${{ github.run_id }}
|
||||
path: |
|
||||
**/target/surefire-reports
|
||||
**/target/failsafe-reports
|
||||
|
||||
- name: Upload coverage reports to Codecov
|
||||
uses: codecov/codecov-action@v4.0.1
|
||||
with:
|
||||
|
||||
+1
-1
@@ -75,7 +75,7 @@ public class DataSourceServiceImpl implements DataSourceService {
|
||||
throw new IllegalArgumentException("Empty expression");
|
||||
}
|
||||
if (executors == null || executors.isEmpty()) {
|
||||
throw new IllegalArgumentException("No query executor found");
|
||||
throw new IllegalArgumentException(bundle.getString("alerter.datasource.executor.not.found"));
|
||||
}
|
||||
QueryExecutor executor = executors.stream().filter(e -> e.support(datasource)).findFirst().orElse(null);
|
||||
|
||||
|
||||
@@ -33,3 +33,4 @@ alerter.priority.0 = Emergency Alert
|
||||
alerter.priority.1 = Critical Alert
|
||||
alerter.priority.2 = Warning Alert
|
||||
alerter.calculate.parse.error = Expression is not fully parsed, may have syntax errors or incomplete inputs
|
||||
alerter.datasource.executor.not.found = No query executor found
|
||||
|
||||
@@ -33,3 +33,4 @@ alerter.priority.0 = 紧急告警
|
||||
alerter.priority.1 = 严重告警
|
||||
alerter.priority.2 = 警告告警
|
||||
alerter.calculate.parse.error = 表达式未完全解析,可能存在语法错误或输入不完整
|
||||
alerter.datasource.executor.not.found = 未找到查询执行器
|
||||
|
||||
@@ -33,3 +33,4 @@ alerter.priority.0 = 緊急警報
|
||||
alerter.priority.1 = 嚴重警報
|
||||
alerter.priority.2 = 警告警報
|
||||
alerter.calculate.parse.error = 表達式未完全解析,可能存在語法錯誤或輸入不完整
|
||||
alerter.datasource.executor.not.found = 未找到查詢執行器
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<mqtt.version>1.3.3</mqtt.version>
|
||||
<mqtt.version>1.2.5</mqtt.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -140,10 +140,19 @@
|
||||
</dependency>
|
||||
<!-- mqtt -->
|
||||
<dependency>
|
||||
<groupId>com.hivemq</groupId>
|
||||
<artifactId>hivemq-mqtt-client</artifactId>
|
||||
<groupId>org.eclipse.paho</groupId>
|
||||
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
|
||||
<version>${mqtt.version}</version>
|
||||
</dependency>
|
||||
<!--Bouncy Castle-->
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcpkix-jdk15on</artifactId>
|
||||
<version>1.68</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<!--plc-->
|
||||
<dependency>
|
||||
<groupId>org.apache.plc4x</groupId>
|
||||
|
||||
+40
-30
@@ -68,6 +68,7 @@ import org.apache.hertzbeat.common.util.Base64Util;
|
||||
import org.apache.hertzbeat.common.util.CommonUtil;
|
||||
import org.apache.hertzbeat.common.util.IpDomainUtil;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.auth.AuthScope;
|
||||
@@ -144,37 +145,46 @@ public class HttpCollectImpl extends AbstractCollect {
|
||||
builder.setMsg(NetworkConstants.STATUS_CODE + SignConstants.BLANK + statusCode);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
this could create large objects, potentially impacting JVM memory space significantly.
|
||||
Option 1: Parse using InputStream, but this requires significant code changes;
|
||||
Option 2: Manually trigger garbage collection, similar to how it's done in Dubbo for large inputs.
|
||||
*/
|
||||
String resp = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
|
||||
if (!StringUtils.hasText(resp)) {
|
||||
log.info("http response entity is empty, status: {}.", statusCode);
|
||||
}
|
||||
Long responseTime = System.currentTimeMillis() - startTime;
|
||||
|
||||
long responseTime = System.currentTimeMillis() - startTime;
|
||||
String parseType = metrics.getHttp().getParseType();
|
||||
HttpEntity entity = response.getEntity();
|
||||
|
||||
try {
|
||||
switch (parseType) {
|
||||
case DispatchConstants.PARSE_JSON_PATH ->
|
||||
parseResponseByJsonPath(resp, metrics.getAliasFields(), metrics.getHttp(), builder, responseTime);
|
||||
case DispatchConstants.PARSE_PROM_QL ->
|
||||
parseResponseByPromQl(resp, metrics.getAliasFields(), metrics.getHttp(), builder);
|
||||
case DispatchConstants.PARSE_PROMETHEUS ->
|
||||
parseResponseByPrometheusExporter(response.getEntity().getContent(), metrics.getAliasFields(), builder);
|
||||
case DispatchConstants.PARSE_XML_PATH ->
|
||||
parseResponseByXmlPath(resp, metrics, builder, responseTime);
|
||||
case DispatchConstants.PARSE_WEBSITE ->
|
||||
parseResponseByWebsite(resp, metrics, metrics.getHttp(), builder, responseTime, statusCode);
|
||||
case DispatchConstants.PARSE_SITE_MAP ->
|
||||
parseResponseBySiteMap(resp, metrics.getAliasFields(), builder);
|
||||
case DispatchConstants.PARSE_HEADER ->
|
||||
parseResponseByHeader(builder, metrics.getAliasFields(), response);
|
||||
case DispatchConstants.PARSE_CONFIG ->
|
||||
parseResponseByConfig(resp, metrics.getAliasFields(), metrics.getHttp(), builder, responseTime);
|
||||
default ->
|
||||
parseResponseByDefault(resp, metrics.getAliasFields(), metrics.getHttp(), builder, responseTime);
|
||||
if (DispatchConstants.PARSE_PROMETHEUS.equals(parseType)) {
|
||||
if (entity != null) {
|
||||
parseResponseByPrometheusExporter(entity.getContent(), metrics.getAliasFields(), builder);
|
||||
}
|
||||
} else if (DispatchConstants.PARSE_HEADER.equals(parseType)) {
|
||||
parseResponseByHeader(builder, metrics.getAliasFields(), response);
|
||||
// Consume entity to release connection
|
||||
EntityUtils.consumeQuietly(entity);
|
||||
} else {
|
||||
/*
|
||||
this could create large objects, potentially impacting JVM memory space significantly.
|
||||
Option 1: Parse using InputStream, but this requires significant code changes;
|
||||
Option 2: Manually trigger garbage collection, similar to how it's done in Dubbo for large inputs.
|
||||
*/
|
||||
String resp = entity == null ? "" : EntityUtils.toString(entity, StandardCharsets.UTF_8);
|
||||
if (!StringUtils.hasText(resp)) {
|
||||
log.info("http response entity is empty, status: {}.", statusCode);
|
||||
}
|
||||
switch (parseType) {
|
||||
case DispatchConstants.PARSE_JSON_PATH ->
|
||||
parseResponseByJsonPath(resp, metrics.getAliasFields(), metrics.getHttp(), builder, responseTime);
|
||||
case DispatchConstants.PARSE_PROM_QL ->
|
||||
parseResponseByPromQl(resp, metrics.getAliasFields(), metrics.getHttp(), builder);
|
||||
case DispatchConstants.PARSE_XML_PATH ->
|
||||
parseResponseByXmlPath(resp, metrics, builder, responseTime);
|
||||
case DispatchConstants.PARSE_WEBSITE ->
|
||||
parseResponseByWebsite(resp, metrics, metrics.getHttp(), builder, responseTime, statusCode);
|
||||
case DispatchConstants.PARSE_SITE_MAP ->
|
||||
parseResponseBySiteMap(resp, metrics.getAliasFields(), builder);
|
||||
case DispatchConstants.PARSE_CONFIG ->
|
||||
parseResponseByConfig(resp, metrics.getAliasFields(), metrics.getHttp(), builder, responseTime);
|
||||
default ->
|
||||
parseResponseByDefault(resp, metrics.getAliasFields(), metrics.getHttp(), builder, responseTime);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.info("parse error: {}.", e.getMessage(), e);
|
||||
@@ -856,4 +866,4 @@ public class HttpCollectImpl extends AbstractCollect {
|
||||
}
|
||||
return successCodeSet.contains(statusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* 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.collector.collect.mqtt;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Formats the private key and certificate, supporting concatenation of multiple certificates in PEM format.
|
||||
*/
|
||||
public class CertificateFormatter {
|
||||
|
||||
public static String formatCertificateChain(String input) {
|
||||
if (input == null || input.trim().isEmpty()) {
|
||||
return input;
|
||||
}
|
||||
|
||||
String normalized = normalizeInput(input);
|
||||
|
||||
List<String> certificates = extractCertificates(normalized);
|
||||
|
||||
if (certificates.isEmpty()) {
|
||||
return formatAsSingleCertificate(normalized);
|
||||
}
|
||||
|
||||
StringBuilder formattedChain = new StringBuilder();
|
||||
for (String cert : certificates) {
|
||||
if (cert.trim().isEmpty()) continue;
|
||||
|
||||
String formatted = formatPemBlock(cert);
|
||||
formattedChain.append(formatted).append("\n");
|
||||
}
|
||||
|
||||
return formattedChain.toString().trim();
|
||||
}
|
||||
|
||||
private static String normalizeInput(String input) {
|
||||
return input
|
||||
.replace("\r\n", "\n")
|
||||
.replace("\r", "\n")
|
||||
.replaceAll("\\s*\\\\n\\s*", "\n")
|
||||
.replaceAll("(?m)^\\s+|\\s+$", "")
|
||||
.trim();
|
||||
}
|
||||
|
||||
private static List<String> extractCertificates(String input) {
|
||||
List<String> certificates = new ArrayList<>();
|
||||
String regex = "(-----BEGIN\\s+[\\w\\s]+?-----)[\\s\\S]*?(-----END\\s+[\\w\\s]+?-----)";
|
||||
|
||||
|
||||
Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
|
||||
Matcher matcher = pattern.matcher(input);
|
||||
|
||||
int lastEnd = 0;
|
||||
while (matcher.find()) {
|
||||
|
||||
if (matcher.start() > lastEnd) {
|
||||
String gap = input.substring(lastEnd, matcher.start());
|
||||
if (!gap.trim().isEmpty()) {
|
||||
certificates.add(gap);
|
||||
}
|
||||
}
|
||||
|
||||
certificates.add(matcher.group());
|
||||
lastEnd = matcher.end();
|
||||
}
|
||||
|
||||
|
||||
if (lastEnd < input.length()) {
|
||||
certificates.add(input.substring(lastEnd));
|
||||
}
|
||||
|
||||
return certificates;
|
||||
}
|
||||
|
||||
private static String formatPemBlock(String block) {
|
||||
try {
|
||||
Pattern pattern = Pattern.compile(
|
||||
"(-----BEGIN\\s+[\\w\\s]+?-----)(.*?)(-----END\\s+[\\w\\s]+?-----)",
|
||||
Pattern.DOTALL | Pattern.CASE_INSENSITIVE
|
||||
);
|
||||
|
||||
Matcher matcher = pattern.matcher(block);
|
||||
if (matcher.find()) {
|
||||
String header = matcher.group(1).trim();
|
||||
String body = matcher.group(2);
|
||||
String footer = matcher.group(3).trim();
|
||||
|
||||
|
||||
if (body == null) body = "";
|
||||
|
||||
String cleanBody = body
|
||||
.replaceAll("\\s", "")
|
||||
.replaceAll("\"", "")
|
||||
.trim();
|
||||
|
||||
|
||||
if (cleanBody.isEmpty() && body != null && !body.trim().isEmpty()) {
|
||||
|
||||
cleanBody = body.replaceAll("[^a-zA-Z0-9+/=]", "").trim();
|
||||
}
|
||||
|
||||
String formattedBody = formatBase64Body(cleanBody);
|
||||
|
||||
return header + "\n" + formattedBody + "\n" + footer;
|
||||
} else {
|
||||
|
||||
return formatAsCertificate(block);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
return block;
|
||||
}
|
||||
}
|
||||
|
||||
private static String formatAsCertificate(String content) {
|
||||
|
||||
String cleanContent = content.replaceAll("[^a-zA-Z0-9+/=]", "").trim();
|
||||
|
||||
if (cleanContent.isEmpty()) {
|
||||
return content;
|
||||
}
|
||||
|
||||
|
||||
String formattedBody = formatBase64Body(cleanContent);
|
||||
|
||||
|
||||
if (cleanContent.toLowerCase().contains("private")) {
|
||||
if (cleanContent.startsWith("MII") || cleanContent.length() > 1000) {
|
||||
return "-----BEGIN PRIVATE KEY-----\n" + formattedBody + "\n-----END PRIVATE KEY-----";
|
||||
} else {
|
||||
return "-----BEGIN RSA PRIVATE KEY-----\n" + formattedBody + "\n-----END RSA PRIVATE KEY-----";
|
||||
}
|
||||
} else {
|
||||
return "-----BEGIN CERTIFICATE-----\n" + formattedBody + "\n-----END CERTIFICATE-----";
|
||||
}
|
||||
}
|
||||
|
||||
private static String formatAsSingleCertificate(String input) {
|
||||
String cleanContent = input.replaceAll("[^a-zA-Z0-9+/=]", "").trim();
|
||||
return formatAsCertificate(cleanContent);
|
||||
}
|
||||
|
||||
private static String formatBase64Body(String body) {
|
||||
|
||||
StringBuilder formatted = new StringBuilder();
|
||||
int index = 0;
|
||||
while (index < body.length()) {
|
||||
int end = Math.min(index + 64, body.length());
|
||||
formatted.append(body.substring(index, end));
|
||||
if (end < body.length()) {
|
||||
formatted.append("\n");
|
||||
}
|
||||
index = end;
|
||||
}
|
||||
return formatted.toString().trim();
|
||||
}
|
||||
|
||||
public static String formatPrivateKey(String input) {
|
||||
if (input == null || input.trim().isEmpty()) {
|
||||
return input;
|
||||
}
|
||||
|
||||
|
||||
String normalized = normalizeInput(input);
|
||||
|
||||
|
||||
if (isPemEncapsulated(normalized)) {
|
||||
return formatPemBlock(normalized);
|
||||
}
|
||||
|
||||
return formatAsCertificate(normalized);
|
||||
}
|
||||
|
||||
private static boolean isPemEncapsulated(String block) {
|
||||
return block.contains("-----BEGIN") && block.contains("-----END");
|
||||
}
|
||||
}
|
||||
+221
-161
@@ -17,26 +17,7 @@
|
||||
|
||||
package org.apache.hertzbeat.collector.collect.mqtt;
|
||||
|
||||
import com.hivemq.client.mqtt.MqttVersion;
|
||||
import com.hivemq.client.mqtt.datatypes.MqttQos;
|
||||
import com.hivemq.client.mqtt.mqtt3.Mqtt3AsyncClient;
|
||||
import com.hivemq.client.mqtt.mqtt3.Mqtt3Client;
|
||||
import com.hivemq.client.mqtt.mqtt3.Mqtt3ClientBuilder;
|
||||
import com.hivemq.client.mqtt.mqtt3.message.connect.connack.Mqtt3ConnAck;
|
||||
import com.hivemq.client.mqtt.mqtt5.Mqtt5AsyncClient;
|
||||
import com.hivemq.client.mqtt.mqtt5.Mqtt5Client;
|
||||
import com.hivemq.client.mqtt.mqtt5.Mqtt5ClientBuilder;
|
||||
import com.hivemq.client.mqtt.mqtt5.message.connect.connack.Mqtt5ConnAck;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.hertzbeat.collector.collect.AbstractCollect;
|
||||
import org.apache.hertzbeat.collector.constants.CollectorConstants;
|
||||
@@ -46,13 +27,27 @@ import org.apache.hertzbeat.common.entity.job.Metrics;
|
||||
import org.apache.hertzbeat.common.entity.job.protocol.MqttProtocol;
|
||||
import org.apache.hertzbeat.common.entity.message.CollectRep;
|
||||
import org.apache.hertzbeat.common.entity.message.CollectRep.MetricsData.Builder;
|
||||
import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
|
||||
import org.eclipse.paho.client.mqttv3.MqttClientPersistence;
|
||||
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
|
||||
import org.eclipse.paho.client.mqttv3.MqttCallback;
|
||||
import org.eclipse.paho.client.mqttv3.MqttMessage;
|
||||
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
|
||||
import org.eclipse.paho.client.mqttv3.IMqttToken;
|
||||
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StopWatch;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* collect mqtt metrics
|
||||
* collect mqtt metrics using Eclipse Paho
|
||||
*/
|
||||
public class MqttCollectImpl extends AbstractCollect {
|
||||
|
||||
@@ -61,138 +56,224 @@ public class MqttCollectImpl extends AbstractCollect {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(MqttCollectImpl.class);
|
||||
|
||||
@Override
|
||||
public void preCheck(Metrics metrics) throws IllegalArgumentException {
|
||||
MqttProtocol mqttProtocol = metrics.getMqtt();
|
||||
Assert.hasText(mqttProtocol.getHost(), "MQTT protocol host is required");
|
||||
Assert.hasText(mqttProtocol.getPort(), "MQTT protocol port is required");
|
||||
Assert.hasText(mqttProtocol.getProtocolVersion(), "MQTT protocol version is required");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collect(Builder builder, Metrics metrics) {
|
||||
MqttProtocol mqtt = metrics.getMqtt();
|
||||
String protocolVersion = mqtt.getProtocolVersion();
|
||||
MqttVersion mqttVersion = MqttVersion.valueOf(protocolVersion);
|
||||
if (mqttVersion == MqttVersion.MQTT_3_1_1) {
|
||||
collectWithVersion3(metrics, builder);
|
||||
} else if (mqttVersion == MqttVersion.MQTT_5_0) {
|
||||
collectWithVersion5(metrics, builder);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String supportProtocol() {
|
||||
return DispatchConstants.PROTOCOL_MQTT;
|
||||
}
|
||||
|
||||
/**
|
||||
* collecting data of MQTT 5
|
||||
*/
|
||||
private void collectWithVersion5(Metrics metrics, Builder builder) {
|
||||
@Override
|
||||
public void preCheck(Metrics metrics) throws IllegalArgumentException {
|
||||
MqttProtocol mqttProtocol = metrics.getMqtt();
|
||||
Assert.hasText(mqttProtocol.getHost(), "MQTT protocol host is required");
|
||||
Assert.hasText(mqttProtocol.getPort(), "MQTT protocol port is required");
|
||||
|
||||
if ("mqtts".equalsIgnoreCase(mqttProtocol.getProtocol())) {
|
||||
if (Boolean.parseBoolean(mqttProtocol.getEnableMutualAuth())) {
|
||||
Assert.hasText(mqttProtocol.getCaCert(), "CA certificate is required for mutual auth");
|
||||
Assert.hasText(mqttProtocol.getClientCert(), "Client certificate is required for mutual auth");
|
||||
Assert.hasText(mqttProtocol.getClientKey(), "Client private key is required for mutual auth");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collect(Builder builder, Metrics metrics) {
|
||||
MqttProtocol mqttProtocol = metrics.getMqtt();
|
||||
Map<Object, String> data = new HashMap<>();
|
||||
Mqtt5AsyncClient client = buildMqtt5Client(mqttProtocol);
|
||||
long responseTime = connectClient(client, mqtt5AsyncClient -> {
|
||||
CompletableFuture<Mqtt5ConnAck> connectFuture = mqtt5AsyncClient.connect();
|
||||
try {
|
||||
connectFuture.get(Long.parseLong(mqttProtocol.getTimeout()), TimeUnit.MILLISECONDS);
|
||||
} catch (InterruptedException | ExecutionException | TimeoutException e) {
|
||||
builder.setCode(CollectRep.Code.FAIL);
|
||||
builder.setMsg(getErrorMessage(e.getMessage()));
|
||||
|
||||
try {
|
||||
MqttAsyncClient client = buildMqttClient(mqttProtocol);
|
||||
long responseTime = connectClient(client, mqttProtocol);
|
||||
testSubscribeAndPublish(client, mqttProtocol, data);
|
||||
convertToMetricsData(builder, metrics, responseTime, data);
|
||||
client.disconnect();
|
||||
} catch (Exception e) {
|
||||
logger.error("MQTT collection error: {}", e.getMessage(), e);
|
||||
builder.setCode(CollectRep.Code.FAIL);
|
||||
builder.setMsg("Collection failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private MqttAsyncClient buildMqttClient(MqttProtocol protocol) throws Exception {
|
||||
String clientId = protocol.getClientId();
|
||||
|
||||
String serverUri = String.format("%s://%s:%s",
|
||||
StringUtils.equals(protocol.getProtocol(), "MQTT") ? "tcp" : "ssl",
|
||||
protocol.getHost(),
|
||||
protocol.getPort());
|
||||
|
||||
MqttClientPersistence persistence = new MemoryPersistence();
|
||||
|
||||
return new MqttAsyncClient(serverUri, clientId, persistence);
|
||||
}
|
||||
|
||||
private long connectClient(MqttAsyncClient client, MqttProtocol protocol) throws Exception {
|
||||
MqttConnectOptions connOpts = new MqttConnectOptions();
|
||||
|
||||
if (protocol.hasAuth()) {
|
||||
connOpts.setUserName(protocol.getUsername());
|
||||
connOpts.setPassword(protocol.getPassword().toCharArray());
|
||||
}
|
||||
|
||||
connOpts.setKeepAliveInterval(Integer.parseInt(protocol.getKeepalive()));
|
||||
connOpts.setConnectionTimeout(Integer.parseInt(protocol.getTimeout()) / 1000);
|
||||
connOpts.setCleanSession(true);
|
||||
connOpts.setAutomaticReconnect(false);
|
||||
if ("mqtts".equalsIgnoreCase(protocol.getProtocol())) {
|
||||
boolean insecureSkipVerify = Boolean.parseBoolean(protocol.getInsecureSkipVerify());
|
||||
if (insecureSkipVerify) {
|
||||
connOpts.setHttpsHostnameVerificationEnabled(false);
|
||||
}
|
||||
if (Boolean.parseBoolean(protocol.getEnableMutualAuth())) {
|
||||
connOpts.setSocketFactory(MqttSslFactory.getMslSocketFactory(protocol, insecureSkipVerify));
|
||||
} else {
|
||||
connOpts.setSocketFactory(MqttSslFactory.getSslSocketFactory(protocol, insecureSkipVerify));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
StopWatch connectWatch = new StopWatch();
|
||||
connectWatch.start();
|
||||
|
||||
client.connect(connOpts).waitForCompletion(Long.parseLong(protocol.getTimeout()));
|
||||
connectWatch.stop();
|
||||
return connectWatch.getTotalTimeMillis();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test MQTT subscribe and publish capabilities
|
||||
*/
|
||||
private void testSubscribeAndPublish(MqttAsyncClient client, MqttProtocol protocol, Map<Object, String> data) {
|
||||
|
||||
// 1 test subscribe
|
||||
if (StringUtils.isNotBlank(protocol.getTopic())) {
|
||||
String subscribe = testSubscribe(client, protocol.getTopic());
|
||||
if (StringUtils.isBlank(subscribe)) {
|
||||
data.put("canSubscribe", "Subscription successful");
|
||||
} else {
|
||||
data.put("canSubscribe", String.format("Subscription failed: %s", subscribe));
|
||||
}
|
||||
|
||||
} else {
|
||||
data.put("canSubscribe", "No topic, subscription test skipped");
|
||||
}
|
||||
|
||||
|
||||
// 2 test publish
|
||||
if (StringUtils.isNotBlank(protocol.getTestMessage())) {
|
||||
String publish = testPublish(client, protocol.getTopic(), protocol.getTestMessage());
|
||||
if (StringUtils.isBlank(publish)) {
|
||||
data.put("canPublish", "Message published successfully");
|
||||
|
||||
// 3 test receive message
|
||||
String receivedData = getReceivedData(client, protocol.getTopic());
|
||||
data.put("canReceive", receivedData);
|
||||
} else {
|
||||
data.put("canPublish", String.format("Message publishing failed: %s", publish));
|
||||
data.put("canReceive", "Message reception skipped due to failed publish");
|
||||
}
|
||||
} else {
|
||||
data.put("canPublish", "No test message, publish test skipped");
|
||||
data.put("canReceive", "No test message, receive test skipped");
|
||||
}
|
||||
|
||||
|
||||
// 4 test unsubscribe
|
||||
if (StringUtils.isNotBlank(protocol.getTopic())) {
|
||||
String subscribe = testUnSubscribe(client, protocol.getTopic());
|
||||
if (StringUtils.isBlank(subscribe)) {
|
||||
data.put("canUnSubscribe", "Unsubscription successful");
|
||||
} else {
|
||||
data.put("canUnSubscribe", String.format("Unsubscription failed: %s", subscribe));
|
||||
}
|
||||
} else {
|
||||
data.put("canUnSubscribe", "No topic, unsubscription test skipped");
|
||||
}
|
||||
}
|
||||
|
||||
private String getReceivedData(MqttAsyncClient client, String topic) {
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
final StringBuilder messageHolder = new StringBuilder();
|
||||
|
||||
|
||||
client.setCallback(new MqttCallback() {
|
||||
@Override
|
||||
public void connectionLost(Throwable cause) {
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messageArrived(String arrivedTopic, MqttMessage message) {
|
||||
|
||||
if (topic.equals(arrivedTopic)) {
|
||||
messageHolder.append(new String(message.getPayload()));
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deliveryComplete(IMqttDeliveryToken token) {
|
||||
}
|
||||
});
|
||||
testDescribeAndPublish5(client, mqttProtocol, data);
|
||||
convertToMetricsData(builder, metrics, responseTime, data);
|
||||
client.disconnect();
|
||||
|
||||
try {
|
||||
boolean received = latch.await(5, TimeUnit.SECONDS);
|
||||
if (messageHolder.length() > 0) {
|
||||
return messageHolder.toString();
|
||||
} else if (!received) {
|
||||
return "Message reception timed out after 5 seconds";
|
||||
} else {
|
||||
return "No valid message received";
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
return e.getMessage();
|
||||
} finally {
|
||||
client.setCallback(null);
|
||||
}
|
||||
}
|
||||
|
||||
private String testSubscribe(MqttAsyncClient client, String topic) {
|
||||
try {
|
||||
IMqttToken subToken = client.subscribe(topic, 1);
|
||||
subToken.waitForCompletion(5000);
|
||||
return "";
|
||||
} catch (MqttException e) {
|
||||
logger.warn("MQTT subscribe test failed: {}", e.getMessage());
|
||||
return e.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
private String testPublish(MqttAsyncClient client, String topic, String message) {
|
||||
try {
|
||||
MqttMessage mqttMessage = new MqttMessage(message.getBytes());
|
||||
mqttMessage.setQos(1);
|
||||
|
||||
IMqttToken pubToken = client.publish(topic, mqttMessage);
|
||||
pubToken.waitForCompletion(5000);
|
||||
|
||||
return "";
|
||||
} catch (MqttException e) {
|
||||
logger.warn("MQTT publish test failed: {}", e.getMessage());
|
||||
return e.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
private String testUnSubscribe(MqttAsyncClient client, String topic) {
|
||||
try {
|
||||
IMqttToken unsubToken = client.unsubscribe(topic);
|
||||
unsubToken.waitForCompletion(5000);
|
||||
return "";
|
||||
} catch (MqttException e) {
|
||||
logger.warn("MQTT unsubscribe test failed: {}", e.getMessage());
|
||||
return e.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* collecting data of MQTT 3.1.1
|
||||
* Convert collected data to MetricsData
|
||||
*/
|
||||
private void collectWithVersion3(Metrics metrics, Builder builder) {
|
||||
MqttProtocol mqttProtocol = metrics.getMqtt();
|
||||
Map<Object, String> data = new HashMap<>();
|
||||
Mqtt3AsyncClient client = buildMqtt3Client(mqttProtocol);
|
||||
long responseTime = connectClient(client, mqtt3AsyncClient -> {
|
||||
CompletableFuture<Mqtt3ConnAck> connectFuture = mqtt3AsyncClient.connect();
|
||||
try {
|
||||
connectFuture.get(Long.parseLong(mqttProtocol.getTimeout()), TimeUnit.MILLISECONDS);
|
||||
} catch (InterruptedException | ExecutionException | TimeoutException e) {
|
||||
builder.setCode(CollectRep.Code.FAIL);
|
||||
builder.setMsg(getErrorMessage(e.getMessage()));
|
||||
}
|
||||
});
|
||||
testDescribeAndPublish3(client, mqttProtocol, data);
|
||||
convertToMetricsData(builder, metrics, responseTime, data);
|
||||
client.disconnect();
|
||||
}
|
||||
|
||||
private void testDescribeAndPublish3(Mqtt3AsyncClient client, MqttProtocol mqttProtocol, Map<Object, String> data) {
|
||||
data.put("canDescribe", test(() -> {
|
||||
client.subscribeWith().topicFilter(mqttProtocol.getTopic()).qos(MqttQos.AT_LEAST_ONCE).send();
|
||||
client.unsubscribeWith().topicFilter(mqttProtocol.getTopic()).send();
|
||||
}, "subscribe").toString());
|
||||
|
||||
data.put("canPublish", !mqttProtocol.testPublish() ? Boolean.FALSE.toString() : test(() -> {
|
||||
client.publishWith().topic(mqttProtocol.getTopic())
|
||||
.payload(mqttProtocol.getTestMessage().getBytes(StandardCharsets.UTF_8))
|
||||
.qos(MqttQos.AT_LEAST_ONCE).send();
|
||||
data.put("canPublish", Boolean.TRUE.toString());
|
||||
}, "publish").toString());
|
||||
}
|
||||
|
||||
private void testDescribeAndPublish5(Mqtt5AsyncClient client, MqttProtocol mqttProtocol, Map<Object, String> data) {
|
||||
data.put("canDescribe", test(() -> {
|
||||
client.subscribeWith().topicFilter(mqttProtocol.getTopic()).qos(MqttQos.AT_LEAST_ONCE).send();
|
||||
client.unsubscribeWith().topicFilter(mqttProtocol.getTopic()).send();
|
||||
}, "subscribe").toString());
|
||||
|
||||
data.put("canPublish", !mqttProtocol.testPublish() ? Boolean.FALSE.toString() : test(() -> {
|
||||
client.publishWith().topic(mqttProtocol.getTopic())
|
||||
.payload(mqttProtocol.getTestMessage().getBytes(StandardCharsets.UTF_8))
|
||||
.qos(MqttQos.AT_LEAST_ONCE).send();
|
||||
data.put("canPublish", Boolean.TRUE.toString());
|
||||
}, "publish").toString());
|
||||
}
|
||||
|
||||
private Mqtt5AsyncClient buildMqtt5Client(MqttProtocol mqttProtocol) {
|
||||
Mqtt5ClientBuilder mqtt5ClientBuilder = Mqtt5Client.builder()
|
||||
.serverHost(mqttProtocol.getHost())
|
||||
.identifier(mqttProtocol.getClientId())
|
||||
.serverPort(Integer.parseInt(mqttProtocol.getPort()));
|
||||
|
||||
if (mqttProtocol.hasAuth()) {
|
||||
mqtt5ClientBuilder.simpleAuth().username(mqttProtocol.getUsername())
|
||||
.password(mqttProtocol.getPassword().getBytes(StandardCharsets.UTF_8))
|
||||
.applySimpleAuth();
|
||||
}
|
||||
return mqtt5ClientBuilder.buildAsync();
|
||||
}
|
||||
|
||||
private Mqtt3AsyncClient buildMqtt3Client(MqttProtocol mqttProtocol) {
|
||||
|
||||
Mqtt3ClientBuilder mqtt3ClientBuilder = Mqtt3Client.builder()
|
||||
.serverHost(mqttProtocol.getHost())
|
||||
.identifier(mqttProtocol.getClientId())
|
||||
.serverPort(Integer.parseInt(mqttProtocol.getPort()));
|
||||
|
||||
if (mqttProtocol.hasAuth()) {
|
||||
mqtt3ClientBuilder.simpleAuth().username(mqttProtocol.getUsername())
|
||||
.password(mqttProtocol.getPassword().getBytes(StandardCharsets.UTF_8))
|
||||
.applySimpleAuth();
|
||||
}
|
||||
return mqtt3ClientBuilder.buildAsync();
|
||||
}
|
||||
|
||||
public <T> long connectClient(T client, Consumer<T> connect) {
|
||||
StopWatch stopWatch = new StopWatch();
|
||||
stopWatch.start();
|
||||
connect.accept(client);
|
||||
stopWatch.stop();
|
||||
return stopWatch.getTotalTimeMillis();
|
||||
}
|
||||
|
||||
private void convertToMetricsData(Builder builder, Metrics metrics, long responseTime, Map<Object, String> data) {
|
||||
CollectRep.ValueRow.Builder valueRowBuilder = CollectRep.ValueRow.newBuilder();
|
||||
for (String column : metrics.getAliasFields()) {
|
||||
@@ -207,25 +288,4 @@ public class MqttCollectImpl extends AbstractCollect {
|
||||
builder.addValueRow(valueRowBuilder.build());
|
||||
}
|
||||
|
||||
private Boolean test(Runnable runnable, String operationName) {
|
||||
try {
|
||||
runnable.run();
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
logger.error("{} fail", operationName, e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private String getErrorMessage(String errorMessage) {
|
||||
if (StringUtils.isBlank(errorMessage)) {
|
||||
return "connect failed";
|
||||
}
|
||||
String[] split = errorMessage.split(":");
|
||||
if (split.length > 1) {
|
||||
return Arrays.stream(split).skip(1).collect(Collectors.joining(":"));
|
||||
}
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* 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.collector.collect.mqtt;
|
||||
|
||||
import org.apache.hertzbeat.common.entity.job.protocol.MqttProtocol;
|
||||
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle.openssl.PEMKeyPair;
|
||||
import org.bouncycastle.openssl.PEMParser;
|
||||
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
|
||||
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.security.KeyStore;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.Security;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Support MQTT SSL Factory
|
||||
*/
|
||||
public class MqttSslFactory {
|
||||
|
||||
/**
|
||||
* Get MSL Socket Factory
|
||||
*/
|
||||
public static SSLSocketFactory getMslSocketFactory(MqttProtocol mqttProtocol, boolean insecureSkipVerify) {
|
||||
try {
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
|
||||
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
ks.load(null, null);
|
||||
|
||||
Certificate[] chain = null;
|
||||
if (mqttProtocol.getClientCert() != null && !mqttProtocol.getClientCert().isEmpty()) {
|
||||
String formatClientCert = CertificateFormatter.formatCertificateChain(mqttProtocol.getClientCert());
|
||||
try (InputStream certIn = new ByteArrayInputStream(formatClientCert.getBytes())) {
|
||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||
Collection<? extends Certificate> certs = cf.generateCertificates(certIn);
|
||||
chain = certs.toArray(new Certificate[0]);
|
||||
}
|
||||
}
|
||||
|
||||
PrivateKey privateKey;
|
||||
if (mqttProtocol.getClientKey() != null && !mqttProtocol.getClientKey().isEmpty()) {
|
||||
String formatClientKey = CertificateFormatter.formatPrivateKey(mqttProtocol.getClientKey());
|
||||
try (PEMParser pemParser = new PEMParser(new StringReader(formatClientKey))) {
|
||||
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
|
||||
Object object = pemParser.readObject();
|
||||
|
||||
if (object instanceof PEMKeyPair) {
|
||||
privateKey = converter.getPrivateKey(((PEMKeyPair) object).getPrivateKeyInfo());
|
||||
} else if (object instanceof PrivateKeyInfo) {
|
||||
privateKey = converter.getPrivateKey((PrivateKeyInfo) object);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported private key type");
|
||||
}
|
||||
|
||||
ks.setKeyEntry("private-key", privateKey, "".toCharArray(), chain);
|
||||
}
|
||||
}
|
||||
|
||||
TrustManager[] trustManagers;
|
||||
if (insecureSkipVerify) {
|
||||
trustManagers = createInsecureTrustManager();
|
||||
} else {
|
||||
String formatCaCert = CertificateFormatter.formatCertificateChain(mqttProtocol.getCaCert());
|
||||
KeyStore trustStore = createMergedTrustStore(formatCaCert);
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||
tmf.init(trustStore);
|
||||
trustManagers = tmf.getTrustManagers();
|
||||
}
|
||||
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
||||
kmf.init(ks, "".toCharArray());
|
||||
|
||||
|
||||
SSLContext context = SSLContext.getInstance(mqttProtocol.getTlsVersion());
|
||||
context.init(kmf.getKeyManagers(), trustManagers, null);
|
||||
|
||||
return context.getSocketFactory();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Fails to SSL initialize: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get SSL Socket Factory
|
||||
*/
|
||||
public static SSLSocketFactory getSslSocketFactory(MqttProtocol mqttProtocol, boolean insecureSkipVerify) {
|
||||
try {
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
|
||||
|
||||
TrustManager[] trustManagers;
|
||||
if (insecureSkipVerify) {
|
||||
trustManagers = createInsecureTrustManager();
|
||||
} else {
|
||||
|
||||
String formatCaCert = CertificateFormatter.formatCertificateChain(mqttProtocol.getCaCert());
|
||||
KeyStore trustStore = createMergedTrustStore(formatCaCert);
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||
tmf.init(trustStore);
|
||||
trustManagers = tmf.getTrustManagers();
|
||||
}
|
||||
|
||||
SSLContext sslContext = SSLContext.getInstance(mqttProtocol.getTlsVersion());
|
||||
sslContext.init(null, trustManagers, null);
|
||||
|
||||
return sslContext.getSocketFactory();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Fails to SSL initialize: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private static TrustManager[] createInsecureTrustManager() {
|
||||
return new TrustManager[]{
|
||||
new X509TrustManager() {
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType) {
|
||||
}
|
||||
|
||||
public void checkServerTrusted(X509Certificate[] chain, String authType) {
|
||||
}
|
||||
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return new X509Certificate[0];
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static KeyStore createMergedTrustStore(String caCertPem) throws Exception {
|
||||
KeyStore mergedKs = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
mergedKs.load(null, null);
|
||||
|
||||
|
||||
TrustManagerFactory systemTmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||
systemTmf.init((KeyStore) null);
|
||||
X509TrustManager systemTm = (X509TrustManager) systemTmf.getTrustManagers()[0];
|
||||
|
||||
int systemIndex = 1;
|
||||
for (X509Certificate cert : systemTm.getAcceptedIssuers()) {
|
||||
mergedKs.setCertificateEntry("system-ca-" + systemIndex++, cert);
|
||||
}
|
||||
|
||||
|
||||
if (caCertPem != null && !caCertPem.isEmpty()) {
|
||||
try (InputStream caIn = new ByteArrayInputStream(caCertPem.getBytes())) {
|
||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||
Collection<? extends Certificate> customCerts = cf.generateCertificates(caIn);
|
||||
|
||||
int customIndex = 1;
|
||||
for (Certificate cert : customCerts) {
|
||||
mergedKs.setCertificateEntry("custom-ca-" + customIndex++, cert);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mergedKs;
|
||||
}
|
||||
}
|
||||
+61
-78
@@ -17,108 +17,91 @@
|
||||
|
||||
package org.apache.hertzbeat.collector.collect.mqtt;
|
||||
|
||||
import com.hivemq.client.mqtt.MqttVersion;
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.apache.hertzbeat.collector.dispatch.DispatchConstants;
|
||||
import org.apache.hertzbeat.common.entity.job.Metrics;
|
||||
import org.apache.hertzbeat.common.entity.job.protocol.MqttProtocol;
|
||||
import org.apache.hertzbeat.common.entity.message.CollectRep;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
/**
|
||||
* Test case for {@link MqttCollectImpl}
|
||||
*/
|
||||
public class MqttCollectTest {
|
||||
class MqttCollectTest {
|
||||
private MqttCollectImpl mqttCollect;
|
||||
private Metrics metrics;
|
||||
private CollectRep.MetricsData.Builder builder;
|
||||
private MqttProtocol.MqttProtocolBuilder mqttBuilder;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
void setup() {
|
||||
mqttCollect = new MqttCollectImpl();
|
||||
MqttProtocol mqtt = MqttProtocol.builder().build();
|
||||
metrics = Metrics.builder()
|
||||
.mqtt(mqtt)
|
||||
.build();
|
||||
builder = CollectRep.MetricsData.newBuilder();
|
||||
metrics = new Metrics();
|
||||
|
||||
// Initialize base MQTT parameters for test cases
|
||||
mqttBuilder = MqttProtocol.builder()
|
||||
.host("example.com")
|
||||
.port("1883")
|
||||
.protocol("mqtt")
|
||||
.timeout("5000")
|
||||
.keepalive("60");
|
||||
}
|
||||
|
||||
// Region: preCheck validation tests
|
||||
|
||||
@Test
|
||||
// Verify preCheck throws exception when host is missing
|
||||
void preCheckShouldThrowWhenHostMissing() {
|
||||
metrics.setMqtt(mqttBuilder.host("").build());
|
||||
assertThrows(IllegalArgumentException.class, () -> mqttCollect.preCheck(metrics));
|
||||
}
|
||||
|
||||
@Test
|
||||
void preCheck() {
|
||||
// host is empty
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
mqttCollect.preCheck(metrics);
|
||||
});
|
||||
|
||||
// port is empty
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
MqttProtocol mqtt = MqttProtocol.builder().build();
|
||||
mqtt.setHost("example.com");
|
||||
metrics.setMqtt(mqtt);
|
||||
mqttCollect.preCheck(metrics);
|
||||
});
|
||||
|
||||
// protocol version is empty
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
MqttProtocol mqtt = MqttProtocol.builder().build();
|
||||
mqtt.setHost("example.com");
|
||||
mqtt.setPort("1883");
|
||||
metrics.setMqtt(mqtt);
|
||||
mqttCollect.preCheck(metrics);
|
||||
});
|
||||
|
||||
// everything is ok
|
||||
assertDoesNotThrow(() -> {
|
||||
MqttProtocol mqtt = MqttProtocol.builder().build();
|
||||
mqtt.setHost("example.com");
|
||||
mqtt.setPort("1883");
|
||||
metrics.setMqtt(mqtt);
|
||||
mqtt.setProtocolVersion("3.1.1");
|
||||
mqttCollect.preCheck(metrics);
|
||||
});
|
||||
// Verify preCheck throws exception when port is missing
|
||||
void preCheckShouldThrowWhenPortMissing() {
|
||||
metrics.setMqtt(mqttBuilder.port("").build());
|
||||
assertThrows(IllegalArgumentException.class, () -> mqttCollect.preCheck(metrics));
|
||||
}
|
||||
|
||||
@Test
|
||||
void supportProtocol() {
|
||||
Assertions.assertEquals(DispatchConstants.PROTOCOL_MQTT, mqttCollect.supportProtocol());
|
||||
// Verify preCheck throws exception when MQTTS mutual auth is enabled but CA cert is missing
|
||||
void preCheckShouldThrowWhenMqttsMutualAuthMissingCerts() {
|
||||
metrics.setMqtt(mqttBuilder
|
||||
.protocol("mqtts")
|
||||
.enableMutualAuth("true")
|
||||
.caCert("")
|
||||
.clientCert("client.crt")
|
||||
.clientKey("client.key")
|
||||
.build());
|
||||
assertThrows(IllegalArgumentException.class, () -> mqttCollect.preCheck(metrics));
|
||||
}
|
||||
|
||||
@Test
|
||||
void collect() {
|
||||
// with version 3.1.1
|
||||
assertDoesNotThrow(() -> {
|
||||
MqttProtocol mqtt = MqttProtocol.builder().build();
|
||||
mqtt.setHost("example.com");
|
||||
mqtt.setPort("1883");
|
||||
mqtt.setClientId("clientid");
|
||||
mqtt.setTimeout("1");
|
||||
mqtt.setProtocolVersion(MqttVersion.MQTT_3_1_1.name());
|
||||
// Verify preCheck succeeds with valid standard MQTT parameters
|
||||
void preCheckShouldSucceedWithValidMqttParams() {
|
||||
metrics.setMqtt(mqttBuilder.build());
|
||||
assertDoesNotThrow(() -> mqttCollect.preCheck(metrics));
|
||||
}
|
||||
|
||||
metrics.setMqtt(mqtt);
|
||||
metrics.setAliasFields(new ArrayList<>());
|
||||
@Test
|
||||
// Verify preCheck succeeds with valid MQTTS parameters including mutual authentication
|
||||
void preCheckShouldSucceedWithValidMqttsMutualAuth() {
|
||||
metrics.setMqtt(mqttBuilder
|
||||
.protocol("mqtts")
|
||||
.enableMutualAuth("true")
|
||||
.caCert("ca.pem")
|
||||
.clientCert("client.crt")
|
||||
.clientKey("client.key")
|
||||
.build());
|
||||
assertDoesNotThrow(() -> mqttCollect.preCheck(metrics));
|
||||
}
|
||||
// End region
|
||||
|
||||
mqttCollect.collect(builder, metrics);
|
||||
});
|
||||
|
||||
|
||||
assertDoesNotThrow(() -> {
|
||||
MqttProtocol mqtt = MqttProtocol.builder().build();
|
||||
mqtt.setHost("example.com");
|
||||
mqtt.setPort("1883");
|
||||
mqtt.setClientId("clientid");
|
||||
mqtt.setTimeout("1");
|
||||
mqtt.setProtocolVersion(MqttVersion.MQTT_5_0.name());
|
||||
|
||||
metrics.setMqtt(mqtt);
|
||||
metrics.setAliasFields(new ArrayList<>());
|
||||
|
||||
mqttCollect.collect(builder, metrics);
|
||||
});
|
||||
@Test
|
||||
// Verify supportProtocol method returns correct MQTT constant
|
||||
void supportProtocolShouldReturnMqttConstant() {
|
||||
assertEquals(DispatchConstants.PROTOCOL_MQTT, mqttCollect.supportProtocol());
|
||||
}
|
||||
}
|
||||
|
||||
+58
-41
@@ -33,49 +33,73 @@ import org.apache.commons.lang3.StringUtils;
|
||||
public class MqttProtocol implements CommonRequestProtocol, Protocol {
|
||||
|
||||
/**
|
||||
* ip address or domain name of the peer host
|
||||
*/
|
||||
private String host;
|
||||
|
||||
/**
|
||||
* peer host port
|
||||
*/
|
||||
private String port;
|
||||
|
||||
/**
|
||||
* username
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* password
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* time out period
|
||||
*/
|
||||
private String timeout;
|
||||
|
||||
/**
|
||||
* client id
|
||||
* mqtt client id
|
||||
*/
|
||||
private String clientId;
|
||||
|
||||
/**
|
||||
* message used to test whether the mqtt connection can be pushed normally
|
||||
* mqtt username
|
||||
*/
|
||||
private String testMessage;
|
||||
|
||||
private String username;
|
||||
/**
|
||||
* protocol version of mqtt
|
||||
* mqtt password
|
||||
*/
|
||||
private String protocolVersion;
|
||||
|
||||
private String password;
|
||||
/**
|
||||
* monitor topic
|
||||
* mqtt host
|
||||
*/
|
||||
private String host;
|
||||
/**
|
||||
* mqtt port
|
||||
*/
|
||||
private String port;
|
||||
/**
|
||||
* mqtt protocol version
|
||||
* MQTT,MQTTS
|
||||
*/
|
||||
private String protocol;
|
||||
/**
|
||||
* mqtt connect timeout
|
||||
* the maximum time to wait for a connection to be established
|
||||
*/
|
||||
private String timeout;
|
||||
/**
|
||||
* mqtt keepalive
|
||||
* between ping requests to the broker to keep the connection alive
|
||||
*/
|
||||
private String keepalive;
|
||||
/**
|
||||
* mqtt topic name
|
||||
*/
|
||||
private String topic;
|
||||
/**
|
||||
* mqtt publish message
|
||||
*/
|
||||
private String testMessage;
|
||||
/**
|
||||
* mqtt tls version
|
||||
* TLSv1.2, TLSv1.3
|
||||
*/
|
||||
private String tlsVersion;
|
||||
/**
|
||||
* mqtt tls insecure skip verify server certificate
|
||||
*/
|
||||
private String insecureSkipVerify;
|
||||
/**
|
||||
* mqtt tls ca cert
|
||||
*/
|
||||
private String caCert;
|
||||
/**
|
||||
* mqtt tls enable mutual auth
|
||||
*/
|
||||
private String enableMutualAuth;
|
||||
/**
|
||||
* mqtt tls client cert
|
||||
*/
|
||||
private String clientCert;
|
||||
/**
|
||||
* mqtt tls client key
|
||||
*/
|
||||
private String clientKey;
|
||||
|
||||
/**
|
||||
* Determine whether authentication is required
|
||||
@@ -85,11 +109,4 @@ public class MqttProtocol implements CommonRequestProtocol, Protocol {
|
||||
return StringUtils.isNotBlank(this.username) && StringUtils.isNotBlank(this.password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether you need to test whether messages can be pushed normally
|
||||
* @return turn if it has test message
|
||||
*/
|
||||
public boolean testPublish(){
|
||||
return StringUtils.isNotBlank(this.testMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,11 +21,13 @@ app: kingbase
|
||||
name:
|
||||
zh-CN: Kingbase数据库
|
||||
en-US: Kingbase DB
|
||||
ja-JP: Kingbaseデータベース
|
||||
# The description and help of this monitoring type
|
||||
help:
|
||||
zh-CN: HertzBeat 使用 <a class='help_module_content' href='https://hertzbeat.apache.org/docs/advanced/extend-jdbc'> JDBC 协议</a> 通过配置 SQL 对 Kingbase 数据库的通用性能指标 (basic、state、activity etc) 进行采集监控,支持版本为 KingbaseV8r6+。<br>您可以点击“<i>新建 Kingbase 数据库</i>”并进行配置,或者选择“<i>更多操作</i>”,导入已有配置。
|
||||
en-US: HertzBeat uses <a class='help_module_content' href='https://hertzbeat.apache.org/docs/advanced/extend-jdbc'> JDBC Protocol</a> to configure SQL for collecting general metrics of Kingbase database (basic、state、activity etc). Supported version is KingbaseV8r6+. <br>You can click "<i>New Kingbase Database</i>" and configure it, or select "<i>More Action</i>" to import the existing configuration.
|
||||
zh-TW: HertzBeat 使用 <a class='help_module_content' href='https://hertzbeat.apache.org/docs/advanced/extend-jdbc'> JDBC 協議</a> 通過配置 SQL 對 Kingbase 數據庫的通用性能指標 (basic、state、activity etc)進行采集監控,支持版本爲 KingbaseV8r6+。<br>您可以點擊“<i>新建 Kingbase 數據庫</i>”並進行配置,或者選擇“<i>更多操作</i>”,導入已有配置。
|
||||
ja-JP: Hertzbeat は <a class='help_module_content' href='https://hertzbeat.apache.org/docs/advanced/extend-jdbc'> JDBCプロトコルを介して</a> Kingbase データベース(V8r6+)の一般的なパフォーマンスのメトリクスを監視します。<br>「<i>新規 Kingbase データベース</i>」をクリックしてパラメタを設定した後、新規することができます。
|
||||
helpLink:
|
||||
zh-CN: https://hertzbeat.apache.org/zh-cn/docs/help/kingbase
|
||||
en-US: https://hertzbeat.apache.org/docs/help/kingbase
|
||||
@@ -37,6 +39,7 @@ params:
|
||||
name:
|
||||
zh-CN: 目标Host
|
||||
en-US: Target Host
|
||||
ja-JP: 目標ホスト
|
||||
# type-param field type(most mapping the html input type)
|
||||
type: host
|
||||
# required-true or false
|
||||
@@ -47,6 +50,7 @@ params:
|
||||
name:
|
||||
zh-CN: 端口
|
||||
en-US: Port
|
||||
ja-JP: ポート
|
||||
# type-param field type(most mapping the html input type)
|
||||
type: number
|
||||
# when type is number, range is required
|
||||
@@ -59,6 +63,7 @@ params:
|
||||
name:
|
||||
zh-CN: 查询超时时间(ms)
|
||||
en-US: Query Timeout(ms)
|
||||
ja-JP: クエリタイムアウト(ms)
|
||||
type: number
|
||||
range: '[400,200000]'
|
||||
required: false
|
||||
@@ -68,6 +73,7 @@ params:
|
||||
name:
|
||||
zh-CN: 数据库名称
|
||||
en-US: Database Name
|
||||
ja-JP: データベース名
|
||||
type: text
|
||||
defaultValue: kingbase
|
||||
required: false
|
||||
@@ -75,6 +81,7 @@ params:
|
||||
name:
|
||||
zh-CN: 用户名
|
||||
en-US: Username
|
||||
ja-JP: ユーザー名
|
||||
type: text
|
||||
limit: 50
|
||||
required: false
|
||||
@@ -82,12 +89,14 @@ params:
|
||||
name:
|
||||
zh-CN: 密码
|
||||
en-US: Password
|
||||
ja-JP: パスワード
|
||||
type: password
|
||||
required: false
|
||||
- field: url
|
||||
name:
|
||||
zh-CN: URL
|
||||
en-US: URL
|
||||
ja-JP: URL
|
||||
type: text
|
||||
required: false
|
||||
hide: true
|
||||
@@ -99,6 +108,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 基本信息
|
||||
en-US: Basic Info
|
||||
ja-JP: 基礎情報
|
||||
# metrics scheduling priority(0->127)->(high->low), metrics with the same priority will be scheduled in parallel
|
||||
# priority 0's metrics is availability metrics, it will be scheduled first, only availability metrics collect success will the scheduling continue
|
||||
priority: 0
|
||||
@@ -111,26 +121,31 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 服务器版本
|
||||
en-US: Server Version
|
||||
ja-JP: バージョン
|
||||
- field: port
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 端口
|
||||
en-US: Port
|
||||
ja-JP: ポート
|
||||
- field: server_encoding
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 服务器编码
|
||||
en-US: Server Encoding
|
||||
ja-JP: サーバーのエンコード
|
||||
- field: data_directory
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 数据目录
|
||||
en-US: Data Directory
|
||||
ja-JP: データディレクトリ
|
||||
- field: max_connections
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 最大连接数
|
||||
en-US: Max Connections
|
||||
ja-JP: 最大接続数
|
||||
# the protocol used for monitoring, eg: sql, ssh, http, telnet, wmi, snmp, sdk
|
||||
protocol: jdbc
|
||||
# the config content when protocol is jdbc
|
||||
@@ -155,6 +170,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 状态信息
|
||||
en-US: State Info
|
||||
ja-JP: 状態情報
|
||||
priority: 1
|
||||
fields:
|
||||
- field: db_name
|
||||
@@ -163,47 +179,55 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 数据库名称
|
||||
en-US: Database Name
|
||||
ja-JP: データベース名
|
||||
- field: conflicts
|
||||
type: 0
|
||||
unit: times
|
||||
i18n:
|
||||
zh-CN: 冲突次数
|
||||
en-US: Conflicts
|
||||
ja-JP: コンフリクト回数
|
||||
- field: deadlocks
|
||||
type: 0
|
||||
unit: times
|
||||
i18n:
|
||||
zh-CN: 死锁次数
|
||||
en-US: Deadlocks
|
||||
ja-JP: デッドロック回数
|
||||
- field: blks_read
|
||||
type: 0
|
||||
unit: blocks per second
|
||||
i18n:
|
||||
zh-CN: 读取块
|
||||
en-US: Blocks Read
|
||||
ja-JP: 読み取られたブロック
|
||||
- field: blks_hit
|
||||
type: 0
|
||||
unit: blocks per second
|
||||
i18n:
|
||||
zh-CN: 命中块
|
||||
en-US: Blocks Hit
|
||||
ja-JP: ヒットブロック
|
||||
- field: blk_read_time
|
||||
type: 0
|
||||
unit: ms
|
||||
i18n:
|
||||
zh-CN: 读取时间
|
||||
en-US: Read Time
|
||||
ja-JP: 読み取られタイム
|
||||
- field: blk_write_time
|
||||
type: 0
|
||||
unit: ms
|
||||
i18n:
|
||||
zh-CN: 写入时间
|
||||
en-US: Write Time
|
||||
ja-JP: 書き込まれ時間
|
||||
- field: stats_reset
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 统计重置
|
||||
en-US: Stats Reset
|
||||
ja-JP: 統計リセット
|
||||
protocol: jdbc
|
||||
jdbc:
|
||||
host: ^_^host^_^
|
||||
@@ -221,6 +245,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 活动信息
|
||||
en-US: Activity Info
|
||||
ja-JP: 活動情報
|
||||
priority: 2
|
||||
fields:
|
||||
- field: running
|
||||
@@ -229,6 +254,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 运行中
|
||||
en-US: Running
|
||||
ja-JP: 実行中
|
||||
protocol: jdbc
|
||||
jdbc:
|
||||
host: ^_^host^_^
|
||||
@@ -246,6 +272,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 资源配置
|
||||
en-US: Resource Config
|
||||
ja-JP: リソース設定
|
||||
priority: 3
|
||||
fields:
|
||||
- field: work_mem
|
||||
@@ -254,34 +281,40 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 工作内存
|
||||
en-US: Work Memory
|
||||
ja-JP: ワークメモリ
|
||||
- field: shared_buffers
|
||||
type: 0
|
||||
unit: MB
|
||||
i18n:
|
||||
zh-CN: 共享缓冲区
|
||||
en-US: Shared Buffers
|
||||
ja-JP: 共有バッファ
|
||||
- field: autovacuum
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 自动清理
|
||||
en-US: Auto Vacuum
|
||||
ja-JP: オートバキューム
|
||||
- field: max_connections
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 最大连接数
|
||||
en-US: Max Connections
|
||||
ja-JP: 最大接続数
|
||||
- field: effective_cache_size
|
||||
type: 0
|
||||
unit: MB
|
||||
i18n:
|
||||
zh-CN: 有效缓存大小
|
||||
en-US: Effective Cache Size
|
||||
ja-JP: キャッシュサイズ
|
||||
- field: wal_buffers
|
||||
type: 0
|
||||
unit: MB
|
||||
i18n:
|
||||
zh-CN: WAL缓冲区
|
||||
en-US: WAL Buffers
|
||||
ja-JP: WALバッファ
|
||||
protocol: jdbc
|
||||
jdbc:
|
||||
host: ^_^host^_^
|
||||
@@ -299,6 +332,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 连接信息
|
||||
en-US: Connection Info
|
||||
ja-JP: 接続情報
|
||||
priority: 4
|
||||
fields:
|
||||
- field: active
|
||||
@@ -306,6 +340,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 活动连接
|
||||
en-US: Active Connection
|
||||
ja-JP: 活躍的な接続
|
||||
protocol: jdbc
|
||||
jdbc:
|
||||
host: ^_^host^_^
|
||||
@@ -323,6 +358,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 连接状态
|
||||
en-US: Connection State
|
||||
ja-JP: 接続状態
|
||||
priority: 5
|
||||
fields:
|
||||
- field: state
|
||||
@@ -331,11 +367,13 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 状态
|
||||
en-US: State
|
||||
ja-JP: 状態
|
||||
- field: num
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 数量
|
||||
en-US: Num
|
||||
ja-JP: 数量
|
||||
protocol: jdbc
|
||||
jdbc:
|
||||
host: ^_^host^_^
|
||||
@@ -353,6 +391,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 连接数据库
|
||||
en-US: Connection Db
|
||||
ja-JP: 接続データベース
|
||||
priority: 6
|
||||
fields:
|
||||
- field: db_name
|
||||
@@ -361,11 +400,13 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 数据库名称
|
||||
en-US: Database Name
|
||||
ja-JP: データベース名
|
||||
- field: active
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 活动连接
|
||||
en-US: Active Connection
|
||||
ja-JP: 活躍的な接続
|
||||
protocol: jdbc
|
||||
jdbc:
|
||||
host: ^_^host^_^
|
||||
@@ -383,6 +424,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 元组信息
|
||||
en-US: Tuple Info
|
||||
ja-JP: 組情報
|
||||
priority: 7
|
||||
fields:
|
||||
- field: fetched
|
||||
@@ -390,26 +432,31 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 获取次数
|
||||
en-US: Fetched
|
||||
ja-JP: フェッチ回数
|
||||
- field: returned
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 返回次数
|
||||
en-US: Returned
|
||||
ja-JP: 戻る回数
|
||||
- field: inserted
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 插入次数
|
||||
en-US: Inserted
|
||||
ja-JP: インサート回数
|
||||
- field: updated
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 更新次数
|
||||
en-US: Updated
|
||||
ja-JP: 更新回数
|
||||
- field: deleted
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 删除次数
|
||||
en-US: Deleted
|
||||
ja-JP: 削除回数
|
||||
protocol: jdbc
|
||||
jdbc:
|
||||
host: ^_^host^_^
|
||||
@@ -427,6 +474,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 临时文件
|
||||
en-US: Temp File
|
||||
ja-JP: 一時ファイル
|
||||
priority: 8
|
||||
fields:
|
||||
- field: db_name
|
||||
@@ -435,17 +483,20 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 数据库名称
|
||||
en-US: Database Name
|
||||
ja-JP: データベース名
|
||||
- field: num
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 次数
|
||||
en-US: Num
|
||||
ja-JP: 数量
|
||||
- field: size
|
||||
type: 0
|
||||
unit: B
|
||||
i18n:
|
||||
zh-CN: 大小
|
||||
en-US: Size
|
||||
ja-JP: サイズ
|
||||
protocol: jdbc
|
||||
jdbc:
|
||||
host: ^_^host^_^
|
||||
@@ -463,6 +514,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 锁信息
|
||||
en-US: Lock Info
|
||||
ja-JP: ロック情報
|
||||
priority: 9
|
||||
fields:
|
||||
- field: db_name
|
||||
@@ -471,18 +523,21 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 数据库名称
|
||||
en-US: Database Name
|
||||
ja-JP: データベース名
|
||||
- field: conflicts
|
||||
type: 0
|
||||
unit: times
|
||||
i18n:
|
||||
zh-CN: 冲突次数
|
||||
en-US: Conflicts
|
||||
ja-JP: コンフリクト回数
|
||||
- field: deadlocks
|
||||
type: 0
|
||||
unit: times
|
||||
i18n:
|
||||
zh-CN: 死锁次数
|
||||
en-US: Deadlocks
|
||||
ja-JP: デッドロック回数
|
||||
protocol: jdbc
|
||||
jdbc:
|
||||
host: ^_^host^_^
|
||||
@@ -500,6 +555,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 慢查询
|
||||
en-US: Slow Sql
|
||||
ja-JP: スローSQL
|
||||
priority: 10
|
||||
fields:
|
||||
- field: sql_text
|
||||
@@ -508,28 +564,33 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: SQL语句
|
||||
en-US: SQL Text
|
||||
ja-JP: SQL文のテキスト
|
||||
- field: calls
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 调用次数
|
||||
en-US: Calls
|
||||
ja-JP: コール回数
|
||||
- field: rows
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 行数
|
||||
en-US: Rows
|
||||
ja-JP: 行
|
||||
- field: avg_time
|
||||
type: 0
|
||||
unit: ms
|
||||
i18n:
|
||||
zh-CN: 平均时间
|
||||
en-US: Avg Time
|
||||
ja-JP: 平均時間
|
||||
- field: total_time
|
||||
type: 0
|
||||
unit: ms
|
||||
i18n:
|
||||
zh-CN: 总时间
|
||||
en-US: Total Time
|
||||
ja-JP: 合計時間
|
||||
aliasFields:
|
||||
- query
|
||||
- calls
|
||||
@@ -557,6 +618,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 事务信息
|
||||
en-US: Transaction Info
|
||||
ja-JP: トランザクション情報
|
||||
priority: 12
|
||||
fields:
|
||||
- field: db_name
|
||||
@@ -565,18 +627,21 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 数据库名称
|
||||
en-US: Database Name
|
||||
ja-JP: データベース名
|
||||
- field: commits
|
||||
type: 0
|
||||
unit: times
|
||||
i18n:
|
||||
zh-CN: 提交次数
|
||||
en-US: Commits
|
||||
ja-JP: コミット回数
|
||||
- field: rollbacks
|
||||
type: 0
|
||||
unit: times
|
||||
i18n:
|
||||
zh-CN: 回滚次数
|
||||
en-US: Rollbacks
|
||||
ja-JP: ロールバック回数
|
||||
protocol: jdbc
|
||||
jdbc:
|
||||
host: ^_^host^_^
|
||||
@@ -594,6 +659,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 冲突信息
|
||||
en-US: Conflicts Info
|
||||
ja-JP: コンフリクト情報
|
||||
priority: 13
|
||||
fields:
|
||||
- field: db_name
|
||||
@@ -602,31 +668,37 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 数据库名称
|
||||
en-US: Database Name
|
||||
ja-JP: データベース名
|
||||
- field: tablespace
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 表空间
|
||||
en-US: Tablespace
|
||||
ja-JP: 表領域
|
||||
- field: lock
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 锁
|
||||
en-US: Lock
|
||||
ja-JP: ロック
|
||||
- field: snapshot
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 快照
|
||||
en-US: Snapshot
|
||||
ja-JP: スナップショット
|
||||
- field: bufferpin
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 缓冲区
|
||||
en-US: Bufferpin
|
||||
ja-JP: バッファ
|
||||
- field: deadlock
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 死锁
|
||||
en-US: Deadlock
|
||||
ja-JP: デッドロック
|
||||
protocol: jdbc
|
||||
jdbc:
|
||||
host: ^_^host^_^
|
||||
@@ -644,6 +716,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 缓存命中率
|
||||
en-US: Cache Hit Ratio
|
||||
ja-JP: キャッシュ命中率
|
||||
priority: 14
|
||||
fields:
|
||||
- field: db_name
|
||||
@@ -652,12 +725,14 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 数据库名称
|
||||
en-US: Database Name
|
||||
ja-JP: データベース名
|
||||
- field: ratio
|
||||
type: 0
|
||||
unit: '%'
|
||||
i18n:
|
||||
zh-CN: 命中率
|
||||
en-US: Hit Ratio
|
||||
ja-JP: 命中率
|
||||
aliasFields:
|
||||
- blks_hit
|
||||
- blks_read
|
||||
@@ -681,6 +756,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: Checkpoint信息
|
||||
en-US: Checkpoint Info
|
||||
ja-JP: チェックポイント情報
|
||||
priority: 15
|
||||
fields:
|
||||
- field: checkpoint_sync_time
|
||||
@@ -689,12 +765,14 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: Checkpoint同步时间
|
||||
en-US: Checkpoint Sync Time
|
||||
ja-JP: チェックポイント同期時間
|
||||
- field: checkpoint_write_time
|
||||
type: 0
|
||||
unit: ms
|
||||
i18n:
|
||||
zh-CN: Checkpoint写入时间
|
||||
en-US: Checkpoint Write Time
|
||||
ja-JP: Checkpoint書き込まれた時間
|
||||
protocol: jdbc
|
||||
jdbc:
|
||||
host: ^_^host^_^
|
||||
@@ -712,6 +790,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: Buffer信息
|
||||
en-US: Buffer Info
|
||||
ja-JP: バッファ情報
|
||||
priority: 16
|
||||
fields:
|
||||
- field: allocated
|
||||
@@ -719,26 +798,31 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 已分配
|
||||
en-US: Allocated
|
||||
ja-JP: 割り当てバッファ
|
||||
- field: fsync_calls_by_backend
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 后端进程直接执行的文件同步调用次数
|
||||
en-US: Fsync Calls By Backend
|
||||
ja-JP: バックエンド同期コール回数
|
||||
- field: written_directly_by_backend
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 后台写入到数据文件
|
||||
en-US: Written Directly By Backend
|
||||
ja-JP: バックエンドによる直接書き込まれたファイル
|
||||
- field: written_by_background_writer
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 后台写入
|
||||
en-US: Written By Background Writer
|
||||
ja-JP: バックグラウンドライターに書き込まれた
|
||||
- field: written_during_checkpoints
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 检查点期间写入
|
||||
en-US: Written During Checkpoints
|
||||
ja-JP: チェックポイント中の書き込み
|
||||
protocol: jdbc
|
||||
jdbc:
|
||||
host: ^_^host^_^
|
||||
|
||||
@@ -21,11 +21,13 @@ app: kubernetes
|
||||
name:
|
||||
zh-CN: Kubernetes
|
||||
en-US: Kubernetes
|
||||
ja-JP: Kubernetes
|
||||
# The description and help of this monitoring type
|
||||
help:
|
||||
zh-CN: HertzBeat 通过查询 Kubernetes ApiServer api 来对 kubernetes 的通用性能指标(nodes、namespaces、pods、services)进行采集监控。<br><span class='help_module_span'>注意⚠️:为了监控 Kubernetes 中的信息,则需要获取到可访问 Api Server 的授权 TOKEN,让采集请求获取到对应的信息,<a class='help_module_content' href='https://hertzbeat.apache.org/zh-cn/docs/help/kubernetes'>点击查看获取步骤</a>。</span>
|
||||
en-US: HertzBeat monitoring Kubernetes general metrics such as nodes, namespaces and pods through querying data from Kubernetes ApiServer api. <br><span class='help_module_span'>Note⚠️:In order to monitor the information of Kubernetes, Hertzbeat need to obtain the authorized TOKEN that can access Api Server. <a class='help_module_content' href='https://hertzbeat.apache.org/docs/help/kubernetes'>Click here to view the specific steps.</a></span>
|
||||
zh-TW: HertzBeat 通過查詢 Kubernetes ApiServer api 來對 kubernetes 的通用性能指標(nodes、namespaces、pods、services)進行采集監控。<br><span class='help_module_span'>注意⚠️:爲了監控 Kubernetes 中的信息,則需要獲取到可訪問 Api Server 的授權 TOKEN,讓采集請求獲取到對應的信息,<a class='help_module_content' href='https://hertzbeat.apache.org/zh-cn/docs/help/kubernetes'>點擊查看獲取步驟</a>。</span>
|
||||
ja-JP: HertzBeat は Kubernetes ApiServer api を呼び出し、kubernetes の一般的なパフォーマンスのメトリクスを収集して監視します。<br><span class='help_module_span'>注意⚠️:Kubernetesでメトリクスを監視するためには、Api Serverにアクセスするための認可されたTOKENを取得する必要があります。<a class='help_module_content' href='https://hertzbeat.apache.org/docs/help/kubernetes'>クリックしてガイドを見ます</a>。</span>
|
||||
helpLink:
|
||||
zh-CN: https://hertzbeat.apache.org/zh-cn/docs/help/kubernetes
|
||||
en-US: https://hertzbeat.apache.org/docs/help/kubernetes
|
||||
@@ -37,6 +39,7 @@ params:
|
||||
name:
|
||||
zh-CN: 目标Host
|
||||
en-US: Target Host
|
||||
ja-JP: 目標ホスト
|
||||
# type-param field type(most mapping the html input type)
|
||||
type: host
|
||||
# required-true or false
|
||||
@@ -47,6 +50,7 @@ params:
|
||||
name:
|
||||
zh-CN: ApiServer端口
|
||||
en-US: ApiServer Port
|
||||
ja-JP: ApiServerポート
|
||||
# type-param field type(most mapping the html input type)
|
||||
type: number
|
||||
# when type is number, range is required
|
||||
@@ -61,6 +65,7 @@ params:
|
||||
name:
|
||||
zh-CN: 认证方式
|
||||
en-US: Auth Type
|
||||
ja-JP: 認証方法
|
||||
# type-param field type(radio mapping the html radio tag)
|
||||
type: radio
|
||||
# required-true or false
|
||||
@@ -74,6 +79,7 @@ params:
|
||||
name:
|
||||
zh-CN: 认证Token
|
||||
en-US: Access Token
|
||||
ja-JP: アクセストークン
|
||||
type: text
|
||||
required: true
|
||||
# collect metrics config list
|
||||
@@ -91,38 +97,45 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 节点名称
|
||||
en-US: Node Name
|
||||
ja-JP: ノード名
|
||||
- field: is_ready
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 节点就绪状态
|
||||
en-US: Node Ready Status
|
||||
ja-JP: ノード準備完了
|
||||
- field: capacity_cpu
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: CPU 容量
|
||||
en-US: CPU Capacity
|
||||
ja-JP: CPU 容量
|
||||
- field: allocatable_cpu
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 可分配 CPU
|
||||
en-US: Allocatable CPU
|
||||
ja-JP: 割り当て可能CPU
|
||||
- field: capacity_memory
|
||||
type: 0
|
||||
unit: Mi
|
||||
i18n:
|
||||
zh-CN: 内存容量
|
||||
en-US: Memory Capacity
|
||||
ja-JP: メモリ容量
|
||||
- field: allocatable_memory
|
||||
type: 0
|
||||
unit: Mi
|
||||
i18n:
|
||||
zh-CN: 可分配内存
|
||||
en-US: Allocatable Memory
|
||||
ja-JP: 割り当て可能CPUメモリ
|
||||
- field: creation_time
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 创建时间
|
||||
en-US: Creation Time
|
||||
ja-JP: 作成時間
|
||||
# (optional)metrics field alias name, it is used as an alias field to map and convert the collected data and metrics field
|
||||
aliasFields:
|
||||
- $.metadata.name
|
||||
@@ -167,16 +180,19 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 命名空间
|
||||
en-US: Namespace
|
||||
ja-JP: 名前空間
|
||||
- field: status
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 状态
|
||||
en-US: Status
|
||||
ja-JP: ステータス
|
||||
- field: creation_time
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 创建时间
|
||||
en-US: Creation Time
|
||||
ja-JP: 作成時間
|
||||
aliasFields:
|
||||
- $.metadata.name
|
||||
- $.status.phase
|
||||
@@ -206,41 +222,49 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: Pod名称
|
||||
en-US: Pod Name
|
||||
ja-JP: ポッド名
|
||||
- field: namespace
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 命名空间
|
||||
en-US: Namespace
|
||||
ja-JP: 名前空間
|
||||
- field: status
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 状态
|
||||
en-US: Status
|
||||
ja-JP: ステータス
|
||||
- field: restart
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 重启次数
|
||||
en-US: Restart Count
|
||||
ja-JP: リスタート回数
|
||||
- field: host_ip
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 主机IP
|
||||
en-US: Host IP
|
||||
ja-JP: ホストIP
|
||||
- field: pod_ip
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: Pod IP
|
||||
en-US: Pod IP
|
||||
ja-JP: ポッドIP
|
||||
- field: creation_time
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 创建时间
|
||||
en-US: Creation Time
|
||||
ja-JP: 作成時間
|
||||
- field: start_time
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 启动时间
|
||||
en-US: Start Time
|
||||
ja-JP: 起動時間
|
||||
aliasFields:
|
||||
- $.metadata.name
|
||||
- $.metadata.namespace
|
||||
@@ -280,31 +304,37 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 服务
|
||||
en-US: Service
|
||||
ja-JP: サービス
|
||||
- field: namespace
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 命名空间
|
||||
en-US: Namespace
|
||||
ja-JP: 名前空間
|
||||
- field: type
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 类型
|
||||
en-US: Type
|
||||
ja-JP: タイプ
|
||||
- field: cluster_ip
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 集群IP
|
||||
en-US: Cluster IP
|
||||
ja-JP: クラスタIP
|
||||
- field: selector
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 选择器
|
||||
en-US: Selector
|
||||
ja-JP: セレクター
|
||||
- field: creation_time
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 创建时间
|
||||
en-US: Creation Time
|
||||
ja-JP: 作成時間
|
||||
aliasFields:
|
||||
- $.metadata.name
|
||||
- $.metadata.namespace
|
||||
|
||||
@@ -21,11 +21,13 @@ app: kvrocks
|
||||
name:
|
||||
zh-CN: Kvrocks 数据库
|
||||
en-US: Kvrocks
|
||||
ja-JP: Kvrocksデータベース
|
||||
# The description and help of this monitoring type
|
||||
help:
|
||||
zh-CN: HertzBeat 对 Apache Kvrocks 数据库的通用性能指标进行采集监控(server、clients、memory、persistence、stats、replication、cpu、cluster、commandstats),支持版本为 Apache Kvrocks 2.9.0+。<br>您可以点击“<i>新建 Kvrocks 数据库</i>”并进行配置,或者选择“<i>更多操作</i>”,导入已有配置。
|
||||
en-US: HertzBeat monitors Apache Kvrocks database of general performance metrics such as memory, persistence, replication and so on. The versions we support is Apache Kvrocks 2.9.0+. <br>You could click the "<i>New Kvrocks</i>" button and proceed with the configuration or import an existing setup through the "<i>More Actions</i>" menu.
|
||||
zh-TW: HertzBeat 對 Apache Kvrocks 數據庫的通用性能指標進行采集監控(server、clients、memory、persistence、stats、replication、cpu、cluster、commandstats),支持版本爲 Apache Kvrocks 2.9.0+。<br>您可以點擊“<i>新建 Kvrocks 數據庫</i>”並進行配置,或者選擇“<i>更多操作</i>”,導入已有配置。
|
||||
ja-JP: Hertzbeat は Apache Kvrocks データベース(2.9.0+)の一般的なパフォーマンスのメトリクスを監視します。<br>「<i>新規 Kvrocks データベース</i>」をクリックしてパラメタを設定した後、新規することができます。
|
||||
helpLink:
|
||||
zh-CN: https://hertzbeat.apache.org/zh-cn/docs/help/kvrocks
|
||||
en-US: https://hertzbeat.apache.org/docs/help/kvrocks
|
||||
@@ -37,6 +39,7 @@ params:
|
||||
name:
|
||||
zh-CN: 目标Host
|
||||
en-US: Target Host
|
||||
ja-JP: 目標ホスト
|
||||
# type-param field type(most mapping the html input type)
|
||||
type: host
|
||||
# required-true or false
|
||||
@@ -47,6 +50,7 @@ params:
|
||||
name:
|
||||
zh-CN: 端口
|
||||
en-US: Port
|
||||
ja-JP: ポート
|
||||
# type-param field type(most mapping the html input type)
|
||||
type: number
|
||||
# when type is number, range is required
|
||||
@@ -61,6 +65,7 @@ params:
|
||||
name:
|
||||
zh-CN: 超时时间
|
||||
en-US: Timeout
|
||||
ja-JP: タイムアウト
|
||||
# type-param field type(most mapping the html input type)
|
||||
type: number
|
||||
# when type is number, range is required
|
||||
@@ -74,6 +79,7 @@ params:
|
||||
name:
|
||||
zh-CN: 用户名
|
||||
en-US: Username
|
||||
ja-JP: ユーザー名
|
||||
type: text
|
||||
limit: 50
|
||||
required: false
|
||||
@@ -82,6 +88,7 @@ params:
|
||||
name:
|
||||
zh-CN: 密码
|
||||
en-US: Password
|
||||
ja-JP: パスワード
|
||||
type: password
|
||||
required: false
|
||||
|
||||
@@ -95,6 +102,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 服务器信息
|
||||
en-US: Server
|
||||
ja-JP: サーバー情報
|
||||
fields:
|
||||
# field-metric name, type-metric type(0-number,1-string), unit-metric unit('%','ms','MB'), label-whether it is a metrics label field
|
||||
- field: kvrocks_version
|
||||
@@ -102,101 +110,121 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: Kvrocks 服务版本
|
||||
en-US: Kvrocks Version
|
||||
ja-JP: Kvrocks バージョン
|
||||
- field: redis_version
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: Redis 服务版本
|
||||
en-US: Redis Version
|
||||
ja-JP: Redis バージョン
|
||||
- field: git_sha1
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: Kvrocks Git SHA1
|
||||
en-US: Kvrocks Git SHA1
|
||||
ja-JP: Kvrocks Git SHA1
|
||||
- field: kvrocks_mode
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 运行模式
|
||||
en-US: Server Mode
|
||||
ja-JP: サーバーモード
|
||||
- field: os
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 操作系统
|
||||
en-US: Operating System
|
||||
ja-JP: オーエス
|
||||
- field: arch_bits
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 架构
|
||||
en-US: Architecture Bits
|
||||
ja-JP: アーキテクチャ
|
||||
- field: multiplexing_api
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: IO多路复用器API
|
||||
en-US: Multiplexing API
|
||||
ja-JP: IO多重化API
|
||||
- field: atomicvar_api
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 原子操作处理API
|
||||
en-US: Atomicvar API
|
||||
ja-JP: 原子操作API
|
||||
- field: gcc_version
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: GCC版本
|
||||
en-US: GCC Version
|
||||
ja-JP: GCC バージョン
|
||||
- field: process_id
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 进程ID
|
||||
en-US: PID
|
||||
ja-JP: プロセスID
|
||||
- field: tcp_port
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: TCP/IP监听端口
|
||||
en-US: TCP Port
|
||||
ja-JP: TCP ポート
|
||||
- field: server_time_usec
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 服务器时间戳
|
||||
en-US: Server Time Usec
|
||||
ja-JP: サーバー時間
|
||||
- field: uptime_in_seconds
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 运行时长(秒)
|
||||
en-US: Uptime(Seconds)
|
||||
ja-JP: アップタイム(秒)
|
||||
- field: uptime_in_days
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 运行时长(天)
|
||||
en-US: Uptime(Days)
|
||||
ja-JP: アップタイム(日)
|
||||
- field: hz
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 事件循环频率
|
||||
en-US: hz
|
||||
ja-JP: hz
|
||||
- field: configured_hz
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 配置的事件循环频率
|
||||
en-US: Configured hz
|
||||
ja-JP: Configured hz
|
||||
- field: lru_clock
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: LRU时钟
|
||||
en-US: LRU Clock
|
||||
ja-JP: LRUクロック
|
||||
- field: executable
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 服务器执行路径
|
||||
en-US: Server's Executable Path
|
||||
ja-JP: サーバーの実行パス
|
||||
- field: config_file
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 配置文件路径
|
||||
en-US: Config File Path
|
||||
ja-JP: 配置ファイルのパス
|
||||
- field: io_threads_active
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 活跃IO线程数
|
||||
en-US: Active IO Threads
|
||||
ja-JP: 活動中のI/Oスレッド数
|
||||
# the protocol used for monitoring, eg: sql, ssh, http, telnet, wmi, snmp, sdk
|
||||
protocol: redis
|
||||
# the config content when protocol is redis
|
||||
@@ -219,6 +247,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 客户端信息
|
||||
en-US: Clients
|
||||
ja-JP: クライアント情報
|
||||
# collect metrics content
|
||||
fields:
|
||||
- field: connected_clients
|
||||
@@ -226,21 +255,25 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 已连接客户端数量
|
||||
en-US: Connected Clients
|
||||
ja-JP: 接続クライアント数
|
||||
- field: maxclients
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 最大客户端连接数
|
||||
en-US: Max Clients
|
||||
ja-JP: 最大クライアント数
|
||||
- field: blocked_clients
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 阻塞客户端数量
|
||||
en-US: Blocked Clients
|
||||
ja-JP: ブロックされたクライアント数
|
||||
- field: monitor_clients
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 监控的客户端数量
|
||||
en-US: monitor Clients
|
||||
ja-JP: モニタークライアント数
|
||||
protocol: redis
|
||||
redis:
|
||||
host: ^_^host^_^
|
||||
@@ -256,6 +289,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 内存信息
|
||||
en-US: Memory
|
||||
ja-JP: メモリ情報
|
||||
# collect metrics content
|
||||
fields:
|
||||
# field-metric name, type-metric type(0-number,1-string), unit-metric unit('%','ms','MB'), label-whether it is a metrics label field
|
||||
@@ -264,28 +298,33 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 已使用内存(字节)
|
||||
en-US: Used Memory RSS
|
||||
ja-JP: 使用した物理メモリ(バイト)
|
||||
- field: used_memory_rss_human
|
||||
type: 0
|
||||
unit: MB
|
||||
i18n:
|
||||
zh-CN: 已使用物理内存
|
||||
en-US: Used Memory RSS Human
|
||||
ja-JP: 使用した物理メモリ
|
||||
- field: used_memory_lua
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: LUA脚本占用的内存(字节)
|
||||
en-US: Used Memory LUA
|
||||
ja-JP: LUAが使用するメモリ(バイト)
|
||||
- field: used_memory_lua_human
|
||||
type: 0
|
||||
unit: KB
|
||||
i18n:
|
||||
zh-CN: LUA脚本占用的内存
|
||||
en-US: Used Memory LUA Human
|
||||
ja-JP: LUAが使用するメモリ
|
||||
- field: used_memory_startup
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 启动占用内存
|
||||
en-US: Used Memory Startup
|
||||
ja-JP: 起動時の使用メモリ
|
||||
# the protocol used for monitoring, eg: sql, ssh, http, telnet, wmi, snmp, sdk
|
||||
protocol: redis
|
||||
# the config content when protocol is redis
|
||||
@@ -309,6 +348,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 持久化信息
|
||||
en-US: Persistence
|
||||
ja-JP: 永続化
|
||||
# collect metrics content
|
||||
fields:
|
||||
# field-metric name, type-metric type(0-number,1-string), unit-metric unit('%','ms','MB'), label-whether it is a metrics label field
|
||||
@@ -317,26 +357,31 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 是否正在加载持久化文件
|
||||
en-US: Loading
|
||||
ja-JP: 読み込み中
|
||||
- field: bgsave_in_progress
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 是否正在进行bgsave
|
||||
en-US: bgsave In Progress
|
||||
ja-JP: bgsaveである
|
||||
- field: last_bgsave_time
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 最近一次bgsave命令执行时间
|
||||
en-US: Last Save Time
|
||||
ja-JP: 最後のbgsave実行時間
|
||||
- field: last_bgsave_status
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 最近一次bgsave命令执行状态
|
||||
en-US: Last bgsave Status
|
||||
ja-JP: 最後のbgsaveの実行状況
|
||||
- field: last_bgsave_time_sec
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 最近一次bgsave命令执行时间(秒)
|
||||
en-US: Last bgsave Time Sec
|
||||
ja-JP: 最後のbgsave実行時間(秒)
|
||||
# the protocol used for monitoring, eg: sql, ssh, http, telnet, wmi, snmp, sdk
|
||||
protocol: redis
|
||||
# the config content when protocol is redis
|
||||
@@ -360,6 +405,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 全局统计信息
|
||||
en-US: Stats
|
||||
ja-JP: 統計情報
|
||||
# collect metrics content
|
||||
fields:
|
||||
# field-metric name, type-metric type(0-number,1-string), unit-metric unit('%','ms','MB'), label-whether it is a metrics label field
|
||||
@@ -368,61 +414,73 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 已接受的总连接数
|
||||
en-US: Total Connections Received
|
||||
ja-JP: 受信された接続数
|
||||
- field: total_commands_processed
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 执行过的命令总数
|
||||
en-US: Total Commands Processed
|
||||
ja-JP: 処理済みのコマンド数
|
||||
- field: instantaneous_ops_per_sec
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 命令处理条数/秒
|
||||
en-US: Instantaneous Ops Per Sec
|
||||
ja-JP: 処理されたコマンド数/秒
|
||||
- field: total_net_input_bytes
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 输入总网络流量(字节)
|
||||
en-US: Total Net Input Bytes
|
||||
ja-JP: 受信されたネットワークトラフィック(バイト)
|
||||
- field: total_net_output_bytes
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 输出总网络流量(字节)
|
||||
en-US: Total Net Output Bytes
|
||||
ja-JP: 転送されたネットワークトラフィック(バイト)
|
||||
- field: instantaneous_input_kbps
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 输入字节数/秒
|
||||
en-US: Instantaneous Input Kbps
|
||||
ja-JP: 受信されたバイト/秒
|
||||
- field: instantaneous_output_kbps
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 输出字节数/秒
|
||||
en-US: Instantaneous Output Kbps
|
||||
ja-JP: 転送されたバイト/秒
|
||||
- field: sync_full
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 主从完全同步成功次数
|
||||
en-US: Sync Full
|
||||
ja-JP: Full Sync回数
|
||||
- field: sync_partial_ok
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 主从部分同步成功次数
|
||||
en-US: Sync Partial OK
|
||||
ja-JP: Partial Sync成功回数
|
||||
- field: sync_partial_err
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 主从部分同步失败次数
|
||||
en-US: Sync Partial Error
|
||||
ja-JP: Partial Sync失敗回数
|
||||
- field: pubsub_channels
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 订阅的频道数量
|
||||
en-US: Pubsub Channels
|
||||
ja-JP: 購読されたチャンネル数
|
||||
- field: pubsub_patterns
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 订阅的模式数量
|
||||
en-US: Pubsub Patterns
|
||||
ja-JP: 購読されたパターン数
|
||||
# the protocol used for monitoring, eg: sql, ssh, http, telnet, wmi, snmp, sdk
|
||||
protocol: redis
|
||||
# the config content when protocol is redis
|
||||
@@ -446,6 +504,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 主从同步信息
|
||||
en-US: Replication
|
||||
ja-JP: レプリケーション情報
|
||||
# collect metrics content
|
||||
fields:
|
||||
# field-metric name, type-metric type(0-number,1-string), unit-metric unit('%','ms','MB'), label-whether it is a metrics label field
|
||||
@@ -454,16 +513,19 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 节点角色
|
||||
en-US: Role
|
||||
ja-JP: 役割
|
||||
- field: connected_slaves
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 已连接的从节点个数
|
||||
en-US: Connected Slaves
|
||||
ja-JP: 接続スレーブ数
|
||||
- field: master_repl_offset
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 主节点偏移量
|
||||
en-US: Master Repl Offset
|
||||
ja-JP: マスターのログオフセット
|
||||
# the protocol used for monitoring, eg: sql, ssh, http, telnet, wmi, snmp, sdk
|
||||
protocol: redis
|
||||
# the config content when protocol is redis
|
||||
@@ -487,6 +549,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: CPU消耗信息
|
||||
en-US: CPU
|
||||
ja-JP: CPU情報
|
||||
# collect metrics content
|
||||
fields:
|
||||
# field-metric name, type-metric type(0-number,1-string), unit-metric unit('%','ms','MB'), label-whether it is a metrics label field
|
||||
@@ -495,11 +558,13 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: Kvrocks进程使用的CPU时钟总和(内核态)
|
||||
en-US: Used CPU Sys
|
||||
ja-JP: Kvrocksが使用するシステム時間
|
||||
- field: used_cpu_user
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: Kvrocks进程使用的CPU时钟总和(用户态)
|
||||
en-US: Used CPU User
|
||||
ja-JP: Kvrocksが使用するユーザー時間
|
||||
# the protocol used for monitoring, eg: sql, ssh, http, telnet, wmi, snmp, sdk
|
||||
protocol: redis
|
||||
# the config content when protocol is redis
|
||||
@@ -523,6 +588,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 命令信息
|
||||
en-US: Command Stats
|
||||
ja-JP: コマンドの統計情報
|
||||
# collect metrics content
|
||||
fields:
|
||||
# field-metric name, type-metric type(0-number,1-string), unit-metric unit('%','ms','MB'), label-whether it is a metrics label field
|
||||
@@ -531,11 +597,13 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 命令
|
||||
en-US: Command Stat Command
|
||||
ja-JP: コマンド
|
||||
- field: cmdstat_info
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 命令监控信息
|
||||
en-US: Command Stat Info
|
||||
ja-JP: コマンドの統計情報
|
||||
# the protocol used for monitoring, eg: sql, ssh, http, telnet, wmi, snmp, sdk
|
||||
protocol: redis
|
||||
# the config content when protocol is redis
|
||||
@@ -558,6 +626,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 集群信息
|
||||
en-US: Cluster
|
||||
ja-JP: クラスター情報
|
||||
fields:
|
||||
# field-metric name, type-metric type(0-number,1-string), unit-metric unit('%','ms','MB'), label-whether it is a metrics label field
|
||||
- field: cluster_enabled
|
||||
@@ -565,6 +634,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 节点是否开启集群模式
|
||||
en-US: Cluster Enabled
|
||||
ja-JP: 有効
|
||||
# the protocol used for monitoring, eg: sql, ssh, http, telnet, wmi, snmp, sdk
|
||||
protocol: redis
|
||||
# the config content when protocol is redis
|
||||
@@ -588,6 +658,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 命令统计信息
|
||||
en-US: Command Stats
|
||||
ja-JP: コマンドの統計情報
|
||||
# collect metrics content
|
||||
fields:
|
||||
# field-metric name, type-metric type(0-number,1-string), unit-metric unit('%','ms','MB'), label-whether it is a metrics label field
|
||||
@@ -596,46 +667,55 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 客户端命令统计
|
||||
en-US: cmdstat client
|
||||
ja-JP: クライエントのコマンド
|
||||
- field: cmdstat_config
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 配置命令统计
|
||||
en-US: cmdstat config
|
||||
ja-JP: 配置のコマンド
|
||||
- field: cmdstat_get
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: get
|
||||
en-US: get
|
||||
ja-JP: get
|
||||
- field: cmdstat_hello
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: hello
|
||||
en-US: hello
|
||||
ja-JP: hello
|
||||
- field: cmdstat_info
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: info
|
||||
en-US: info
|
||||
ja-JP: info
|
||||
- field: cmdstat_keys
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: keys
|
||||
en-US: keys
|
||||
ja-JP: keys
|
||||
- field: cmdstat_ping
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: ping
|
||||
en-US: ping
|
||||
ja-JP: ping
|
||||
- field: cmdstat_select
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: select
|
||||
en-US: select
|
||||
ja-JP: select
|
||||
- field: cmdstat_set
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: set
|
||||
en-US: set
|
||||
ja-JP: set
|
||||
# the protocol used for monitoring, eg: sql, ssh, http, telnet, wmi, snmp, sdk
|
||||
protocol: redis
|
||||
# the config content when protocol is redis
|
||||
@@ -659,6 +739,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 数据库统计信息
|
||||
en-US: Keyspace
|
||||
ja-JP: キー空間
|
||||
# collect metrics content
|
||||
fields:
|
||||
# field-metric name, type-metric type(0-number,1-string), unit-metric unit('%','ms','MB'), label-whether it is a metrics label field
|
||||
@@ -667,41 +748,49 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: db0
|
||||
en-US: db0
|
||||
ja-JP: db0
|
||||
- field: sequence
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 序列
|
||||
en-US: sequence
|
||||
ja-JP: シーケンス
|
||||
- field: used_db_size
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 数据库使用大小
|
||||
en-US: used_db_size
|
||||
ja-JP: 使用したサイズ
|
||||
- field: max_db_size
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 数据库最大使用大小
|
||||
en-US: max_db_size
|
||||
ja-JP: 最大サイズ
|
||||
- field: used_percent
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 数据库使用百分比
|
||||
en-US: used_percent
|
||||
ja-JP: パーセント
|
||||
- field: disk_capacity
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 磁盘容量
|
||||
en-US: disk_capacity
|
||||
ja-JP: ディスク容量
|
||||
- field: used_disk_size
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 占用磁盘大小
|
||||
en-US: used_disk_size
|
||||
ja-JP: 使用したディスクサイズ
|
||||
- field: used_disk_percent
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 占用磁盘百分比
|
||||
en-US: used_disk_percent
|
||||
ja-JP: 使用したディスク率
|
||||
# the protocol used for monitoring, eg: sql, ssh, http, telnet, wmi, snmp, sdk
|
||||
protocol: redis
|
||||
# the config content when protocol is redis
|
||||
|
||||
@@ -21,11 +21,13 @@ app: linux
|
||||
name:
|
||||
zh-CN: Linux操作系统
|
||||
en-US: OS Linux
|
||||
ja-JP: OS Linux
|
||||
# The description and help of this monitoring type
|
||||
help:
|
||||
zh-CN: Hertzbeat 使用 <a class='help_module_content' href='https://hertzbeat.apache.org/docs/advanced/extend-ssh'> SSH 协议</a> 对 Linux 操作系统的通用性能指标 (系统信息、CPU、内存、磁盘、网卡、文件系统、TOP资源进程等) 进行采集监控。<br>您可以点击“<i>新建 Linux</i>”并配置HOST端口账户等相关参数进行添加,支持SSH账户密码或密钥认证。或者选择“<i>更多操作</i>”,导入已有配置。
|
||||
en-US: HertzBeat uses <a class='help_module_content' href='https://hertzbeat.apache.org/docs/advanced/extend-ssh'> SSH protocol</a> to monitors Linux operating system's general performance metrics such as cpu, memory, disk, basic, interface, disk_free, top_process etc. <br>You can click the "<i>New Linux</i>" and config host port and other related params to add, auth support password or secretKey. Or import an existing setup through the "<i>More Actions</i>" menu.
|
||||
zh-TW: Hertzbeat 使用 <a class='help_module_content' href='https://hertzbeat.apache.org/docs/advanced/extend-ssh'> SSH 协议</a> 對 Linux 操作系统的通用性能指標 (系統信息、CPU、內存、磁盤、網卡、文件系統、TOP資源進程等) 進行採集監控。<br>您可以點擊“<i>新建 Linux</i>”並配置HOST端口賬戶等相關參數進行添加,支持SSH賬戶密碼或密鑰認證。或者選擇“<i>更多操作</i>”,導入已有配寘。
|
||||
ja-JP: Hertzbeat は <a class='help_module_content' href='https://hertzbeat.apache.org/docs/advanced/extend-ssh'> SSHプロトコルを介して</a> Linuxシステムの一般的なパフォーマンスのメトリクスを監視します。<br>「<i>新規 Linux</i>」をクリックしてホストなどのパラメタを設定した後、新規することができます。SSHまたはキー認証をサポートします。
|
||||
helpLink:
|
||||
zh-CN: https://hertzbeat.apache.org/zh-cn/docs/help/linux
|
||||
en-US: https://hertzbeat.apache.org/docs/help/linux
|
||||
@@ -37,6 +39,7 @@ params:
|
||||
name:
|
||||
zh-CN: 目标Host
|
||||
en-US: Target Host
|
||||
ja-JP: 目標ホスト
|
||||
# type-param field type(most mapping the html input type)
|
||||
type: host
|
||||
# required-true or false
|
||||
@@ -47,6 +50,7 @@ params:
|
||||
name:
|
||||
zh-CN: 端口
|
||||
en-US: Port
|
||||
ja-JP: ポート
|
||||
# type-param field type(most mapping the html input type)
|
||||
type: number
|
||||
# when type is number, range is required
|
||||
@@ -61,6 +65,7 @@ params:
|
||||
name:
|
||||
zh-CN: 超时时间(ms)
|
||||
en-US: Timeout(ms)
|
||||
ja-JP: タイムアウト(ms)
|
||||
# type-param field type(most mapping the html input type)
|
||||
type: number
|
||||
# when type is number, range is required
|
||||
@@ -75,6 +80,7 @@ params:
|
||||
name:
|
||||
zh-CN: 复用连接
|
||||
en-US: Reuse Connection
|
||||
ja-JP: 接続再利用
|
||||
# type-param field type(most mapping the html input type)
|
||||
type: boolean
|
||||
# required-true or false
|
||||
@@ -86,6 +92,7 @@ params:
|
||||
name:
|
||||
zh-CN: 使用代理
|
||||
en-US: Use Proxy Connection
|
||||
ja-JP: プロキシ接続利用
|
||||
# type-param field type(most mapping the html input type)
|
||||
type: boolean
|
||||
# required-true or false
|
||||
@@ -97,6 +104,7 @@ params:
|
||||
name:
|
||||
zh-CN: 用户名
|
||||
en-US: Username
|
||||
ja-JP: ユーザー名
|
||||
# type-param field type(most mapping the html input type)
|
||||
type: text
|
||||
# when type is text, use limit to limit string length
|
||||
@@ -109,6 +117,7 @@ params:
|
||||
name:
|
||||
zh-CN: 密码
|
||||
en-US: Password
|
||||
ja-JP: パスワード
|
||||
# type-param field type(most mapping the html input tag)
|
||||
type: password
|
||||
# required-true or false
|
||||
@@ -119,6 +128,7 @@ params:
|
||||
name:
|
||||
zh-CN: 私钥
|
||||
en-US: PrivateKey
|
||||
ja-JP: 秘密鍵
|
||||
# type-param field type(most mapping the html input type)
|
||||
type: textarea
|
||||
placeholder: -----BEGIN RSA PRIVATE KEY-----
|
||||
@@ -131,6 +141,7 @@ params:
|
||||
name:
|
||||
zh-CN: 密钥短语
|
||||
en-US: PrivateKey PassPhrase
|
||||
ja-JP: 秘密鍵フレーズ
|
||||
# type-param field type(most mapping the html input type)
|
||||
type: password
|
||||
# required-true or false
|
||||
@@ -143,6 +154,7 @@ params:
|
||||
name:
|
||||
zh-CN: 代理主机
|
||||
en-US: Proxy Host
|
||||
ja-JP: プロキシホスト
|
||||
# type-param field type(most mapping the html input type)
|
||||
type: text
|
||||
# required-true or false
|
||||
@@ -154,6 +166,7 @@ params:
|
||||
name:
|
||||
zh-CN: 代理端口
|
||||
en-US: Proxy Port
|
||||
ja-JP: プロキシポート
|
||||
# type-param field type(most mapping the html input type)
|
||||
type: number
|
||||
# when type is number, range is required
|
||||
@@ -170,6 +183,7 @@ params:
|
||||
name:
|
||||
zh-CN: 代理用户名
|
||||
en-US: Proxy Username
|
||||
ja-JP: プロキシユーザー名
|
||||
# type-param field type(most mapping the html input type)
|
||||
type: text
|
||||
# when type is text, use limit to limit string length
|
||||
@@ -184,6 +198,7 @@ params:
|
||||
name:
|
||||
zh-CN: 代理密码
|
||||
en-US: Proxy Password
|
||||
ja-JP: プロキシパスワード
|
||||
# type-param field type(most mapping the html input tag)
|
||||
type: password
|
||||
# required-true or false
|
||||
@@ -196,6 +211,7 @@ params:
|
||||
name:
|
||||
zh-CN: 代理主机私钥
|
||||
en-US: proxyPrivateKey
|
||||
ja-JP: プロキシ秘密鍵
|
||||
# type-param field type(most mapping the html input type)
|
||||
type: textarea
|
||||
placeholder: -----BEGIN RSA PRIVATE KEY-----
|
||||
@@ -210,6 +226,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 系统基本信息
|
||||
en-US: Basic Info
|
||||
ja-JP: システム基礎情報
|
||||
# metrics scheduling priority(0->127)->(high->low), metrics with the same priority will be scheduled in parallel
|
||||
# priority 0's metrics is availability metrics, it will be scheduled first, only availability metrics collect success will the scheduling continue
|
||||
priority: 0
|
||||
@@ -222,16 +239,19 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 主机名称
|
||||
en-US: Host Name
|
||||
ja-JP: ホスト名
|
||||
- field: version
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 操作系统版本
|
||||
en-US: System Version
|
||||
ja-JP: オーエスバージョン
|
||||
- field: uptime
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 启动时间
|
||||
en-US: Uptime
|
||||
ja-JP: アップタイム
|
||||
# the protocol used for monitoring, eg: sql, ssh, http, telnet, wmi, snmp, sdk
|
||||
protocol: ssh
|
||||
# the config content when protocol is ssh
|
||||
@@ -271,6 +291,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: CPU 信息
|
||||
en-US: CPU Info
|
||||
ja-JP: CPU情報
|
||||
priority: 1
|
||||
fields:
|
||||
- field: info
|
||||
@@ -278,32 +299,38 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 型号
|
||||
en-US: Info
|
||||
ja-JP: バージョン
|
||||
- field: cores
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 核数
|
||||
en-US: Cores
|
||||
ja-JP: コア数
|
||||
- field: interrupt
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 中断数
|
||||
en-US: Interrupt
|
||||
ja-JP: 割り込み数
|
||||
- field: load
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 负载
|
||||
en-US: Load
|
||||
ja-JP: ロード
|
||||
- field: context_switch
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 上下文切换
|
||||
en-US: Context Switch
|
||||
ja-JP: コンテキストスイッチ
|
||||
- field: usage
|
||||
type: 0
|
||||
unit: '%'
|
||||
i18n:
|
||||
zh-CN: 使用率
|
||||
en-US: Usage
|
||||
ja-JP: 使用率
|
||||
# (optional)metrics field alias name, it is used as an alias field to map and convert the collected data and metrics field
|
||||
aliasFields:
|
||||
- info
|
||||
@@ -350,6 +377,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 内存信息
|
||||
en-US: Memory Info
|
||||
ja-JP: メモリ情報
|
||||
priority: 2
|
||||
fields:
|
||||
- field: total
|
||||
@@ -358,36 +386,42 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 总内存容量
|
||||
en-US: Total Memory
|
||||
ja-JP: メモリ容量
|
||||
- field: used
|
||||
type: 0
|
||||
unit: Mb
|
||||
i18n:
|
||||
zh-CN: 用户程序内存量
|
||||
en-US: User Program Memory
|
||||
ja-JP: ユーザープログラムメモリ
|
||||
- field: free
|
||||
type: 0
|
||||
unit: Mb
|
||||
i18n:
|
||||
zh-CN: 空闲内存容量
|
||||
en-US: Free Memory
|
||||
ja-JP: 空きメモリ
|
||||
- field: buff_cache
|
||||
type: 0
|
||||
unit: Mb
|
||||
i18n:
|
||||
zh-CN: 缓存占用内存
|
||||
en-US: Buff Cache Memory
|
||||
ja-JP: バッファメモリ
|
||||
- field: available
|
||||
type: 0
|
||||
unit: Mb
|
||||
i18n:
|
||||
zh-CN: 剩余可用内存
|
||||
en-US: Available Memory
|
||||
ja-JP: 使用可能のメモリ
|
||||
- field: usage
|
||||
type: 0
|
||||
unit: '%'
|
||||
i18n:
|
||||
zh-CN: 内存使用率
|
||||
en-US: Memory Usage
|
||||
ja-JP: メモリ使用率
|
||||
aliasFields:
|
||||
- total
|
||||
- used
|
||||
@@ -430,6 +464,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 磁盘信息
|
||||
en-US: Disk Info
|
||||
ja-JP: ディスク情報
|
||||
priority: 3
|
||||
fields:
|
||||
- field: disk_num
|
||||
@@ -437,27 +472,32 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 磁盘总数
|
||||
en-US: Disk Num
|
||||
ja-JP: ディスク番号
|
||||
- field: partition_num
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 分区总数
|
||||
en-US: Partition Num
|
||||
ja-JP: パーティション
|
||||
- field: block_write
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 写磁盘块数
|
||||
en-US: Block Write
|
||||
ja-JP: 書き込みディスクブロック数
|
||||
- field: block_read
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 读磁盘块数
|
||||
en-US: Block Read
|
||||
ja-JP: 読み取りブロック数
|
||||
- field: write_rate
|
||||
type: 0
|
||||
unit: iops
|
||||
i18n:
|
||||
zh-CN: 磁盘写速率
|
||||
en-US: Write Rate
|
||||
ja-JP: ディスク書き込み速度
|
||||
protocol: ssh
|
||||
ssh:
|
||||
host: ^_^host^_^
|
||||
@@ -487,6 +527,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 网卡信息
|
||||
en-US: Interface Info
|
||||
ja-JP: ネットワークカード情報
|
||||
priority: 4
|
||||
fields:
|
||||
- field: interface_name
|
||||
@@ -495,18 +536,21 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 网卡名称
|
||||
en-US: Interface Name
|
||||
ja-JP: ネットワークカード名
|
||||
- field: receive_bytes
|
||||
type: 0
|
||||
unit: Mb
|
||||
i18n:
|
||||
zh-CN: 入站数据流量
|
||||
en-US: Receive Bytes
|
||||
ja-JP: 受信されたバイト数
|
||||
- field: transmit_bytes
|
||||
type: 0
|
||||
unit: Mb
|
||||
i18n:
|
||||
zh-CN: 出站数据流量
|
||||
en-US: Transmit Bytes
|
||||
ja-JP: 転送されたバイト数
|
||||
units:
|
||||
- receive_bytes=B->MB
|
||||
- transmit_bytes=B->MB
|
||||
@@ -539,6 +583,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 文件系统
|
||||
en-US: Disk Free
|
||||
ja-JP: ファイルシステム
|
||||
priority: 5
|
||||
fields:
|
||||
- field: filesystem
|
||||
@@ -546,30 +591,35 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 文件系统
|
||||
en-US: Filesystem
|
||||
ja-JP: ファイルシステム
|
||||
- field: used
|
||||
type: 0
|
||||
unit: Mb
|
||||
i18n:
|
||||
zh-CN: 已使用量
|
||||
en-US: Used
|
||||
ja-JP: 使用済み
|
||||
- field: available
|
||||
type: 0
|
||||
unit: Mb
|
||||
i18n:
|
||||
zh-CN: 可用量
|
||||
en-US: Available
|
||||
ja-JP: 使用可能
|
||||
- field: usage
|
||||
type: 0
|
||||
unit: '%'
|
||||
i18n:
|
||||
zh-CN: 使用率
|
||||
en-US: Usage
|
||||
ja-JP: 使用率
|
||||
- field: mounted
|
||||
type: 1
|
||||
label: true
|
||||
i18n:
|
||||
zh-CN: 挂载点
|
||||
en-US: Mounted
|
||||
ja-JP: マウント
|
||||
protocol: ssh
|
||||
ssh:
|
||||
host: ^_^host^_^
|
||||
@@ -599,6 +649,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: Top10 CPU 进程
|
||||
en-US: Top10 CPU Process
|
||||
ja-JP: トップ10 CPUプロセス
|
||||
priority: 6
|
||||
fields:
|
||||
- field: pid
|
||||
@@ -607,23 +658,27 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 进程ID
|
||||
en-US: PID
|
||||
ja-JP: プロセスID
|
||||
- field: cpu_usage
|
||||
type: 0
|
||||
unit: '%'
|
||||
i18n:
|
||||
zh-CN: CPU占用率
|
||||
en-US: CPU Usage
|
||||
ja-JP: CPU使用率
|
||||
- field: mem_usage
|
||||
type: 0
|
||||
unit: '%'
|
||||
i18n:
|
||||
zh-CN: 内存占用率
|
||||
en-US: Memory Usage
|
||||
ja-JP: メモリ使用率
|
||||
- field: command
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 执行命令
|
||||
en-US: Command
|
||||
ja-JP: コマンド
|
||||
protocol: ssh
|
||||
ssh:
|
||||
host: ^_^host^_^
|
||||
@@ -653,6 +708,7 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: Top10 内存进程
|
||||
en-US: Top10 Memory Process
|
||||
ja-JP: トップ10 メモリプロセス
|
||||
priority: 7
|
||||
fields:
|
||||
- field: pid
|
||||
@@ -661,23 +717,27 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 进程ID
|
||||
en-US: PID
|
||||
ja-JP: プロセスID
|
||||
- field: mem_usage
|
||||
type: 0
|
||||
unit: '%'
|
||||
i18n:
|
||||
zh-CN: 内存占用率
|
||||
en-US: Memory Usage
|
||||
ja-JP: メモリ使用率
|
||||
- field: cpu_usage
|
||||
type: 0
|
||||
unit: '%'
|
||||
i18n:
|
||||
zh-CN: CPU占用率
|
||||
en-US: CPU Usage
|
||||
ja-JP: CPU使用率
|
||||
- field: command
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 执行命令
|
||||
en-US: Command
|
||||
ja-JP: コマンド
|
||||
protocol: ssh
|
||||
ssh:
|
||||
host: ^_^host^_^
|
||||
|
||||
@@ -13,15 +13,12 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# The monitoring type category:service-application service monitoring db-database monitoring mid-middleware custom-custom monitoring os-operating system monitoring
|
||||
|
||||
category: service
|
||||
# The monitoring type eg: linux windows tomcat mysql aws...
|
||||
app: mqtt
|
||||
# The app api i18n name
|
||||
name:
|
||||
zh-CN: MQTT 连接
|
||||
en-US: MQTT Connection
|
||||
# The description and help of this monitoring type
|
||||
help:
|
||||
zh-CN: HertzBeat 对 MQTT 连接进行监测。<br>您可以点击 “<i>新建 MQTT 连接</i>” 并进行配置,或者选择“<i>更多操作</i>”,导入已有配置。
|
||||
en-US: HertzBeat monitors MQTT connections. <br>You can click "<i>New MQTT connection</i>" and configure it, or select "<i>More actions</i>" to import an existing configuration.
|
||||
@@ -29,83 +26,121 @@ help:
|
||||
helpLink:
|
||||
zh-CN: https://hertzbeat.apache.org/zh-cn/docs/help/mqtt
|
||||
en-US: https://hertzbeat.apache.org/docs/help/mqtt
|
||||
# Input params define for monitoring(render web ui by the definition)
|
||||
params:
|
||||
# field-param field key
|
||||
- field: host
|
||||
# name-param field display i18n name
|
||||
name:
|
||||
zh-CN: MQTT的Host
|
||||
en-US: Target Host
|
||||
# type-param field type(most mapping the html input type)
|
||||
type: host
|
||||
# required-true or false
|
||||
required: true
|
||||
# field-param field key
|
||||
- field: port
|
||||
# name-param field display i18n name
|
||||
name:
|
||||
zh-CN: 端口
|
||||
en-US: 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: true
|
||||
# default value 1883
|
||||
defaultValue: 1883
|
||||
- field: protocolVersion
|
||||
name:
|
||||
zh-CN: 协议版本
|
||||
en-US: Protocol version
|
||||
type: radio
|
||||
options:
|
||||
- label: MQTT 3.1.1
|
||||
value: MQTT_3_1_1
|
||||
- label: MQTT 5.0
|
||||
value: MQTT_5_0
|
||||
required: true
|
||||
defaultValue: MQTT_3_1_1
|
||||
# field-param field key
|
||||
- field: timeout
|
||||
# name-param field display i18n name
|
||||
name:
|
||||
zh-CN: 连接超时时间(ms)
|
||||
en-US: Connect Timeout(ms)
|
||||
# type-param field type(most mapping the html input type)
|
||||
type: number
|
||||
# when type is number, range is required
|
||||
range: '[0,100000]'
|
||||
# required-true or false
|
||||
required: true
|
||||
# default value 6000
|
||||
defaultValue: 6000
|
||||
# field-param field key
|
||||
- field: username
|
||||
name:
|
||||
zh-CN: 用户名
|
||||
en-US: Username
|
||||
type: text
|
||||
hide: true
|
||||
# required-true or false
|
||||
required: false
|
||||
- field: password
|
||||
name:
|
||||
zh-CN: 密码
|
||||
en-US: Password
|
||||
type: text
|
||||
hide: true
|
||||
# required-true or false
|
||||
required: false
|
||||
|
||||
- field: clientId
|
||||
name:
|
||||
zh-CN: 客户端ID
|
||||
en-US: Client Id
|
||||
type: text
|
||||
defaultValue: hertzbeat-mqtt-client
|
||||
# required-true or false
|
||||
required: true
|
||||
- field: username
|
||||
name:
|
||||
zh-CN: 用户名
|
||||
en-US: Username
|
||||
type: text
|
||||
required: false
|
||||
- field: password
|
||||
name:
|
||||
zh-CN: 密码
|
||||
en-US: Password
|
||||
type: password
|
||||
required: false
|
||||
|
||||
- field: host
|
||||
name:
|
||||
zh-CN: MQTT的Host
|
||||
en-US: Target Host
|
||||
type: host
|
||||
required: true
|
||||
- field: port
|
||||
name:
|
||||
zh-CN: 端口
|
||||
en-US: Port
|
||||
type: number
|
||||
range: '[0,65535]'
|
||||
required: true
|
||||
defaultValue: 1883
|
||||
- field: protocol
|
||||
name:
|
||||
zh-CN: 连接协议
|
||||
en-US: Protocol
|
||||
type: radio
|
||||
options:
|
||||
- label: MQTT
|
||||
value: MQTT
|
||||
- label: MQTTS
|
||||
value: MQTTS
|
||||
required: true
|
||||
defaultValue: MQTT
|
||||
|
||||
- field: timeout
|
||||
name:
|
||||
zh-CN: 连接超时时间(ms)
|
||||
en-US: Connect Timeout(ms)
|
||||
type: number
|
||||
range: '[0,100000]'
|
||||
required: true
|
||||
defaultValue: 10000
|
||||
- field: keepalive
|
||||
name:
|
||||
zh-CN: 心跳检测时间(s)
|
||||
en-US: Keep Alive(s)
|
||||
type: number
|
||||
range: '[0,100000]'
|
||||
required: true
|
||||
defaultValue: 30
|
||||
|
||||
- field: tlsVersion
|
||||
name:
|
||||
zh-CN: TLS版本
|
||||
en-US: TLS Version
|
||||
type: radio
|
||||
options:
|
||||
- label: TLSv1.2
|
||||
value: TLSv1.2
|
||||
- label: TLSv1.3
|
||||
value: TLSv1.3
|
||||
defaultValue: TLSv1.2
|
||||
required: false
|
||||
hide: true
|
||||
- field: insecureSkipVerify
|
||||
name:
|
||||
zh-CN: 跳过证书验证
|
||||
en-US: Skip Certificate Verification
|
||||
type: boolean
|
||||
defaultValue: false
|
||||
hide: true
|
||||
- field: caCert
|
||||
name:
|
||||
zh-CN: CA证书
|
||||
en-US: CA Certificate
|
||||
type: text
|
||||
required: false
|
||||
hide: true
|
||||
- field: enableMutualAuth
|
||||
name:
|
||||
zh-CN: 双向认证
|
||||
en-US: Enable Mutual Auth
|
||||
type: boolean
|
||||
defaultValue: false
|
||||
hide: true
|
||||
- field: clientCert
|
||||
name:
|
||||
zh-CN: 客户端证书
|
||||
en-US: Client Certificate
|
||||
type: text
|
||||
required: false
|
||||
hide: true
|
||||
- field: clientKey
|
||||
name:
|
||||
zh-CN: 客户端私钥
|
||||
en-US: Client Private Key
|
||||
type: text
|
||||
required: false
|
||||
hide: true
|
||||
|
||||
|
||||
- field: topic
|
||||
name:
|
||||
@@ -119,17 +154,12 @@ params:
|
||||
en-US: Test message
|
||||
type: text
|
||||
required: false
|
||||
# collect metrics config list
|
||||
metrics:
|
||||
# metrics - summary
|
||||
- name: summary
|
||||
i18n:
|
||||
zh-CN: 概要
|
||||
en-US: Summary
|
||||
# metrics scheduling priority(0->127)->(high->low), metrics with the same priority will be scheduled in parallel
|
||||
# priority 0's metrics is availability metrics, it will be scheduled first, only availability metrics collect success will the scheduling continue
|
||||
priority: 0
|
||||
# field-metric name, type-metric type(0-number,1-string), unit-metric unit('%','ms','MB'), label-whether it is a metrics label field
|
||||
fields:
|
||||
- field: responseTime
|
||||
type: 0
|
||||
@@ -137,37 +167,41 @@ metrics:
|
||||
i18n:
|
||||
zh-CN: 响应时间
|
||||
en-US: Response Time
|
||||
- field: canDescribe
|
||||
- field: canSubscribe
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 正常订阅
|
||||
en-US: Normal subscription
|
||||
zh-CN: 订阅状态
|
||||
en-US: Normal subscribe
|
||||
- field: canPublish
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 正常推送
|
||||
zh-CN: 发布状态
|
||||
en-US: Normal publish
|
||||
# the protocol used for monitoring, eg: sql, ssh, http, telnet, wmi, snmp, sdk
|
||||
- field: canReceive
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 接收数据
|
||||
en-US: Receive data
|
||||
- field: canUnSubscribe
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 取消订阅状态
|
||||
en-US: Normal unsubscribe
|
||||
protocol: mqtt
|
||||
# Specific collection configuration when protocol is telnet protocol
|
||||
mqtt:
|
||||
# telnet host
|
||||
host: ^_^host^_^
|
||||
# port
|
||||
port: ^_^port^_^
|
||||
# timeout
|
||||
timeout: ^_^timeout^_^
|
||||
# email
|
||||
topic: ^_^topic^_^
|
||||
# clientId
|
||||
clientId: ^_^clientId^_^
|
||||
# protocolVersion
|
||||
protocolVersion: ^_^protocolVersion^_^
|
||||
# username
|
||||
username: ^_^username^_^
|
||||
# password
|
||||
password: ^_^password^_^
|
||||
# testMessage
|
||||
host: ^_^host^_^
|
||||
port: ^_^port^_^
|
||||
protocol: ^_^protocol^_^
|
||||
timeout: ^_^timeout^_^
|
||||
keepalive: ^_^keepalive^_^
|
||||
tlsVersion: ^_^tlsVersion^_^
|
||||
insecureSkipVerify: ^_^insecureSkipVerify^_^
|
||||
caCert: ^_^caCert^_^
|
||||
enableMutualAuth: ^_^enableMutualAuth^_^
|
||||
clientCert: ^_^clientCert^_^
|
||||
clientKey: ^_^clientKey^_^
|
||||
topic: ^_^topic^_^
|
||||
testMessage: ^_^testMessage^_^
|
||||
|
||||
|
||||
|
||||
+6
-2
@@ -182,8 +182,12 @@ public class JpaDatabaseDataStorage extends AbstractHistoryDataStorage {
|
||||
.str(formatStrValue(columnValue));
|
||||
case CommonConstants.TYPE_TIME -> historyBuilder.metricType(CommonConstants.TYPE_TIME)
|
||||
.int32(Integer.parseInt(columnValue));
|
||||
default -> historyBuilder.metricType(CommonConstants.TYPE_NUMBER)
|
||||
.dou(Double.parseDouble(columnValue));
|
||||
default -> {
|
||||
Double v = Double.parseDouble(columnValue);
|
||||
v = v.isNaN() ? null : v;
|
||||
historyBuilder.metricType(CommonConstants.TYPE_NUMBER)
|
||||
.dou(v);
|
||||
}
|
||||
}
|
||||
|
||||
if (cell.getMetadataAsBoolean(MetricDataConstants.LABEL)) {
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
---
|
||||
title: Welcome HertzBeat's New Community Committer!
|
||||
author: bigcyy
|
||||
author_title: Yang Chen
|
||||
author_url: https://github.com/bigcyy
|
||||
author_image_url: https://avatars.githubusercontent.com/u/73413979
|
||||
tags: [opensource, practice]
|
||||
keywords:
|
||||
[
|
||||
open source monitoring system,
|
||||
alerting system,
|
||||
Apache,
|
||||
Apache Committer,
|
||||
Hertzbeat,
|
||||
]
|
||||
---
|
||||
|
||||
Hello everyone, I'm Yang Chen, currently a graduate student at Chongqing University of Posts and Telecommunications. I'm deeply honored to receive recognition and invitation from the Apache HertzBeat community to officially become a project Committer. This marks the true beginning of my open-source journey!
|
||||
|
||||
## My Open Source Exploration
|
||||
|
||||
As early as my undergraduate years, I had exposure to open source.
|
||||
Back then, I developed a [epidemic notice QQ bot](https://github.com/bigcyy/GroupNotifier) based on the open-source [Mirai](https://github.com/mamoe/mirai) framework. However, that was more at the usage level.
|
||||
In my junior year, I attempted to independently open-source an AI project called [customized_chat](https://github.com/bigcyy/customized-chat), which was my first step into "open source."
|
||||
But these experiences were all solo explorations, and I deeply felt that this wasn't true open source, as it failed to establish a complete community ecosystem.
|
||||
|
||||
## Meeting HertzBeat: True Open Source Practice
|
||||
|
||||
To participate more deeply in open source, I began searching for suitable open-source activities and thus encountered HertzBeat. For me, this was the true beginning of my open-source journey. Here, I not only learned solid technical development but also experienced a mature community ecosystem. I deeply understood the essence of the "Apache Way" - the community builds the project, not the project builds the community.
|
||||
|
||||
I first learned about HertzBeat through GSoC (Google Summer of Code), when the community's proposal about developing monitoring MCP deeply attracted me. So I proactively contacted Tom and officially began participating in community activities. Tom was very enthusiastic, and the entire community was exceptionally active.
|
||||
I clearly remember my first PR (Pull Request), when I even conducted online testing with a user in an Issue, which was quite a unique experience for me. Although I wasn't ultimately selected for GSoC, during that period, I had already deeply participated in the community and fully experienced its excellence.
|
||||
|
||||
## Growth and Gains from Open Source
|
||||
|
||||
Participating in open source has indeed significantly improved my abilities. By reading HertzBeat's architectural design and actively participating in community discussions, I've accumulated many valuable experiences, such as:
|
||||
|
||||
- Cutting-edge Technology: I gained deep understanding of monitoring system design and implementation, and practiced core technologies like concurrent programming and distributed systems in the project.
|
||||
- Practical Abilities: Through solving real problems and participating in code contributions, I successfully transformed theoretical knowledge into practical operational skills.
|
||||
- Community Culture Experience: I personally experienced the unique charm of the "Apache Way" and engaged in deep exchanges and learning with developers from around the world.
|
||||
|
||||
My experience has convinced me that open source is not just about writing code, but an excellent platform for learning, growing, and contributing.
|
||||
|
||||
If you're also passionate about technology, eager to improve yourself through practice, and want to experience true community collaboration, then the Apache HertzBeat community is definitely your best choice!
|
||||
|
||||
## Finally
|
||||
|
||||
I sincerely thank [Tom](https://github.com/tomsun28), [Shenghang](https://github.com/zhangshenghang), [Logic](https://github.com/zqr10159), and other community members for their meticulous code reviews and patient guidance. I hope Apache HertzBeat continues to thrive!
|
||||
@@ -60,14 +60,14 @@ The following table is filled according to the [Apache Maturity Model](https://c
|
||||
|
||||
### Community
|
||||
|
||||
| **ID** | **Description** | **Status** |
|
||||
| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| **CO10** | The project has a well-known homepage that points to all the information required to operate according to this maturity model. | **YES** The [official website](https://hertzbeat.apache.org/) includes all information user need to run Apache HertzBeat. |
|
||||
| **CO20** | The community welcomes contributions from anyone who acts in good faith and in a respectful manner, and who adds value to the project. | **Yes** We provide contributing guides for every component. And we also have a [general contributing guide](https://hertzbeat.apache.org/docs/community/contribution) |
|
||||
| **CO30** | Contributions include source code, documentation, constructive bug reports, constructive discussions, marketing and generally anything that adds value to the project. | **YES** All good contributions including code and non-code are welcomed. |
|
||||
| **CO40** | The community strives to be meritocratic and gives more rights and responsibilities to contributors who, over time, add value to the project. | **YES** The community has elected 2 new PPMC members and 12 new committers so far. |
|
||||
| **CO50** | The project documents how contributors can earn more rights such as commit access or decision power, and applies these principles consistently. | **YES** The community has clear docs on nominating committers and PPMC members |
|
||||
| **CO60** | The community operates based on consensus of its members (see CS10) who have decision power. Dictators, benevolent or not, are not welcome in Apache projects. | **YES** All decisions are made after vote by community members. |
|
||||
| **ID** | **Description** | **Status** |
|
||||
| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| **CO10** | The project has a well-known homepage that points to all the information required to operate according to this maturity model. | **YES** The [official website](https://hertzbeat.apache.org/) includes all information user need to run Apache HertzBeat. |
|
||||
| **CO20** | The community welcomes contributions from anyone who acts in good faith and in a respectful manner, and who adds value to the project. | **Yes** We provide contributing guides for every component. And we also have a [general contributing guide](https://hertzbeat.apache.org/docs/community/contribution) |
|
||||
| **CO30** | Contributions include source code, documentation, constructive bug reports, constructive discussions, marketing and generally anything that adds value to the project. | **YES** All good contributions including code and non-code are welcomed. |
|
||||
| **CO40** | The community strives to be meritocratic and gives more rights and responsibilities to contributors who, over time, add value to the project. | **YES** The community has elected 3 new PPMC members and 13 new committers so far. |
|
||||
| **CO50** | The project documents how contributors can earn more rights such as commit access or decision power, and applies these principles consistently. | **YES** The community has clear docs on nominating committers and PPMC members |
|
||||
| **CO60** | The community operates based on consensus of its members (see CS10) who have decision power. Dictators, benevolent or not, are not welcome in Apache projects. | **YES** All decisions are made after vote by community members. |
|
||||
| **CO70** | The project strives to answer user questions in a timely manner. | **YES** We use <dev@hertzbeat.apache.org>, [GitHub issue](https://github.com/apache/hertzbeat/issues) and [GitHub discussion](https://github.com/apache/hertzbeat/discussions) to do this in a timely manner. |
|
||||
|
||||
### Consensus
|
||||
|
||||
@@ -21,6 +21,24 @@ sidebar_label: Common issues
|
||||
> When you install HertzBeat via DockerDocker root is enabled by default. No such problem.
|
||||
> See <https://stackoverflow.com/questions/11506321/how-to-ping-an-ip-address>
|
||||
|
||||
4. Configured Kubernetes monitoring, but the actual monitoring is not executing at the correct interval
|
||||
Please troubleshoot the issue by following these steps:
|
||||
|
||||
> 1. First, check HertzBeat's error logs. If you see the message 'desc: SQL statement too long, check maxSQLLength config',
|
||||
> 2. You need to adjust the TDengine configuration file. Create a taos.cfg file on the server and modify # max length of an SQL : maxSQLLength 654800, then restart TDengine. Ensure the configuration file is properly mounted.
|
||||
> 3. If TDengine fails to restart, adjust the configuration in the mounted data file. Refer to .../taosdata/dnode/dnodeEps.json and change dnodeFqdn to the Docker ID of the failed startup instance, then run docker restart tdengine.
|
||||
|
||||
5. Configured HTTP API monitoring for business interface probing to ensure service availability. The API has token authentication, e.g., "Authorization: Bearer eyJhbGciOiJIUzI1....". After configuration, testing returns "StatusCode 401". The server receives the token as "Authorization: Bearer%20eyJhbGciOiJIUzI1....". HertzBeat escapes spaces to %20, but the server does not unescape it, causing authentication failure. It is recommended to make the escaping feature optional.
|
||||
|
||||
6. What is the task limit for a single collector?
|
||||
|
||||
> Specific limit parameters:
|
||||
Core thread count: Math.max(2, Runtime.getRuntime().availableProcessors()) – at least 2 threads, or equal to the number of CPU cores.
|
||||
Maximum thread count: Runtime.getRuntime().availableProcessors() * 16 – 16 times the number of CPU cores.
|
||||
> The limit depends entirely on the server's CPU core count. For example, on an 8-core CPU server, a maximum of 8 × 16 = 128 collection tasks can be processed simultaneously. Exceeding this number triggers the error message. This is a dynamic configuration that adjusts automatically based on the hardware specifications of the runtime environment.
|
||||
> If the runtime exceeds the maximum thread count, an error will appear: "the worker pool is full, reject this metrics task, put in queue again".
|
||||
> In such cases, it is recommended to configure a new collector in public mode. HertzBeat will automatically distribute tasks to other collectors, avoiding errors due to the task limit of a single collector.
|
||||
|
||||
### Docker Deployment common issues
|
||||
|
||||
1. **MYSQL, TDENGINE and HertzBeat are deployed on the same host by Docker,HertzBeat use localhost or 127.0.0.1 connect to the database but fail**
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
title: 热烈欢迎 HertzBeat 小伙伴新晋社区 Committer!
|
||||
author: bigcyy
|
||||
author_title: Yang Chen
|
||||
author_url: https://github.com/bigcyy
|
||||
author_image_url: https://avatars.githubusercontent.com/u/73413979
|
||||
tags: [opensource, practice]
|
||||
keywords:
|
||||
[
|
||||
open source monitoring system,
|
||||
alerting system,
|
||||
Apache,
|
||||
Apache Committer,
|
||||
Hertzbeat,
|
||||
]
|
||||
---
|
||||
|
||||
大家好,我是陈阳,目前是重庆邮电大学的一名研究生。非常荣幸能得到 Apache HertzBeat 社区的认可与邀请,正式成为项目的 Committer,这标志着我真正意义上的开源之旅的开启!
|
||||
|
||||
## 我的开源初探
|
||||
|
||||
早在本科时期,我就接触过开源,那时曾基于开源的 [Mirai](https://github.com/mamoe/mirai) 框架开发了一个[疫情防控 QQ 机器人](https://github.com/bigcyy/GroupNotifier)。然而,那更多是停留在使用层面。
|
||||
大三时,我尝试独立开源了名为 [customized_chat](https://github.com/bigcyy/customized-chat) 的 AI 项目,这算是我迈出的“开源”第一步。
|
||||
但这些经历都是独自摸索,我深感这并非真正的开源,因为它未能建立起一个完整的社区生态。
|
||||
|
||||
## 结缘 HertzBeat:真正意义的开源实践
|
||||
|
||||
为了更深入地参与开源,我开始寻找合适的开源活动,并因此结识了 HertzBeat。这对我而言,是真正意义上的开源之旅。在这里,我不仅学到了扎实的技术开发,更领略了成熟的社区生态。我深刻理解了 “Apache Way” 的精髓——社区成就项目,而非项目成就社区。
|
||||
|
||||
我最初是通过 GSoC(Google Summer of Code)了解到 HertzBeat 的,当时社区关于开发监控 MCP 的提案深深吸引了我。于是,我主动联系了 Tom ,并正式开始参与社区活动。Tom 非常热情,整个社区也异常活跃。我清晰地记得我的第一个 PR(Pull Request),当时甚至与一位用户在 Issue 中进行了在线测试,这对我来说是一次相当独特的经历。尽管最终未能入选 GSoC,但在此期间,我已深度参与到社区中,并充分感受到了它的卓越之处。
|
||||
|
||||
## 开源带来的成长与收获
|
||||
|
||||
参与开源,确实让我的能力得到了显著提升。通过阅读 HertzBeat 的架构设计并积极参与社区讨论,我积累了许多宝贵的经验,例如:
|
||||
|
||||
- 前沿技术: 我深入了解了监控系统的设计与实现,并在项目中实践了并发编程、分布式等核心技术。
|
||||
- 实战能力: 通过解决实际问题和参与代码贡献,我成功地将理论知识转化为了实际操作能力。
|
||||
- 社区文化体验: 我亲身感受了“Apache Way”的独特魅力,并与来自世界各地的开发者们进行了深入交流与学习。
|
||||
|
||||
我的经历让我深信,开源不仅仅是编写代码,更是一个学习、成长和贡献的绝佳平台。
|
||||
|
||||
如果你也对技术充满热情,渴望在实践中提升自我,并希望体验真正意义上的社区协作,那么 Apache HertzBeat 社区绝对是你的不二选择!
|
||||
|
||||
## 最后
|
||||
|
||||
我衷心感谢 [Tom](https://github.com/tomsun28)、[Shenghang](https://github.com/zhangshenghang)、[Logic](https://github.com/zqr10159) 等社区的小伙伴们,感谢你们对我的代码进行细致的 Review 与悉心指导。希望 Apache HertzBeat 能够越来越好!
|
||||
@@ -60,14 +60,14 @@ The following table is filled according to the [Apache Maturity Model](https://c
|
||||
|
||||
### Community
|
||||
|
||||
| **ID** | **Description** | **Status** |
|
||||
| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| **CO10** | The project has a well-known homepage that points to all the information required to operate according to this maturity model. | **YES** The [official website](https://hertzbeat.apache.org/) includes all information user need to run Apache HertzBeat. |
|
||||
| **CO20** | The community welcomes contributions from anyone who acts in good faith and in a respectful manner, and who adds value to the project. | **Yes** We provide contributing guides for every component. And we also have a [general contributing guide](https://hertzbeat.apache.org/docs/community/contribution) |
|
||||
| **CO30** | Contributions include source code, documentation, constructive bug reports, constructive discussions, marketing and generally anything that adds value to the project. | **YES** All good contributions including code and non-code are welcomed. |
|
||||
| **CO40** | The community strives to be meritocratic and gives more rights and responsibilities to contributors who, over time, add value to the project. | **YES** The community has elected 2 new PPMC members and 12 new committers so far. |
|
||||
| **CO50** | The project documents how contributors can earn more rights such as commit access or decision power, and applies these principles consistently. | **YES** The community has clear docs on nominating committers and PPMC members |
|
||||
| **CO60** | The community operates based on consensus of its members (see CS10) who have decision power. Dictators, benevolent or not, are not welcome in Apache projects. | **YES** All decisions are made after vote by community members. |
|
||||
| **ID** | **Description** | **Status** |
|
||||
| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| **CO10** | The project has a well-known homepage that points to all the information required to operate according to this maturity model. | **YES** The [official website](https://hertzbeat.apache.org/) includes all information user need to run Apache HertzBeat. |
|
||||
| **CO20** | The community welcomes contributions from anyone who acts in good faith and in a respectful manner, and who adds value to the project. | **Yes** We provide contributing guides for every component. And we also have a [general contributing guide](https://hertzbeat.apache.org/docs/community/contribution) |
|
||||
| **CO30** | Contributions include source code, documentation, constructive bug reports, constructive discussions, marketing and generally anything that adds value to the project. | **YES** All good contributions including code and non-code are welcomed. |
|
||||
| **CO40** | The community strives to be meritocratic and gives more rights and responsibilities to contributors who, over time, add value to the project. | **YES** The community has elected 3 new PPMC members and 13 new committers so far. |
|
||||
| **CO50** | The project documents how contributors can earn more rights such as commit access or decision power, and applies these principles consistently. | **YES** The community has clear docs on nominating committers and PPMC members |
|
||||
| **CO60** | The community operates based on consensus of its members (see CS10) who have decision power. Dictators, benevolent or not, are not welcome in Apache projects. | **YES** All decisions are made after vote by community members. |
|
||||
| **CO70** | The project strives to answer user questions in a timely manner. | **YES** We use <dev@hertzbeat.apache.org>, [GitHub issue](https://github.com/apache/hertzbeat/issues) and [GitHub discussion](https://github.com/apache/hertzbeat/discussions) to do this in a timely manner. |
|
||||
|
||||
### Consensus
|
||||
|
||||
@@ -30,6 +30,15 @@ sidebar_label: 常见问题
|
||||
|
||||
5. 配置http api监控,用于进行业务接口探测,确保业务可以用,另外接口有进行token鉴权校验,"Authorization:Bearer eyJhbGciOiJIUzI1....",配置后测试,提示“StatusCode 401”。服务端应用收到的token为"Authorization:Bearer%20eyJhbGciOiJIUzI1....",hertzbeat对空格进行转义为“%20”,服务器没有转义导致鉴权失败,建议转义功能作为可选项。
|
||||
|
||||
6. 单个采集器的任务上限是多少?
|
||||
|
||||
> 具体上限参数
|
||||
核心线程数: Math.max(2, Runtime.getRuntime().availableProcessors()) - 至少2个线程,或等于CPU核心数。
|
||||
最大线程数: Runtime.getRuntime().availableProcessors() * 16 - CPU核心数的16倍。
|
||||
> 上限完全取决于服务器的CPU核心数。例如,在8核CPU的服务器上,最大可同时处理 8 × 16 = 128 个采集任务。当超过这个数量时就会触发该错误消息。这是一个动态配置,会根据运行环境的硬件规格自动调整。
|
||||
> 当运行时超出最大线程数会报错提示"the worker pool is full, reject this metrics task,put in queue again"。
|
||||
> 此时建议配置新的采集器,并设置为public模式,hertzbeat会自动将任务分配给其他采集器,不会因为单个采集器任务上限而报错。
|
||||
|
||||
### Docker部署常见问题
|
||||
|
||||
1. **MYSQL,TDENGINE和HertzBeat都Docker部署在同一主机上,HertzBeat使用localhost或127.0.0.1连接数据库失败**
|
||||
|
||||
@@ -86,6 +86,11 @@
|
||||
"githubId": "30208283",
|
||||
"gitUrl": "https://github.com/LiuTianyou",
|
||||
"name": "LiuTianyou"
|
||||
},
|
||||
{
|
||||
"githubId": "25810623",
|
||||
"gitUrl": "https://github.com/Aias00",
|
||||
"name": "Aias00"
|
||||
}
|
||||
],
|
||||
"committer" : [
|
||||
@@ -114,11 +119,6 @@
|
||||
"gitUrl": "https://github.com/yuluo-yx",
|
||||
"name": "Shown"
|
||||
},
|
||||
{
|
||||
"githubId": "25810623",
|
||||
"gitUrl": "https://github.com/Aias00",
|
||||
"name": "Aias00"
|
||||
},
|
||||
{
|
||||
"githubId": "61108539",
|
||||
"gitUrl": "https://github.com/zuobiao-zhou",
|
||||
@@ -133,6 +133,16 @@
|
||||
"githubId": "69385076",
|
||||
"gitUrl": "https://github.com/pwallk",
|
||||
"name": "Kang Li"
|
||||
},
|
||||
{
|
||||
"githubId": "22274133",
|
||||
"gitUrl": "https://github.com/masamiyui",
|
||||
"name": "Yijun Yin"
|
||||
},
|
||||
{
|
||||
"githubId": "73413979",
|
||||
"gitUrl": "https://github.com/bigcyy",
|
||||
"name": "Yang Chen"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user