Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a4fbc57aa | ||
|
|
f44e19e537 | ||
|
|
49ad608ed9 | ||
|
|
22a7ae55e3 |
@@ -1,133 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.alert.controller;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;
|
||||
|
||||
import org.apache.hertzbeat.alert.service.AlertInhibitService;
|
||||
import org.apache.hertzbeat.common.constants.CommonConstants;
|
||||
import org.apache.hertzbeat.common.entity.alerter.AlertInhibit;
|
||||
import org.apache.hertzbeat.common.util.JsonUtil;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* test case for {@link AlertInhibitControllerTest}
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class AlertInhibitControllerTest {
|
||||
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Mock
|
||||
private AlertInhibitService alertInhibitService;
|
||||
|
||||
@InjectMocks
|
||||
private AlertInhibitController alertInhibitController;
|
||||
|
||||
private AlertInhibit alertInhibit;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
this.mockMvc = standaloneSetup(alertInhibitController).build();
|
||||
|
||||
HashMap<String, String> sourceLabels = new HashMap<>();
|
||||
HashMap<String, String> targetLabels = new HashMap<>();
|
||||
|
||||
alertInhibit = AlertInhibit.builder()
|
||||
.id(1L)
|
||||
.name("test")
|
||||
.sourceLabels(sourceLabels)
|
||||
.targetLabels(targetLabels)
|
||||
.creator("test")
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAddNewAlertInhibit() throws Exception {
|
||||
|
||||
doNothing().when(alertInhibitService).validate(any(AlertInhibit.class), eq(false));
|
||||
doNothing().when(alertInhibitService).addAlertInhibit(any(AlertInhibit.class));
|
||||
|
||||
mockMvc.perform(post("/api/alert/inhibit")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(JsonUtil.toJson(alertInhibit)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value((int) CommonConstants.SUCCESS_CODE))
|
||||
.andExpect(jsonPath("$.msg").value("Add success"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testModifyAlertInhibit() throws Exception {
|
||||
|
||||
doNothing().when(alertInhibitService).validate(any(AlertInhibit.class), eq(true));
|
||||
doNothing().when(alertInhibitService).modifyAlertInhibit(any(AlertInhibit.class));
|
||||
|
||||
mockMvc.perform(put("/api/alert/inhibit")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(JsonUtil.toJson(alertInhibit)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value((int) CommonConstants.SUCCESS_CODE))
|
||||
.andExpect(jsonPath("$.msg").value("Modify success"));
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAlertInhibitExists() throws Exception {
|
||||
|
||||
when(alertInhibitService.getAlertInhibit(1L)).thenReturn(alertInhibit);
|
||||
|
||||
mockMvc.perform(get("/api/alert/inhibit/{id}", 1L)
|
||||
.accept(MediaType.APPLICATION_JSON))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.data.id").value(alertInhibit.getId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAlertInhibitNotExists() throws Exception {
|
||||
|
||||
when(alertInhibitService.getAlertInhibit(1L)).thenReturn(null);
|
||||
|
||||
mockMvc.perform(get("/api/alert/inhibit/{id}", 1L)
|
||||
.accept(MediaType.APPLICATION_JSON))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value((int) CommonConstants.MONITOR_NOT_EXIST_CODE))
|
||||
.andExpect(jsonPath("$.msg").value("AlertInhibit not exist."));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -41,12 +41,12 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import java.util.HashMap;
|
||||
import org.apache.hertzbeat.alert.service.impl.DataSourceServiceImpl;
|
||||
import org.apache.hertzbeat.warehouse.db.QueryExecutor;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.mockito.Mockito;
|
||||
import org.apache.hertzbeat.warehouse.db.QueryExecutor;
|
||||
|
||||
/**
|
||||
* test case for {@link DataSourceService}
|
||||
|
||||
@@ -155,11 +155,6 @@
|
||||
<artifactId>plc4j-driver-modbus</artifactId>
|
||||
<version>0.12.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.plc4x</groupId>
|
||||
<artifactId>plc4j-driver-s7</artifactId>
|
||||
<version>0.12.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.sshd</groupId>
|
||||
<artifactId>sshd-sftp</artifactId>
|
||||
|
||||
@@ -40,10 +40,6 @@ import java.util.stream.Stream;
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.collector.collect.AbstractCollect;
|
||||
import org.apache.hertzbeat.collector.collect.common.http.CommonHttpClient;
|
||||
@@ -67,9 +63,11 @@ import org.apache.hertzbeat.common.util.CommonUtil;
|
||||
import org.apache.hertzbeat.common.util.IpDomainUtil;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.auth.AuthScope;
|
||||
import org.apache.http.auth.UsernamePasswordCredentials;
|
||||
import org.apache.http.client.AuthCache;
|
||||
import org.apache.http.client.ClientProtocolException;
|
||||
import org.apache.http.client.CredentialsProvider;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
@@ -79,6 +77,8 @@ import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.client.methods.RequestBuilder;
|
||||
import org.apache.http.client.protocol.HttpClientContext;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.auth.DigestScheme;
|
||||
import org.apache.http.impl.client.BasicAuthCache;
|
||||
import org.apache.http.impl.client.BasicCredentialsProvider;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
@@ -91,8 +91,6 @@ import org.xml.sax.InputSource;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.apache.hertzbeat.common.entity.job.Metrics.Field;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* http https collect
|
||||
@@ -123,7 +121,7 @@ public class HttpCollectImpl extends AbstractCollect {
|
||||
if (CollectionUtils.isEmpty(httpProtocol.getSuccessCodes())) {
|
||||
httpProtocol.setSuccessCodes(List.of(HttpStatus.SC_OK + ""));
|
||||
}
|
||||
|
||||
|
||||
HttpContext httpContext = createHttpContext(metrics.getHttp());
|
||||
HttpUriRequest request = createHttpRequest(metrics.getHttp());
|
||||
try (CloseableHttpResponse response = CommonHttpClient.getHttpClient().execute(request, httpContext)) {
|
||||
@@ -154,7 +152,7 @@ public class HttpCollectImpl extends AbstractCollect {
|
||||
case DispatchConstants.PARSE_PROMETHEUS ->
|
||||
parseResponseByPrometheusExporter(resp, metrics.getAliasFields(), builder);
|
||||
case DispatchConstants.PARSE_XML_PATH ->
|
||||
parseResponseByXmlPath(resp, metrics, builder, responseTime);
|
||||
parseResponseByXmlPath(resp, metrics.getAliasFields(), metrics.getHttp(), builder);
|
||||
case DispatchConstants.PARSE_WEBSITE ->
|
||||
parseResponseByWebsite(resp, metrics, metrics.getHttp(), builder, responseTime);
|
||||
case DispatchConstants.PARSE_SITE_MAP ->
|
||||
@@ -331,95 +329,8 @@ public class HttpCollectImpl extends AbstractCollect {
|
||||
}
|
||||
}
|
||||
|
||||
private void parseResponseByXmlPath(String resp, Metrics metrics,
|
||||
CollectRep.MetricsData.Builder builder, Long responseTime) {
|
||||
HttpProtocol http = metrics.getHttp();
|
||||
List<String> aliasFields = metrics.getAliasFields();
|
||||
String xpathExpression = http.getParseScript();
|
||||
if (!StringUtils.hasText(xpathExpression)) {
|
||||
log.warn("Http collect parse type is xmlPath, but the xpath expression is empty.");
|
||||
builder.setCode(CollectRep.Code.FAIL);
|
||||
builder.setMsg("XPath expression is empty");
|
||||
return;
|
||||
}
|
||||
int keywordNum = CollectUtil.countMatchKeyword(resp, http.getKeyword());
|
||||
|
||||
try {
|
||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
|
||||
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
|
||||
dbf.setXIncludeAware(false);
|
||||
dbf.setExpandEntityReferences(false);
|
||||
|
||||
DocumentBuilder db = dbf.newDocumentBuilder();
|
||||
Document document = db.parse(new InputSource(new StringReader(resp)));
|
||||
|
||||
XPathFactory xpathFactory = XPathFactory.newInstance();
|
||||
XPath xpath = xpathFactory.newXPath();
|
||||
|
||||
NodeList nodeList = (NodeList) xpath.evaluate(xpathExpression, document, XPathConstants.NODESET);
|
||||
|
||||
if (nodeList == null || nodeList.getLength() == 0) {
|
||||
log.debug("XPath expression '{}' returned no nodes.", xpathExpression);
|
||||
boolean requestedSummaryFields = aliasFields.stream()
|
||||
.anyMatch(alias -> NetworkConstants.RESPONSE_TIME.equalsIgnoreCase(alias)
|
||||
|| CollectorConstants.KEYWORD.equalsIgnoreCase(alias));
|
||||
|
||||
if (requestedSummaryFields) {
|
||||
CollectRep.ValueRow.Builder valueRowBuilder = CollectRep.ValueRow.newBuilder();
|
||||
for (String alias : aliasFields) {
|
||||
if (NetworkConstants.RESPONSE_TIME.equalsIgnoreCase(alias)) {
|
||||
valueRowBuilder.addColumn(responseTime.toString());
|
||||
} else if (CollectorConstants.KEYWORD.equalsIgnoreCase(alias)) {
|
||||
valueRowBuilder.addColumn(Integer.toString(keywordNum));
|
||||
} else {
|
||||
valueRowBuilder.addColumn(CommonConstants.NULL_VALUE);
|
||||
}
|
||||
}
|
||||
builder.addValueRow(valueRowBuilder.build());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Field> fieldMap = metrics.getFields().stream()
|
||||
.collect(Collectors.toMap(Field::getField, Function.identity(), (field1, field2) -> field1));
|
||||
|
||||
for (int i = 0; i < nodeList.getLength(); i++) {
|
||||
Node node = nodeList.item(i);
|
||||
CollectRep.ValueRow.Builder valueRowBuilder = CollectRep.ValueRow.newBuilder();
|
||||
|
||||
for (String alias : aliasFields) {
|
||||
if (NetworkConstants.RESPONSE_TIME.equalsIgnoreCase(alias)) {
|
||||
valueRowBuilder.addColumn(responseTime.toString());
|
||||
} else if (CollectorConstants.KEYWORD.equalsIgnoreCase(alias)) {
|
||||
valueRowBuilder.addColumn(Integer.toString(keywordNum));
|
||||
} else {
|
||||
Field field = fieldMap.get(alias);
|
||||
if (field == null || !StringUtils.hasText(field.getXpath())) {
|
||||
log.warn("No field definition or xpath found for alias '{}' in XML path parsing.", alias);
|
||||
valueRowBuilder.addColumn(CommonConstants.NULL_VALUE);
|
||||
continue;
|
||||
}
|
||||
|
||||
String relativeXpath = field.getXpath();
|
||||
try {
|
||||
String value = (String) xpath.evaluate(relativeXpath, node, XPathConstants.STRING);
|
||||
valueRowBuilder.addColumn(StringUtils.hasText(value) ? value : CommonConstants.NULL_VALUE);
|
||||
} catch (XPathExpressionException e) {
|
||||
log.warn("Failed to evaluate relative XPath '{}' (from field definition) for node [{}]: {}", relativeXpath, node.getNodeName(), e.getMessage());
|
||||
valueRowBuilder.addColumn(CommonConstants.NULL_VALUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
builder.addValueRow(valueRowBuilder.build());
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to parse XML response with XPath '{}': {}", xpathExpression, e.getMessage(), e);
|
||||
builder.setCode(CollectRep.Code.FAIL);
|
||||
builder.setMsg("Failed to parse XML response: " + e.getMessage());
|
||||
}
|
||||
private void parseResponseByXmlPath(String resp, List<String> aliasFields, HttpProtocol http,
|
||||
CollectRep.MetricsData.Builder builder) {
|
||||
}
|
||||
|
||||
private void parseResponseByJsonPath(String resp, List<String> aliasFields, HttpProtocol http,
|
||||
@@ -562,10 +473,11 @@ public class HttpCollectImpl extends AbstractCollect {
|
||||
CredentialsProvider provider = new BasicCredentialsProvider();
|
||||
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(auth.getDigestAuthUsername(),
|
||||
auth.getDigestAuthPassword());
|
||||
AuthScope authScope = new AuthScope(httpProtocol.getHost(), Integer.parseInt(httpProtocol.getPort()));
|
||||
provider.setCredentials(authScope, credentials);
|
||||
|
||||
provider.setCredentials(AuthScope.ANY, credentials);
|
||||
AuthCache authCache = new BasicAuthCache();
|
||||
authCache.put(new HttpHost(httpProtocol.getHost(), Integer.parseInt(httpProtocol.getPort())), new DigestScheme());
|
||||
clientContext.setCredentialsProvider(provider);
|
||||
clientContext.setAuthCache(authCache);
|
||||
return clientContext;
|
||||
}
|
||||
}
|
||||
@@ -600,7 +512,7 @@ public class HttpCollectImpl extends AbstractCollect {
|
||||
Map<String, String> params = httpProtocol.getParams();
|
||||
boolean enableUrlEncoding = Boolean.parseBoolean(httpProtocol.getEnableUrlEncoding());
|
||||
StringBuilder queryParams = new StringBuilder();
|
||||
|
||||
|
||||
if (params != null && !params.isEmpty()) {
|
||||
for (Map.Entry<String, String> param : params.entrySet()) {
|
||||
String key = param.getKey();
|
||||
@@ -610,7 +522,7 @@ public class HttpCollectImpl extends AbstractCollect {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!queryParams.isEmpty()) {
|
||||
if (queryParams.length() > 0) {
|
||||
queryParams.append("&");
|
||||
}
|
||||
|
||||
@@ -628,7 +540,7 @@ public class HttpCollectImpl extends AbstractCollect {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// The default request header can be overridden if customized
|
||||
// keep-alive
|
||||
requestBuilder.addHeader(HttpHeaders.CONNECTION, NetworkConstants.KEEP_ALIVE);
|
||||
@@ -669,7 +581,7 @@ public class HttpCollectImpl extends AbstractCollect {
|
||||
|
||||
// if it has payload, would override post params
|
||||
if (StringUtils.hasLength(httpProtocol.getPayload()) && (HttpMethod.POST.matches(httpMethod) || HttpMethod.PUT.matches(httpMethod))) {
|
||||
requestBuilder.setEntity(new StringEntity(TimeExpressionUtil.calculate(httpProtocol.getPayload()), StandardCharsets.UTF_8));
|
||||
requestBuilder.setEntity(new StringEntity(httpProtocol.getPayload(), StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
// uri encode
|
||||
@@ -688,10 +600,10 @@ public class HttpCollectImpl extends AbstractCollect {
|
||||
}
|
||||
|
||||
// append query params
|
||||
if (!queryParams.isEmpty()) {
|
||||
uri += (uri.contains("?") ? "&" : "?") + queryParams;
|
||||
if (queryParams.length() > 0) {
|
||||
uri += (uri.contains("?") ? "&" : "?") + queryParams.toString();
|
||||
}
|
||||
|
||||
|
||||
String finalUri;
|
||||
if (IpDomainUtil.isHasSchema(httpProtocol.getHost())) {
|
||||
finalUri = httpProtocol.getHost() + ":" + httpProtocol.getPort() + uri;
|
||||
@@ -707,7 +619,7 @@ public class HttpCollectImpl extends AbstractCollect {
|
||||
finalUri = NetworkConstants.HTTP_HEADER + baseUri;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
requestBuilder.setUri(finalUri);
|
||||
} catch (IllegalArgumentException e) {
|
||||
|
||||
@@ -33,7 +33,7 @@ import java.util.stream.Stream;
|
||||
import javax.net.ssl.SSLException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.collector.collect.common.http.CommonHttpClient;
|
||||
import org.apache.hertzbeat.common.entity.dto.MetricFamily;
|
||||
import org.apache.hertzbeat.collector.collect.prometheus.parser.MetricFamily;
|
||||
import org.apache.hertzbeat.collector.collect.prometheus.parser.TextParser;
|
||||
import org.apache.hertzbeat.collector.dispatch.DispatchConstants;
|
||||
import org.apache.hertzbeat.collector.util.CollectUtil;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.common.entity.dto;
|
||||
package org.apache.hertzbeat.collector.collect.prometheus.parser;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
@@ -15,20 +15,18 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.common.util;
|
||||
package org.apache.hertzbeat.collector.collect.prometheus.parser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.common.entity.dto.MetricFamily;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
|
||||
@@ -38,23 +36,9 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
@Slf4j
|
||||
public class OnlineParser {
|
||||
|
||||
private static final Map<Integer, Integer> escapeMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
escapeMap.put((int) 'n', (int) '\n');
|
||||
escapeMap.put((int) 'b', (int) '\b');
|
||||
escapeMap.put((int) 't', (int) '\t');
|
||||
escapeMap.put((int) 'r', (int) '\r');
|
||||
escapeMap.put((int) 'f', (int) '\f');
|
||||
escapeMap.put((int) '\'', (int) '\'');
|
||||
escapeMap.put((int) '\"', (int) '\"');
|
||||
escapeMap.put((int) '\\', (int) '\\');
|
||||
}
|
||||
|
||||
private static class FormatException extends Exception {
|
||||
|
||||
public FormatException() {
|
||||
}
|
||||
public FormatException() {}
|
||||
|
||||
public FormatException(String message) {
|
||||
super(message);
|
||||
@@ -139,65 +123,51 @@ public class OnlineParser {
|
||||
|
||||
}
|
||||
|
||||
private static int getChar(InputStream inputStream) throws IOException, FormatException {
|
||||
private static CharChecker parseOneChar(InputStream inputStream) throws IOException {
|
||||
int i = inputStream.read();
|
||||
if (i == '\\') {
|
||||
i = inputStream.read();
|
||||
if (escapeMap.containsKey(i)) {
|
||||
return escapeMap.get(i);
|
||||
} else {
|
||||
throw new FormatException("Escape character failed.");
|
||||
}
|
||||
} else {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
private static CharChecker parseOneChar(InputStream inputStream) throws IOException, FormatException {
|
||||
int i = getChar(inputStream);
|
||||
return new CharChecker(i);
|
||||
}
|
||||
|
||||
private static CharChecker parseOneDouble(InputStream inputStream, StringBuilder stringBuilder) throws IOException, FormatException {
|
||||
int i = getChar(inputStream);
|
||||
private static CharChecker parseOneDouble(InputStream inputStream, StringBuilder stringBuilder) throws IOException {
|
||||
int i = inputStream.read();
|
||||
while ((i >= '0' && i <= '9') || (i >= 'a' && i <= 'z') || (i >= 'A' && i <= 'Z') || i == '-' || i == '+' || i == 'e' || i == '.') {
|
||||
stringBuilder.append((char) i);
|
||||
i = getChar(inputStream);
|
||||
i = inputStream.read();
|
||||
}
|
||||
return new CharChecker(i);
|
||||
}
|
||||
|
||||
private static CharChecker skipOneLong(InputStream inputStream) throws IOException, FormatException {
|
||||
int i = getChar(inputStream);
|
||||
private static CharChecker skipOneLong(InputStream inputStream) throws IOException {
|
||||
int i = inputStream.read();
|
||||
while (i >= '0' && i <= '9') {
|
||||
i = getChar(inputStream);
|
||||
i = inputStream.read();
|
||||
}
|
||||
return new CharChecker(i);
|
||||
}
|
||||
|
||||
private static CharChecker parseMetricName(InputStream inputStream, StringBuilder stringBuilder) throws IOException, FormatException {
|
||||
int i = getChar(inputStream);
|
||||
private static CharChecker parseMetricName(InputStream inputStream, StringBuilder stringBuilder) throws IOException {
|
||||
int i = inputStream.read();
|
||||
while ((i >= 'a' && i <= 'z') || (i >= 'A' && i <= 'Z') || (i >= '0' && i <= '9') || i == '_' || i == ':') {
|
||||
stringBuilder.append((char) i);
|
||||
i = getChar(inputStream);
|
||||
i = inputStream.read();
|
||||
}
|
||||
return new CharChecker(i);
|
||||
}
|
||||
|
||||
private static CharChecker parseLabelName(InputStream inputStream, StringBuilder stringBuilder) throws IOException, FormatException {
|
||||
int i = getChar(inputStream);
|
||||
private static CharChecker parseLabelName(InputStream inputStream, StringBuilder stringBuilder) throws IOException {
|
||||
int i = inputStream.read();
|
||||
while ((i >= 'a' && i <= 'z') || (i >= 'A' && i <= 'Z') || (i >= '0' && i <= '9') || i == '_') {
|
||||
stringBuilder.append((char) i);
|
||||
i = getChar(inputStream);
|
||||
i = inputStream.read();
|
||||
}
|
||||
return new CharChecker(i);
|
||||
}
|
||||
|
||||
private static CharChecker parseLabelValue(InputStream inputStream, StringBuilder stringBuilder) throws IOException, FormatException {
|
||||
int i = getChar(inputStream);
|
||||
int i = inputStream.read();
|
||||
while (i != '"' && i != -1) {
|
||||
if (i == '\\') {
|
||||
i = getChar(inputStream);
|
||||
i = inputStream.read();
|
||||
switch (i) {
|
||||
case 'n':
|
||||
stringBuilder.append('\n');
|
||||
@@ -211,26 +181,27 @@ public class OnlineParser {
|
||||
default:
|
||||
throw new FormatException();
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
stringBuilder.append((char) i);
|
||||
}
|
||||
i = getChar(inputStream);
|
||||
i = inputStream.read();
|
||||
}
|
||||
return new CharChecker(i);
|
||||
}
|
||||
|
||||
private static CharChecker skipSpaces(InputStream inputStream) throws IOException, FormatException {
|
||||
int i = getChar(inputStream);
|
||||
private static CharChecker skipSpaces(InputStream inputStream) throws IOException {
|
||||
int i = inputStream.read();
|
||||
while (i == ' ') {
|
||||
i = getChar(inputStream);
|
||||
i = inputStream.read();
|
||||
}
|
||||
return new CharChecker(i);
|
||||
}
|
||||
|
||||
private static CharChecker skipToLineEnd(InputStream inputStream) throws IOException, FormatException {
|
||||
int i = getChar(inputStream);
|
||||
private static CharChecker skipToLineEnd(InputStream inputStream) throws IOException {
|
||||
int i = inputStream.read();
|
||||
while (i != '\n' && i != -1) {
|
||||
i = getChar(inputStream);
|
||||
i = inputStream.read();
|
||||
}
|
||||
return new CharChecker(i);
|
||||
}
|
||||
@@ -296,18 +267,18 @@ public class OnlineParser {
|
||||
metricFamily.setMetricList(new ArrayList<>());
|
||||
metricFamily.setName(metricName);
|
||||
metricFamilyMap.put(metricName, metricFamily);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
metricFamily = metricFamilyMap.get(metricName);
|
||||
}
|
||||
|
||||
if (i == ' ') {
|
||||
i = skipSpaces(inputStream).getInt();
|
||||
}
|
||||
|
||||
List<MetricFamily.Label> labelList = new LinkedList<>();
|
||||
metric.setLabels(labelList);
|
||||
if (i == '{') {
|
||||
List<MetricFamily.Label> labelList = new LinkedList<>();
|
||||
parseLabels(inputStream, stringBuilder, labelList);
|
||||
metric.setLabels(labelList);
|
||||
i = skipSpaces(inputStream).getInt();
|
||||
}
|
||||
|
||||
@@ -336,8 +307,8 @@ public class OnlineParser {
|
||||
|
||||
public static Map<String, MetricFamily> parseMetrics(InputStream inputStream) throws IOException {
|
||||
Map<String, MetricFamily> metricFamilyMap = new ConcurrentHashMap<>(10);
|
||||
int i = inputStream.read();
|
||||
try {
|
||||
int i = getChar(inputStream);
|
||||
while (i != -1) {
|
||||
if (i == '#' || i == '\n') {
|
||||
skipToLineEnd(inputStream).maybeEol().maybeEof().noElse();
|
||||
@@ -346,7 +317,7 @@ public class OnlineParser {
|
||||
stringBuilder.append((char) i);
|
||||
parseMetric(inputStream, metricFamilyMap, stringBuilder);
|
||||
}
|
||||
i = getChar(inputStream);
|
||||
i = inputStream.read();
|
||||
}
|
||||
} catch (FormatException e) {
|
||||
log.error("prometheus parser failed because of wrong input format. {}", e.getMessage());
|
||||
@@ -24,7 +24,6 @@ import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.collector.collect.http.promethus.ParseException;
|
||||
import org.apache.hertzbeat.common.entity.dto.MetricFamily;
|
||||
import org.apache.hertzbeat.common.util.StrBuffer;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.collector.collect.s7;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.collector.collect.plc.AbstractPlcCollectImpl;
|
||||
import org.apache.hertzbeat.collector.dispatch.DispatchConstants;
|
||||
import org.apache.hertzbeat.common.entity.job.Metrics;
|
||||
import org.apache.hertzbeat.common.entity.job.protocol.PlcProtocol;
|
||||
import org.apache.hertzbeat.common.entity.job.protocol.S7Protocol;
|
||||
import org.apache.hertzbeat.common.entity.message.CollectRep;
|
||||
import org.apache.plc4x.java.api.PlcConnection;
|
||||
import org.apache.plc4x.java.api.messages.PlcReadRequest;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* plc collect
|
||||
*/
|
||||
@Slf4j
|
||||
public class S7CollectImpl extends AbstractPlcCollectImpl {
|
||||
|
||||
@Override
|
||||
public void preCheck(Metrics metrics) throws IllegalArgumentException {
|
||||
S7Protocol s7 = metrics.getS7();
|
||||
List<String> registerAddressList = s7.getRegisterAddresses();
|
||||
// check RackId
|
||||
if (!StringUtils.hasText(s7.getRackId())) {
|
||||
s7.setRackId("0");
|
||||
}
|
||||
// check SlotId
|
||||
if (!StringUtils.hasText(s7.getSlotId())) {
|
||||
s7.setSlotId("0");
|
||||
}
|
||||
// check controllerType
|
||||
if (!StringUtils.hasText(s7.getControllerType())) {
|
||||
s7.setControllerType("S7_1500");
|
||||
}
|
||||
if (!StringUtils.hasText(s7.getTimeout())) {
|
||||
s7.setTimeout("5000");
|
||||
}
|
||||
PlcProtocol plc = metrics.getPlc() == null ? new PlcProtocol() : metrics.getPlc();
|
||||
plc.setRegisterAddresses(registerAddressList);
|
||||
BeanUtils.copyProperties(s7, plc);
|
||||
metrics.setPlc(plc);
|
||||
super.preCheck(metrics);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collect(CollectRep.MetricsData.Builder builder, Metrics metrics) {
|
||||
super.collect(builder, metrics);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String supportProtocol() {
|
||||
return DispatchConstants.PROTOCOL_S7;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getConnectionString(Metrics metrics) {
|
||||
S7Protocol s7Protocol = metrics.getS7();
|
||||
return "s7://" + s7Protocol.getHost() + ":" + s7Protocol.getPort() + "?remote-rack:" + s7Protocol.getRackId()
|
||||
+ "&remote-slot:" + s7Protocol.getSlotId() + "&controller-type=" + s7Protocol.getControllerType();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PlcReadRequest buildRequest(Metrics metrics, PlcConnection connection) {
|
||||
S7Protocol s7Protocol = metrics.getS7();
|
||||
List<String> registerAddressList = s7Protocol.getRegisterAddresses();
|
||||
// Create a new read request:
|
||||
PlcReadRequest.Builder requestBuilder = connection.readRequestBuilder();
|
||||
for (int i = 0; i < registerAddressList.size(); i++) {
|
||||
String s1 = registerAddressList.get(i);
|
||||
requestBuilder.addTagAddress(metrics.getS7().getAddressSyntax() + ":" + i, s1);
|
||||
}
|
||||
return requestBuilder.build();
|
||||
}
|
||||
}
|
||||
@@ -47,28 +47,31 @@ public class DnsCollectImplTest {
|
||||
.address("www.google.com")
|
||||
.timeout("3000")
|
||||
.port("53")
|
||||
.tcp("tcp")
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreCheck() {
|
||||
CollectRep.MetricsData.Builder builder = CollectRep.MetricsData.newBuilder();
|
||||
//metrics is null
|
||||
dnsCollect.collect(builder, null);
|
||||
assertEquals(CollectRep.Code.FAIL, builder.getCode());
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
Metrics metrics = new Metrics();
|
||||
metrics.setName("question");
|
||||
metrics.setDns(dnsProtocol);
|
||||
dnsCollect.preCheck(metrics);
|
||||
});
|
||||
|
||||
//invalid DnsProtocol
|
||||
Metrics metrics = new Metrics();
|
||||
//query class is blank
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
DnsProtocol dns = DnsProtocol.builder().build();
|
||||
|
||||
Metrics metrics = new Metrics();
|
||||
metrics.setDns(dns);
|
||||
dnsCollect.preCheck(metrics);
|
||||
});
|
||||
|
||||
//validated DnsProtocol
|
||||
// no exception throws
|
||||
assertDoesNotThrow(() -> {
|
||||
metrics.setName("question");
|
||||
dnsProtocol.setTcp("tcp");
|
||||
Metrics metrics = new Metrics();
|
||||
metrics.setDns(dnsProtocol);
|
||||
dnsCollect.preCheck(metrics);
|
||||
});
|
||||
@@ -77,23 +80,28 @@ public class DnsCollectImplTest {
|
||||
@Test
|
||||
public void testCollect() {
|
||||
CollectRep.MetricsData.Builder builder = CollectRep.MetricsData.newBuilder();
|
||||
Metrics metrics0 = Metrics.builder()
|
||||
.name("question")
|
||||
.dns(dnsProtocol)
|
||||
.aliasFields(Collections.singletonList("section"))
|
||||
.build();
|
||||
dnsCollect.collect(builder, metrics0);
|
||||
assertEquals(CollectRep.Code.SUCCESS, builder.getCode());
|
||||
long monitorId = 666;
|
||||
String app = "testDNS";
|
||||
Metrics metrics = new Metrics();
|
||||
metrics.setName("question");
|
||||
metrics.setDns(dnsProtocol);
|
||||
metrics.setAliasFields(Collections.singletonList("section"));
|
||||
dnsCollect.collect(builder, metrics);
|
||||
assertNotNull(builder.getValues(0).getColumns(0));
|
||||
|
||||
// dns is null, no exception throws
|
||||
assertDoesNotThrow(() -> {
|
||||
dnsCollect.collect(builder, null);
|
||||
});
|
||||
|
||||
// metric name is header
|
||||
Metrics metrics1 = Metrics.builder()
|
||||
.name("header")
|
||||
.dns(dnsProtocol)
|
||||
.aliasFields(Collections.singletonList("section"))
|
||||
.build();
|
||||
dnsCollect.collect(builder, metrics1);
|
||||
assertEquals(CollectRep.Code.SUCCESS, builder.getCode());
|
||||
assertDoesNotThrow(() -> {
|
||||
Metrics metrics1 = new Metrics();
|
||||
metrics1.setName("header");
|
||||
metrics1.setDns(dnsProtocol);
|
||||
metrics1.setAliasFields(Collections.singletonList("section"));
|
||||
dnsCollect.collect(builder, metrics1);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -18,14 +18,7 @@
|
||||
package org.apache.hertzbeat.collector.collect.http;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.apache.hertzbeat.collector.dispatch.DispatchConstants;
|
||||
import org.apache.hertzbeat.common.entity.job.Metrics;
|
||||
import org.apache.hertzbeat.common.entity.job.protocol.HttpProtocol;
|
||||
import org.apache.hertzbeat.common.entity.message.CollectRep;
|
||||
@@ -48,7 +41,7 @@ class HttpCollectImplTest {
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
httpCollectImpl.preCheck(null);
|
||||
});
|
||||
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
Metrics metrics = Metrics.builder().build();
|
||||
httpCollectImpl.preCheck(metrics);
|
||||
@@ -72,92 +65,4 @@ class HttpCollectImplTest {
|
||||
String protocol = httpCollectImpl.supportProtocol();
|
||||
assert "http".equals(protocol);
|
||||
}
|
||||
|
||||
@Test
|
||||
void parseResponseByXmlPath() throws Exception {
|
||||
// Create a sample XML response
|
||||
String xmlResponse = """
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<root>
|
||||
<server>
|
||||
<name>Server1</name>
|
||||
<status>Running</status>
|
||||
<metrics>
|
||||
<cpu>75.5</cpu>
|
||||
<memory>1024</memory>
|
||||
<disk>500</disk>
|
||||
</metrics>
|
||||
</server>
|
||||
<server>
|
||||
<name>Server2</name>
|
||||
<status>Stopped</status>
|
||||
<metrics>
|
||||
<cpu>0.0</cpu>
|
||||
<memory>0</memory>
|
||||
<disk>500</disk>
|
||||
</metrics>
|
||||
</server>
|
||||
</root>
|
||||
""";
|
||||
|
||||
// Set up HttpProtocol with XML path parsing
|
||||
HttpProtocol http = HttpProtocol.builder()
|
||||
.parseType(DispatchConstants.PARSE_XML_PATH)
|
||||
.parseScript("//server") // XPath to select all server nodes
|
||||
.build();
|
||||
|
||||
// Set up Metrics with fields that have XPath expressions
|
||||
List<Metrics.Field> fields = new ArrayList<>();
|
||||
fields.add(Metrics.Field.builder().field("name").xpath("name").build());
|
||||
fields.add(Metrics.Field.builder().field("status").xpath("status").build());
|
||||
fields.add(Metrics.Field.builder().field("cpu").xpath("metrics/cpu").build());
|
||||
fields.add(Metrics.Field.builder().field("memory").xpath("metrics/memory").build());
|
||||
|
||||
Metrics metrics = Metrics.builder()
|
||||
.http(http)
|
||||
.fields(fields)
|
||||
.aliasFields(Arrays.asList("name", "status", "cpu", "memory"))
|
||||
.build();
|
||||
|
||||
// Create a custom builder that captures added rows
|
||||
List<CollectRep.ValueRow> capturedRows = new ArrayList<>();
|
||||
CollectRep.MetricsData.Builder builder = new CollectRep.MetricsData.Builder() {
|
||||
@Override
|
||||
public CollectRep.MetricsData.Builder addValueRow(CollectRep.ValueRow valueRow) {
|
||||
capturedRows.add(valueRow);
|
||||
return super.addValueRow(valueRow);
|
||||
}
|
||||
};
|
||||
|
||||
// Use reflection to access the private parseResponseByXmlPath method
|
||||
Method parseMethod = HttpCollectImpl.class.getDeclaredMethod(
|
||||
"parseResponseByXmlPath",
|
||||
String.class,
|
||||
Metrics.class,
|
||||
CollectRep.MetricsData.Builder.class,
|
||||
Long.class);
|
||||
parseMethod.setAccessible(true);
|
||||
|
||||
// Call the method
|
||||
parseMethod.invoke(httpCollectImpl, xmlResponse, metrics, builder, 100L);
|
||||
|
||||
// Verify the results
|
||||
assertEquals(2, capturedRows.size(), "Should have parsed 2 server nodes");
|
||||
|
||||
// Check first server
|
||||
CollectRep.ValueRow firstRow = capturedRows.get(0);
|
||||
assertEquals(4, firstRow.getColumnsCount(), "First row should have 4 columns");
|
||||
assertEquals("Server1", firstRow.getColumns(0), "First server name should be Server1");
|
||||
assertEquals("Running", firstRow.getColumns(1), "First server status should be Running");
|
||||
assertEquals("75.5", firstRow.getColumns(2), "First server CPU should be 75.5");
|
||||
assertEquals("1024", firstRow.getColumns(3), "First server memory should be 1024");
|
||||
|
||||
// Check second server
|
||||
CollectRep.ValueRow secondRow = capturedRows.get(1);
|
||||
assertEquals(4, secondRow.getColumnsCount(), "Second row should have 4 columns");
|
||||
assertEquals("Server2", secondRow.getColumns(0), "Second server name should be Server2");
|
||||
assertEquals("Stopped", secondRow.getColumns(1), "Second server status should be Stopped");
|
||||
assertEquals("0.0", secondRow.getColumns(2), "Second server CPU should be 0.0");
|
||||
assertEquals("0", secondRow.getColumns(3), "Second server memory should be 0");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
|
||||
package org.apache.hertzbeat.collector.collect.prometheus.parser;
|
||||
|
||||
import org.apache.hertzbeat.common.entity.dto.MetricFamily;
|
||||
import org.apache.hertzbeat.common.util.OnlineParser;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
||||
@@ -29,5 +29,4 @@ org.apache.hertzbeat.collector.collect.mqtt.MqttCollectImpl
|
||||
org.apache.hertzbeat.collector.collect.ipmi2.IpmiCollectImpl
|
||||
org.apache.hertzbeat.collector.collect.kafka.KafkaCollectImpl
|
||||
org.apache.hertzbeat.collector.collect.sd.HttpSdCollectImpl
|
||||
org.apache.hertzbeat.collector.collect.modbus.ModbusCollectImpl
|
||||
org.apache.hertzbeat.collector.collect.s7.S7CollectImpl
|
||||
org.apache.hertzbeat.collector.collect.modbus.ModbusCollectImpl
|
||||
@@ -227,9 +227,4 @@ public interface DispatchConstants {
|
||||
* protocol modbus
|
||||
*/
|
||||
String PROTOCOL_MODBUS = "modbus";
|
||||
|
||||
/**
|
||||
* protocol modbus
|
||||
*/
|
||||
String PROTOCOL_S7 = "s7";
|
||||
}
|
||||
|
||||
@@ -242,7 +242,6 @@ public class KafkaCollectImpl extends AbstractCollect {
|
||||
boolean isKafkaCommand = SupportedCommand.isKafkaCommand(command);
|
||||
if (!isKafkaCommand) {
|
||||
log.error("Unsupported command: {}", command);
|
||||
builder.setCode(CollectRep.Code.FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -274,7 +273,7 @@ public class KafkaCollectImpl extends AbstractCollect {
|
||||
}
|
||||
}
|
||||
|
||||
protected AdminClient getAdminClient(KafkaProtocol kafkaProtocol) {
|
||||
private AdminClient getAdminClient(KafkaProtocol kafkaProtocol) {
|
||||
CacheIdentifier kafkaAdminClientIdentifier = CacheIdentifier.builder()
|
||||
.ip(kafkaProtocol.getHost()).port(kafkaProtocol.getPort())
|
||||
.build();
|
||||
|
||||
@@ -17,24 +17,12 @@
|
||||
|
||||
package org.apache.hertzbeat.collector.collect.kafka;
|
||||
|
||||
import org.apache.hertzbeat.collector.collect.kafka.constants.SupportedCommand;
|
||||
import org.apache.hertzbeat.collector.dispatch.DispatchConstants;
|
||||
import org.apache.hertzbeat.common.entity.job.Metrics;
|
||||
import org.apache.hertzbeat.common.entity.job.protocol.KafkaProtocol;
|
||||
import org.apache.hertzbeat.common.entity.message.CollectRep;
|
||||
import org.apache.kafka.clients.admin.AdminClient;
|
||||
import org.apache.kafka.clients.admin.ListTopicsOptions;
|
||||
import org.apache.kafka.clients.admin.ListTopicsResult;
|
||||
import org.apache.kafka.common.KafkaFuture;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
@@ -43,25 +31,12 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
/**
|
||||
* Test case for {@link KafkaCollectImpl}
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class KafkaCollectTest {
|
||||
|
||||
private static final String HOST = "127.0.0.1";
|
||||
private static final String PORT = "9092";
|
||||
|
||||
private KafkaCollectImpl collect;
|
||||
|
||||
@Mock
|
||||
private AdminClient adminClient;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() throws Exception {
|
||||
collect = new KafkaCollectImpl(){
|
||||
@Override
|
||||
protected AdminClient getAdminClient(KafkaProtocol protocol) {
|
||||
return adminClient;
|
||||
}
|
||||
};
|
||||
collect = new KafkaCollectImpl();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -84,51 +59,38 @@ public class KafkaCollectTest {
|
||||
});
|
||||
// kafka port is null
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
kafka.setHost(HOST);
|
||||
kafka.setHost("127.0.0.1");
|
||||
collect.preCheck(metric);
|
||||
});
|
||||
// no exception throw
|
||||
assertDoesNotThrow(() -> {
|
||||
kafka.setPort(PORT);
|
||||
kafka.setPort("9092");
|
||||
collect.preCheck(metric);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCollect() throws Exception {
|
||||
Set<String> topicSet = new HashSet<>();
|
||||
topicSet.add("test-topic");
|
||||
|
||||
ListTopicsResult listTopicsResult = Mockito.mock(ListTopicsResult.class);
|
||||
KafkaFuture<Set<String>> future = Mockito.mock(KafkaFuture.class);
|
||||
|
||||
Mockito.when(adminClient.listTopics(Mockito.any(ListTopicsOptions.class))).thenReturn(listTopicsResult);
|
||||
Mockito.when(listTopicsResult.names()).thenReturn(future);
|
||||
Mockito.when(future.get()).thenReturn(topicSet);
|
||||
|
||||
KafkaProtocol kafka = KafkaProtocol.builder()
|
||||
.host(HOST)
|
||||
.port(PORT)
|
||||
.build();
|
||||
|
||||
Metrics metrics = Metrics.builder()
|
||||
.kclient(kafka)
|
||||
.build();
|
||||
|
||||
// test if not kafka command
|
||||
CollectRep.MetricsData.Builder builder = CollectRep.MetricsData.newBuilder();
|
||||
collect.collect(builder, metrics);
|
||||
assertEquals(CollectRep.Code.FAIL, builder.getCode());
|
||||
void collect() {
|
||||
// metrics is null
|
||||
assertThrows(NullPointerException.class, () -> {
|
||||
CollectRep.MetricsData.Builder builder = CollectRep.MetricsData.newBuilder();
|
||||
collect.collect(builder, null);
|
||||
});
|
||||
|
||||
KafkaProtocol kafka = KafkaProtocol.builder().host("127.0.0.1").port("9092").build();
|
||||
Metrics metrics = Metrics.builder().kclient(kafka).build();
|
||||
//test if not kafka command
|
||||
assertDoesNotThrow(() -> {
|
||||
CollectRep.MetricsData.Builder builder = CollectRep.MetricsData.newBuilder();
|
||||
collect.collect(builder, metrics);
|
||||
});
|
||||
//test kafka command
|
||||
kafka.setCommand(SupportedCommand.TOPIC_LIST.getCommand());
|
||||
builder.setCode(CollectRep.Code.forNumber(6));
|
||||
collect.collect(builder, metrics);
|
||||
assertDoesNotThrow(() -> {
|
||||
CollectRep.MetricsData.Builder builder = CollectRep.MetricsData.newBuilder();
|
||||
metrics.getKclient().setCommand("topic-list");
|
||||
collect.collect(builder, metrics);
|
||||
});
|
||||
|
||||
assertEquals(CollectRep.Code.SUCCESS, builder.getCode());
|
||||
assertEquals(1, builder.getValuesList().size());
|
||||
assertEquals("test-topic", builder.getValues(0).getColumns(0));
|
||||
Mockito.verify(adminClient).listTopics(Mockito.any(ListTopicsOptions.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -455,19 +455,4 @@ public interface CommonConstants {
|
||||
* status page incident state resolved
|
||||
*/
|
||||
byte STATUS_PAGE_INCIDENT_STATE_RESOLVED = 3;
|
||||
|
||||
/**
|
||||
* status page incident state resolved
|
||||
*/
|
||||
byte MONITOR_TYPE_NORMAL = 0;
|
||||
|
||||
/**
|
||||
* status page incident state resolved
|
||||
*/
|
||||
byte MONITOR_TYPE_PUSH_AUTO_CREATE = 1;
|
||||
|
||||
/**
|
||||
* status page incident state resolved
|
||||
*/
|
||||
byte MONITOR_TYPE_DISCOVERY_AUTO_CREATE = 2;
|
||||
}
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.common.entity.dto.query;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Metric History Range Query Data
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Metric Query Data")
|
||||
public class MetricQueryData {
|
||||
|
||||
@Schema(title = "Metric Schema")
|
||||
private MetricSchema schema;
|
||||
|
||||
@Schema(title = "metrics row values, first is the timestamp-ts", example = "[[29,32,44],[32,34,true]]")
|
||||
private List<List<Object>> values;
|
||||
|
||||
/**
|
||||
* Metric Schema
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public static final class MetricSchema {
|
||||
|
||||
@Schema(title = "Metrics Field")
|
||||
private List<MetricField> fields;
|
||||
|
||||
@Schema(title = "Meta Information")
|
||||
private Map<String, String> meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Metric Field
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public static final class MetricField {
|
||||
|
||||
@Schema(title = "Metric Field Name")
|
||||
private String name;
|
||||
|
||||
@Schema(title = "Field Type: number, string, time, bool")
|
||||
private String type;
|
||||
|
||||
@Schema(title = "Field Unit: %, Mb, Kbps etc.")
|
||||
private String unit;
|
||||
|
||||
@Schema(title = "Whether is a label")
|
||||
private Boolean label;
|
||||
}
|
||||
}
|
||||
@@ -54,7 +54,6 @@ import org.apache.hertzbeat.common.entity.job.protocol.PushProtocol;
|
||||
import org.apache.hertzbeat.common.entity.job.protocol.RedfishProtocol;
|
||||
import org.apache.hertzbeat.common.entity.job.protocol.RedisProtocol;
|
||||
import org.apache.hertzbeat.common.entity.job.protocol.RocketmqProtocol;
|
||||
import org.apache.hertzbeat.common.entity.job.protocol.S7Protocol;
|
||||
import org.apache.hertzbeat.common.entity.job.protocol.ScriptProtocol;
|
||||
import org.apache.hertzbeat.common.entity.job.protocol.SmtpProtocol;
|
||||
import org.apache.hertzbeat.common.entity.job.protocol.SnmpProtocol;
|
||||
@@ -271,10 +270,6 @@ public class Metrics {
|
||||
* Monitoring configuration information using the public modBus protocol
|
||||
*/
|
||||
private ModbusProtocol modbus;
|
||||
/**
|
||||
* Monitoring configuration information using the public s7 protocol
|
||||
*/
|
||||
private S7Protocol s7;
|
||||
/**
|
||||
* collector use - Temporarily store subTask metrics response data
|
||||
*/
|
||||
@@ -377,10 +372,5 @@ public class Metrics {
|
||||
* Metric unit
|
||||
*/
|
||||
private String unit;
|
||||
|
||||
/**
|
||||
* when parse type is xmlParse, use it, like NetPortStatusList/NetPortStatus[id='1']/workSpeed
|
||||
*/
|
||||
private String xpath;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,9 +91,6 @@ public class Monitor {
|
||||
@Max(4)
|
||||
private byte status;
|
||||
|
||||
@Schema(title = "Task type 0: Normal, 1: push auto create, 2: discovery auto create")
|
||||
private byte type;
|
||||
|
||||
@Schema(title = "task label", example = "{env:test}", accessMode = READ_WRITE)
|
||||
@Convert(converter = JsonMapAttributeConverter.class)
|
||||
@Column(length = 4096)
|
||||
|
||||
@@ -28,7 +28,6 @@ import org.springframework.context.annotation.ImportRuntimeHints;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
/**
|
||||
* start up class.
|
||||
@@ -42,7 +41,6 @@ import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
@ConfigurationPropertiesScan(basePackages = {"org.apache.hertzbeat"})
|
||||
@ImportRuntimeHints(HertzbeatRuntimeHintsRegistrar.class)
|
||||
@EnableAsync
|
||||
@EnableScheduling
|
||||
public class Manager {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Manager.class, args);
|
||||
|
||||
@@ -531,7 +531,7 @@ public class MonitorServiceImpl implements MonitorService {
|
||||
MonitorDto monitorDto = new MonitorDto();
|
||||
List<Param> params = paramDao.findParamsByMonitorId(id);
|
||||
monitorDto.setParams(params);
|
||||
if (DispatchConstants.PROTOCOL_PROMETHEUS.equalsIgnoreCase(monitor.getApp()) || monitor.getType() == CommonConstants.MONITOR_TYPE_PUSH_AUTO_CREATE) {
|
||||
if (DispatchConstants.PROTOCOL_PROMETHEUS.equalsIgnoreCase(monitor.getApp())) {
|
||||
List<CollectRep.MetricsData> metricsDataList = warehouseService.queryMonitorMetricsData(id);
|
||||
List<String> metrics = metricsDataList.stream().map(CollectRep.MetricsData::getMetrics).collect(Collectors.toList());
|
||||
monitorDto.setMetrics(metrics);
|
||||
|
||||
@@ -1,250 +0,0 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# The monitoring type category:service-application service monitoring db-database monitoring custom-custom monitoring os-operating system monitoring
|
||||
category: server
|
||||
# The monitoring type eg: linux windows tomcat mysql aws...
|
||||
app: hikvision_isapi
|
||||
# The monitoring i18n name
|
||||
name:
|
||||
zh-CN: 海康威视 ISAPI
|
||||
en-US: Hikvision ISAPI
|
||||
# The description and help of this monitoring type
|
||||
help:
|
||||
zh-CN: 通过ISAPI接口监控海康威视设备状态,获取设备健康数据。
|
||||
en-US: Monitor Hikvision devices through ISAPI interface to collect health data.
|
||||
|
||||
# Input params define for monitoring(render web ui by the definition)
|
||||
params:
|
||||
- field: host
|
||||
name:
|
||||
zh-CN: 主机Host
|
||||
en-US: Host
|
||||
type: host
|
||||
required: true
|
||||
- field: port
|
||||
name:
|
||||
zh-CN: 端口
|
||||
en-US: Port
|
||||
type: number
|
||||
range: '[0,65535]'
|
||||
required: true
|
||||
defaultValue: 80
|
||||
- field: timeout
|
||||
name:
|
||||
zh-CN: 超时时间(ms)
|
||||
en-US: Timeout(ms)
|
||||
type: number
|
||||
range: '[1000,60000]'
|
||||
required: true
|
||||
defaultValue: 5000
|
||||
- field: username
|
||||
name:
|
||||
zh-CN: 用户名
|
||||
en-US: Username
|
||||
type: text
|
||||
required: true
|
||||
- field: password
|
||||
name:
|
||||
zh-CN: 密码
|
||||
en-US: Password
|
||||
type: password
|
||||
required: true
|
||||
- field: ssl
|
||||
name:
|
||||
zh-CN: 启用HTTPS
|
||||
en-US: SSL
|
||||
type: boolean
|
||||
required: false
|
||||
defaultValue: false
|
||||
|
||||
# collect metrics config list
|
||||
metrics:
|
||||
- name: system_info
|
||||
i18n:
|
||||
zh-CN: 系统信息
|
||||
en-US: System Info
|
||||
priority: 0
|
||||
protocol: http
|
||||
http:
|
||||
host: ^_^host^_^
|
||||
port: ^_^port^_^
|
||||
ssl: ^_^ssl^_^
|
||||
url: /ISAPI/System/deviceInfo
|
||||
method: GET
|
||||
timeout: ^_^timeout^_^
|
||||
authorization:
|
||||
type: Digest Auth
|
||||
digestAuthUsername: ^_^username^_^
|
||||
digestAuthPassword: ^_^password^_^
|
||||
parseType: xmlPath
|
||||
parseScript: 'DeviceInfo'
|
||||
fields:
|
||||
- field: deviceName
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 设备名称
|
||||
en-US: Device Name
|
||||
xpath: deviceName
|
||||
- field: deviceID
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 设备ID
|
||||
en-US: Device ID
|
||||
xpath: deviceID
|
||||
- field: firmwareVersion
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 固件版本
|
||||
en-US: Firmware Version
|
||||
xpath: firmwareVersion
|
||||
- field: model
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 设备型号
|
||||
en-US: Device Model
|
||||
xpath: model
|
||||
- field: macAddress
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: mac地址
|
||||
en-US: Mac Address
|
||||
xpath: macAddress
|
||||
- name: status
|
||||
protocol: http
|
||||
http:
|
||||
host: ^_^host^_^
|
||||
port: ^_^port^_^
|
||||
ssl: ^_^ssl^_^
|
||||
url: /ISAPI/System/status
|
||||
method: GET
|
||||
timeout: ^_^timeout^_^
|
||||
authorization:
|
||||
type: Digest Auth
|
||||
digestAuthUsername: ^_^username^_^
|
||||
digestAuthPassword: ^_^password^_^
|
||||
parseType: xmlPath
|
||||
parseScript: 'DeviceStatus'
|
||||
fields:
|
||||
- field: cpuUtilization
|
||||
i18n:
|
||||
zh-CN: CPU 利用率
|
||||
en-US: CPU Utilization
|
||||
type: 0
|
||||
unit: '%'
|
||||
xpath: CPUList/CPU/cpuUtilization
|
||||
- field: memoryUsage
|
||||
i18n:
|
||||
zh-CN: 内存使用量
|
||||
en-US: Memory Usage
|
||||
type: 0
|
||||
unit: MB
|
||||
xpath: MemoryList/Memory/memoryUsage
|
||||
- field: memoryAvailable
|
||||
i18n:
|
||||
zh-CN: 可用内存
|
||||
en-US: Memory Available
|
||||
type: 0
|
||||
unit: MB
|
||||
xpath: MemoryList/Memory/memoryAvailable
|
||||
- field: cacheSize
|
||||
i18n:
|
||||
zh-CN: 缓存大小
|
||||
en-US: Cache Size
|
||||
type: 0
|
||||
unit: MB
|
||||
xpath: MemoryList/Memory/cacheSize
|
||||
- field: netPort1Speed
|
||||
i18n:
|
||||
zh-CN: 网口1速度
|
||||
en-US: Net Port 1 Speed
|
||||
type: 0
|
||||
unit: Mbps
|
||||
xpath: NetPortStatusList/NetPortStatus[id='1']/workSpeed
|
||||
- field: netPort2Speed
|
||||
i18n:
|
||||
zh-CN: 网口2速度
|
||||
en-US: Net Port 2 Speed
|
||||
type: 0
|
||||
unit: Mbps
|
||||
xpath: NetPortStatusList/NetPortStatus[id='2']/workSpeed
|
||||
- field: bootTime
|
||||
i18n:
|
||||
zh-CN: 启动时间
|
||||
en-US: Boot Time
|
||||
type: 1
|
||||
xpath: bootTime
|
||||
- field: deviceUpTime
|
||||
i18n:
|
||||
zh-CN: 运行时长
|
||||
en-US: Device Uptime
|
||||
type: 1
|
||||
xpath: deviceUpTime
|
||||
- field: lastCalibrationTime
|
||||
i18n:
|
||||
zh-CN: 上次校时时间
|
||||
en-US: Last Calibration Time
|
||||
type: 1
|
||||
xpath: lastCalibrationTime
|
||||
- field: lastCalibrationTimeDiff
|
||||
i18n:
|
||||
zh-CN: 上次校时时间差
|
||||
en-US: Last Calibration Time Diff
|
||||
type: 0
|
||||
unit: s
|
||||
xpath: lastCalibrationTimeDiff
|
||||
- field: avgUploadTime
|
||||
i18n:
|
||||
zh-CN: 平均上传耗时
|
||||
en-US: Avg Upload Time
|
||||
type: 0
|
||||
unit: ms
|
||||
xpath: uploadTimeConsumingList/avgTime
|
||||
- field: maxUploadTime
|
||||
i18n:
|
||||
zh-CN: 最大上传耗时
|
||||
en-US: Max Upload Time
|
||||
type: 0
|
||||
unit: ms
|
||||
xpath: uploadTimeConsumingList/maxTime
|
||||
- field: minUploadTime
|
||||
i18n:
|
||||
zh-CN: 最小上传耗时
|
||||
en-US: Min Upload Time
|
||||
type: 0
|
||||
unit: ms
|
||||
xpath: uploadTimeConsumingList/minTime
|
||||
- field: lastCalibrationMode
|
||||
i18n:
|
||||
zh-CN: 上次校时模式
|
||||
en-US: Last Calibration Mode
|
||||
type: 1
|
||||
xpath: lastCalibrationTimeMode
|
||||
- field: lastCalibrationAddress
|
||||
i18n:
|
||||
zh-CN: 上次校时地址
|
||||
en-US: Last Calibration Address
|
||||
type: 1
|
||||
xpath: lastCalibrationTimeAddress
|
||||
- field: responseTime
|
||||
i18n:
|
||||
zh-CN: 响应时间
|
||||
en-US: Response Time
|
||||
type: 0
|
||||
unit: ms
|
||||
units:
|
||||
- memoryUsage=KB->MB
|
||||
- memoryAvailable=KB->MB
|
||||
- cacheSize=KB->MB
|
||||
@@ -1,263 +0,0 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# 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: s7
|
||||
# The app api i18n name
|
||||
name:
|
||||
zh-CN: s7服务器
|
||||
en-US: s7 Server
|
||||
# The description and help of this monitoring type
|
||||
help:
|
||||
zh-CN: HertzBeat对支持s7协议的服务进行(保持寄存器和线圈)相关指标进行采集
|
||||
en-US: HertzBeat collects metrics related to maintaining registers and coils for services that support s7 protocol
|
||||
zh-TW: HertzBeat對支持s7協定的服務進行(保持寄存器和線圈)相關名額進行採集
|
||||
# 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: s7服务Host
|
||||
en-US: s7 Server 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
|
||||
defaultValue: 102
|
||||
- field: rackId
|
||||
# name-param field display i18n name
|
||||
name:
|
||||
zh-CN: rackId
|
||||
en-US: rackId
|
||||
# type-param field type(most mapping the html input type)
|
||||
type: text
|
||||
# required-true or false
|
||||
required: false
|
||||
defaultValue: 0
|
||||
- field: slotId
|
||||
# name-param field display i18n name
|
||||
name:
|
||||
zh-CN: slotId
|
||||
en-US: slotId
|
||||
# type-param field type(most mapping the html input type)
|
||||
type: text
|
||||
# required-true or false
|
||||
required: false
|
||||
defaultValue: 0
|
||||
- field: controllerType
|
||||
# name-param field display i18n name
|
||||
name:
|
||||
zh-CN: controllerType
|
||||
en-US: controllerType
|
||||
# type-param field type(most mapping the html input type)
|
||||
type: text
|
||||
# required-true or false
|
||||
required: false
|
||||
defaultValue: S7_1500
|
||||
- field: timeout
|
||||
name:
|
||||
zh-CN: 请求超时时间(ms)
|
||||
en-US: Request Timeout(ms)
|
||||
type: number
|
||||
# when type is number, range is required
|
||||
range: '[400,200000]'
|
||||
required: false
|
||||
defaultValue: 6000
|
||||
hide: true
|
||||
- field: holdingRegisterAddresses
|
||||
# name-param field display i18n name
|
||||
name:
|
||||
zh-CN: 保持寄存器地址
|
||||
en-US: Holding Registers address
|
||||
# type-param field type(most mapping the html input type)
|
||||
type: array
|
||||
# param field input placeholder
|
||||
placeholder: 'Input RegisterAddress'
|
||||
# required-true or false
|
||||
required: true
|
||||
# hide param-true or false
|
||||
# hide: true
|
||||
- field: coilRegisterAddresses
|
||||
# name-param field display i18n name
|
||||
name:
|
||||
zh-CN: 线圈寄存器地址
|
||||
en-US: Coil Register address
|
||||
# type-param field type(most mapping the html input type)
|
||||
type: array
|
||||
# param field input placeholder
|
||||
placeholder: 'Input RegisterAddress'
|
||||
# required-true or false
|
||||
required: true
|
||||
# hide param-true or false
|
||||
# hide: true
|
||||
|
||||
# collect metrics config list
|
||||
metrics:
|
||||
# metrics - summary
|
||||
- name: holding-register
|
||||
i18n:
|
||||
zh-CN: 保持寄存器 统计信息
|
||||
en-US: holding-register stats
|
||||
# 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
|
||||
# collect metrics content
|
||||
fields:
|
||||
- field: responseTime
|
||||
type: 0
|
||||
unit: ms
|
||||
i18n:
|
||||
zh-CN: 响应时间
|
||||
en-US: Response Time
|
||||
# field-metric name, type-metric type(0-number,1-string), unit-metric unit('%','ms','MB'), label-whether it is a metrics label field
|
||||
- field: address-0
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: address-0
|
||||
en-US: address-0
|
||||
# field-metric name, type-metric type(0-number,1-string), unit-metric unit('%','ms','MB'), label-whether it is a metrics label field
|
||||
- field: address-1
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: address-1
|
||||
en-US: address-1
|
||||
- field: address-2
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: address-2
|
||||
en-US: address-2
|
||||
- field: address-3
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: address-3
|
||||
en-US: address-3
|
||||
# 指标别名列表,按照寄存器地址来进行命名的
|
||||
# 例如 地址为下标为0 ,值为m holding-register:0
|
||||
# 地址为下标为1,值为m[2] holding-register:1-0 holding-register:1-1
|
||||
aliasFields:
|
||||
- responseTime
|
||||
- holding-register:0
|
||||
- holding-register:1
|
||||
- holding-register:2
|
||||
- holding-register:3
|
||||
# mapping and conversion expressions, use thesand aliasField above to calculate metrics value# (可选)指标映射转换计算表达式,与上面的别名一起作用,计算出最终需要的指标值# eg: cores=core1+core2, usage=usage, waitTimeallTime-runningTime
|
||||
calculates:
|
||||
- responseTime=responseTime
|
||||
- address-0=holding-register:0
|
||||
- address-1=holding-register:1
|
||||
- address-2=holding-register:2
|
||||
- address-3=holding-register:3
|
||||
protocol: s7
|
||||
# the config content when protocol is http
|
||||
s7:
|
||||
# host
|
||||
host: ^_^host^_^
|
||||
# port
|
||||
port: ^_^port^_^
|
||||
driverName: s7
|
||||
addressSyntax: holding-register
|
||||
rackId: ^_^rackId^_^
|
||||
slotId: ^_^slotId^_^
|
||||
controllerType: ^_^controllerType^_^
|
||||
timeout: ^_^timeout^_^
|
||||
registerAddresses: [ ^_^holdingRegisterAddresses^_^ ]
|
||||
|
||||
# metrics - summary
|
||||
- name: coil
|
||||
i18n:
|
||||
zh-CN: 线圈 统计信息
|
||||
en-US: coil stats
|
||||
# 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: 1
|
||||
# collect metrics content
|
||||
fields:
|
||||
- field: responseTime
|
||||
type: 0
|
||||
unit: ms
|
||||
i18n:
|
||||
zh-CN: 响应时间
|
||||
en-US: Response Time
|
||||
# field-metric name, type-metric type(0-number,1-string), unit-metric unit('%','ms','MB'), label-whether it is a metrics label field
|
||||
- field: address-0
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: address-0
|
||||
en-US: address-0
|
||||
# field-metric name, type-metric type(0-number,1-string), unit-metric unit('%','ms','MB'), label-whether it is a metrics label field
|
||||
- field: address-1
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: address-1
|
||||
en-US: address-1
|
||||
- field: address-2
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: address-2
|
||||
en-US: address-2
|
||||
- field: address-3
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: address-3
|
||||
en-US: address-3
|
||||
# 指标别名列表,按照寄存器地址来进行命名的
|
||||
# 例如 地址为下标为0 ,值为m coil:0
|
||||
# 地址为下标为1,值为m[2] coil:1-0 coil:1-1
|
||||
aliasFields:
|
||||
- responseTime
|
||||
- coil:0
|
||||
- coil:1
|
||||
- coil:2
|
||||
- coil:3
|
||||
# mapping and conversion expressions, use thesand aliasField above to calculate metrics value# (可选)指标映射转换计算表达式,与上面的别名一起作用,计算出最终需要的指标值# eg: cores=core1+core2, usage=usage, waitTimeallTime-runningTime
|
||||
calculates:
|
||||
- responseTime=responseTime
|
||||
- address-0=coil:0
|
||||
- address-1=coil:1
|
||||
- address-2=coil:2
|
||||
- address-3=coil:3
|
||||
protocol: s7
|
||||
# the config content when protocol is http
|
||||
s7:
|
||||
# host
|
||||
host: ^_^host^_^
|
||||
# port
|
||||
port: ^_^port^_^
|
||||
driverName: s7
|
||||
addressSyntax: coil
|
||||
rackId: ^_^rackId^_^
|
||||
slotId: ^_^slotId^_^
|
||||
controllerType: ^_^controllerType^_^
|
||||
timeout: ^_^timeout^_^
|
||||
registerAddresses: [ ^_^coilRegisterAddresses^_^ ]
|
||||
|
||||
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.push.config;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletRequestWrapper;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* push error request wrapper
|
||||
*/
|
||||
@Getter
|
||||
public class PushErrorRequestWrapper extends HttpServletRequestWrapper {
|
||||
|
||||
|
||||
private final String job;
|
||||
|
||||
private final String instance;
|
||||
|
||||
public PushErrorRequestWrapper(HttpServletRequest request, String job, String instance) {
|
||||
super(request);
|
||||
this.job = job;
|
||||
this.instance = instance;
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.push.config;
|
||||
|
||||
import org.apache.hertzbeat.push.service.PushGatewayService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Configuration
|
||||
public class PushFilterConfig {
|
||||
|
||||
@Autowired
|
||||
private PushGatewayService pushGatewayService;
|
||||
|
||||
private static final String URI_PREFIX = "/api/push/prometheus/*";
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<PushPrometheusStreamReadingFilter> contentTypeFilter() {
|
||||
FilterRegistrationBean<PushPrometheusStreamReadingFilter> registrationBean = new FilterRegistrationBean<>();
|
||||
registrationBean.setFilter(new PushPrometheusStreamReadingFilter(pushGatewayService));
|
||||
registrationBean.addUrlPatterns(URI_PREFIX);
|
||||
registrationBean.setOrder(Integer.MIN_VALUE);
|
||||
return registrationBean;
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.push.config;
|
||||
|
||||
import jakarta.servlet.Filter;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.FilterConfig;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.ServletRequest;
|
||||
import jakarta.servlet.ServletResponse;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
import org.apache.hertzbeat.push.service.PushGatewayService;
|
||||
|
||||
|
||||
/**
|
||||
* todo
|
||||
*/
|
||||
public class PushPrometheusStreamReadingFilter implements Filter {
|
||||
|
||||
private final PushGatewayService pushGatewayService;
|
||||
|
||||
private final Pattern pathPattern = Pattern.compile("^/api/push/prometheus/job/([a-zA-Z0-9_]*)(?:/instance/([a-zA-Z0-9_]*))?$");
|
||||
|
||||
public PushPrometheusStreamReadingFilter(PushGatewayService pushGatewayService) {
|
||||
this.pushGatewayService = pushGatewayService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
if (request instanceof HttpServletRequest httpRequest) {
|
||||
String uri = httpRequest.getRequestURI();
|
||||
Matcher matcher = pathPattern.matcher(uri);
|
||||
String job = null;
|
||||
String instance = null;
|
||||
if (matcher.matches()) {
|
||||
job = matcher.group(1);
|
||||
instance = matcher.group(2);
|
||||
boolean flag = pushGatewayService.pushPrometheusMetrics(request.getInputStream(), job, instance);
|
||||
if (flag) {
|
||||
PushSuccessRequestWrapper successRequestWrapper = new PushSuccessRequestWrapper(httpRequest, job, instance);
|
||||
chain.doFilter(successRequestWrapper, response);
|
||||
} else {
|
||||
PushErrorRequestWrapper errorRequestWrapper = new PushErrorRequestWrapper(httpRequest, job, instance);
|
||||
chain.doFilter(errorRequestWrapper, response);
|
||||
}
|
||||
} else {
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
} else {
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.push.config;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletRequestWrapper;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* push success request wrapper
|
||||
*/
|
||||
@Getter
|
||||
public class PushSuccessRequestWrapper extends HttpServletRequestWrapper {
|
||||
|
||||
private final String job;
|
||||
|
||||
private final String instance;
|
||||
|
||||
public PushSuccessRequestWrapper(HttpServletRequest request, String job, String instance) {
|
||||
super(request);
|
||||
this.job = job;
|
||||
this.instance = instance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.push.controller;
|
||||
|
||||
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.apache.hertzbeat.common.entity.dto.Message;
|
||||
import org.apache.hertzbeat.common.entity.push.PushMetricsDto;
|
||||
import org.apache.hertzbeat.push.service.PushService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* push controller
|
||||
*/
|
||||
@Tag(name = "Metrics Push API")
|
||||
@RestController
|
||||
@RequestMapping(value = "/api/push", produces = {APPLICATION_JSON_VALUE})
|
||||
public class PushController {
|
||||
|
||||
@Autowired
|
||||
private PushService pushService;
|
||||
|
||||
@PostMapping
|
||||
@Operation(summary = "Push metric data to hertzbeat", description = "Push metric data to hertzbeat")
|
||||
public ResponseEntity<Message<Void>> pushMetrics(@RequestBody PushMetricsDto pushMetricsDto) {
|
||||
pushService.pushMetricsData(pushMetricsDto);
|
||||
return ResponseEntity.ok(Message.success("Push success"));
|
||||
}
|
||||
|
||||
@GetMapping()
|
||||
@Operation(summary = "Get metric data for hertzbeat", description = "Get metric data for hertzbeat")
|
||||
public ResponseEntity<Message<PushMetricsDto>> getMetrics(
|
||||
@Parameter(description = "Monitor ID", example = "6565463543") @RequestParam("id") final Long id,
|
||||
@Parameter(description = "Last pull time", example = "6565463543") @RequestParam("time") final Long time) {
|
||||
PushMetricsDto pushMetricsDto = pushService.getPushMetricData(id, time);
|
||||
return ResponseEntity.ok(Message.success(pushMetricsDto));
|
||||
}
|
||||
}
|
||||
@@ -22,9 +22,11 @@ package org.apache.hertzbeat.push.controller;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import org.apache.hertzbeat.common.entity.dto.Message;
|
||||
import org.apache.hertzbeat.push.config.PushErrorRequestWrapper;
|
||||
import org.apache.hertzbeat.push.config.PushSuccessRequestWrapper;
|
||||
import org.apache.hertzbeat.push.service.PushGatewayService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -35,23 +37,22 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
*/
|
||||
@Tag(name = "Metrics Push Gateway API")
|
||||
@RestController
|
||||
@RequestMapping(value = "/api/push/prometheus/**")
|
||||
public class PushPrometheusController {
|
||||
@RequestMapping(value = "/api/push/pushgateway")
|
||||
public class PushGatewayController {
|
||||
|
||||
@Autowired
|
||||
private PushGatewayService pushGatewayService;
|
||||
|
||||
@PostMapping()
|
||||
@Operation(summary = "Prometheus push gateway", description = "Push prometheus metric data to hertzbeat")
|
||||
public ResponseEntity<Message<Void>> pushMetrics(HttpServletRequest request) {
|
||||
if (request instanceof PushErrorRequestWrapper error) {
|
||||
return ResponseEntity.badRequest().body(Message.success(String.format("Push failed, job: %s, instance: %s",
|
||||
error.getJob(), error.getInstance())));
|
||||
}
|
||||
else if (request instanceof PushSuccessRequestWrapper success) {
|
||||
return ResponseEntity.ok(Message.success(String.format("Push success, job: %s, instance: %s",
|
||||
success.getJob(), success.getInstance())));
|
||||
@Operation(summary = "Push metric data to hertzbeat pushgateway", description = "Push metric data to hertzbeat pushgateway")
|
||||
public ResponseEntity<Message<Void>> pushMetrics(HttpServletRequest request) throws IOException {
|
||||
InputStream inputStream = request.getInputStream();
|
||||
boolean result = pushGatewayService.pushMetricsData(inputStream);
|
||||
if (result) {
|
||||
return ResponseEntity.ok(Message.success("Push success"));
|
||||
}
|
||||
else {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(Message.success(String.format("Request %s not matched.", request.getRequestURI())));
|
||||
return ResponseEntity.ok(Message.success("Push failed"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,45 +15,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.common.entity.job.protocol;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
package org.apache.hertzbeat.push.dao;
|
||||
|
||||
import org.apache.hertzbeat.common.entity.push.PushMetrics;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Modbus Protocol
|
||||
* push metrics dao
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class S7Protocol implements Protocol {
|
||||
public interface PushMetricsDao extends JpaRepository<PushMetrics, Long> {
|
||||
|
||||
PushMetrics findFirstByMonitorIdOrderByTimeDesc(Long monitorId);
|
||||
|
||||
/**
|
||||
* IP ADDRESS OR DOMAIN NAME OF THE PEER HOST
|
||||
*/
|
||||
private String host;
|
||||
/**
|
||||
* Port number
|
||||
*/
|
||||
private String port;
|
||||
|
||||
private String driverName;
|
||||
|
||||
private String addressSyntax;
|
||||
|
||||
private String rackId;
|
||||
|
||||
private String slotId;
|
||||
|
||||
private String controllerType;
|
||||
|
||||
private String timeout;
|
||||
|
||||
private List<String> registerAddresses;
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
void deleteAllByTimeBefore(Long time);
|
||||
}
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
package org.apache.hertzbeat.push.dao;
|
||||
|
||||
import java.util.List;
|
||||
import org.apache.hertzbeat.common.entity.manager.Monitor;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
@@ -25,11 +24,4 @@ import org.springframework.data.jpa.repository.JpaRepository;
|
||||
* push monitor dao
|
||||
*/
|
||||
public interface PushMonitorDao extends JpaRepository<Monitor, Long> {
|
||||
|
||||
/**
|
||||
* Find all monitoring entities by type
|
||||
* @param type Monitoring type
|
||||
* @return Monitoring entity list
|
||||
*/
|
||||
List<Monitor> findMonitorsByType(byte type);
|
||||
}
|
||||
|
||||
@@ -19,24 +19,17 @@
|
||||
|
||||
package org.apache.hertzbeat.push.service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* push gateway service
|
||||
* push gateway metrics
|
||||
*/
|
||||
|
||||
@Service
|
||||
public interface PushGatewayService {
|
||||
|
||||
|
||||
/**
|
||||
* push prometheus metrics data
|
||||
* @param inputStream input stream
|
||||
* @param job job name, maybe null
|
||||
* @param instance instance name, maybe null
|
||||
* @return push success or not
|
||||
*/
|
||||
boolean pushPrometheusMetrics(InputStream inputStream, String job, String instance);
|
||||
boolean pushMetricsData(InputStream inputStream) throws IOException;
|
||||
|
||||
}
|
||||
|
||||
@@ -15,32 +15,17 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.warehouse.service;
|
||||
package org.apache.hertzbeat.push.service;
|
||||
|
||||
import org.apache.hertzbeat.common.entity.dto.query.MetricQueryData;
|
||||
|
||||
import java.util.List;
|
||||
import org.apache.hertzbeat.common.entity.push.PushMetricsDto;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* metrics data query service
|
||||
* push metrics
|
||||
*/
|
||||
public interface MetricsDataQueryService {
|
||||
|
||||
/**
|
||||
* Query metrics data
|
||||
* @param queries query expr
|
||||
* @param time time
|
||||
* @return data
|
||||
*/
|
||||
List<MetricQueryData> query(List<String> queries, String queryType, long time);
|
||||
@Service
|
||||
public interface PushService {
|
||||
void pushMetricsData(PushMetricsDto pushMetricsData);
|
||||
|
||||
/**
|
||||
* Query metrics data range
|
||||
* @param queries query expr
|
||||
* @param start start
|
||||
* @param end end
|
||||
* @param step step
|
||||
* @return data
|
||||
*/
|
||||
List<MetricQueryData> queryRange(List<String> queries, String queryType, long start, long end, String step);
|
||||
PushMetricsDto getPushMetricData(Long monitorId, Long time);
|
||||
}
|
||||
@@ -19,23 +19,9 @@
|
||||
|
||||
package org.apache.hertzbeat.push.service.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.time.Instant;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.common.constants.CommonConstants;
|
||||
import org.apache.hertzbeat.common.entity.dto.MetricFamily;
|
||||
import org.apache.hertzbeat.common.entity.manager.Monitor;
|
||||
import org.apache.hertzbeat.common.entity.message.CollectRep;
|
||||
import org.apache.hertzbeat.common.queue.CommonDataQueue;
|
||||
import org.apache.hertzbeat.common.util.OnlineParser;
|
||||
import org.apache.hertzbeat.common.util.SnowFlakeIdGenerator;
|
||||
import org.apache.hertzbeat.push.dao.PushMonitorDao;
|
||||
import org.apache.hertzbeat.push.service.PushGatewayService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -46,88 +32,9 @@ import org.springframework.stereotype.Service;
|
||||
@Slf4j
|
||||
@Service
|
||||
public class PushGatewayServiceImpl implements PushGatewayService {
|
||||
|
||||
private final CommonDataQueue commonDataQueue;
|
||||
|
||||
private final PushMonitorDao pushMonitorDao;
|
||||
|
||||
private final Map<String, Long> jobInstanceMap;
|
||||
|
||||
public PushGatewayServiceImpl(CommonDataQueue commonDataQueue, PushMonitorDao pushMonitorDao) {
|
||||
this.commonDataQueue = commonDataQueue;
|
||||
this.pushMonitorDao = pushMonitorDao;
|
||||
jobInstanceMap = new ConcurrentHashMap<>();
|
||||
pushMonitorDao.findMonitorsByType((byte) 1).forEach(monitor ->
|
||||
jobInstanceMap.put(monitor.getApp() + "_" + monitor.getName(), monitor.getId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pushPrometheusMetrics(InputStream inputStream, String job, String instance) {
|
||||
try {
|
||||
long curTime = Instant.now().toEpochMilli();
|
||||
Map<String, MetricFamily> metricFamilyMap = OnlineParser.parseMetrics(inputStream);
|
||||
if (metricFamilyMap == null) {
|
||||
log.error("parse prometheus metrics is null, job: {}, instance: {}", job, instance);
|
||||
return false;
|
||||
}
|
||||
long id = 0L;
|
||||
if (job != null && instance != null) {
|
||||
// auto create monitor when job and instance not null
|
||||
// job is app, instance is the name
|
||||
id = jobInstanceMap.computeIfAbsent(job + "_" + instance, key -> {
|
||||
log.info("auto create monitor by prometheus push, job: {}, instance: {}", job, instance);
|
||||
long monitorId = SnowFlakeIdGenerator.generateId();
|
||||
Monitor monitor = Monitor.builder()
|
||||
.id(monitorId)
|
||||
.app(job)
|
||||
.name(instance)
|
||||
.host(instance)
|
||||
.type((byte) 1)
|
||||
.status(CommonConstants.MONITOR_UP_CODE)
|
||||
.build();
|
||||
this.pushMonitorDao.save(monitor);
|
||||
return monitorId;
|
||||
});
|
||||
}
|
||||
for (Map.Entry<String, MetricFamily> entry : metricFamilyMap.entrySet()) {
|
||||
CollectRep.MetricsData.Builder builder = CollectRep.MetricsData.newBuilder();
|
||||
builder.setId(id);
|
||||
builder.setApp(job);
|
||||
builder.setTime(curTime);
|
||||
String metricsName = entry.getKey();
|
||||
builder.setMetrics(metricsName);
|
||||
MetricFamily metricFamily = entry.getValue();
|
||||
if (!metricFamily.getMetricList().isEmpty()) {
|
||||
List<String> metricsFields = new LinkedList<>();
|
||||
for (int index = 0; index < metricFamily.getMetricList().size(); index++) {
|
||||
MetricFamily.Metric metric = metricFamily.getMetricList().get(index);
|
||||
if (index == 0) {
|
||||
metric.getLabels().forEach(label -> {
|
||||
metricsFields.add(label.getName());
|
||||
builder.addField(CollectRep.Field.newBuilder().setName(label.getName())
|
||||
.setType(CommonConstants.TYPE_STRING).setLabel(true).build());
|
||||
});
|
||||
builder.addField(CollectRep.Field.newBuilder().setName("value")
|
||||
.setType(CommonConstants.TYPE_NUMBER).setLabel(false).build());
|
||||
}
|
||||
Map<String, String> labelMap = metric.getLabels()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(MetricFamily.Label::getName, MetricFamily.Label::getValue));
|
||||
CollectRep.ValueRow.Builder valueRowBuilder = CollectRep.ValueRow.newBuilder();
|
||||
for (String field : metricsFields) {
|
||||
String fieldValue = labelMap.get(field);
|
||||
valueRowBuilder.addColumn(fieldValue == null ? CommonConstants.NULL_VALUE : fieldValue);
|
||||
}
|
||||
valueRowBuilder.addColumn(String.valueOf(metric.getValue()));
|
||||
builder.addValueRow(valueRowBuilder.build());
|
||||
}
|
||||
commonDataQueue.sendMetricsData(builder.build());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("push prometheus metrics error", e);
|
||||
return false;
|
||||
}
|
||||
public boolean pushMetricsData(InputStream inputStream) throws IOException {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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.push.service.impl;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.common.entity.manager.Monitor;
|
||||
import org.apache.hertzbeat.common.entity.push.PushMetrics;
|
||||
import org.apache.hertzbeat.common.entity.push.PushMetricsDto;
|
||||
import org.apache.hertzbeat.common.util.JsonUtil;
|
||||
import org.apache.hertzbeat.push.dao.PushMetricsDao;
|
||||
import org.apache.hertzbeat.push.dao.PushMonitorDao;
|
||||
import org.apache.hertzbeat.push.service.PushService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* push service impl
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class PushServiceImpl implements PushService {
|
||||
|
||||
@Autowired
|
||||
private PushMonitorDao monitorDao;
|
||||
|
||||
@Autowired
|
||||
private PushMetricsDao metricsDao;
|
||||
|
||||
private final Map<Long, Long> monitorIdCache; // key: monitorId, value: time stamp of last query
|
||||
|
||||
private static final long cacheTimeout = 5000L; // ms
|
||||
|
||||
private final Map<Long, PushMetricsDto.Metrics> lastPushMetrics;
|
||||
|
||||
private static final long deleteMetricsPeriod = 1000 * 60 * 60 * 12L;
|
||||
|
||||
private static final long deleteBeforeTime = deleteMetricsPeriod / 2;
|
||||
|
||||
public PushServiceImpl(){
|
||||
monitorIdCache = new HashMap<>();
|
||||
lastPushMetrics = new HashMap<>();
|
||||
|
||||
new Timer().schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
deletePeriodically();
|
||||
} catch (Exception e) {
|
||||
log.error("periodical deletion failed. {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}, 1000, deleteMetricsPeriod);
|
||||
}
|
||||
|
||||
public void deletePeriodically(){
|
||||
metricsDao.deleteAllByTimeBefore(System.currentTimeMillis() - deleteBeforeTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pushMetricsData(PushMetricsDto pushMetricsDto) throws RuntimeException {
|
||||
List<PushMetrics> pushMetricsList = new ArrayList<>();
|
||||
long curTime = System.currentTimeMillis();
|
||||
for (PushMetricsDto.Metrics metrics : pushMetricsDto.getMetricsList()) {
|
||||
long monitorId = metrics.getMonitorId();
|
||||
metrics.setTime(curTime);
|
||||
|
||||
if (!monitorIdCache.containsKey(monitorId) || (monitorIdCache.containsKey(monitorId) && curTime > monitorIdCache.get(monitorId) + cacheTimeout)) {
|
||||
Optional<Monitor> queryOption = monitorDao.findById(monitorId);
|
||||
if (queryOption.isEmpty()) {
|
||||
monitorIdCache.remove(monitorId);
|
||||
continue;
|
||||
}
|
||||
monitorIdCache.put(monitorId, curTime);
|
||||
}
|
||||
|
||||
PushMetrics pushMetrics = PushMetrics.builder()
|
||||
.monitorId(metrics.getMonitorId())
|
||||
.time(curTime)
|
||||
.metrics(JsonUtil.toJson(metrics.getMetrics())).build();
|
||||
lastPushMetrics.put(monitorId, metrics);
|
||||
pushMetricsList.add(pushMetrics);
|
||||
}
|
||||
|
||||
metricsDao.saveAll(pushMetricsList);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public PushMetricsDto getPushMetricData(final Long monitorId, final Long time) {
|
||||
PushMetricsDto.Metrics metrics;
|
||||
PushMetricsDto pushMetricsDto = new PushMetricsDto();
|
||||
if (lastPushMetrics.containsKey(monitorId)) {
|
||||
metrics = lastPushMetrics.get(monitorId);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
PushMetrics pushMetrics = metricsDao.findFirstByMonitorIdOrderByTimeDesc(monitorId);
|
||||
if (pushMetrics == null || pushMetrics.getMetrics() == null) {
|
||||
return pushMetricsDto;
|
||||
}
|
||||
List<Map<String, String>> jsonMap = JsonUtil.fromJson(pushMetrics.getMetrics(), new TypeReference<>() {
|
||||
});
|
||||
metrics = PushMetricsDto.Metrics.builder().monitorId(monitorId).metrics(jsonMap).time(pushMetrics.getTime()).build();
|
||||
lastPushMetrics.put(monitorId, metrics);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("no metrics found, monitor id: {}, {}", monitorId, e.getMessage(), e);
|
||||
return pushMetricsDto;
|
||||
}
|
||||
}
|
||||
if (time > metrics.getTime()) {
|
||||
// return void because time param is invalid
|
||||
return pushMetricsDto;
|
||||
}
|
||||
pushMetricsDto.getMetricsList().add(metrics);
|
||||
return pushMetricsDto;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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.push.controller;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;
|
||||
import org.apache.hertzbeat.common.constants.CommonConstants;
|
||||
import org.apache.hertzbeat.common.entity.push.PushMetricsDto;
|
||||
import org.apache.hertzbeat.common.util.JsonUtil;
|
||||
import org.apache.hertzbeat.push.service.PushService;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
|
||||
/**
|
||||
* test case for {@link PushController}
|
||||
*/
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class PushControllerTest {
|
||||
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Mock
|
||||
private PushService pushService;
|
||||
|
||||
@InjectMocks
|
||||
private PushController pushController;
|
||||
|
||||
private PushMetricsDto mockPushMetricsDto;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
|
||||
this.mockMvc = standaloneSetup(this.pushController).build();
|
||||
|
||||
mockPushMetricsDto = PushMetricsDto.builder().build();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPushMetrics() throws Exception {
|
||||
|
||||
this.mockMvc.perform(MockMvcRequestBuilders.post("/api/push")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(JsonUtil.toJson(mockPushMetricsDto)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value((int) CommonConstants.SUCCESS_CODE))
|
||||
.andReturn();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetMetrics() throws Exception {
|
||||
|
||||
Long id = 6565463543L;
|
||||
Long time = 6565463543L;
|
||||
|
||||
when(pushService.getPushMetricData(id, time)).thenReturn(mockPushMetricsDto);
|
||||
|
||||
this.mockMvc.perform(MockMvcRequestBuilders.get("/api/push")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.param("id", id.toString())
|
||||
.param("time", time.toString()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value((int) CommonConstants.SUCCESS_CODE))
|
||||
.andReturn();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,11 +22,12 @@ package org.apache.hertzbeat.push.controller;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
import java.io.InputStream;
|
||||
import org.apache.hertzbeat.common.constants.CommonConstants;
|
||||
import org.apache.hertzbeat.push.service.PushGatewayService;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
@@ -37,12 +38,11 @@ import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
|
||||
/**
|
||||
* test case for {@link PushPrometheusController}
|
||||
* test case for {@link PushGatewayController}
|
||||
*/
|
||||
|
||||
@Disabled
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class PushPrometheusControllerTest {
|
||||
class PushGatewayControllerTest {
|
||||
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@@ -50,7 +50,7 @@ class PushPrometheusControllerTest {
|
||||
private PushGatewayService pushGatewayService;
|
||||
|
||||
@InjectMocks
|
||||
private PushPrometheusController gatewayController;
|
||||
private PushGatewayController gatewayController;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
@@ -63,12 +63,14 @@ class PushPrometheusControllerTest {
|
||||
|
||||
String mockData = "some metric data";
|
||||
|
||||
when(pushGatewayService.pushPrometheusMetrics(any(InputStream.class), any(), any())).thenReturn(true);
|
||||
when(pushGatewayService.pushMetricsData(any(InputStream.class))).thenReturn(true);
|
||||
|
||||
mockMvc.perform(post("/api/push/pushgateway")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(mockData))
|
||||
.andExpect(status().isOk());
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value((int) CommonConstants.SUCCESS_CODE))
|
||||
.andExpect(jsonPath("$.msg").value("Push success"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -76,12 +78,13 @@ class PushPrometheusControllerTest {
|
||||
|
||||
String mockData = "some metric data";
|
||||
|
||||
when(pushGatewayService.pushPrometheusMetrics(any(InputStream.class), any(), any())).thenReturn(false);
|
||||
when(pushGatewayService.pushMetricsData(any(InputStream.class))).thenReturn(false);
|
||||
|
||||
mockMvc.perform(post("/api/push/pushgateway")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(mockData))
|
||||
.andExpect(status().isOk());
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.msg").value("Push failed"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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.push.dao;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.apache.hertzbeat.common.entity.push.PushMetrics;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
/**
|
||||
* test case for {@link PushMetricsDao}
|
||||
*/
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class PushMetricsDaoTest {
|
||||
@Mock
|
||||
private PushMetricsDao pushMetricsDao;
|
||||
|
||||
@InjectMocks
|
||||
private PushMetricsDaoTest pushMetricsDaoTest;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
MockitoAnnotations.openMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shallFindFirstByMonitorIdOrderByTimeDesc() {
|
||||
|
||||
PushMetrics expectedMetrics = new PushMetrics();
|
||||
expectedMetrics.setMonitorId(1L);
|
||||
expectedMetrics.setTime(System.currentTimeMillis());
|
||||
|
||||
when(pushMetricsDao.findFirstByMonitorIdOrderByTimeDesc(1L)).thenReturn(expectedMetrics);
|
||||
|
||||
PushMetrics actualMetrics = pushMetricsDao.findFirstByMonitorIdOrderByTimeDesc(1L);
|
||||
|
||||
assertEquals(expectedMetrics, actualMetrics);
|
||||
verify(pushMetricsDao, times(1)).findFirstByMonitorIdOrderByTimeDesc(1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shallDeleteAllByTimeBefore() {
|
||||
|
||||
doNothing().when(pushMetricsDao).deleteAllByTimeBefore(anyLong());
|
||||
|
||||
pushMetricsDao.deleteAllByTimeBefore(1000L);
|
||||
|
||||
verify(pushMetricsDao, times(1)).deleteAllByTimeBefore(1000L);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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.push.service;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.apache.hertzbeat.common.entity.manager.Monitor;
|
||||
import org.apache.hertzbeat.common.entity.push.PushMetrics;
|
||||
import org.apache.hertzbeat.common.entity.push.PushMetricsDto;
|
||||
import org.apache.hertzbeat.push.dao.PushMetricsDao;
|
||||
import org.apache.hertzbeat.push.dao.PushMonitorDao;
|
||||
import org.apache.hertzbeat.push.service.impl.PushServiceImpl;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
/**
|
||||
* test case for {@link PushServiceImpl}
|
||||
*/
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class PushServiceTest {
|
||||
|
||||
@Mock
|
||||
private PushMonitorDao monitorDao;
|
||||
|
||||
@Mock
|
||||
private PushMetricsDao metricsDao;
|
||||
|
||||
@InjectMocks
|
||||
private PushServiceImpl pushService;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
|
||||
pushService = new PushServiceImpl();
|
||||
|
||||
ReflectionTestUtils.setField(pushService, "monitorDao", monitorDao);
|
||||
ReflectionTestUtils.setField(pushService, "metricsDao", metricsDao);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPushMetricsData() {
|
||||
|
||||
PushMetricsDto pushMetricsDto = new PushMetricsDto();
|
||||
List<PushMetricsDto.Metrics> metricsList = new ArrayList<>();
|
||||
PushMetricsDto.Metrics metrics = new PushMetricsDto.Metrics();
|
||||
metrics.setMonitorId(1L);
|
||||
metricsList.add(metrics);
|
||||
pushMetricsDto.setMetricsList(metricsList);
|
||||
|
||||
when(monitorDao.findById(anyLong())).thenReturn(Optional.of(new Monitor()));
|
||||
|
||||
pushService.pushMetricsData(pushMetricsDto);
|
||||
|
||||
verify(metricsDao, times(1)).saveAll(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetPushMetricData() {
|
||||
|
||||
Long monitorId = 1L;
|
||||
Long time = System.currentTimeMillis();
|
||||
PushMetrics pushMetrics = PushMetrics.builder()
|
||||
.monitorId(monitorId)
|
||||
.time(time)
|
||||
.metrics("[{\"key\":\"value\"}]")
|
||||
.build();
|
||||
|
||||
when(metricsDao.findFirstByMonitorIdOrderByTimeDesc(monitorId)).thenReturn(pushMetrics);
|
||||
|
||||
PushMetricsDto result = pushService.getPushMetricData(monitorId, time);
|
||||
|
||||
assertEquals(1, result.getMetricsList().size());
|
||||
assertEquals(monitorId, result.getMetricsList().get(0).getMonitorId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetPushMetricDataTimeInvalid() {
|
||||
|
||||
Long monitorId = 1L;
|
||||
Long time = System.currentTimeMillis() + 10000;
|
||||
PushMetrics pushMetrics = PushMetrics.builder()
|
||||
.monitorId(monitorId)
|
||||
.time(System.currentTimeMillis())
|
||||
.metrics("[{\"key\":\"value\"}]")
|
||||
.build();
|
||||
|
||||
when(metricsDao.findFirstByMonitorIdOrderByTimeDesc(monitorId)).thenReturn(pushMetrics);
|
||||
|
||||
PushMetricsDto result = pushService.getPushMetricData(monitorId, time);
|
||||
|
||||
assertTrue(result.getMetricsList().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeletePeriodically() {
|
||||
|
||||
pushService.deletePeriodically();
|
||||
verify(metricsDao, times(1)).deleteAllByTimeBefore(anyLong());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -56,8 +56,4 @@ public interface WarehouseConstants {
|
||||
String MEMORY = "memory";
|
||||
}
|
||||
|
||||
String PROMQL = "promql";
|
||||
|
||||
String SQL = "sql";
|
||||
|
||||
}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.warehouse.controller;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.apache.hertzbeat.common.entity.dto.Message;
|
||||
import org.apache.hertzbeat.common.entity.dto.query.MetricQueryData;
|
||||
import org.apache.hertzbeat.warehouse.service.MetricsDataQueryService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
||||
|
||||
/**
|
||||
* Metrics Data Query API
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(produces = {APPLICATION_JSON_VALUE})
|
||||
@Tag(name = "Metrics Data Query API")
|
||||
public class MetricsDataQueryController {
|
||||
|
||||
|
||||
@Autowired
|
||||
private MetricsDataQueryService queryService;
|
||||
|
||||
|
||||
@GetMapping("/api/warehouse/query")
|
||||
@Operation(summary = "Query Real Time Metrics Data")
|
||||
public ResponseEntity<Message<List<MetricQueryData>>> queryMetricsData(
|
||||
@Parameter(description = "Query PromQL expr list", example = "cpu")
|
||||
@RequestParam List<String> queries,
|
||||
@Parameter(description = "Query type", example = "promql")
|
||||
@RequestParam String type,
|
||||
@Parameter(description = "Query timestamp", example = "1725854804451")
|
||||
@RequestParam long time) {
|
||||
return ResponseEntity.ok(Message.success(queryService.query(queries, type, time)));
|
||||
}
|
||||
|
||||
@GetMapping("/api/warehouse/query/range")
|
||||
@Operation(summary = "Query Range Metrics Data")
|
||||
public ResponseEntity<Message<List<MetricQueryData>>> queryMetricsDataRange(
|
||||
@Parameter(description = "Query PromQL expr list", example = "cpu")
|
||||
@RequestParam List<String> queries,
|
||||
@Parameter(description = "Query type", example = "promql")
|
||||
@RequestParam String type,
|
||||
@Parameter(description = "Query start timestamp", example = "1725854804451")
|
||||
@RequestParam long start,
|
||||
@Parameter(description = "Query end timestamp", example = "1733630804452")
|
||||
@RequestParam long end,
|
||||
@Parameter(description = "Query step", example = "4m")
|
||||
@RequestParam String step
|
||||
) {
|
||||
return ResponseEntity.ok(Message.success(queryService.queryRange(queries, type, start, end, step)));
|
||||
}
|
||||
}
|
||||
@@ -18,12 +18,29 @@
|
||||
package org.apache.hertzbeat.warehouse.db;
|
||||
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.common.constants.NetworkConstants;
|
||||
import org.apache.hertzbeat.common.constants.SignConstants;
|
||||
import org.apache.hertzbeat.common.util.Base64Util;
|
||||
import org.apache.hertzbeat.warehouse.store.history.greptime.GreptimeProperties;
|
||||
import org.apache.hertzbeat.warehouse.store.history.vm.PromQlQueryContent;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
/**
|
||||
* query executor for victor metrics
|
||||
@@ -31,15 +48,71 @@ import org.springframework.web.client.RestTemplate;
|
||||
@Component
|
||||
@ConditionalOnProperty(prefix = "warehouse.store.greptime", name = "enabled", havingValue = "true")
|
||||
@Slf4j
|
||||
public class GreptimePromqlQueryExecutor extends PromqlQueryExecutor {
|
||||
public class GreptimePromqlQueryExecutor implements QueryExecutor {
|
||||
|
||||
private static final String QUERY_PATH = "/v1/prometheus/api/v1/query";
|
||||
|
||||
private final GreptimeProperties greptimeProperties;
|
||||
|
||||
private final RestTemplate restTemplate;
|
||||
|
||||
public GreptimePromqlQueryExecutor(GreptimeProperties greptimeProperties, RestTemplate restTemplate) {
|
||||
super(restTemplate, new HttpPromqlProperties(greptimeProperties.httpEndpoint() + QUERY_PATH,
|
||||
greptimeProperties.username(), greptimeProperties.password()));
|
||||
this.greptimeProperties = greptimeProperties;
|
||||
this.restTemplate = restTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> execute(String query) {
|
||||
// http run the promql query
|
||||
List<Map<String, Object>> results = new LinkedList<>();
|
||||
try {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.setAccept(List.of(MediaType.APPLICATION_JSON));
|
||||
if (StringUtils.hasText(greptimeProperties.username())
|
||||
&& StringUtils.hasText(greptimeProperties.password())) {
|
||||
String authStr = greptimeProperties.username() + ":" + greptimeProperties.password();
|
||||
String encodedAuth = Base64Util.encode(authStr);
|
||||
headers.add(HttpHeaders.AUTHORIZATION, NetworkConstants.BASIC + SignConstants.BLANK + encodedAuth);
|
||||
}
|
||||
HttpEntity<Void> httpEntity = new HttpEntity<>(headers);
|
||||
URI uri = UriComponentsBuilder.fromHttpUrl(greptimeProperties.httpEndpoint() + QUERY_PATH)
|
||||
.queryParam("query", URLEncoder.encode(query, StandardCharsets.UTF_8))
|
||||
.build(true).toUri();
|
||||
ResponseEntity<PromQlQueryContent> responseEntity = restTemplate.exchange(uri,
|
||||
HttpMethod.GET, httpEntity, PromQlQueryContent.class);
|
||||
if (responseEntity.getStatusCode().is2xxSuccessful()) {
|
||||
if (responseEntity.getBody() != null && responseEntity.getBody().getData() != null
|
||||
&& responseEntity.getBody().getData().getResult() != null) {
|
||||
List<PromQlQueryContent.ContentData.Content> contents = responseEntity.getBody().getData().getResult();
|
||||
for (PromQlQueryContent.ContentData.Content content : contents) {
|
||||
Map<String, String> labels = content.getMetric();
|
||||
Map<String, Object> queryResult = new HashMap<>(8);
|
||||
queryResult.putAll(labels);
|
||||
if (content.getValue() != null && content.getValue().length == 2) {
|
||||
queryResult.put("__timestamp__", content.getValue()[0]);
|
||||
queryResult.put("__value__", content.getValue()[1]);
|
||||
} else if (content.getValues() != null && !content.getValues().isEmpty()) {
|
||||
List<Object> values = new LinkedList<>();
|
||||
for (Object[] valueArr : content.getValues()) {
|
||||
values.add(valueArr[1]);
|
||||
}
|
||||
queryResult.put("__value__", values);
|
||||
}
|
||||
results.add(queryResult);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.error("query metrics data from greptime failed. {}", responseEntity);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.toString(), e);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean support(String datasource) {
|
||||
return "promql".equals(datasource);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,166 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.warehouse.db;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.common.constants.NetworkConstants;
|
||||
import org.apache.hertzbeat.common.constants.SignConstants;
|
||||
import org.apache.hertzbeat.common.entity.dto.query.MetricQueryData;
|
||||
import org.apache.hertzbeat.common.util.Base64Util;
|
||||
import org.apache.hertzbeat.warehouse.store.history.vm.PromQlQueryContent;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.apache.hertzbeat.warehouse.constants.WarehouseConstants.PROMQL;
|
||||
|
||||
/**
|
||||
* abstract class for promql query executor
|
||||
*/
|
||||
@Slf4j
|
||||
public abstract class PromqlQueryExecutor implements QueryExecutor {
|
||||
|
||||
private static final String supportQueryLanguage = PROMQL;
|
||||
protected static final String HTTP_QUERY_PARAM = "query";
|
||||
protected static final String HTTP_TIME_PARAM = "time";
|
||||
protected static final String HTTP_START_PARAM = "start";
|
||||
protected static final String HTTP_END_PARAM = "end";
|
||||
protected static final String HTTP_STEP_PARAM = "step";
|
||||
|
||||
private final RestTemplate restTemplate;
|
||||
|
||||
private final HttpPromqlProperties httpPromqlProperties;
|
||||
|
||||
PromqlQueryExecutor(RestTemplate restTemplate, HttpPromqlProperties httpPromqlProperties) {
|
||||
this.restTemplate = restTemplate;
|
||||
this.httpPromqlProperties = httpPromqlProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* record class for promql http connection
|
||||
*/
|
||||
protected record HttpPromqlProperties (
|
||||
String url,
|
||||
String username,
|
||||
String password
|
||||
){}
|
||||
|
||||
protected List<Map<String, Object>> http_promql(Map<String, Object> params) {
|
||||
// http run the promql query
|
||||
List<Map<String, Object>> results = new LinkedList<>();
|
||||
try {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.setAccept(List.of(MediaType.APPLICATION_JSON));
|
||||
if (StringUtils.hasText(httpPromqlProperties.username())
|
||||
&& StringUtils.hasText(httpPromqlProperties.password())) {
|
||||
String authStr = httpPromqlProperties.username() + ":" + httpPromqlProperties.password();
|
||||
String encodedAuth = Base64Util.encode(authStr);
|
||||
headers.add(HttpHeaders.AUTHORIZATION, NetworkConstants.BASIC + SignConstants.BLANK + encodedAuth);
|
||||
}
|
||||
HttpEntity<Void> httpEntity = new HttpEntity<>(headers);
|
||||
UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromHttpUrl(httpPromqlProperties.url);
|
||||
for (Map.Entry<String, Object> entry : params.entrySet()) {
|
||||
uriComponentsBuilder.queryParam(entry.getKey(), entry.getValue());
|
||||
}
|
||||
URI uri = uriComponentsBuilder.build(true).toUri();
|
||||
ResponseEntity<PromQlQueryContent> responseEntity = restTemplate.exchange(uri,
|
||||
HttpMethod.GET, httpEntity, PromQlQueryContent.class);
|
||||
if (responseEntity.getStatusCode().is2xxSuccessful()) {
|
||||
if (responseEntity.getBody() != null && responseEntity.getBody().getData() != null
|
||||
&& responseEntity.getBody().getData().getResult() != null) {
|
||||
List<PromQlQueryContent.ContentData.Content> contents = responseEntity.getBody().getData().getResult();
|
||||
for (PromQlQueryContent.ContentData.Content content : contents) {
|
||||
Map<String, String> labels = content.getMetric();
|
||||
Map<String, Object> queryResult = new HashMap<>(8);
|
||||
queryResult.putAll(labels);
|
||||
if (content.getValue() != null && content.getValue().length == 2) {
|
||||
queryResult.put("__timestamp__", content.getValue()[0]);
|
||||
queryResult.put("__value__", content.getValue()[1]);
|
||||
} else if (content.getValues() != null && !content.getValues().isEmpty()) {
|
||||
List<Object> values = new LinkedList<>();
|
||||
for (Object[] valueArr : content.getValues()) {
|
||||
values.add(valueArr[1]);
|
||||
}
|
||||
queryResult.put("__value__", values);
|
||||
}
|
||||
results.add(queryResult);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.error("query metrics data from greptime failed. {}", responseEntity);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.toString(), e);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
public MetricQueryData convertToMetricQueryData(Object object) {
|
||||
MetricQueryData metricQueryData = new MetricQueryData();
|
||||
try {
|
||||
List<Map<String, Object>> metrics = (List<Map<String, Object>>) object;
|
||||
// todo
|
||||
} catch (Exception e) {
|
||||
log.error("converting to metric query data failed.");
|
||||
}
|
||||
return metricQueryData;
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> execute(String queryString) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put(HTTP_QUERY_PARAM, URLEncoder.encode(queryString, StandardCharsets.UTF_8));
|
||||
return http_promql(params);
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> query(String queryString, long time) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put(HTTP_QUERY_PARAM, URLEncoder.encode(queryString, StandardCharsets.UTF_8));
|
||||
params.put(HTTP_TIME_PARAM, time);
|
||||
return http_promql(params);
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> query_range(String queryString, long start, long end, String step) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put(HTTP_QUERY_PARAM, URLEncoder.encode(queryString, StandardCharsets.UTF_8));
|
||||
params.put(HTTP_START_PARAM, start);
|
||||
params.put(HTTP_END_PARAM, end);
|
||||
params.put(HTTP_STEP_PARAM, step);
|
||||
return http_promql(params);
|
||||
}
|
||||
|
||||
public boolean support(String datasource) {
|
||||
return supportQueryLanguage.equals(datasource);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,8 +17,6 @@
|
||||
|
||||
package org.apache.hertzbeat.warehouse.db;
|
||||
|
||||
import org.apache.hertzbeat.common.entity.dto.query.MetricQueryData;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -26,14 +24,8 @@ import java.util.Map;
|
||||
* query executor interface
|
||||
*/
|
||||
public interface QueryExecutor {
|
||||
|
||||
MetricQueryData convertToMetricQueryData(Object object);
|
||||
|
||||
|
||||
List<Map<String, Object>> execute(String query);
|
||||
|
||||
List<Map<String, Object>> query(String query, long time);
|
||||
|
||||
List<Map<String, Object>> query_range(String query, long start, long end, String step);
|
||||
|
||||
boolean support(String datasource);
|
||||
}
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.warehouse.db;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.common.entity.dto.query.MetricQueryData;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.apache.hertzbeat.warehouse.constants.WarehouseConstants.SQL;
|
||||
|
||||
/**
|
||||
* abstract class for sql query executor
|
||||
*/
|
||||
@Slf4j
|
||||
public abstract class SqlQueryExecutor implements QueryExecutor {
|
||||
|
||||
private static final String supportQueryLanguage = SQL;
|
||||
|
||||
/**
|
||||
* record class for sql connection
|
||||
*/
|
||||
protected record ConnectorSqlProperties () {}
|
||||
|
||||
protected abstract List<Map<String, Object>> do_sql(Map<String, Object> params);
|
||||
|
||||
public MetricQueryData convertToMetricQueryData(Object object) {
|
||||
MetricQueryData metricQueryData = new MetricQueryData();
|
||||
try {
|
||||
List<Map<String, Object>> metrics = (List<Map<String, Object>>) object;
|
||||
// todo
|
||||
} catch (Exception e) {
|
||||
log.error("converting to metric query data failed.");
|
||||
}
|
||||
return metricQueryData;
|
||||
}
|
||||
|
||||
public abstract List<Map<String, Object>> execute(String query);
|
||||
|
||||
public abstract List<Map<String, Object>> query(String query, long time);
|
||||
|
||||
public abstract List<Map<String, Object>> query_range(String query, long start, long end, String step);
|
||||
|
||||
|
||||
public boolean support(String datasource) {
|
||||
return supportQueryLanguage.equals(datasource);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,11 +18,29 @@
|
||||
package org.apache.hertzbeat.warehouse.db;
|
||||
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.common.constants.NetworkConstants;
|
||||
import org.apache.hertzbeat.common.constants.SignConstants;
|
||||
import org.apache.hertzbeat.common.util.Base64Util;
|
||||
import org.apache.hertzbeat.warehouse.store.history.vm.PromQlQueryContent;
|
||||
import org.apache.hertzbeat.warehouse.store.history.vm.VictoriaMetricsProperties;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
/**
|
||||
* query executor for victor metrics
|
||||
@@ -30,16 +48,71 @@ import org.springframework.web.client.RestTemplate;
|
||||
@Component
|
||||
@ConditionalOnProperty(prefix = "warehouse.store.victoria-metrics", name = "enabled", havingValue = "true")
|
||||
@Slf4j
|
||||
public class VictoriaMetricsQueryExecutor extends PromqlQueryExecutor {
|
||||
public class VictoriaMetricsQueryExecutor implements QueryExecutor {
|
||||
|
||||
private static final String QUERY_PATH = "/api/v1/query";
|
||||
|
||||
private final VictoriaMetricsProperties victoriaMetricsProp;
|
||||
|
||||
private final RestTemplate restTemplate;
|
||||
|
||||
public VictoriaMetricsQueryExecutor(VictoriaMetricsProperties victoriaMetricsProp, RestTemplate restTemplate) {
|
||||
super(restTemplate, new HttpPromqlProperties(victoriaMetricsProp.url() + QUERY_PATH,
|
||||
victoriaMetricsProp.username(), victoriaMetricsProp.password()));
|
||||
this.victoriaMetricsProp = victoriaMetricsProp;
|
||||
this.restTemplate = restTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> execute(String query) {
|
||||
// http run the promql query
|
||||
List<Map<String, Object>> results = new LinkedList<>();
|
||||
try {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.setAccept(List.of(MediaType.APPLICATION_JSON));
|
||||
if (StringUtils.hasText(victoriaMetricsProp.username())
|
||||
&& StringUtils.hasText(victoriaMetricsProp.password())) {
|
||||
String authStr = victoriaMetricsProp.username() + ":" + victoriaMetricsProp.password();
|
||||
String encodedAuth = Base64Util.encode(authStr);
|
||||
headers.add(HttpHeaders.AUTHORIZATION, NetworkConstants.BASIC + SignConstants.BLANK + encodedAuth);
|
||||
}
|
||||
HttpEntity<Void> httpEntity = new HttpEntity<>(headers);
|
||||
URI uri = UriComponentsBuilder.fromHttpUrl(victoriaMetricsProp.url() + QUERY_PATH)
|
||||
.queryParam("query", URLEncoder.encode(query, StandardCharsets.UTF_8))
|
||||
.build(true).toUri();
|
||||
ResponseEntity<PromQlQueryContent> responseEntity = restTemplate.exchange(uri,
|
||||
HttpMethod.GET, httpEntity, PromQlQueryContent.class);
|
||||
if (responseEntity.getStatusCode().is2xxSuccessful()) {
|
||||
if (responseEntity.getBody() != null && responseEntity.getBody().getData() != null
|
||||
&& responseEntity.getBody().getData().getResult() != null) {
|
||||
List<PromQlQueryContent.ContentData.Content> contents = responseEntity.getBody().getData().getResult();
|
||||
for (PromQlQueryContent.ContentData.Content content : contents) {
|
||||
Map<String, String> labels = content.getMetric();
|
||||
Map<String, Object> queryResult = new HashMap<>(8);
|
||||
queryResult.putAll(labels);
|
||||
if (content.getValue() != null && content.getValue().length == 2) {
|
||||
queryResult.put("__timestamp__", content.getValue()[0]);
|
||||
queryResult.put("__value__", content.getValue()[1]);
|
||||
} else if (content.getValues() != null && !content.getValues().isEmpty()) {
|
||||
List<Object> values = new LinkedList<>();
|
||||
for (Object[] valueArr : content.getValues()) {
|
||||
values.add(valueArr[1]);
|
||||
}
|
||||
queryResult.put("__value__", values);
|
||||
}
|
||||
results.add(queryResult);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.error("query metrics data from victor-metrics failed. {}", responseEntity);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.toString(), e);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean support(String datasource) {
|
||||
return "promql".equals(datasource);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.warehouse.service.impl;
|
||||
|
||||
import org.apache.hertzbeat.common.entity.dto.query.MetricQueryData;
|
||||
import org.apache.hertzbeat.warehouse.db.QueryExecutor;
|
||||
import org.apache.hertzbeat.warehouse.service.MetricsDataQueryService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class MetricsDataQueryServiceImpl implements MetricsDataQueryService {
|
||||
@Autowired(required = false)
|
||||
List<QueryExecutor> executors;
|
||||
|
||||
@Override
|
||||
public List<MetricQueryData> query(List<String> queries, String queryType, long time) {
|
||||
if (queries == null || executors.isEmpty()) {
|
||||
throw new IllegalArgumentException("No query executor found");
|
||||
}
|
||||
QueryExecutor executor = executors.stream().filter(e -> e.support(queryType)).findFirst().orElse(null);
|
||||
if (executor == null) {
|
||||
throw new IllegalArgumentException("Unsupported datasource: " + queryType);
|
||||
}
|
||||
List<MetricQueryData> metricQueryDataList = new ArrayList<>();
|
||||
for (String query : queries) {
|
||||
metricQueryDataList.add(executor.convertToMetricQueryData(executor.query(query, time)));
|
||||
}
|
||||
return metricQueryDataList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetricQueryData> queryRange(List<String> queries, String queryType, long start, long end, String step) {
|
||||
if (queries == null || executors.isEmpty()) {
|
||||
throw new IllegalArgumentException("No query executor found");
|
||||
}
|
||||
QueryExecutor executor = executors.stream().filter(e -> e.support(queryType)).findFirst().orElse(null);
|
||||
if (executor == null) {
|
||||
throw new IllegalArgumentException("Unsupported datasource: " + queryType);
|
||||
}
|
||||
List<MetricQueryData> metricQueryDataList = new ArrayList<>();
|
||||
for (String query : queries) {
|
||||
metricQueryDataList.add(executor.convertToMetricQueryData(executor.query_range(query, start, end, step)));
|
||||
}
|
||||
return metricQueryDataList;
|
||||
}
|
||||
}
|
||||
@@ -1,258 +0,0 @@
|
||||
---
|
||||
id: extend-http-xmlpath
|
||||
title: HTTP Protocol XmlPath Parsing Method
|
||||
sidebar_label: XmlPath Parsing Method
|
||||
---
|
||||
|
||||
> After calling the HTTP API to obtain the response data, use the XmlPath script parsing method to parse the response data.
|
||||
|
||||
Note⚠️ The response data must be in XML format.
|
||||
|
||||
**Use XPath scripts to parse the response data into data that conforms to the data structure rules specified by HertzBeat.**
|
||||
|
||||
### XmlPath Parsing Logic
|
||||
|
||||
The XmlPath parsing method in HertzBeat uses a two-step XPath process:
|
||||
|
||||
1. **Main XPath Expression (`parseScript`)**: This XPath expression is defined in the `http` configuration section under `parseScript`. It is used to select one or more main XML nodes from the response. Each selected node will correspond to one row of metric data in HertzBeat.
|
||||
2. **Relative Field XPath Expressions (`xpath`)**: For each metric field defined in the `fields` list, you can specify a relative `xpath`. This XPath expression is evaluated *relative to each main node* selected by the `parseScript` in step 1. It extracts the specific value for that metric field from the current main node.
|
||||
|
||||
This allows you to easily parse structured XML data where multiple records or items are present.
|
||||
|
||||
**Special Metrics**:
|
||||
|
||||
* `responseTime`: This built-in metric represents the HTTP request's response time and is automatically collected. It does not require an `xpath`.
|
||||
|
||||
* `keyword`: This built-in metric counts the occurrences of a specified keyword (configured in `http.keyword`) in the raw response body. It does not require an `xpath`.
|
||||
|
||||
### Example
|
||||
|
||||
Assume the HTTP API returns the following XML data:
|
||||
|
||||
```xml
|
||||
<DeviceStatus xmlns="http://www.isapi.org/ver20/XMLSchema" version="2.0">
|
||||
<CPUList>
|
||||
<CPU>
|
||||
<cpuUtilization>36.400002</cpuUtilization>
|
||||
</CPU>
|
||||
</CPUList>
|
||||
<MemoryList>
|
||||
<Memory>
|
||||
<memoryUsage>399640</memoryUsage>
|
||||
<memoryAvailable>98792</memoryAvailable>
|
||||
<cacheSize>228492</cacheSize>
|
||||
</Memory>
|
||||
</MemoryList>
|
||||
<NetPortStatusList>
|
||||
<NetPortStatus>
|
||||
<id>1</id>
|
||||
<workSpeed>1000</workSpeed>
|
||||
</NetPortStatus>
|
||||
<NetPortStatus>
|
||||
<id>2</id>
|
||||
<workSpeed>0</workSpeed>
|
||||
</NetPortStatus>
|
||||
</NetPortStatusList>
|
||||
<bootTime>2025-01-06 10:27:48</bootTime>
|
||||
<deviceUpTime>87天0时55分59秒</deviceUpTime>
|
||||
<lastCalibrationTime>2025-04-03 11:09:18</lastCalibrationTime>
|
||||
<lastCalibrationTimeDiff>1</lastCalibrationTimeDiff>
|
||||
<uploadTimeConsumingList>
|
||||
<avgTime>16</avgTime>
|
||||
<maxTime>23</maxTime>
|
||||
<minTime>12</minTime>
|
||||
</uploadTimeConsumingList>
|
||||
<lastCalibrationTimeMode>NTP</lastCalibrationTimeMode>
|
||||
<lastCalibrationTimeAddress>34.191.45.101</lastCalibrationTimeAddress>
|
||||
</DeviceStatus>
|
||||
```
|
||||
|
||||
We want to monitor the device status and extract various metrics.
|
||||
|
||||
Here's how you would configure the monitoring template YML:
|
||||
|
||||
```yaml
|
||||
category: server
|
||||
# The monitoring type eg: linux windows tomcat mysql aws...
|
||||
app: hikvision_isapi
|
||||
# The monitoring i18n name
|
||||
name:
|
||||
zh-CN: 海康威视 ISAPI
|
||||
en-US: Hikvision ISAPI
|
||||
# The description and help of this monitoring type
|
||||
help:
|
||||
zh-CN: 通过ISAPI接口监控海康威视设备状态,获取设备健康数据。
|
||||
en-US: Monitor Hikvision devices through ISAPI interface to collect health data.
|
||||
|
||||
# Input params define for monitoring(render web ui by the definition)
|
||||
params:
|
||||
- field: host
|
||||
name:
|
||||
zh-CN: 主机Host
|
||||
en-US: Host
|
||||
type: host
|
||||
required: true
|
||||
- field: port
|
||||
name:
|
||||
zh-CN: 端口
|
||||
en-US: Port
|
||||
type: number
|
||||
range: '[0,65535]'
|
||||
required: true
|
||||
defaultValue: 80
|
||||
- field: timeout
|
||||
name:
|
||||
zh-CN: 超时时间(ms)
|
||||
en-US: Timeout(ms)
|
||||
type: number
|
||||
range: '[1000,60000]'
|
||||
required: true
|
||||
defaultValue: 5000
|
||||
- field: username
|
||||
name:
|
||||
zh-CN: 用户名
|
||||
en-US: Username
|
||||
type: text
|
||||
required: true
|
||||
- field: password
|
||||
name:
|
||||
zh-CN: 密码
|
||||
en-US: Password
|
||||
type: password
|
||||
required: true
|
||||
- field: ssl
|
||||
name:
|
||||
zh-CN: 启用HTTPS
|
||||
en-US: SSL
|
||||
type: boolean
|
||||
required: false
|
||||
defaultValue: false
|
||||
|
||||
# collect metrics config list
|
||||
metrics:
|
||||
- name: status
|
||||
protocol: http
|
||||
http:
|
||||
host: ^_^host^_^
|
||||
port: ^_^port^_^
|
||||
ssl: ^_^ssl^_^
|
||||
url: /ISAPI/System/status
|
||||
method: GET
|
||||
timeout: ^_^timeout^_^
|
||||
authorization:
|
||||
type: Digest Auth
|
||||
digestAuthUsername: ^_^username^_^
|
||||
digestAuthPassword: ^_^password^_^
|
||||
parseType: xmlPath
|
||||
parseScript: 'DeviceStatus'
|
||||
fields:
|
||||
- field: cpuUtilization
|
||||
i18n:
|
||||
zh-CN: CPU 利用率
|
||||
en-US: CPU Utilization
|
||||
type: 0
|
||||
unit: '%'
|
||||
xpath: CPUList/CPU/cpuUtilization
|
||||
- field: memoryUsage
|
||||
i18n:
|
||||
zh-CN: 内存使用量
|
||||
en-US: Memory Usage
|
||||
type: 0
|
||||
unit: MB
|
||||
xpath: MemoryList/Memory/memoryUsage
|
||||
- field: memoryAvailable
|
||||
i18n:
|
||||
zh-CN: 可用内存
|
||||
en-US: Memory Available
|
||||
type: 0
|
||||
unit: MB
|
||||
xpath: MemoryList/Memory/memoryAvailable
|
||||
- field: cacheSize
|
||||
i18n:
|
||||
zh-CN: 缓存大小
|
||||
en-US: Cache Size
|
||||
type: 0
|
||||
unit: MB
|
||||
xpath: MemoryList/Memory/cacheSize
|
||||
- field: netPort1Speed
|
||||
i18n:
|
||||
zh-CN: 网口1速度
|
||||
en-US: Net Port 1 Speed
|
||||
type: 0
|
||||
unit: Mbps
|
||||
xpath: NetPortStatusList/NetPortStatus[id='1']/workSpeed
|
||||
- field: netPort2Speed
|
||||
i18n:
|
||||
zh-CN: 网口2速度
|
||||
en-US: Net Port 2 Speed
|
||||
type: 0
|
||||
unit: Mbps
|
||||
xpath: NetPortStatusList/NetPortStatus[id='2']/workSpeed
|
||||
- field: bootTime
|
||||
i18n:
|
||||
zh-CN: 启动时间
|
||||
en-US: Boot Time
|
||||
type: 1
|
||||
xpath: bootTime
|
||||
- field: deviceUpTime
|
||||
i18n:
|
||||
zh-CN: 运行时长
|
||||
en-US: Device Uptime
|
||||
type: 1
|
||||
xpath: deviceUpTime
|
||||
- field: lastCalibrationTime
|
||||
i18n:
|
||||
zh-CN: 上次校时时间
|
||||
en-US: Last Calibration Time
|
||||
type: 1
|
||||
xpath: lastCalibrationTime
|
||||
- field: lastCalibrationTimeDiff
|
||||
i18n:
|
||||
zh-CN: 上次校时时间差
|
||||
en-US: Last Calibration Time Diff
|
||||
type: 0
|
||||
unit: s
|
||||
xpath: lastCalibrationTimeDiff
|
||||
- field: avgUploadTime
|
||||
i18n:
|
||||
zh-CN: 平均上传耗时
|
||||
en-US: Avg Upload Time
|
||||
type: 0
|
||||
unit: ms
|
||||
xpath: uploadTimeConsumingList/avgTime
|
||||
- field: maxUploadTime
|
||||
i18n:
|
||||
zh-CN: 最大上传耗时
|
||||
en-US: Max Upload Time
|
||||
type: 0
|
||||
unit: ms
|
||||
xpath: uploadTimeConsumingList/maxTime
|
||||
- field: minUploadTime
|
||||
i18n:
|
||||
zh-CN: 最小上传耗时
|
||||
en-US: Min Upload Time
|
||||
type: 0
|
||||
unit: ms
|
||||
xpath: uploadTimeConsumingList/minTime
|
||||
- field: lastCalibrationMode
|
||||
i18n:
|
||||
zh-CN: 上次校时模式
|
||||
en-US: Last Calibration Mode
|
||||
type: 1
|
||||
xpath: lastCalibrationTimeMode
|
||||
- field: lastCalibrationAddress
|
||||
i18n:
|
||||
zh-CN: 上次校时地址
|
||||
en-US: Last Calibration Address
|
||||
type: 1
|
||||
xpath: lastCalibrationTimeAddress
|
||||
- field: responseTime
|
||||
i18n:
|
||||
zh-CN: 响应时间
|
||||
en-US: Response Time
|
||||
type: 0
|
||||
unit: ms
|
||||
units:
|
||||
- memoryUsage=KB->MB
|
||||
- memoryAvailable=KB->MB
|
||||
- cacheSize=KB->MB
|
||||
@@ -341,7 +341,7 @@ svn commit -m "release for HertzBeat 1.6.0"
|
||||
|
||||
- Check Apache SVN Commit Results
|
||||
|
||||
> Visit the address <https://dist.apache.org/repos/dist/dev/incubator/hertzbeat/> in the browser, check if existed the new material package
|
||||
> Visit the address <https://dist.apache.org/repos/dist/dev/incubator/hertzbeat/1.6.0-RC1/> in the browser, check if existed the new material package
|
||||
|
||||
## 4. Enter the community voting stage
|
||||
|
||||
|
||||
@@ -20,10 +20,9 @@ sidebar_label: Download
|
||||
Previous releases of HertzBeat may be affected by security issues, please use the latest one.
|
||||
:::
|
||||
|
||||
| Version | Date | Download | Release Notes |
|
||||
| ------- | ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
|
||||
| v1.7.0 | 2025.04.02 | [apache-hertzbeat-1.7.0-incubating-bin.tar.gz](https://dist.apache.org/repos/dist/release/incubator/hertzbeat/1.7.0/apache-hertzbeat-1.7.0-incubating-bin.tar.gz) (HertzBeat) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.7.0/apache-hertzbeat-1.7.0-incubating-bin.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.7.0/apache-hertzbeat-1.7.0-incubating-bin.tar.gz.sha512) ) <br/> [apache-hertzbeat-collector-1.7.0-incubating-bin.tar.gz](https://downloads.apache.org/incubator/hertzbeat/1.7.0/apache-hertzbeat-collector-1.7.0-incubating-bin.tar.gz) (HertzBeat Collector) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.7.0/apache-hertzbeat-collector-1.7.0-incubating-bin.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.7.0/apache-hertzbeat-collector-1.7.0-incubating-bin.tar.gz.sha512) ) <br/> [apache-hertzbeat-1.7.0-incubating-src.tar.gz](https://downloads.apache.org/incubator/hertzbeat/1.7.0/apache-hertzbeat-1.7.0-incubating-src.tar.gz) (HertzBeat Source) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.7.0/apache-hertzbeat-1.7.0-incubating-src.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.7.0/apache-hertzbeat-1.7.0-incubating-src.tar.gz.sha512) ) <br/> [apache-hertzbeat-1.7.0-incubating-docker-compose.tar.gz](https://dist.apache.org/repos/dist/release/incubator/hertzbeat/1.7.0/apache-hertzbeat-1.7.0-incubating-docker-compose.tar.gz) (docker-compose) ( [signature](https://dist.apache.org/repos/dist/release/incubator/hertzbeat/1.7.0/apache-hertzbeat-1.7.0-incubating-docker-compose.tar.gz.asc) , [sha512](https://dist.apache.org/repos/dist/release/incubator/hertzbeat/1.7.0/apache-hertzbeat-1.7.0-incubating-docker-compose.tar.gz.sha512) ) | [release note](https://github.com/apache/hertzbeat/releases/tag/v1.7.0) |
|
||||
| v1.6.1 | 2024.10.29 | [apache-hertzbeat-1.6.1-incubating-bin.tar.gz](https://dist.apache.org/repos/dist/release/incubator/hertzbeat/1.6.1/apache-hertzbeat-1.6.1-incubating-bin.tar.gz) (HertzBeat) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.6.1/apache-hertzbeat-1.6.1-incubating-bin.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.6.1/apache-hertzbeat-1.6.1-incubating-bin.tar.gz.sha512) ) <br/> [apache-hertzbeat-collector-1.6.1-incubating-bin.tar.gz](https://downloads.apache.org/incubator/hertzbeat/1.6.1/apache-hertzbeat-collector-1.6.1-incubating-bin.tar.gz) (HertzBeat Collector) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.6.1/apache-hertzbeat-collector-1.6.1-incubating-bin.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.6.1/apache-hertzbeat-collector-1.6.1-incubating-bin.tar.gz.sha512) ) <br/> [apache-hertzbeat-1.6.1-incubating-src.tar.gz](https://downloads.apache.org/incubator/hertzbeat/1.6.1/apache-hertzbeat-1.6.1-incubating-src.tar.gz) (HertzBeat Source) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.6.1/apache-hertzbeat-1.6.1-incubating-src.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.6.1/apache-hertzbeat-1.6.1-incubating-src.tar.gz.sha512) ) <br/> [apache-hertzbeat-1.6.1-incubating-docker-compose.tar.gz](https://dist.apache.org/repos/dist/release/incubator/hertzbeat/1.6.1/apache-hertzbeat-1.6.1-incubating-docker-compose.tar.gz) (docker-compose) ( [signature](https://dist.apache.org/repos/dist/release/incubator/hertzbeat/1.6.1/apache-hertzbeat-1.6.1-incubating-docker-compose.tar.gz.asc) , [sha512](https://dist.apache.org/repos/dist/release/incubator/hertzbeat/1.6.1/apache-hertzbeat-1.6.1-incubating-docker-compose.tar.gz.sha512) ) | [release note](https://github.com/apache/hertzbeat/releases/tag/v1.6.1) |
|
||||
| Version | Date | Download | Release Notes |
|
||||
|---------|------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------|
|
||||
| v1.6.1 | 2024.10.29 | [apache-hertzbeat-1.6.1-incubating-bin.tar.gz](https://dist.apache.org/repos/dist/release/incubator/hertzbeat/1.6.1/apache-hertzbeat-1.6.1-incubating-bin.tar.gz) (HertzBeat) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.6.1/apache-hertzbeat-1.6.1-incubating-bin.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.6.1/apache-hertzbeat-1.6.1-incubating-bin.tar.gz.sha512) ) <br/> [apache-hertzbeat-collector-1.6.1-incubating-bin.tar.gz](https://downloads.apache.org/incubator/hertzbeat/1.6.1/apache-hertzbeat-collector-1.6.1-incubating-bin.tar.gz) (HertzBeat Collector) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.6.1/apache-hertzbeat-collector-1.6.1-incubating-bin.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.6.1/apache-hertzbeat-collector-1.6.1-incubating-bin.tar.gz.sha512) ) <br/> [apache-hertzbeat-1.6.1-incubating-src.tar.gz](https://downloads.apache.org/incubator/hertzbeat/1.6.1/apache-hertzbeat-1.6.1-incubating-src.tar.gz) (HertzBeat Source) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.6.1/apache-hertzbeat-1.6.1-incubating-src.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.6.1/apache-hertzbeat-1.6.1-incubating-src.tar.gz.sha512) ) <br/> [apache-hertzbeat-1.6.1-incubating-docker-compose.tar.gz](https://dist.apache.org/repos/dist/release/incubator/hertzbeat/1.6.1/apache-hertzbeat-1.6.1-incubating-docker-compose.tar.gz) (docker-compose) ( [signature](https://dist.apache.org/repos/dist/release/incubator/hertzbeat/1.6.1/apache-hertzbeat-1.6.1-incubating-docker-compose.tar.gz.asc) , [sha512](https://dist.apache.org/repos/dist/release/incubator/hertzbeat/1.6.1/apache-hertzbeat-1.6.1-incubating-docker-compose.tar.gz.sha512) ) | [release note](https://github.com/apache/hertzbeat/releases/tag/v1.6.1)|
|
||||
| v1.6.0 | 2024.06.10 | [apache-hertzbeat-1.6.0-incubating-bin.tar.gz](https://downloads.apache.org/incubator/hertzbeat/1.6.0/apache-hertzbeat-1.6.0-incubating-bin.tar.gz) (HertzBeat) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.6.0/apache-hertzbeat-1.6.0-incubating-bin.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.6.0/apache-hertzbeat-1.6.0-incubating-bin.tar.gz.sha512) ) <br/> [apache-hertzbeat-collector-1.6.0-incubating-bin.tar.gz](https://downloads.apache.org/incubator/hertzbeat/1.6.0/apache-hertzbeat-collector-1.6.0-incubating-bin.tar.gz) (HertzBeat Collector) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.6.0/apache-hertzbeat-collector-1.6.0-incubating-bin.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.6.0/apache-hertzbeat-collector-1.6.0-incubating-bin.tar.gz.sha512) ) <br/> [apache-hertzbeat-1.6.0-incubating-src.tar.gz](https://downloads.apache.org/incubator/hertzbeat/1.6.0/apache-hertzbeat-1.6.0-incubating-src.tar.gz) (HertzBeat Source) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.6.0/apache-hertzbeat-1.6.0-incubating-src.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.6.0/apache-hertzbeat-1.6.0-incubating-src.tar.gz.sha512) ) | [release note](https://github.com/apache/hertzbeat/releases/tag/v1.6.0) |
|
||||
|
||||
## Release Docker Image
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
---
|
||||
id: alarm_group
|
||||
title: Alarm Grouping
|
||||
sidebar_label: Alarm Grouping
|
||||
keywords: [Open source monitoring system, alarm reduce, alarm grouping]
|
||||
---
|
||||
|
||||
> Group convergence supports grouping and convergence of alarms for specified packet labels, deduplication and convergence of the same repeated alarms for the time period. When the threshold rule triggers the alarm or external alarm reporting, it will enter the packet convergence to alarm grouping to deduplicate the alarm to avoid a large number of alarm messages causing alarm storms.
|
||||
|
||||
## Grouping Policy Parameter Configuration
|
||||
|
||||
- Strategy Name: The name that uniquely identifies the grouping policy
|
||||
- Group Labels: Alarm grouping tag, support up to 10 tags
|
||||
|
||||
> Tag source: monitoring, threshold rules, tags carried by external alarms
|
||||
|
||||
- Wait Time: Waiting time after a new alarm is generated. The same alarms received during this time will be grouped, with a default of 30 seconds.
|
||||
|
||||
> When a new (unable to join an existing group) alarm is generated, the group convergence will wait according to the `wait time`, during which time, the same alarm or the alarm that meets the grouping conditions will be grouped. The alarm after the grouping is sent to the alarm suppression module for subsequent processing until the time interval between the current time and the first alarm generation in the packet exceeds the `wait time`.
|
||||
|
||||
- Interval time: The minimum time interval for sending group alarm notifications to avoid excessive alarm notifications, default 5 minutes
|
||||
- Repeat interval: The minimum notification interval for repeated alarms. For continuously triggered alarms, avoid repeated notifications, default 4 hours
|
||||
|
||||
**Note**: Only grouped alarms can be suppressed using suppression rules.
|
||||
@@ -1,45 +0,0 @@
|
||||
---
|
||||
id: alarm_inhibit
|
||||
title: Alarm Inhibition
|
||||
sidebar_label: Alarm Inhibition
|
||||
keywords: [ Open Source Monitoring System, Alarm Convergence, Alarm Inhibition ]
|
||||
---
|
||||
|
||||
> Alarm inhibition is used to configure the inhibition relationship between alarms. When an alarm occurs, other alarms can be suppressed. It can be understood as "important" alarms suppressing "
|
||||
> unimportant" alarms. For example, the alarm generated by a server crash suppresses the alarms generated by other services on this server.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Correctly configure the alarm grouping rule
|
||||
|
||||
## Inhibit rule configuration
|
||||
|
||||
- Inhibit Rule Name: The name that uniquely identifies the suppression rule
|
||||
|
||||
- Source Labels: When the alarm contains these tags, the target alarm will be suppressed. Multiple tags can be added.
|
||||
|
||||
> Identify the tag of the "important" alarm. The alarm tag needs to contain all source tags to suppress the alarm marked by the target tag.
|
||||
|
||||
- Target Labels: Alarms matching these tags will be suppressed.
|
||||
|
||||
> Identify the label of "unimportant" alarms. Alarm labels need to contain all target labels to be suppressed.
|
||||
|
||||
- Equal Labels: Labels for determining alarm correlation. Supports up to 10 labels.
|
||||
- Enabled: Enable or disable this inhibit rule
|
||||
|
||||
## Example
|
||||
|
||||
Scenario: Use Hertzbeat to monitor two Centos servers 192.168.1.1, 192.168.1.2, and Redis services Redis-1 and Redis-2 deployed on the two servers.
|
||||
And configure the following threshold rules:
|
||||
|
||||
- Monitor Centos Linux / Monitor availability. Bind label `server-status:down`
|
||||
- Monitor Redis database / Monitor availability. Bind label `redis-status:down`
|
||||
|
||||
If you need to achieve that when the Centos downtime alarm is generated, the Redis alarm will no longer be generated, you can configure the following alarm suppression rules:
|
||||
|
||||
- Source label: `server-status:down`
|
||||
- Target label: `redis-status:down`
|
||||
- Equal label: `instancehost`
|
||||
|
||||
When the Centos 192.168.1.1 downtime alarm is generated, the Redis-1 unavailable alarm will no longer be generated. And at the same time, when Centos 192.168.1.2 is running normally and Redis-2 is
|
||||
unavailable, the alarm notifying Redis-2 unavailable will be generated normally.
|
||||
@@ -1,15 +1,15 @@
|
||||
---
|
||||
id: api
|
||||
title: Monitoring HTTP API
|
||||
sidebar_label: HTTP API
|
||||
keywords: [ open source monitoring tool, monitoring http api ]
|
||||
id: api
|
||||
title: Monitoring HTTP API
|
||||
sidebar_label: HTTP API
|
||||
keywords: [open source monitoring tool, monitoring http api]
|
||||
---
|
||||
|
||||
> Call HTTP API interface, check whether the interface is available, and monitor its response time and other Metrics.
|
||||
|
||||
### Configuration parameter
|
||||
|
||||
| Parameter name | Parameter help description |
|
||||
| Parameter name | Parameter help description |
|
||||
|---------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Monitoring Host | Monitored IPV4, IPV6 or domain name. Note⚠️Without protocol header (eg: https://, http://) |
|
||||
| Monitoring name | Identify the name of this monitoring. The name needs to be unique |
|
||||
@@ -22,7 +22,7 @@ keywords: [ open source monitoring tool, monitoring http api ]
|
||||
| Headers | HTTP request headers |
|
||||
| Params | HTTP query params, support [time expression](time_expression) |
|
||||
| Content-Type | Set the resource type when carrying the BODY request body data request |
|
||||
| Request BODY | Set the carry BODY request body data, which is valid when PUT or POST request method is used, support [time expression](time_expression) |
|
||||
| Request BODY | Set the carry BODY request body data, which is valid when PUT or POST request method is used |
|
||||
| Collection interval | Interval time of monitor periodic data collection, unit: second, and the minimum interval that can be set is 30 seconds |
|
||||
| Whether to detect | Whether to detect and check the availability of monitoring before adding monitoring. Adding and modifying operations will continue only after the detection is successful |
|
||||
| Description remarks | For more information about identifying and describing this monitoring, users can note information here |
|
||||
|
||||
@@ -116,13 +116,6 @@ More details see 👉 [Alarm center](alarm_center)
|
||||
More details see 👉 [Threshold alarm](alert_threshold) <br />
|
||||
   👉 [Threshold expression](alert_threshold_expr)
|
||||
|
||||
### Alarm reduce
|
||||
|
||||
> Combine related alarms through alarm grouping, alarm suppression and other functions to reduce the alarm storm caused by one event, reduce alarm noise and improve alarm response efficiency.
|
||||
|
||||
More details see 👉 [Alarm grouping](alarm_group) <br />
|
||||
   👉 [Alarm inhibit](alarm_inhibit)
|
||||
|
||||
### Alarm notification
|
||||
|
||||
> After triggering the alarm information, in addition to being displayed in the alarm center list, it can also be notified to the designated recipient in a specified way (e-mail, wechat and FeiShu etc.)
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
---
|
||||
id: hikvision_isapi
|
||||
title: Monitor Hikvision ISAPI
|
||||
sidebar_label: Hikvision ISAPI
|
||||
keywords: [ monitor, hikvision_isapi ]
|
||||
---
|
||||
|
||||
> Monitor Hikvision devices through ISAPI interface to collect health data.
|
||||
|
||||
## Monitor Configuration
|
||||
|
||||
| Parameter | Description |
|
||||
| ----------- | ----------- |
|
||||
| Host | The IP or domain name of the monitored device. Note⚠️ Do not include protocol prefix (eg: https://, http://). |
|
||||
| Name | The unique name that identifies this monitor. |
|
||||
| Port | Network request port, default is 80. |
|
||||
| Timeout | Timeout period, in milliseconds, default is 5000ms. |
|
||||
| Username | Login username for Hikvision device. |
|
||||
| Password | Login password for Hikvision device. |
|
||||
| SSL | Whether to enable HTTPS, disabled by default. |
|
||||
| Collection Interval | The interval time for periodic data collection, in seconds. The minimum interval is 30 seconds. |
|
||||
|
||||
## Metrics
|
||||
|
||||
### System Info
|
||||
|
||||
- Device Name
|
||||
- Device ID
|
||||
- Firmware Version
|
||||
- Device Model
|
||||
- Mac Address
|
||||
|
||||
### Status
|
||||
|
||||
- CPU Utilization (%)
|
||||
- Memory Usage (MB)
|
||||
- Memory Available (MB)
|
||||
- Cache Size (MB)
|
||||
- Net Port 1 Speed (Mbps)
|
||||
- Net Port 2 Speed (Mbps)
|
||||
- Boot Time
|
||||
- Device Uptime
|
||||
- Last Calibration Time
|
||||
- Last Calibration Time Diff (s)
|
||||
- Avg Upload Time (ms)
|
||||
- Max Upload Time (ms)
|
||||
- Min Upload Time (ms)
|
||||
- Last Calibration Mode
|
||||
- Last Calibration Address
|
||||
- Response Time (ms)
|
||||
|
||||
## Implementation Principle
|
||||
|
||||
The monitoring is implemented by accessing the Hikvision device's ISAPI interface:
|
||||
|
||||
1. Collect system information through: `/ISAPI/System/deviceInfo`
|
||||
|
||||
2. Collect device status through: `/ISAPI/System/status`
|
||||
|
||||
It uses HTTP protocol with Digest Authentication to access the interfaces and parses XML response data to extract monitoring metrics.
|
||||
@@ -73,4 +73,4 @@ Use advanced settings when adding `SqlServer` monitoring, customize JDBC URL, ad
|
||||
|
||||
Example: ```jdbc:sqlserver://127.0.0.1:1433;DatabaseName=demo;encrypt=true;trustServerCertificate=true;```
|
||||
|
||||
Reference document: [microsoft pkix-path-building-failed-unable-to-find-valid-certification](https://techcommunity.microsoft.com/t5/azure-database-support-blog/pkix-path-building-failed-unable-to-find-valid-certification/ba-p/2591304)
|
||||
Reference document: [microsoft pkix-path-building-failed-unable-to-find-valid-certification](<https://techcommunity.microsoft.com/t5/azure-database-support-blog/pkix-path-building-> failed-unable-to-find-valid-certification/ba-p/2591304)
|
||||
|
||||
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 8.0 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 104 KiB |
|
Before Width: | Height: | Size: 178 KiB After Width: | Height: | Size: 178 KiB |
@@ -16,23 +16,23 @@ sidebar_label: Template Marketplace
|
||||
|
||||
1. **No filter: displayed in order of upload**
|
||||
|
||||

|
||||

|
||||
|
||||
2. **Filtering by category: currently divided into six categories**
|
||||
|
||||
> **📋Todo:** develop tag function, subdivided within the category, such as database monitoring template can be divided into MySQL, Oracle, etc.
|
||||
|
||||

|
||||

|
||||
|
||||
3. **Fuzzy search by Title**
|
||||
|
||||

|
||||

|
||||
|
||||
4. **Hover window function: download the latest version, view details, favorite/un-favorite**
|
||||
|
||||
> Show if the user has favorites after logging in
|
||||
|
||||

|
||||

|
||||
|
||||
5. **Sort: Eight Sorting Methods**
|
||||
|
||||
@@ -48,19 +48,19 @@ sidebar_label: Template Marketplace
|
||||
|
||||
> **📋Todo:** Upgrade to MarkDown format
|
||||
|
||||

|
||||

|
||||
|
||||
2. **Version: Historical version download, sharing and basic information display**
|
||||
|
||||
> **📋Todo:** Set up a view function for each historical version to display information such as the version description.
|
||||
|
||||

|
||||

|
||||
|
||||
3. **FAQ**
|
||||
|
||||
> **📋Todo:** Discussion or issue Q&A section
|
||||
|
||||

|
||||

|
||||
|
||||
4. **Download**
|
||||
|
||||
@@ -68,7 +68,7 @@ sidebar_label: Template Marketplace
|
||||
> The latest version can also be downloaded directly from the template detail page.
|
||||
> The historical version can be downloaded from the version page.
|
||||
|
||||

|
||||

|
||||
|
||||
5. **Share**
|
||||
|
||||
@@ -78,7 +78,7 @@ sidebar_label: Template Marketplace
|
||||
>
|
||||
> **📋Todo:** Shared template detail page is accessed through the URL of the shared template, and the shared person is free to choose whether to download or not.
|
||||
|
||||

|
||||

|
||||
|
||||
### User Center
|
||||
|
||||
@@ -94,21 +94,21 @@ sidebar_label: Template Marketplace
|
||||
>
|
||||
> **📋Todo:** Function to update template information
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
2. **Version Upgrade**
|
||||
|
||||
> The user defines the new version number under this template family, updates the version information, and uploads the latest version of the file
|
||||
|
||||

|
||||

|
||||
|
||||
3. **Star**
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
4. **Upload**
|
||||
|
||||
@@ -116,7 +116,7 @@ sidebar_label: Template Marketplace
|
||||
>
|
||||
> Fill in the template name, select the template category, fill in the description information and version information, and upload files
|
||||
|
||||

|
||||

|
||||
|
||||
### Sign Up & Login
|
||||
|
||||
@@ -128,13 +128,13 @@ sidebar_label: Template Marketplace
|
||||
>
|
||||
> **📋Todo:** Captcha function, email verification function
|
||||
|
||||

|
||||

|
||||
|
||||
2. **Login**
|
||||
|
||||
> **📋Todo:** Captcha function and forgot password function
|
||||
|
||||

|
||||

|
||||
|
||||
## Development Steps
|
||||
|
||||
|
||||
@@ -53,7 +53,6 @@ ${FORMATTER [{ + | - }<DURATION> <TIME_UNIT>]}
|
||||
#### Where to Use
|
||||
|
||||
- Request parameters for HTTP protocol monitoring types
|
||||
- Request Body for HTTP protocol monitoring types
|
||||
|
||||
#### Usage Examples
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"version.label": {
|
||||
"message": "v1.7.x",
|
||||
"message": "v1.6.x",
|
||||
"description": "The label for version current"
|
||||
},
|
||||
"sidebar.docs.category.quickstart": {
|
||||
@@ -51,10 +51,6 @@
|
||||
"message": "Threshold Alarm Setting",
|
||||
"description": "The label for category threshold in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.reduce": {
|
||||
"message": "Alarm Reduce Setting",
|
||||
"description": "The label for category reduce in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.notice": {
|
||||
"message": "Alarm Notice Setting",
|
||||
"description": "The label for category notice in sidebar docs"
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
{
|
||||
"version.label": {
|
||||
"message": "v1.5.x",
|
||||
"description": "The label for version v1.5.x"
|
||||
},
|
||||
"sidebar.docs.category.quickstart": {
|
||||
"message": "quickstart",
|
||||
"description": "The label for category quickstart in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.custom": {
|
||||
"message": "custom",
|
||||
"description": "The label for category custom in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.http": {
|
||||
"message": "http",
|
||||
"description": "The label for category http in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.jdbc": {
|
||||
"message": "jdbc",
|
||||
"description": "The label for category jdbc in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.ssh": {
|
||||
"message": "ssh",
|
||||
"description": "The label for category ssh in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.jmx": {
|
||||
"message": "jmx",
|
||||
"description": "The label for category jmx in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.snmp": {
|
||||
"message": "snmp",
|
||||
"description": "The label for category snmp in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.push": {
|
||||
"message": "push",
|
||||
"description": "The label for category push in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.NGQL": {
|
||||
"message": "NGQL",
|
||||
"description": "The label for category NGQL in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.Community": {
|
||||
"message": "Community",
|
||||
"description": "The label for category Community in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.contribution": {
|
||||
"message": "contribution",
|
||||
"description": "The label for category contribution in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.submit": {
|
||||
"message": "submit",
|
||||
"description": "The label for category submit in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.release": {
|
||||
"message": "release",
|
||||
"description": "The label for category release in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.help": {
|
||||
"message": "help",
|
||||
"description": "The label for category help in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.service": {
|
||||
"message": "service",
|
||||
"description": "The label for category service in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.program": {
|
||||
"message": "program",
|
||||
"description": "The label for category program in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.database": {
|
||||
"message": "database",
|
||||
"description": "The label for category database in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.cache": {
|
||||
"message": "cache",
|
||||
"description": "The label for category cache in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.os": {
|
||||
"message": "os",
|
||||
"description": "The label for category os in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.mid": {
|
||||
"message": "mid",
|
||||
"description": "The label for category mid in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.bigdata": {
|
||||
"message": "bigdata",
|
||||
"description": "The label for category bigdata in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.webserver": {
|
||||
"message": "webserver",
|
||||
"description": "The label for category webserver in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.cloud-native": {
|
||||
"message": "cloud-native",
|
||||
"description": "The label for category cloud-native in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.llm": {
|
||||
"message": "llm",
|
||||
"description": "The label for category llm in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.network": {
|
||||
"message": "network",
|
||||
"description": "The label for category network in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.threshold": {
|
||||
"message": "threshold",
|
||||
"description": "The label for category threshold in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.notice": {
|
||||
"message": "notice",
|
||||
"description": "The label for category notice in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.Others": {
|
||||
"message": "Others",
|
||||
"description": "The label for category Others in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.link.Install via Helm": {
|
||||
"message": "Install via Helm",
|
||||
"description": "The label for link Install via Helm in sidebar docs, linking to https://artifacthub.io/packages/helm/hertzbeat/hertzbeat"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"version.label": {
|
||||
"message": "v1.7.x",
|
||||
"message": "v1.6.x",
|
||||
"description": "The label for version current"
|
||||
},
|
||||
"sidebar.docs.category.quickstart": {
|
||||
@@ -55,10 +55,6 @@
|
||||
"message": "阈值告警配置",
|
||||
"description": "The label for category threshold in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.reduce": {
|
||||
"message": "告警收敛配置",
|
||||
"description": "The label for category reduce in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.notice": {
|
||||
"message": "告警通知配置",
|
||||
"description": "The label for category notice in sidebar docs"
|
||||
|
||||
@@ -1,258 +0,0 @@
|
||||
---
|
||||
id: extend-http-xmlpath
|
||||
title: HTTP 协议 XmlPath 解析方法
|
||||
sidebar_label: XmlPath 解析方法
|
||||
---
|
||||
|
||||
> 调用 HTTP API 获取响应数据后,使用 XmlPath 脚本解析方法解析响应数据。
|
||||
|
||||
注意⚠️ 响应数据必须是 XML 格式。
|
||||
|
||||
**使用 XPath 脚本将响应数据解析为符合 HertzBeat 指定的数据结构规则的数据。**
|
||||
|
||||
### XmlPath 解析逻辑
|
||||
|
||||
HertzBeat 中的 XmlPath 解析方法使用两步 XPath 处理:
|
||||
|
||||
1. **主 XPath 表达式 (`parseScript`)**: 此 XPath 表达式在 `http` 配置部分的 `parseScript` 中定义。它用于从响应中选择一个或多个主要的 XML 节点。每个选中的节点将对应 HertzBeat 中的一行指标数据。
|
||||
2. **相对字段 XPath 表达式 (`xpath`)**: 对于在 `fields` 列表中定义的每个指标字段,您可以指定一个相对的 `xpath`。此 XPath 表达式是*相对于*步骤 1 中 `parseScript` 选择的每个主节点进行评估的。它从当前主节点中提取该指标字段的具体值。
|
||||
|
||||
这使您可以轻松地解析包含多个记录或项目的结构化 XML 数据。
|
||||
|
||||
**特殊指标**:
|
||||
|
||||
* `responseTime`: 这个内置指标代表 HTTP 请求的响应时间,是自动收集的。它不需要 `xpath`。
|
||||
|
||||
* `keyword`: 这个内置指标计算原始响应体中指定关键字(在 `http.keyword` 中配置)的出现次数。它不需要 `xpath`。
|
||||
|
||||
### 示例
|
||||
|
||||
假设 HTTP API 返回以下 XML 数据:
|
||||
|
||||
```xml
|
||||
<DeviceStatus xmlns="http://www.isapi.org/ver20/XMLSchema" version="2.0">
|
||||
<CPUList>
|
||||
<CPU>
|
||||
<cpuUtilization>36.400002</cpuUtilization>
|
||||
</CPU>
|
||||
</CPUList>
|
||||
<MemoryList>
|
||||
<Memory>
|
||||
<memoryUsage>399640</memoryUsage>
|
||||
<memoryAvailable>98792</memoryAvailable>
|
||||
<cacheSize>228492</cacheSize>
|
||||
</Memory>
|
||||
</MemoryList>
|
||||
<NetPortStatusList>
|
||||
<NetPortStatus>
|
||||
<id>1</id>
|
||||
<workSpeed>1000</workSpeed>
|
||||
</NetPortStatus>
|
||||
<NetPortStatus>
|
||||
<id>2</id>
|
||||
<workSpeed>0</workSpeed>
|
||||
</NetPortStatus>
|
||||
</NetPortStatusList>
|
||||
<bootTime>2025-01-06 10:27:48</bootTime>
|
||||
<deviceUpTime>87天0时55分59秒</deviceUpTime>
|
||||
<lastCalibrationTime>2025-04-03 11:09:18</lastCalibrationTime>
|
||||
<lastCalibrationTimeDiff>1</lastCalibrationTimeDiff>
|
||||
<uploadTimeConsumingList>
|
||||
<avgTime>16</avgTime>
|
||||
<maxTime>23</maxTime>
|
||||
<minTime>12</minTime>
|
||||
</uploadTimeConsumingList>
|
||||
<lastCalibrationTimeMode>NTP</lastCalibrationTimeMode>
|
||||
<lastCalibrationTimeAddress>34.191.45.101</lastCalibrationTimeAddress>
|
||||
</DeviceStatus>
|
||||
```
|
||||
|
||||
我们想要监控设备状态并提取各种指标。
|
||||
|
||||
以下是您将如何配置监控模板 YML:
|
||||
|
||||
```yaml
|
||||
category: server
|
||||
# The monitoring type eg: linux windows tomcat mysql aws...
|
||||
app: hikvision_isapi
|
||||
# The monitoring i18n name
|
||||
name:
|
||||
zh-CN: 海康威视 ISAPI
|
||||
en-US: Hikvision ISAPI
|
||||
# The description and help of this monitoring type
|
||||
help:
|
||||
zh-CN: 通过ISAPI接口监控海康威视设备状态,获取设备健康数据。
|
||||
en-US: Monitor Hikvision devices through ISAPI interface to collect health data.
|
||||
|
||||
# Input params define for monitoring(render web ui by the definition)
|
||||
params:
|
||||
- field: host
|
||||
name:
|
||||
zh-CN: 主机Host
|
||||
en-US: Host
|
||||
type: host
|
||||
required: true
|
||||
- field: port
|
||||
name:
|
||||
zh-CN: 端口
|
||||
en-US: Port
|
||||
type: number
|
||||
range: '[0,65535]'
|
||||
required: true
|
||||
defaultValue: 80
|
||||
- field: timeout
|
||||
name:
|
||||
zh-CN: 超时时间(ms)
|
||||
en-US: Timeout(ms)
|
||||
type: number
|
||||
range: '[1000,60000]'
|
||||
required: true
|
||||
defaultValue: 5000
|
||||
- field: username
|
||||
name:
|
||||
zh-CN: 用户名
|
||||
en-US: Username
|
||||
type: text
|
||||
required: true
|
||||
- field: password
|
||||
name:
|
||||
zh-CN: 密码
|
||||
en-US: Password
|
||||
type: password
|
||||
required: true
|
||||
- field: ssl
|
||||
name:
|
||||
zh-CN: 启用HTTPS
|
||||
en-US: SSL
|
||||
type: boolean
|
||||
required: false
|
||||
defaultValue: false
|
||||
|
||||
# collect metrics config list
|
||||
metrics:
|
||||
- name: status
|
||||
protocol: http
|
||||
http:
|
||||
host: ^_^host^_^
|
||||
port: ^_^port^_^
|
||||
ssl: ^_^ssl^_^
|
||||
url: /ISAPI/System/status
|
||||
method: GET
|
||||
timeout: ^_^timeout^_^
|
||||
authorization:
|
||||
type: Digest Auth
|
||||
digestAuthUsername: ^_^username^_^
|
||||
digestAuthPassword: ^_^password^_^
|
||||
parseType: xmlPath
|
||||
parseScript: 'DeviceStatus'
|
||||
fields:
|
||||
- field: cpuUtilization
|
||||
i18n:
|
||||
zh-CN: CPU 利用率
|
||||
en-US: CPU Utilization
|
||||
type: 0
|
||||
unit: '%'
|
||||
xpath: CPUList/CPU/cpuUtilization
|
||||
- field: memoryUsage
|
||||
i18n:
|
||||
zh-CN: 内存使用量
|
||||
en-US: Memory Usage
|
||||
type: 0
|
||||
unit: MB
|
||||
xpath: MemoryList/Memory/memoryUsage
|
||||
- field: memoryAvailable
|
||||
i18n:
|
||||
zh-CN: 可用内存
|
||||
en-US: Memory Available
|
||||
type: 0
|
||||
unit: MB
|
||||
xpath: MemoryList/Memory/memoryAvailable
|
||||
- field: cacheSize
|
||||
i18n:
|
||||
zh-CN: 缓存大小
|
||||
en-US: Cache Size
|
||||
type: 0
|
||||
unit: MB
|
||||
xpath: MemoryList/Memory/cacheSize
|
||||
- field: netPort1Speed
|
||||
i18n:
|
||||
zh-CN: 网口1速度
|
||||
en-US: Net Port 1 Speed
|
||||
type: 0
|
||||
unit: Mbps
|
||||
xpath: NetPortStatusList/NetPortStatus[id='1']/workSpeed
|
||||
- field: netPort2Speed
|
||||
i18n:
|
||||
zh-CN: 网口2速度
|
||||
en-US: Net Port 2 Speed
|
||||
type: 0
|
||||
unit: Mbps
|
||||
xpath: NetPortStatusList/NetPortStatus[id='2']/workSpeed
|
||||
- field: bootTime
|
||||
i18n:
|
||||
zh-CN: 启动时间
|
||||
en-US: Boot Time
|
||||
type: 1
|
||||
xpath: bootTime
|
||||
- field: deviceUpTime
|
||||
i18n:
|
||||
zh-CN: 运行时长
|
||||
en-US: Device Uptime
|
||||
type: 1
|
||||
xpath: deviceUpTime
|
||||
- field: lastCalibrationTime
|
||||
i18n:
|
||||
zh-CN: 上次校时时间
|
||||
en-US: Last Calibration Time
|
||||
type: 1
|
||||
xpath: lastCalibrationTime
|
||||
- field: lastCalibrationTimeDiff
|
||||
i18n:
|
||||
zh-CN: 上次校时时间差
|
||||
en-US: Last Calibration Time Diff
|
||||
type: 0
|
||||
unit: s
|
||||
xpath: lastCalibrationTimeDiff
|
||||
- field: avgUploadTime
|
||||
i18n:
|
||||
zh-CN: 平均上传耗时
|
||||
en-US: Avg Upload Time
|
||||
type: 0
|
||||
unit: ms
|
||||
xpath: uploadTimeConsumingList/avgTime
|
||||
- field: maxUploadTime
|
||||
i18n:
|
||||
zh-CN: 最大上传耗时
|
||||
en-US: Max Upload Time
|
||||
type: 0
|
||||
unit: ms
|
||||
xpath: uploadTimeConsumingList/maxTime
|
||||
- field: minUploadTime
|
||||
i18n:
|
||||
zh-CN: 最小上传耗时
|
||||
en-US: Min Upload Time
|
||||
type: 0
|
||||
unit: ms
|
||||
xpath: uploadTimeConsumingList/minTime
|
||||
- field: lastCalibrationMode
|
||||
i18n:
|
||||
zh-CN: 上次校时模式
|
||||
en-US: Last Calibration Mode
|
||||
type: 1
|
||||
xpath: lastCalibrationTimeMode
|
||||
- field: lastCalibrationAddress
|
||||
i18n:
|
||||
zh-CN: 上次校时地址
|
||||
en-US: Last Calibration Address
|
||||
type: 1
|
||||
xpath: lastCalibrationTimeAddress
|
||||
- field: responseTime
|
||||
i18n:
|
||||
zh-CN: 响应时间
|
||||
en-US: Response Time
|
||||
type: 0
|
||||
unit: ms
|
||||
units:
|
||||
- memoryUsage=KB->MB
|
||||
- memoryAvailable=KB->MB
|
||||
- cacheSize=KB->MB
|
||||
@@ -22,7 +22,6 @@ sidebar_label: Download
|
||||
|
||||
| 版本 | 日期 | 下载 | Release Notes |
|
||||
|--------|------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------|
|
||||
| v1.7.0 | 2025.04.02 | [apache-hertzbeat-1.7.0-incubating-bin.tar.gz](https://dist.apache.org/repos/dist/release/incubator/hertzbeat/1.7.0/apache-hertzbeat-1.7.0-incubating-bin.tar.gz) (HertzBeat 主程序) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.7.0/apache-hertzbeat-1.7.0-incubating-bin.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.7.0/apache-hertzbeat-1.7.0-incubating-bin.tar.gz.sha512) ) <br/> [apache-hertzbeat-collector-1.7.0-incubating-bin.tar.gz](https://downloads.apache.org/incubator/hertzbeat/1.7.0/apache-hertzbeat-collector-1.7.0-incubating-bin.tar.gz) (HertzBeat 采集器) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.7.0/apache-hertzbeat-collector-1.7.0-incubating-bin.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.7.0/apache-hertzbeat-collector-1.7.0-incubating-bin.tar.gz.sha512) ) <br/> [apache-hertzbeat-1.7.0-incubating-src.tar.gz](https://downloads.apache.org/incubator/hertzbeat/1.7.0/apache-hertzbeat-1.7.0-incubating-src.tar.gz) (HertzBeat 源代码) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.7.0/apache-hertzbeat-1.7.0-incubating-src.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.7.0/apache-hertzbeat-1.7.0-incubating-src.tar.gz.sha512) ) <br/> [apache-hertzbeat-1.7.0-incubating-docker-compose.tar.gz](https://dist.apache.org/repos/dist/release/incubator/hertzbeat/1.7.0/apache-hertzbeat-1.7.0-incubating-docker-compose.tar.gz) (docker-compose) ( [signature](https://dist.apache.org/repos/dist/release/incubator/hertzbeat/1.7.0/apache-hertzbeat-1.7.0-incubating-docker-compose.tar.gz.asc) , [sha512](https://dist.apache.org/repos/dist/release/incubator/hertzbeat/1.7.0/apache-hertzbeat-1.7.0-incubating-docker-compose.tar.gz.sha512) ) | [release note](https://github.com/apache/hertzbeat/releases/tag/v1.7.0) |
|
||||
| v1.6.1 | 2024.10.29 | [apache-hertzbeat-1.6.1-incubating-bin.tar.gz](https://downloads.apache.org/incubator/hertzbeat/1.6.1/apache-hertzbeat-1.6.1-incubating-bin.tar.gz) (HertzBeat 主程序) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.6.1/apache-hertzbeat-1.6.1-incubating-bin.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.6.1/apache-hertzbeat-1.6.1-incubating-bin.tar.gz.sha512) ) <br/> [apache-hertzbeat-collector-1.6.1-incubating-bin.tar.gz](https://downloads.apache.org/incubator/hertzbeat/1.6.1/apache-hertzbeat-collector-1.6.1-incubating-bin.tar.gz) (HertzBeat 采集器) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.6.1/apache-hertzbeat-collector-1.6.1-incubating-bin.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.6.1/apache-hertzbeat-collector-1.6.1-incubating-bin.tar.gz.sha512) ) <br/> [apache-hertzbeat-1.6.1-incubating-src.tar.gz](https://downloads.apache.org/incubator/hertzbeat/1.6.1/apache-hertzbeat-1.6.1-incubating-src.tar.gz) (HertzBeat 源代码包) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.6.1/apache-hertzbeat-1.6.1-incubating-src.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.6.1/apache-hertzbeat-1.6.1-incubating-src.tar.gz.sha512) ) <br/> [apache-hertzbeat-1.6.1-incubating-docker-compose.tar.gz](https://dist.apache.org/repos/dist/release/incubator/hertzbeat/1.6.1/apache-hertzbeat-1.6.1-incubating-docker-compose.tar.gz) (docker-compose) ( [signature](https://dist.apache.org/repos/dist/release/incubator/hertzbeat/1.6.1/apache-hertzbeat-1.6.1-incubating-docker-compose.tar.gz.asc) , [sha512](https://dist.apache.org/repos/dist/release/incubator/hertzbeat/1.6.1/apache-hertzbeat-1.6.1-incubating-docker-compose.tar.gz.sha512) ) | [release note](https://github.com/apache/hertzbeat/releases/tag/v1.6.1) |
|
||||
| v1.6.0 | 2024.06.10 | [apache-hertzbeat-1.6.0-incubating-bin.tar.gz](https://downloads.apache.org/incubator/hertzbeat/1.6.0/apache-hertzbeat-1.6.0-incubating-bin.tar.gz) (HertzBeat 主程序) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.6.0/apache-hertzbeat-1.6.0-incubating-bin.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.6.0/apache-hertzbeat-1.6.0-incubating-bin.tar.gz.sha512) ) <br/> [apache-hertzbeat-collector-1.6.0-incubating-bin.tar.gz](https://downloads.apache.org/incubator/hertzbeat/1.6.0/apache-hertzbeat-collector-1.6.0-incubating-bin.tar.gz) (HertzBeat 采集器) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.6.0/apache-hertzbeat-collector-1.6.0-incubating-bin.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.6.0/apache-hertzbeat-collector-1.6.0-incubating-bin.tar.gz.sha512) ) <br/> [apache-hertzbeat-1.6.0-incubating-src.tar.gz](https://downloads.apache.org/incubator/hertzbeat/1.6.0/apache-hertzbeat-1.6.0-incubating-src.tar.gz) (HertzBeat 源代码包) ( [signature](https://downloads.apache.org/incubator/hertzbeat/1.6.0/apache-hertzbeat-1.6.0-incubating-src.tar.gz.asc) , [sha512](https://downloads.apache.org/incubator/hertzbeat/1.6.0/apache-hertzbeat-1.6.0-incubating-src.tar.gz.sha512) ) | [release note](https://github.com/apache/hertzbeat/releases/tag/v1.6.0) |
|
||||
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
---
|
||||
id: alarm_group
|
||||
title: 分组收敛
|
||||
sidebar_label: 分组收敛
|
||||
keywords: [ 开源监控系统, 告警收敛, 告警分组 ]
|
||||
---
|
||||
|
||||
> 分组收敛支持对指定分组标签的告警进行分组合并,对时间段的相同重复告警去重收敛。 当阈值规则触发告警或外部告警上报后,会进入到分组收敛进行告警分组,告警去重,以避免大量告警消息导致告警风暴。
|
||||
|
||||
## 分组策略参数配置
|
||||
|
||||
- 策略名称:唯一标识分组策略的名称
|
||||
- 分组标签:告警分组标签,最多支持添加10个标签
|
||||
|
||||
> 标签来源:监控,阈值规则,外部告警携带的标签
|
||||
|
||||
- 等待时间:新告警产生后等待时间,在此时间内收到的相同告警将被分组,默认30秒
|
||||
|
||||
> 当一条新(无法加入已有分组)的告警产生,分组收敛将按照 `等待时间` 等待,在此期间,相同告警或满足分组条件的告警将被分组。直到当前时间与该分组第一条告警产生时间间隔超过 `等待时间`,分组后的告警才被发送到告警抑制模块进行后续处理。
|
||||
|
||||
- 间隔时间:发送分组告警通知的最小时间间隔,避免告警通知过于频繁,默认5分钟
|
||||
- 重复间隔:重复告警的最小通知间隔,对于持续触发的告警,避免重复发送通知,默认4小时
|
||||
|
||||
**注意**:只有分组后的告警才能使用抑制规则进行告警抑制。
|
||||
@@ -1,38 +0,0 @@
|
||||
---
|
||||
id: alarm_inhibit
|
||||
title: 告警抑制
|
||||
sidebar_label: 告警抑制
|
||||
keywords: [ 开源监控系统, 告警收敛, 告警抑制 ]
|
||||
---
|
||||
|
||||
> 告警抑制用于配置告警之间的抑制关系。当某个告警发生时,可以抑制其他告警的产生,可以理解为“重要”告警抑制“不重要”告警的产生,例如一台服务器宕机产生的告警抑制这台服务器上其他服务产生的告警。
|
||||
|
||||
## 前置条件
|
||||
|
||||
- 正确配置分组收敛规则
|
||||
|
||||
## 抑制规则配置
|
||||
|
||||
- 抑制规则名称: 唯一标识抑制规则的名称;
|
||||
- 源标签: 当告警包含这些标签时,将会抑制目标告警,支持添加多个标签;
|
||||
> 识别“重要”告警的标签,告警标签需要包含全部源标签才会抑制被目标标签标记的告警。
|
||||
- 目标标签: 匹配这些标签的告警将被抑制;
|
||||
> 识别“不重要”告警的标签,告警标签需要包含全部目标标签才会被抑制。
|
||||
- 相等标签: 判断告警相关性的标签。支持最多10个标签;
|
||||
- 启用状态: 启用或禁用该抑制规则。
|
||||
|
||||
## 示例
|
||||
|
||||
场景: 使用 Hertzbeat 监控 两个 Centos 服务器 192.168.1.1 和 192.168.1.2,和部署在两个服务器上的 Redis 服务 Redis-1 和 Redis-2。
|
||||
并配置如下阈值规则:
|
||||
|
||||
- 监控 Centos Linux /监控可用性。绑定标签 `server-status:down`
|
||||
- 监控 Redis数据库 /监控可用性。绑定标签 `redis-status:down`
|
||||
|
||||
如果需要实现当Centos 宕机告警产生后,Redis 告警不再产生,则可以配置如下告警抑制规则:
|
||||
|
||||
- 源标签: `server-status:down`
|
||||
- 目标标签: `redis-status:down`
|
||||
- 相等标签: `instancehost`
|
||||
|
||||
当 Centos 192.168.1.1 宕机告警产生时,通知Redis-1 不可用的告警将不再产生。且同时 Centos 192.168.1.2 运行正常且 Redis-2 不可用时,通知 Redis-2 不可用的告警将正常产生。
|
||||
@@ -1,15 +1,15 @@
|
||||
---
|
||||
id: api
|
||||
title: 监控:HTTP API
|
||||
sidebar_label: HTTP API
|
||||
keywords: [ 开源监控系统, 开源网站监控, HTTP API监控 ]
|
||||
id: api
|
||||
title: 监控:HTTP API
|
||||
sidebar_label: HTTP API
|
||||
keywords: [开源监控系统, 开源网站监控, HTTP API监控]
|
||||
---
|
||||
|
||||
> 调用HTTP API接口,查看接口是否可用,对其响应时间等指标进行监测
|
||||
|
||||
### 配置参数
|
||||
|
||||
| 参数名称 | 参数帮助描述 |
|
||||
| 参数名称 | 参数帮助描述 |
|
||||
|--------------|-------------------------------------------------------------------|
|
||||
| 监控Host | 被监控的对端IPV4,IPV6或域名。注意⚠️不带协议头(eg: https://, http://)。 |
|
||||
| 任务名称 | 标识此监控的名称,名称需要保证唯一性。 |
|
||||
@@ -22,7 +22,7 @@ keywords: [ 开源监控系统, 开源网站监控, HTTP API监控 ]
|
||||
| 请求Headers | HTTP 请求头 |
|
||||
| 查询Params | HTTP查询参数,支持[时间表达式](time_expression) |
|
||||
| Content-Type | 设置携带BODY请求体数据请求时的资源类型 |
|
||||
| 请求BODY | 设置携带BODY请求体数据,PUT POST请求方式时有效,支持[时间表达式](time_expression) |
|
||||
| 请求BODY | 设置携带BODY请求体数据,PUT POST请求方式时有效 |
|
||||
| 采集间隔 | 监控周期性采集数据间隔时间,单位秒,可设置的最小间隔为30秒 |
|
||||
| 是否探测 | 新增监控前是否先探测检查监控可用性,探测成功才会继续新增修改操作 |
|
||||
| 描述备注 | 更多标识和描述此监控的备注信息,用户可以在这里备注信息 |
|
||||
@@ -31,6 +31,6 @@ keywords: [ 开源监控系统, 开源网站监控, HTTP API监控 ]
|
||||
|
||||
#### 指标集合:summary
|
||||
|
||||
| 指标名称 | 指标单位 | 指标帮助描述 |
|
||||
| 指标名称 | 指标单位 | 指标帮助描述 |
|
||||
|--------------|------|--------|
|
||||
| responseTime | ms毫秒 | 网站响应时间 |
|
||||
|
||||
@@ -116,13 +116,6 @@ sidebar_label: 帮助入门
|
||||
详见 👉 [阈值告警](alert_threshold) <br />
|
||||
   👉 [阈值表达式](alert_threshold_expr)
|
||||
|
||||
### 告警收敛
|
||||
|
||||
> 通过分组收敛、告警抑制等功能合并相关告警,减少由一个事件引发的告警风暴,降低告警噪声,提升告警响应效率。
|
||||
|
||||
详见 👉 [分组收敛](alarm_group) <br />
|
||||
   👉 [告警抑制](alarm_inhibit)
|
||||
|
||||
### 告警通知
|
||||
|
||||
> 触发告警信息后,除了显示在告警中心列表外,还可以用指定方式(邮件钉钉微信飞书等)通知给指定接收人。
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
---
|
||||
id: hikvision_isapi
|
||||
title: 监控 海康ISAPI
|
||||
sidebar_label: 海康ISAPI
|
||||
keywords: [ monitor, hikvision_isapi, 海康 ]
|
||||
---
|
||||
|
||||
> 通过ISAPI接口监控海康威视设备状态,获取设备健康数据。
|
||||
|
||||
## 监控配置参数
|
||||
|
||||
| 参数名称 | 参数帮助描述 |
|
||||
| ----------- | ----------- |
|
||||
| 监控Host | 被监控的对端IP或域名。注意⚠️不带协议头(eg: https://, http://)。 |
|
||||
| 监控名称 | 标识此监控的名称,名称需要保证唯一性。 |
|
||||
| 端口 | 网络请求端口,默认为80。 |
|
||||
| 超时时间 | 设置超时时间,单位ms毫秒,默认5000毫秒。 |
|
||||
| 用户名 | 海康设备登录用户名。 |
|
||||
| 密码 | 海康设备登录密码。 |
|
||||
| 启用HTTPS | 是否启用HTTPS,默认未启用。 |
|
||||
| 采集间隔 | 监控周期性采集数据间隔时间,单位秒,可设置的最小间隔为30秒 |
|
||||
|
||||
## 采集指标
|
||||
|
||||
### 系统信息
|
||||
|
||||
- 设备名称
|
||||
- 设备ID
|
||||
- 固件版本
|
||||
- 设备型号
|
||||
- mac地址
|
||||
|
||||
### 设备状态
|
||||
|
||||
- CPU 利用率(%)
|
||||
- 内存使用量(MB)
|
||||
- 可用内存(MB)
|
||||
- 缓存大小(MB)
|
||||
- 网口1速度(Mbps)
|
||||
- 网口2速度(Mbps)
|
||||
- 启动时间
|
||||
- 运行时长
|
||||
- 上次校时时间
|
||||
- 上次校时时间差(s)
|
||||
- 平均上传耗时(ms)
|
||||
- 最大上传耗时(ms)
|
||||
- 最小上传耗时(ms)
|
||||
- 上次校时模式
|
||||
- 上次校时地址
|
||||
- 响应时间(ms)
|
||||
|
||||
## 监控实现原理
|
||||
|
||||
通过海康威视设备的ISAPI接口获取设备信息和状态:
|
||||
|
||||
1. 采集系统信息:`/ISAPI/System/deviceInfo`
|
||||
|
||||
2. 采集设备状态:`/ISAPI/System/status`
|
||||
|
||||
采用HTTP协议Digest认证方式访问接口,解析XML格式响应数据获取监控指标。
|
||||
@@ -53,7 +53,6 @@ ${FORMATTER [{ + | - }<DURATION> <TIME_UNIT>]}
|
||||
#### 在哪里可以使用
|
||||
|
||||
- HTTP协议监控类型的请求参数
|
||||
- HTTP协议监控类型的请求体
|
||||
|
||||
#### 使用示例
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ Docker 工具自身的下载请参考 [Docker官网文档](https://docs.docker.c
|
||||
|
||||
### 创建数据库实例
|
||||
|
||||
> [TDengine CLI 小技巧](https://docs.taosdata.com/develop/)
|
||||
> [TDengine CLI 小技巧](https://docs.taosdata.com/develop/model/)
|
||||
|
||||
1. 进入数据库Docker容器
|
||||
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
{
|
||||
"version.label": {
|
||||
"message": "v1.5.x",
|
||||
"description": "The label for version v1.5.x"
|
||||
},
|
||||
"sidebar.docs.category.quickstart": {
|
||||
"message": "quickstart",
|
||||
"description": "The label for category quickstart in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.custom": {
|
||||
"message": "custom",
|
||||
"description": "The label for category custom in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.http": {
|
||||
"message": "http",
|
||||
"description": "The label for category http in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.jdbc": {
|
||||
"message": "jdbc",
|
||||
"description": "The label for category jdbc in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.ssh": {
|
||||
"message": "ssh",
|
||||
"description": "The label for category ssh in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.jmx": {
|
||||
"message": "jmx",
|
||||
"description": "The label for category jmx in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.snmp": {
|
||||
"message": "snmp",
|
||||
"description": "The label for category snmp in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.push": {
|
||||
"message": "push",
|
||||
"description": "The label for category push in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.NGQL": {
|
||||
"message": "NGQL",
|
||||
"description": "The label for category NGQL in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.Community": {
|
||||
"message": "Community",
|
||||
"description": "The label for category Community in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.contribution": {
|
||||
"message": "contribution",
|
||||
"description": "The label for category contribution in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.submit": {
|
||||
"message": "submit",
|
||||
"description": "The label for category submit in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.release": {
|
||||
"message": "release",
|
||||
"description": "The label for category release in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.help": {
|
||||
"message": "help",
|
||||
"description": "The label for category help in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.service": {
|
||||
"message": "service",
|
||||
"description": "The label for category service in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.program": {
|
||||
"message": "program",
|
||||
"description": "The label for category program in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.database": {
|
||||
"message": "database",
|
||||
"description": "The label for category database in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.cache": {
|
||||
"message": "cache",
|
||||
"description": "The label for category cache in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.os": {
|
||||
"message": "os",
|
||||
"description": "The label for category os in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.mid": {
|
||||
"message": "mid",
|
||||
"description": "The label for category mid in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.bigdata": {
|
||||
"message": "bigdata",
|
||||
"description": "The label for category bigdata in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.webserver": {
|
||||
"message": "webserver",
|
||||
"description": "The label for category webserver in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.cloud-native": {
|
||||
"message": "cloud-native",
|
||||
"description": "The label for category cloud-native in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.llm": {
|
||||
"message": "llm",
|
||||
"description": "The label for category llm in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.network": {
|
||||
"message": "network",
|
||||
"description": "The label for category network in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.threshold": {
|
||||
"message": "threshold",
|
||||
"description": "The label for category threshold in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.notice": {
|
||||
"message": "notice",
|
||||
"description": "The label for category notice in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.Others": {
|
||||
"message": "Others",
|
||||
"description": "The label for category Others in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.link.Install via Helm": {
|
||||
"message": "Install via Helm",
|
||||
"description": "The label for link Install via Helm in sidebar docs, linking to https://artifacthub.io/packages/helm/hertzbeat/hertzbeat"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
---
|
||||
id: extend-http-default
|
||||
title: HTTP协议系统默认解析方式
|
||||
sidebar_label: 系统默认解析方式
|
||||
---
|
||||
|
||||
> HTTP接口调用获取响应数据后,用 Apache HertzBeat (incubating) 默认的解析方式去解析响应数据。
|
||||
|
||||
**此需接口响应数据结构符合HertzBeat指定的数据结构规则**
|
||||
|
||||
### HertzBeat数据格式规范
|
||||
|
||||
注意⚠️ 响应数据为JSON
|
||||
|
||||
单层格式:key-value
|
||||
|
||||
```json
|
||||
{
|
||||
"metricName1": "metricValue",
|
||||
"metricName2": "metricValue",
|
||||
"metricName3": "metricValue",
|
||||
"metricName4": "metricValue"
|
||||
}
|
||||
```
|
||||
|
||||
多层格式:数组里面套key-value
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"metricName1": "metricValue",
|
||||
"metricName2": "metricValue",
|
||||
"metricName3": "metricValue",
|
||||
"metricName4": "metricValue"
|
||||
},
|
||||
{
|
||||
"metricName1": "metricValue",
|
||||
"metricName2": "metricValue",
|
||||
"metricName3": "metricValue",
|
||||
"metricName4": "metricValue"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
样例:
|
||||
查询自定义系统的CPU信息,其暴露接口为 `/metrics/cpu`,我们需要其中的`hostname,core,useage`指标
|
||||
若只有一台虚拟机,其单层格式为:
|
||||
|
||||
```json
|
||||
{
|
||||
"hostname": "linux-1",
|
||||
"core": 1,
|
||||
"usage": 78.0,
|
||||
"allTime": 200,
|
||||
"runningTime": 100
|
||||
}
|
||||
```
|
||||
|
||||
若有多台虚拟机,其多层格式为:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"hostname": "linux-1",
|
||||
"core": 1,
|
||||
"usage": 78.0,
|
||||
"allTime": 200,
|
||||
"runningTime": 100
|
||||
},
|
||||
{
|
||||
"hostname": "linux-2",
|
||||
"core": 3,
|
||||
"usage": 78.0,
|
||||
"allTime": 566,
|
||||
"runningTime": 34
|
||||
},
|
||||
{
|
||||
"hostname": "linux-3",
|
||||
"core": 4,
|
||||
"usage": 38.0,
|
||||
"allTime": 500,
|
||||
"runningTime": 20
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
**对应的监控模版YML可以配置为如下**
|
||||
|
||||
```yaml
|
||||
# 监控类型所属类别:service-应用服务 program-应用程序 db-数据库 custom-自定义 os-操作系统 bigdata-大数据 mid-中间件 webserver-web服务器 cache-缓存 cn-云原生 network-网络监控等等
|
||||
category: custom
|
||||
# 监控应用类型(与文件名保持一致) eg: linux windows tomcat mysql aws...
|
||||
app: example
|
||||
name:
|
||||
zh-CN: 模拟应用类型
|
||||
en-US: EXAMPLE APP
|
||||
# 监控参数定义. field 这些为输入参数变量,即可以用^_^host^_^的形式写到后面的配置中,系统自动变量值替换
|
||||
# 强制固定必须参数 - host
|
||||
params:
|
||||
# field-字段名称标识符
|
||||
- field: host
|
||||
# name-参数字段显示名称
|
||||
name:
|
||||
zh-CN: 主机Host
|
||||
en-US: Host
|
||||
# type-字段类型,样式(大部分映射input标签type属性)
|
||||
type: host
|
||||
# 是否是必输项 true-必填 false-可选
|
||||
required: true
|
||||
- field: port
|
||||
name:
|
||||
zh-CN: 端口
|
||||
en-US: Port
|
||||
type: number
|
||||
# 当type为number时,用range表示范围
|
||||
range: '[0,65535]'
|
||||
required: true
|
||||
# 端口默认值
|
||||
defaultValue: 80
|
||||
# 参数输入框提示信息
|
||||
placeholder: '请输入端口'
|
||||
# collect metrics config list
|
||||
# 采集指标配置列表
|
||||
metrics:
|
||||
# First monitoring metric group cpu
|
||||
# Note: The built-in monitoring metrics include (responseTime - response time)
|
||||
- name: cpu
|
||||
# 指标调度优先级(0-127)越小优先级越高,优先级低的指标会等优先级高的指标采集完成后才会被调度,相同优先级的指标会并行调度采集
|
||||
# 优先级为0的指标为可用性指标,即它会被首先调度,采集成功才会继续调度其它指标,采集失败则中断调度
|
||||
priority: 0
|
||||
# 具体监控指标列表
|
||||
fields:
|
||||
# 指标信息 包括 field名称 type字段类型:0-number数字,1-string字符串 label是否为标签 unit:指标单位
|
||||
- field: hostname
|
||||
type: 1
|
||||
label: true
|
||||
- field: usage
|
||||
type: 0
|
||||
unit: '%'
|
||||
- field: core
|
||||
type: 0
|
||||
# 监控采集使用协议 eg: sql, ssh, http, telnet, wmi, snmp, sdk
|
||||
protocol: http
|
||||
# 当protocol为http协议时具体的采集配置
|
||||
http:
|
||||
# 主机host: ipv4 ipv6 域名
|
||||
host: ^_^host^_^
|
||||
# 端口
|
||||
port: ^_^port^_^
|
||||
# url请求接口路径
|
||||
url: /metrics/cpu
|
||||
# 请求方式 GET POST PUT DELETE PATCH
|
||||
method: GET
|
||||
# 是否启用ssl/tls,即是http还是https,默认false
|
||||
ssl: false
|
||||
# 响应数据解析方式: default-系统规则,jsonPath-jsonPath脚本,website-网站可用性指标监控
|
||||
# 这里使用HertzBeat默认解析
|
||||
parseType: default
|
||||
```
|
||||
@@ -67,25 +67,18 @@ sidebar_label: 教程一:适配一款HTTP协议监控
|
||||
样例:自定义一个名称为`hertzbeat`的自定义监控类型,其使用HTTP协议采集指标数据。
|
||||
|
||||
```yaml
|
||||
# 监控类型所属类别:service-应用服务 program-应用程序 db-数据库 custom-自定义 os-操作系统 bigdata-大数据 mid-中间件 webserver-web服务器 cache-缓存 cn-云原生 network-网络监控等等
|
||||
category: custom
|
||||
# The monitoring type eg: linux windows tomcat mysql aws...
|
||||
# 监控应用类型名称(与文件名保持一致) eg: linux windows tomcat mysql aws...
|
||||
app: hertzbeat
|
||||
name:
|
||||
zh-CN: HertzBeat
|
||||
en-US: HertzBeat
|
||||
# The description and help of this monitoring type
|
||||
help:
|
||||
zh-CN: Hertzbeat 对 Hertzbeat 监控系统的通用指标进行测量监控。<br>您可以点击 “<i>新建 HertzBeat监控系统</i>” 并进行配置,或者选择“<i>更多操作</i>”,导入已有配置。
|
||||
en-US: Hertzbeat monitors HertzBeat Monitor through general performance metric. You could click the "<i>New HertzBeat Monitor</i>" button and proceed with the configuration or import an existing setup through the "<i>More Actions</i>" menu.
|
||||
zh-TW: Hertzbeat對Hertzbeat監控系統的通用名額進行量測監控。<br>您可以點擊“<i>新建HertzBeat監控系統</i>”並進行配寘,或者選擇“<i>更多操作</i>”,導入已有配寘。
|
||||
helpLink:
|
||||
zh-CN: https://hertzbeat.apache.org/zh-cn/docs/help/hertzbeat
|
||||
en-US: https://hertzbeat.apache.org/docs/help/hertzbeat
|
||||
zh-CN: HertzBeat监控系统
|
||||
en-US: HertzBeat Monitor
|
||||
params:
|
||||
- field: host
|
||||
name:
|
||||
zh-CN: 目标Host
|
||||
en-US: Target Host
|
||||
zh-CN: 主机Host
|
||||
en-US: Host
|
||||
type: host
|
||||
required: true
|
||||
- field: port
|
||||
@@ -136,16 +129,21 @@ params:
|
||||
type: password
|
||||
required: false
|
||||
hide: true
|
||||
# collect metrics config list
|
||||
# 采集指标配置列表
|
||||
metrics:
|
||||
# the first metrics summary
|
||||
# attention: Built-in monitoring metrics contains (responseTime - Response time)
|
||||
# metrics - summary
|
||||
# 监控指标 - summary
|
||||
- name: 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
|
||||
# 指标调度优先级(0-127)越小优先级越高,优先级低的指标会等优先级高的指标采集完成后才会被调度,相同优先级的指标会并行调度采集
|
||||
# 优先级为0的指标为可用性指标,即它会被首先调度,采集成功才会继续调度其它指标,采集失败则中断调度
|
||||
priority: 0
|
||||
# collect metrics content
|
||||
# 具体监控指标列表
|
||||
fields:
|
||||
# metrics content contains field-metric name, type-metric type:0-number,1-string, instance-if is metrics, unit-metric unit('%','ms','MB')
|
||||
# 指标信息 包括 field名称 type字段类型:0-number数字,1-string字符串 label是否为标签 unit:指标单位
|
||||
- field: responseTime
|
||||
type: 0
|
||||
unit: ms
|
||||
- field: app
|
||||
type: 1
|
||||
label: true
|
||||
@@ -156,33 +154,33 @@ metrics:
|
||||
- field: size
|
||||
type: 0
|
||||
- field: availableSize
|
||||
type: 0
|
||||
# the protocol used for monitoring, eg: sql, ssh, http, telnet, wmi, snmp, sdk, we use HTTP protocol here
|
||||
type: 0
|
||||
# 监控采集使用协议 eg: sql, ssh, http, telnet, wmi, snmp, sdk, 我们这里使用HTTP协议
|
||||
protocol: http
|
||||
# the config content when protocol is http
|
||||
# 当protocol为http协议时具体的采集配置
|
||||
http:
|
||||
# host: ipv4 ipv6 domain
|
||||
# 主机host: ipv4 ipv6 域名
|
||||
host: ^_^host^_^
|
||||
# http port
|
||||
# 端口
|
||||
port: ^_^port^_^
|
||||
# http url, we don't need to enter a parameter here, just set the fixed value to /api/summary
|
||||
# url请求接口路径,我们这里不需要输入传参,写死为 /api/summary
|
||||
url: /api/summary
|
||||
timeout: ^_^timeout^_^
|
||||
# http method: GET POST PUT DELETE PATCH, default fixed value is GET
|
||||
# 请求方式 GET POST PUT DELETE PATCH,写死为
|
||||
method: GET
|
||||
# if enabled https, default value is false
|
||||
# 是否启用ssl/tls,即是http还是https,默认false
|
||||
ssl: ^_^ssl^_^
|
||||
# http auth
|
||||
# 认证
|
||||
authorization:
|
||||
# http auth type: Basic Auth, Digest Auth, Bearer Token
|
||||
# 认证方式: Basic Auth, Digest Auth, Bearer Token
|
||||
type: ^_^authType^_^
|
||||
basicAuthUsername: ^_^username^_^
|
||||
basicAuthPassword: ^_^password^_^
|
||||
digestAuthUsername: ^_^username^_^
|
||||
digestAuthPassword: ^_^password^_^
|
||||
# http response data parse type: default-hertzbeat rule, jsonpath-jsonpath script, website-for website monitoring, we use jsonpath to parse response data here
|
||||
# 响应数据解析方式: default-系统规则,jsonPath-jsonPath脚本,website-网站可用性指标监控,我们这里使用jsonpath来解析响应数据
|
||||
parseType: jsonPath
|
||||
parseScript: '$.data.apps.*'
|
||||
parseScript: '$.data.apps.*'
|
||||
|
||||
```
|
||||
|
||||
@@ -44,49 +44,41 @@ sidebar_label: 教程二:获取TOKEN后续认证使用
|
||||
我们直接复用 app-hertzbeat.yml 里面的定义内容,修改为我们当前的监控类型`hertzbeat_auth`配置参数, 比如 `app, category等`。
|
||||
|
||||
```yaml
|
||||
# 监控类型所属类别:service-应用服务 program-应用程序 db-数据库 custom-自定义 os-操作系统 bigdata-大数据 mid-中间件 webserver-web服务器 cache-缓存 cn-云原生 network-网络监控等等
|
||||
category: custom
|
||||
# The monitoring type eg: linux windows tomcat mysql aws...
|
||||
# 监控应用类型(与文件名保持一致) eg: linux windows tomcat mysql aws...
|
||||
app: hertzbeat_token
|
||||
# The monitoring i18n name
|
||||
name:
|
||||
zh-CN: HertzBeat(Token)
|
||||
en-US: HertzBeat(Token)
|
||||
# The description and help of this monitoring type
|
||||
help:
|
||||
zh-CN: Hertzbeat 对 HertzBeat监控(Token)进行测量监控。<br>您可以点击 “<i>新建 HertzBeat监控(Token)</i>” 并进行配置,或者选择“<i>更多操作</i>”,导入已有配置。
|
||||
en-US: Hertzbeat monitors HertzBeat Monitor(Token). You could click the "<i>New HertzBeat Monitor(Token)</i>" button and proceed with the configuration or import an existing setup through the "<i>More Actions</i>" menu.
|
||||
zh-TW: Hertzbeat對HertzBeat監控(Token)進行量測監控。<br>您可以點擊“<i>新建HertzBeat監控(Token)</i>”並進行配寘,或者選擇“<i>更多操作</i>”,導入已有配寘。
|
||||
helpLink:
|
||||
zh-CN: https://hertzbeat.apache.org/zh-cn/docs/help/hertzbeat_token
|
||||
en-US: https://hertzbeat.apache.org/docs/help/hertzbeat_token
|
||||
# Input params define for monitoring(render web ui by the definition)
|
||||
zh-CN: HertzBeat监控(Token)
|
||||
en-US: HertzBeat Monitor(Token)
|
||||
params:
|
||||
# field-param field key
|
||||
# field-字段名称标识符
|
||||
- field: host
|
||||
# name-param field display i18n name
|
||||
# name-参数字段显示名称
|
||||
name:
|
||||
zh-CN: 目标Host
|
||||
en-US: Target Host
|
||||
# type-param field type(most mapping the html input type)
|
||||
zh-CN: 主机Host
|
||||
en-US: Host
|
||||
# type-字段类型,样式(大部分映射input标签type属性)
|
||||
type: host
|
||||
# required-true or false
|
||||
# 是否是必输项 true-必填 false-可选
|
||||
required: true
|
||||
- field: port
|
||||
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
|
||||
# 当type为number时,用range表示范围
|
||||
range: '[0,65535]'
|
||||
required: true
|
||||
# 端口默认值
|
||||
defaultValue: 1157
|
||||
placeholder: 'Please input port'
|
||||
# 参数输入框提示信息
|
||||
placeholder: '请输入端口'
|
||||
- field: ssl
|
||||
name:
|
||||
zh-CN: 启动SSL
|
||||
en-US: SSL
|
||||
# type-param field type(boolean mapping the html switch tag)
|
||||
# 当type为boolean时,前端用switch展示开关
|
||||
type: boolean
|
||||
required: false
|
||||
- field: contentType
|
||||
@@ -103,6 +95,9 @@ params:
|
||||
type: textarea
|
||||
placeholder: 'Available When POST PUT'
|
||||
required: false
|
||||
# 采集指标配置列表 todo 下方配置
|
||||
metrics: ......
|
||||
|
||||
```
|
||||
|
||||
### 定义监控指标`auth`登录请求获取`token`
|
||||
@@ -111,49 +106,41 @@ params:
|
||||
|
||||
```yaml
|
||||
|
||||
# 监控类型所属类别:service-应用服务 program-应用程序 db-数据库 custom-自定义 os-操作系统 bigdata-大数据 mid-中间件 webserver-web服务器 cache-缓存 cn-云原生 network-网络监控等等
|
||||
category: custom
|
||||
# The monitoring type eg: linux windows tomcat mysql aws...
|
||||
# 监控应用类型(与文件名保持一致) eg: linux windows tomcat mysql aws...
|
||||
app: hertzbeat_token
|
||||
# The monitoring i18n name
|
||||
name:
|
||||
zh-CN: HertzBeat(Token)
|
||||
en-US: HertzBeat(Token)
|
||||
# The description and help of this monitoring type
|
||||
help:
|
||||
zh-CN: Hertzbeat 对 HertzBeat监控(Token)进行测量监控。<br>您可以点击 “<i>新建 HertzBeat监控(Token)</i>” 并进行配置,或者选择“<i>更多操作</i>”,导入已有配置。
|
||||
en-US: Hertzbeat monitors HertzBeat Monitor(Token). You could click the "<i>New HertzBeat Monitor(Token)</i>" button and proceed with the configuration or import an existing setup through the "<i>More Actions</i>" menu.
|
||||
zh-TW: Hertzbeat對HertzBeat監控(Token)進行量測監控。<br>您可以點擊“<i>新建HertzBeat監控(Token)</i>”並進行配寘,或者選擇“<i>更多操作</i>”,導入已有配寘。
|
||||
helpLink:
|
||||
zh-CN: https://hertzbeat.apache.org/zh-cn/docs/help/hertzbeat_token
|
||||
en-US: https://hertzbeat.apache.org/docs/help/hertzbeat_token
|
||||
# Input params define for monitoring(render web ui by the definition)
|
||||
zh-CN: HertzBeat监控(Token)
|
||||
en-US: HertzBeat Monitor(Token)
|
||||
params:
|
||||
# field-param field key
|
||||
# field-字段名称标识符
|
||||
- field: host
|
||||
# name-param field display i18n name
|
||||
# name-参数字段显示名称
|
||||
name:
|
||||
zh-CN: 目标Host
|
||||
en-US: Target Host
|
||||
# type-param field type(most mapping the html input type)
|
||||
zh-CN: 主机Host
|
||||
en-US: Host
|
||||
# type-字段类型,样式(大部分映射input标签type属性)
|
||||
type: host
|
||||
# required-true or false
|
||||
# 是否是必输项 true-必填 false-可选
|
||||
required: true
|
||||
- field: port
|
||||
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
|
||||
# 当type为number时,用range表示范围
|
||||
range: '[0,65535]'
|
||||
required: true
|
||||
# 端口默认值
|
||||
defaultValue: 1157
|
||||
placeholder: 'Please input port'
|
||||
# 参数输入框提示信息
|
||||
placeholder: '请输入端口'
|
||||
- field: ssl
|
||||
name:
|
||||
zh-CN: 启动SSL
|
||||
en-US: SSL
|
||||
# type-param field type(boolean mapping the html switch tag)
|
||||
# 当type为boolean时,前端用switch展示开关
|
||||
type: boolean
|
||||
required: false
|
||||
- field: contentType
|
||||
@@ -170,43 +157,40 @@ params:
|
||||
type: textarea
|
||||
placeholder: 'Available When POST PUT'
|
||||
required: false
|
||||
# collect metrics config list
|
||||
# 采集指标配置列表
|
||||
metrics:
|
||||
# metrics - auth
|
||||
# 第一个监控指标 auth
|
||||
# 注意:内置监控指标有 (responseTime - 响应时间)
|
||||
- name: auth
|
||||
# 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
|
||||
# 指标调度优先级(0-127)越小优先级越高,优先级低的指标会等优先级高的指标采集完成后才会被调度,相同优先级的指标会并行调度采集
|
||||
# 优先级为0的指标为可用性指标,即它会被首先调度,采集成功才会继续调度其它指标,采集失败则中断调度
|
||||
priority: 0
|
||||
# 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
|
||||
# 指标信息 包括 field名称 type字段类型:0-number数字,1-string字符串 label是否为标签 unit:指标单位
|
||||
- field: token
|
||||
type: 1
|
||||
- field: refreshToken
|
||||
type: 1
|
||||
# the protocol used for monitoring, eg: sql, ssh, http, telnet, wmi, snmp, sdk
|
||||
# 监控采集使用协议 eg: sql, ssh, http, telnet, wmi, snmp, sdk
|
||||
protocol: http
|
||||
# the config content when protocol is http
|
||||
# 当protocol为http协议时具体的采集配置
|
||||
http:
|
||||
# http host: ipv4 ipv6 domain
|
||||
# 主机host: ipv4 ipv6 域名
|
||||
host: ^_^host^_^
|
||||
# http port
|
||||
# 端口
|
||||
port: ^_^port^_^
|
||||
# http url
|
||||
# url请求接口路径
|
||||
url: /api/account/auth/form
|
||||
# http method: GET POST PUT DELETE PATCH
|
||||
# 请求方式 GET POST PUT DELETE PATCH
|
||||
method: POST
|
||||
# if enabled https
|
||||
# 是否启用ssl/tls,即是http还是https,默认false
|
||||
ssl: ^_^ssl^_^
|
||||
payload: ^_^payload^_^
|
||||
# http request header content
|
||||
# 请求头内容
|
||||
headers:
|
||||
content-type: ^_^contentType^_^
|
||||
^_^headers^_^: ^_^headers^_^
|
||||
# http request params
|
||||
params:
|
||||
^_^params^_^: ^_^params^_^
|
||||
# http response data parse type: default-hertzbeat rule, jsonpath-jsonpath script, website-for website monitoring, prometheus-prometheus exporter rule
|
||||
# 响应数据解析方式: default-系统规则,jsonPath-jsonPath脚本,website-网站可用性指标监控
|
||||
parseType: jsonPath
|
||||
parseScript: '$.data'
|
||||
|
||||
@@ -249,49 +233,41 @@ metrics:
|
||||
|
||||
```yaml
|
||||
|
||||
# 监控类型所属类别:service-应用服务 program-应用程序 db-数据库 custom-自定义 os-操作系统 bigdata-大数据 mid-中间件 webserver-web服务器 cache-缓存 cn-云原生 network-网络监控等等
|
||||
category: custom
|
||||
# The monitoring type eg: linux windows tomcat mysql aws...
|
||||
# 监控应用类型(与文件名保持一致) eg: linux windows tomcat mysql aws...
|
||||
app: hertzbeat_token
|
||||
# The monitoring i18n name
|
||||
name:
|
||||
zh-CN: HertzBeat(Token)
|
||||
en-US: HertzBeat(Token)
|
||||
# The description and help of this monitoring type
|
||||
help:
|
||||
zh-CN: Hertzbeat 对 HertzBeat监控(Token)进行测量监控。<br>您可以点击 “<i>新建 HertzBeat监控(Token)</i>” 并进行配置,或者选择“<i>更多操作</i>”,导入已有配置。
|
||||
en-US: Hertzbeat monitors HertzBeat Monitor(Token). You could click the "<i>New HertzBeat Monitor(Token)</i>" button and proceed with the configuration or import an existing setup through the "<i>More Actions</i>" menu.
|
||||
zh-TW: Hertzbeat對HertzBeat監控(Token)進行量測監控。<br>您可以點擊“<i>新建HertzBeat監控(Token)</i>”並進行配寘,或者選擇“<i>更多操作</i>”,導入已有配寘。
|
||||
helpLink:
|
||||
zh-CN: https://hertzbeat.apache.org/zh-cn/docs/help/hertzbeat_token
|
||||
en-US: https://hertzbeat.apache.org/docs/help/hertzbeat_token
|
||||
# Input params define for monitoring(render web ui by the definition)
|
||||
zh-CN: HertzBeat监控(Token)
|
||||
en-US: HertzBeat Monitor(Token)
|
||||
params:
|
||||
# field-param field key
|
||||
# field-字段名称标识符
|
||||
- field: host
|
||||
# name-param field display i18n name
|
||||
# name-参数字段显示名称
|
||||
name:
|
||||
zh-CN: 目标Host
|
||||
en-US: Target Host
|
||||
# type-param field type(most mapping the html input type)
|
||||
zh-CN: 主机Host
|
||||
en-US: Host
|
||||
# type-字段类型,样式(大部分映射input标签type属性)
|
||||
type: host
|
||||
# required-true or false
|
||||
# 是否是必输项 true-必填 false-可选
|
||||
required: true
|
||||
- field: port
|
||||
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
|
||||
# 当type为number时,用range表示范围
|
||||
range: '[0,65535]'
|
||||
required: true
|
||||
# 端口默认值
|
||||
defaultValue: 1157
|
||||
placeholder: 'Please input port'
|
||||
# 参数输入框提示信息
|
||||
placeholder: '请输入端口'
|
||||
- field: ssl
|
||||
name:
|
||||
zh-CN: 启动SSL
|
||||
en-US: SSL
|
||||
# type-param field type(boolean mapping the html switch tag)
|
||||
# 当type为boolean时,前端用switch展示开关
|
||||
type: boolean
|
||||
required: false
|
||||
- field: contentType
|
||||
@@ -308,72 +284,83 @@ params:
|
||||
type: textarea
|
||||
placeholder: 'Available When POST PUT'
|
||||
required: false
|
||||
# collect metrics config list
|
||||
# 采集指标配置列表
|
||||
metrics:
|
||||
# metrics - auth
|
||||
# 第一个监控指标 cpu
|
||||
# 注意:内置监控指标有 (responseTime - 响应时间)
|
||||
- name: auth
|
||||
# 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
|
||||
# 指标调度优先级(0-127)越小优先级越高,优先级低的指标会等优先级高的指标采集完成后才会被调度,相同优先级的指标会并行调度采集
|
||||
# 优先级为0的指标为可用性指标,即它会被首先调度,采集成功才会继续调度其它指标,采集失败则中断调度
|
||||
priority: 0
|
||||
# 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
|
||||
# 指标信息 包括 field名称 type字段类型:0-number数字,1-string字符串 label是否为标签 unit:指标单位
|
||||
- field: token
|
||||
type: 1
|
||||
- field: refreshToken
|
||||
type: 1
|
||||
# the protocol used for monitoring, eg: sql, ssh, http, telnet, wmi, snmp, sdk
|
||||
# 监控采集使用协议 eg: sql, ssh, http, telnet, wmi, snmp, sdk
|
||||
protocol: http
|
||||
# the config content when protocol is http
|
||||
# 当protocol为http协议时具体的采集配置
|
||||
http:
|
||||
# http host: ipv4 ipv6 domain
|
||||
# 主机host: ipv4 ipv6 域名
|
||||
host: ^_^host^_^
|
||||
# http port
|
||||
# 端口
|
||||
port: ^_^port^_^
|
||||
# http url
|
||||
# url请求接口路径
|
||||
url: /api/account/auth/form
|
||||
# http method: GET POST PUT DELETE PATCH
|
||||
# 请求方式 GET POST PUT DELETE PATCH
|
||||
method: POST
|
||||
# if enabled https
|
||||
# 是否启用ssl/tls,即是http还是https,默认false
|
||||
ssl: ^_^ssl^_^
|
||||
payload: ^_^payload^_^
|
||||
# http request header content
|
||||
# 请求头内容
|
||||
headers:
|
||||
content-type: ^_^contentType^_^
|
||||
^_^headers^_^: ^_^headers^_^
|
||||
# http request params
|
||||
# 请求参数内容
|
||||
params:
|
||||
^_^params^_^: ^_^params^_^
|
||||
# http response data parse type: default-hertzbeat rule, jsonpath-jsonpath script, website-for website monitoring, prometheus-prometheus exporter rule
|
||||
# 响应数据解析方式: default-系统规则,jsonPath-jsonPath脚本,website-网站可用性指标监控
|
||||
parseType: jsonPath
|
||||
parseScript: '$.data'
|
||||
|
||||
|
||||
- name: summary
|
||||
# 指标调度优先级(0-127)越小优先级越高,优先级低的指标会等优先级高的指标采集完成后才会被调度,相同优先级的指标会并行调度采集
|
||||
# 优先级为0的指标为可用性指标,即它会被首先调度,采集成功才会继续调度其它指标,采集失败则中断调度
|
||||
priority: 1
|
||||
# 具体监控指标列表
|
||||
fields:
|
||||
- field: app
|
||||
type: 1
|
||||
label: true
|
||||
# 指标信息 包括 field名称 type字段类型:0-number数字,1-string字符串 label是否为标签 unit:指标单位
|
||||
- field: category
|
||||
type: 1
|
||||
- field: status
|
||||
type: 0
|
||||
- field: app
|
||||
type: 1
|
||||
- field: size
|
||||
type: 0
|
||||
- field: availableSize
|
||||
- field: status
|
||||
type: 0
|
||||
# 监控采集使用协议 eg: sql, ssh, http, telnet, wmi, snmp, sdk
|
||||
protocol: http
|
||||
# 当protocol为http协议时具体的采集配置
|
||||
http:
|
||||
# 主机host: ipv4 ipv6 域名
|
||||
host: ^_^host^_^
|
||||
# 端口
|
||||
port: ^_^port^_^
|
||||
# url请求接口路径
|
||||
url: /api/summary
|
||||
# 请求方式 GET POST PUT DELETE PATCH
|
||||
method: GET
|
||||
# 是否启用ssl/tls,即是http还是https,默认false
|
||||
ssl: ^_^ssl^_^
|
||||
# 认证
|
||||
authorization:
|
||||
# 认证方式: Basic Auth, Digest Auth, Bearer Token
|
||||
type: Bearer Token
|
||||
# ^o^xxx^o^ ^o^ substitution represents the value of the acquisition metric xxx of the previous priority
|
||||
bearerTokenToken: ^o^token^o^
|
||||
# 响应数据解析方式: default-系统规则,jsonPath-jsonPath脚本,website-网站可用性指标监控
|
||||
parseType: jsonPath
|
||||
parseScript: '$.data.apps.*'
|
||||
|
||||
@@ -107,8 +107,9 @@ sidebar_label: JsonPath解析方式
|
||||
**对应的监控模版YML可以配置为如下**
|
||||
|
||||
```yaml
|
||||
# 监控类型所属类别:service-应用服务 program-应用程序 db-数据库 custom-自定义 os-操作系统 bigdata-大数据 mid-中间件 webserver-web服务器 cache-缓存 cn-云原生 network-网络监控等等
|
||||
category: custom
|
||||
# 监控应用类型 eg: linux windows tomcat mysql aws...
|
||||
# 监控应用类型(与文件名保持一致) eg: linux windows tomcat mysql aws...
|
||||
app: example
|
||||
name:
|
||||
zh-CN: 模拟应用类型
|
||||
@@ -0,0 +1,206 @@
|
||||
---
|
||||
id: extend-http
|
||||
title: HTTP协议自定义监控
|
||||
sidebar_label: HTTP协议自定义监控
|
||||
---
|
||||
|
||||
> 从[自定义监控](extend-point)了解熟悉了怎么自定义类型,指标,协议等,这里我们来详细介绍下用HTTP协议自定义指标监控。
|
||||
|
||||
### HTTP协议采集流程
|
||||
|
||||
【**HTTP接口调用**】->【**响应校验**】->【**响应数据解析**】->【**默认方式解析|JsonPath脚本解析 | XmlPath解析(todo) | Prometheus解析**】->【**指标数据提取**】
|
||||
|
||||
由流程可见,我们自定义一个HTTP协议的监控类型,需要配置HTTP请求参数,配置获取哪些指标,对响应数据配置解析方式和解析脚本。
|
||||
HTTP协议支持我们自定义HTTP请求路径,请求header,请求参数,请求方式,请求体等。
|
||||
|
||||
**系统默认解析方式**:http接口返回hertzbeat规定的json数据结构,即可用默认解析方式解析数据提取对应的指标数据,详细介绍见 [**系统默认解析**](extend-http-default)
|
||||
**JsonPath脚本解析方式**:用JsonPath脚本对响应的json数据进行解析,返回系统指定的数据结构,然后提供对应的指标数据,详细介绍见 [**JsonPath脚本解析**](extend-http-jsonpath)
|
||||
|
||||
### 自定义步骤
|
||||
|
||||
**HertzBeat页面** -> **监控模版菜单** -> **新增监控类型** -> **配置自定义监控模版YML** -> **点击保存应用** -> **使用新监控类型添加监控**
|
||||
|
||||

|
||||
|
||||
-------
|
||||
|
||||
下面详细介绍下监控模版YML的配置用法,请注意看使用注释。
|
||||
|
||||
### 监控模版YML
|
||||
|
||||
> 监控模版YML用于定义 *监控类型的名称(国际化), 请求参数结构定义(前端页面根据配置自动渲染UI), 采集指标信息, 采集协议配置* 等。
|
||||
> 即我们通过自定义这个监控模版,配置定义什么监控类型,前端页面需要输入什么参数,采集哪些性能指标,通过什么协议去采集。
|
||||
|
||||
样例:自定义一个名称为example_http的自定义监控类型,其使用HTTP协议采集指标数据。
|
||||
|
||||
```yaml
|
||||
# 监控类型所属类别:service-应用服务 program-应用程序 db-数据库 custom-自定义 os-操作系统 bigdata-大数据 mid-中间件 webserver-web服务器 cache-缓存 cn-云原生 network-网络监控等等
|
||||
category: custom
|
||||
# 监控应用类型(与文件名保持一致) eg: linux windows tomcat mysql aws...
|
||||
app: example_http
|
||||
name:
|
||||
zh-CN: 模拟应用类型
|
||||
en-US: EXAMPLE APP
|
||||
# 监控参数定义. field 这些为输入参数变量,即可以用^_^host^_^的形式写到后面的配置中,系统自动变量值替换
|
||||
# 强制固定必须参数 - host
|
||||
params:
|
||||
# field-字段名称标识符
|
||||
- field: host
|
||||
# name-参数字段显示名称
|
||||
name:
|
||||
zh-CN: 主机Host
|
||||
en-US: Host
|
||||
# type-字段类型,样式(大部分映射input标签type属性)
|
||||
type: host
|
||||
# 是否是必输项 true-必填 false-可选
|
||||
required: true
|
||||
- field: port
|
||||
name:
|
||||
zh-CN: 端口
|
||||
en-US: Port
|
||||
type: number
|
||||
# 当type为number时,用range表示范围
|
||||
range: '[0,65535]'
|
||||
required: true
|
||||
# 端口默认值
|
||||
defaultValue: 80
|
||||
# 参数输入框提示信息
|
||||
placeholder: '请输入端口'
|
||||
- field: username
|
||||
name:
|
||||
zh-CN: 用户名
|
||||
en-US: Username
|
||||
type: text
|
||||
# 当type为text时,用limit表示字符串限制大小
|
||||
limit: 50
|
||||
required: false
|
||||
- field: password
|
||||
name:
|
||||
zh-CN: 密码
|
||||
en-US: Password
|
||||
type: password
|
||||
required: false
|
||||
- field: ssl
|
||||
name:
|
||||
zh-CN: 启动SSL
|
||||
en-US: Enable SSL
|
||||
# 当type为boolean时,前端用switch展示开关
|
||||
type: boolean
|
||||
required: false
|
||||
- field: method
|
||||
name:
|
||||
zh-CN: 请求方式
|
||||
en-US: Method
|
||||
type: radio
|
||||
required: true
|
||||
# 当type为radio单选框,checkbox复选框时,option表示可选项值列表 {name1:value1,name2:value2}
|
||||
options:
|
||||
- label: GET请求
|
||||
value: GET
|
||||
- label: POST请求
|
||||
value: POST
|
||||
- label: PUT请求
|
||||
value: PUT
|
||||
- label: DELETE请求
|
||||
value: DELETE
|
||||
# 采集指标配置列表
|
||||
metrics:
|
||||
# 第一个监控指标 cpu
|
||||
# 注意:内置监控指标有 (responseTime - 响应时间)
|
||||
- name: cpu
|
||||
# 指标调度优先级(0-127)越小优先级越高,优先级低的指标会等优先级高的指标采集完成后才会被调度,相同优先级的指标会并行调度采集
|
||||
# 优先级为0的指标为可用性指标,即它会被首先调度,采集成功才会继续调度其它指标,采集失败则中断调度
|
||||
priority: 0
|
||||
# 具体监控指标列表
|
||||
fields:
|
||||
# 指标信息 包括 field名称 type字段类型:0-number数字,1-string字符串 label是否为标签 unit:指标单位
|
||||
- field: hostname
|
||||
type: 1
|
||||
label: true
|
||||
- field: usage
|
||||
type: 0
|
||||
unit: '%'
|
||||
- field: cores
|
||||
type: 0
|
||||
- field: waitTime
|
||||
type: 0
|
||||
unit: s
|
||||
# (非必须)监控指标别名,与上面的指标名映射。用于采集接口数据字段不直接是最终指标名称,需要此别名做映射转换
|
||||
aliasFields:
|
||||
- hostname
|
||||
- core1
|
||||
- core2
|
||||
- usage
|
||||
- allTime
|
||||
- runningTime
|
||||
# (非必须)指标计算表达式,与上面的别名一起作用,计算出最终需要的指标值
|
||||
# eg: cores=core1+core2, usage=usage, waitTime=allTime-runningTime
|
||||
calculates:
|
||||
- hostname=hostname
|
||||
- cores=core1+core2
|
||||
- usage=usage
|
||||
- waitTime=allTime-runningTime
|
||||
# 监控采集使用协议 eg: sql, ssh, http, telnet, wmi, snmp, sdk
|
||||
protocol: http
|
||||
# 当protocol为http协议时具体的采集配置
|
||||
http:
|
||||
# 主机host: ipv4 ipv6 域名
|
||||
host: ^_^host^_^
|
||||
# 端口
|
||||
port: ^_^port^_^
|
||||
# url请求接口路径
|
||||
url: /metrics/cpu
|
||||
# 请求方式 GET POST PUT DELETE PATCH
|
||||
method: GET
|
||||
# 是否启用ssl/tls,即是http还是https,默认false
|
||||
ssl: false
|
||||
# 请求头内容
|
||||
headers:
|
||||
apiVersion: v1
|
||||
# 请求参数内容
|
||||
params:
|
||||
param1: param1
|
||||
param2: param2
|
||||
# 认证
|
||||
authorization:
|
||||
# 认证方式: Basic Auth, Digest Auth, Bearer Token
|
||||
type: Basic Auth
|
||||
basicAuthUsername: ^_^username^_^
|
||||
basicAuthPassword: ^_^password^_^
|
||||
# 响应数据解析方式: default-系统规则,jsonPath-jsonPath脚本,website-网站可用性指标监控
|
||||
# todo xmlPath-xmlPath脚本,prometheus-Prometheus数据规则
|
||||
parseType: jsonPath
|
||||
parseScript: '$'
|
||||
|
||||
- name: memory
|
||||
priority: 1
|
||||
fields:
|
||||
- field: hostname
|
||||
type: 1
|
||||
label: true
|
||||
- field: total
|
||||
type: 0
|
||||
unit: kb
|
||||
- field: usage
|
||||
type: 0
|
||||
unit: '%'
|
||||
- field: speed
|
||||
type: 0
|
||||
protocol: http
|
||||
http:
|
||||
host: ^_^host^_^
|
||||
port: ^_^port^_^
|
||||
url: /metrics/memory
|
||||
method: GET
|
||||
headers:
|
||||
apiVersion: v1
|
||||
# 查询参数,支持使用时间表达式
|
||||
params:
|
||||
param1: param1
|
||||
param2: param2
|
||||
authorization:
|
||||
type: Basic Auth
|
||||
basicAuthUsername: ^_^username^_^
|
||||
basicAuthPassword: ^_^password^_^
|
||||
parseType: default
|
||||
```
|
||||
@@ -155,7 +155,7 @@ metrics:
|
||||
# 具体监控指标列表
|
||||
fields:
|
||||
# field-metric name, type-metric type(0-number,1-string), unit-metric unit('%','ms','MB'), label-if is metrics label
|
||||
# field-指标名称, type-指标类型(0-number数字,1-string字符串), unit-指标单位('%','ms','MB'), label-是否是指标集合唯一标识符字段
|
||||
# field-指标名称, type-指标类型(0-number数字,1-string字符串), unit-指标单位('%','ms','MB'), instance-是否是指标集合唯一标识符字段
|
||||
- field: VmName
|
||||
type: 1
|
||||
- field: VmVendor
|
||||
@@ -13,10 +13,6 @@ sidebar_label: 自定义监控
|
||||
|
||||

|
||||
|
||||
### 自定义监控指标刷新时间
|
||||
|
||||
现在,HertzBeat支持为每组监控指标设置不同的刷新时间。您可以在监控模板的 `metrics` 部分通过设置 `interval` 字段来实现,单位为秒。若不进行设置,则使用创建监控时设置的默认刷新时间。
|
||||
|
||||
-------
|
||||
|
||||
### 监控模版YML
|
||||
@@ -43,14 +39,6 @@ app: example2
|
||||
name:
|
||||
zh-CN: 模拟网站监测
|
||||
en-US: EXAMPLE WEBSITE
|
||||
# The description and help of this monitoring type
|
||||
help:
|
||||
zh-CN: HertzBeat 支持自定义监控,您只需配置监控模版 YML 就能适配一款自定义的监控类型。<br>定义流程如下:HertzBeat 页面 -> 监控模版菜单 -> 新增监控类型 -> 配置自定义监控模版YML -> 点击保存应用 -> 使用新监控类型添加监控。
|
||||
en-US: "HertzBeat supports custom monitoring, and you only need to configure the monitoring template YML to adapt to a custom monitoring type. <br>Definition process as follow: HertzBeat Pages -> Main Menu -> Monitor Template -> edit and save -> apply this template."
|
||||
zh-TW: HertzBeat支持自定義監控,您只需配寘監控模版YML就能適配一款自定義的監控類型。<br>定義流程如下:HertzBeat頁面->監控模版選單->新增監控類型->配寘自定義監控模版YML ->點擊保存應用->使用新監控類型添加監控。
|
||||
helpLink:
|
||||
zh-CN: https://hertzbeat.apache.org/zh-cn/docs/advanced/extend-point/
|
||||
en-US: https://hertzbeat.apache.org/docs/advanced/extend-point/
|
||||
# 监控所需输入参数定义(根据定义渲染页面UI)
|
||||
# Input params define for monitoring(render web ui by the definition)
|
||||
params:
|
||||
@@ -150,14 +138,11 @@ metrics:
|
||||
# 指标采集调度优先级(0->127)->(优先级高->低) 优先级低的指标会等优先级高的指标采集完成后才会被调度, 相同优先级的指标会并行调度采集
|
||||
# 优先级为0的指标为可用性指标,即它会被首先调度,采集成功才会继续调度其它指标,采集失败则中断调度
|
||||
priority: 0
|
||||
# refresh interval for this metrics group
|
||||
# 该指标组刷新时间
|
||||
interval: 10
|
||||
# collect metrics content
|
||||
# 具体监控指标列表
|
||||
fields:
|
||||
# field-metric name, type-metric type(0-number,1-string), unit-metric unit('%','ms','MB'), label-if is metrics label
|
||||
# field-指标名称, type-指标类型(0-number数字,1-string字符串), unit-指标单位('%','ms','MB'), label-是否是指标集合唯一标识符字段
|
||||
# field-指标名称, type-指标类型(0-number数字,1-string字符串), unit-指标单位('%','ms','MB'), instance-是否是指标集合唯一标识符字段
|
||||
- field: responseTime
|
||||
type: 0
|
||||
unit: ms
|
||||