mirror of
https://github.com/dromara/hertzbeat.git
synced 2026-09-17 18:19:02 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c98843efb |
@@ -2298,33 +2298,6 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "yasminvo",
|
||||
"name": "yasminvo",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/107528848?v=4",
|
||||
"profile": "https://github.com/yasminvo",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "notbugggg",
|
||||
"name": "不关银渐层的事哦",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/147966331?v=4",
|
||||
"profile": "https://github.com/notbugggg",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "yyahang",
|
||||
"name": "yyahang",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/90464876?v=4",
|
||||
"profile": "https://github.com/yyahang",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
[](https://discord.gg/Fb6M73htGr)
|
||||
[](https://www.reddit.com/r/hertzbeat/)
|
||||
[](https://x.com/hertzbeat1024)
|
||||
[](https://twitter.com/hertzbeat1024)
|
||||
[](https://www.bestpractices.dev/projects/8139)
|
||||
[](https://app.codecov.io/gh/apache/hertzbeat)
|
||||
[](https://hub.docker.com/r/apache/hertzbeat)
|
||||
@@ -507,9 +507,6 @@ Thanks to these wonderful people, welcome to join us:
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/myangle1120"><img src="https://avatars.githubusercontent.com/u/19237013?v=4?s=100" width="100px;" alt="myangle1120"/><br /><sub><b>myangle1120</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=myangle1120" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yasminvo"><img src="https://avatars.githubusercontent.com/u/107528848?v=4?s=100" width="100px;" alt="yasminvo"/><br /><sub><b>yasminvo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yasminvo" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/notbugggg"><img src="https://avatars.githubusercontent.com/u/147966331?v=4?s=100" width="100px;" alt="不关银渐层的事哦"/><br /><sub><b>不关银渐层的事哦</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=notbugggg" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yyahang"><img src="https://avatars.githubusercontent.com/u/90464876?v=4?s=100" width="100px;" alt="yyahang"/><br /><sub><b>yyahang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yyahang" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -537,7 +534,7 @@ WeChat Public : Search ID `usthecom`.
|
||||
|
||||
[Reddit Community](https://www.reddit.com/r/hertzbeat/)
|
||||
|
||||
[Follow Us Twitter](https://x.com/hertzbeat1024)
|
||||
[Follow Us Twitter](https://twitter.com/hertzbeat1024)
|
||||
|
||||
[Subscribe YouTube](https://www.youtube.com/channel/UCri75zfWX0GHqJFPENEbLow)
|
||||
|
||||
|
||||
+2
-5
@@ -12,7 +12,7 @@
|
||||
|
||||
[](https://discord.gg/Fb6M73htGr)
|
||||
[](https://www.reddit.com/r/hertzbeat/)
|
||||
[](https://x.com/hertzbeat1024)
|
||||
[](https://twitter.com/hertzbeat1024)
|
||||
[](https://www.bestpractices.dev/projects/8139)
|
||||
[](https://app.codecov.io/gh/apache/hertzbeat)
|
||||
[](https://hub.docker.com/r/apache/hertzbeat)
|
||||
@@ -506,9 +506,6 @@ Thanks these wonderful people, welcome to join us:
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/myangle1120"><img src="https://avatars.githubusercontent.com/u/19237013?v=4?s=100" width="100px;" alt="myangle1120"/><br /><sub><b>myangle1120</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=myangle1120" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yasminvo"><img src="https://avatars.githubusercontent.com/u/107528848?v=4?s=100" width="100px;" alt="yasminvo"/><br /><sub><b>yasminvo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yasminvo" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/notbugggg"><img src="https://avatars.githubusercontent.com/u/147966331?v=4?s=100" width="100px;" alt="不关银渐层的事哦"/><br /><sub><b>不关银渐层的事哦</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=notbugggg" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yyahang"><img src="https://avatars.githubusercontent.com/u/90464876?v=4?s=100" width="100px;" alt="yyahang"/><br /><sub><b>yyahang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yyahang" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -536,7 +533,7 @@ Thanks these wonderful people, welcome to join us:
|
||||
|
||||
[Reddit Community](https://www.reddit.com/r/hertzbeat/)
|
||||
|
||||
[Follow Us Twitter](https://x.com/hertzbeat1024)
|
||||
[Follow Us Twitter](https://twitter.com/hertzbeat1024)
|
||||
|
||||
[Subscribe YouTube](https://www.youtube.com/channel/UCri75zfWX0GHqJFPENEbLow)
|
||||
|
||||
|
||||
+2
-9
@@ -19,7 +19,6 @@
|
||||
|
||||
package org.apache.hertzbeat.alert.config;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
@@ -31,7 +30,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
/**
|
||||
* SSE manager for alert
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class AlertSseManager {
|
||||
private final Map<Long, SseEmitter> emitters = new ConcurrentHashMap<>();
|
||||
@@ -40,7 +38,6 @@ public class AlertSseManager {
|
||||
SseEmitter emitter = new SseEmitter(Long.MAX_VALUE);
|
||||
emitter.onCompletion(() -> removeEmitter(clientId));
|
||||
emitter.onTimeout(() -> removeEmitter(clientId));
|
||||
emitter.onError((ex) -> removeEmitter(clientId));
|
||||
emitters.put(clientId, emitter);
|
||||
return emitter;
|
||||
}
|
||||
@@ -53,11 +50,7 @@ public class AlertSseManager {
|
||||
.id(String.valueOf(System.currentTimeMillis()))
|
||||
.name("ALERT_EVENT")
|
||||
.data(data));
|
||||
} catch (IOException | IllegalStateException e) {
|
||||
emitter.complete();
|
||||
removeEmitter(clientId);
|
||||
} catch (Exception exception) {
|
||||
log.error("Failed to broadcast alert data to client: {}", exception.getMessage());
|
||||
} catch (IOException e) {
|
||||
emitter.complete();
|
||||
removeEmitter(clientId);
|
||||
}
|
||||
@@ -67,4 +60,4 @@ public class AlertSseManager {
|
||||
private void removeEmitter(Long clientId) {
|
||||
emitters.remove(clientId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,8 +54,4 @@ public class SmsConfig {
|
||||
*/
|
||||
private UniSmsProperties unisms;
|
||||
|
||||
/**
|
||||
* Smslocal SMS configuration
|
||||
*/
|
||||
private SmslocalSmsProperties smslocal;
|
||||
}
|
||||
-33
@@ -1,33 +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.config;
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Smslocal SMS Properties
|
||||
*/
|
||||
@Data
|
||||
public class SmslocalSmsProperties {
|
||||
/**
|
||||
* SmsLocal account api key
|
||||
*/
|
||||
private String apiKey;
|
||||
|
||||
}
|
||||
+3
-6
@@ -20,7 +20,6 @@ package org.apache.hertzbeat.alert.service;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.alert.config.SmsConfig;
|
||||
import org.apache.hertzbeat.alert.service.impl.SmsLocalSmsClientImpl;
|
||||
import org.apache.hertzbeat.alert.service.impl.TencentSmsClientImpl;
|
||||
import org.apache.hertzbeat.alert.service.impl.UniSmsClientImpl;
|
||||
import org.apache.hertzbeat.alert.service.impl.AlibabaSmsClientImpl;
|
||||
@@ -34,7 +33,6 @@ import org.springframework.stereotype.Component;
|
||||
import static org.apache.hertzbeat.common.constants.SmsConstants.ALIBABA;
|
||||
import static org.apache.hertzbeat.common.constants.SmsConstants.TENCENT;
|
||||
import static org.apache.hertzbeat.common.constants.SmsConstants.UNISMS;
|
||||
import static org.apache.hertzbeat.common.constants.SmsConstants.SMSLOCAL;
|
||||
|
||||
/**
|
||||
* SMS client factory
|
||||
@@ -51,7 +49,9 @@ public class SmsClientFactory {
|
||||
|
||||
private volatile SmsClient currentSmsClient;
|
||||
|
||||
public SmsClientFactory(GeneralConfigDao generalConfigDao, ObjectMapper objectMapper, SmsConfig yamlSmsConfig) {
|
||||
public SmsClientFactory(GeneralConfigDao generalConfigDao,
|
||||
ObjectMapper objectMapper,
|
||||
SmsConfig yamlSmsConfig) {
|
||||
this.generalConfigDao = generalConfigDao;
|
||||
this.objectMapper = objectMapper;
|
||||
this.yamlSmsConfig = yamlSmsConfig;
|
||||
@@ -133,9 +133,6 @@ public class SmsClientFactory {
|
||||
case ALIBABA:
|
||||
currentSmsClient = new AlibabaSmsClientImpl(smsConfig.getAlibaba());
|
||||
break;
|
||||
case SMSLOCAL:
|
||||
currentSmsClient = new SmsLocalSmsClientImpl(smsConfig.getSmslocal());
|
||||
break;
|
||||
default:
|
||||
log.warn("[SmsClientFactory] Unsupported SMS provider type: {}", smsConfig.getType());
|
||||
break;
|
||||
|
||||
-146
@@ -1,146 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.alert.service.impl;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.alert.config.SmslocalSmsProperties;
|
||||
import org.apache.hertzbeat.alert.service.SmsClient;
|
||||
import org.apache.hertzbeat.common.constants.SmsConstants;
|
||||
import org.apache.hertzbeat.common.entity.alerter.GroupAlert;
|
||||
import org.apache.hertzbeat.common.entity.alerter.NoticeReceiver;
|
||||
import org.apache.hertzbeat.common.entity.alerter.NoticeTemplate;
|
||||
import org.apache.hertzbeat.common.support.exception.SendMessageException;
|
||||
import org.apache.hertzbeat.common.util.JsonUtil;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Smslocal SMS Client Implement
|
||||
*/
|
||||
@Slf4j
|
||||
public class SmsLocalSmsClientImpl implements SmsClient {
|
||||
private static final String HOST = "secure.smslocal.com";
|
||||
|
||||
private static final String PATH = "/api/service/enterprise-service/external/sms";
|
||||
|
||||
private static final String FROM = "Hertzbeat";
|
||||
|
||||
private static final String SUCCESS_CODE = "200";
|
||||
|
||||
private final SmslocalSmsProperties config;
|
||||
|
||||
public SmsLocalSmsClientImpl(SmslocalSmsProperties smslocalSmsProperties) {
|
||||
this.config = smslocalSmsProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(NoticeReceiver receiver, NoticeTemplate noticeTemplate, GroupAlert alert) {
|
||||
if (Objects.isNull(receiver) || Objects.isNull(alert)) {
|
||||
log.warn("receiver and alert can not be null! receiver: {}, alert:{}", receiver, alert);
|
||||
return;
|
||||
}
|
||||
|
||||
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
|
||||
String content = alert.getCommonAnnotations().get("summary");
|
||||
if (Objects.isNull(content) || Objects.isNull(alert.getCommonAnnotations().get("description"))) {
|
||||
content = alert.getAlerts().get(0).getContent();
|
||||
}
|
||||
SmsMessage smsMessage = new SmsMessage(FROM, receiver.getPhone(), content);
|
||||
|
||||
String payload = JsonUtil.toJson(smsMessage);
|
||||
|
||||
HttpPost httpPost = new HttpPost("https://" + HOST + PATH);
|
||||
httpPost.setHeader("Content-Type", "application/json; charset=utf-8");
|
||||
httpPost.setHeader("Token", config.getApiKey());
|
||||
httpPost.setEntity(new StringEntity(payload, StandardCharsets.UTF_8));
|
||||
|
||||
log.debug("Sending SMS request to {}, payload: {}", httpPost.getURI(), payload);
|
||||
|
||||
// send http request and handle response
|
||||
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
String responseBody = EntityUtils.toString(response.getEntity());
|
||||
|
||||
log.debug("SMS response status: {}, body: {}", statusCode, responseBody);
|
||||
|
||||
if (statusCode != 200) {
|
||||
throw new SendMessageException("HTTP request failed with status code: " + statusCode);
|
||||
}
|
||||
|
||||
JsonNode jsonResponse = JsonUtil.fromJson(responseBody);
|
||||
JsonNode jsonNode = jsonResponse.get(0);
|
||||
if (Objects.isNull(jsonNode)) {
|
||||
log.warn("jsonResponse parse errorCode failed: {}", jsonResponse);
|
||||
return;
|
||||
}
|
||||
String errorCode = jsonNode.get("errorCode").asText();
|
||||
if (!SUCCESS_CODE.equals(errorCode)) {
|
||||
String msgid = jsonNode.get("id").asText();
|
||||
throw new SendMessageException(errorCode + ":" + msgid);
|
||||
}
|
||||
|
||||
log.info("Successfully sent SMS to phone: {}", receiver.getPhone());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to send SMS: {}", e.getMessage());
|
||||
throw new SendMessageException(e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return SmsConstants.SMSLOCAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkConfig() {
|
||||
if (Objects.isNull(config) || Objects.isNull(config.getApiKey()) || config.getApiKey().isBlank()) {
|
||||
log.warn("smslocal properties can not be null: {}", config);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private static class SmsMessage {
|
||||
String from;
|
||||
String to;
|
||||
String content;
|
||||
final int datacoding = 0;
|
||||
final String direction = "mt";
|
||||
|
||||
public SmsMessage(String from, String to, String content) {
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.content = content;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+27
-41
@@ -88,7 +88,6 @@ public class JdbcCommonCollect extends AbstractCollect {
|
||||
SshTunnel sshTunnel = jdbcProtocol.getSshTunnel();
|
||||
|
||||
int timeout = CollectUtil.getTimeout(jdbcProtocol.getTimeout());
|
||||
boolean reuseConnection = Boolean.parseBoolean(jdbcProtocol.getReuseConnection());
|
||||
Statement statement = null;
|
||||
String databaseUrl;
|
||||
try {
|
||||
@@ -100,7 +99,7 @@ public class JdbcCommonCollect extends AbstractCollect {
|
||||
}
|
||||
|
||||
statement = getConnection(jdbcProtocol.getUsername(),
|
||||
jdbcProtocol.getPassword(), databaseUrl, timeout, reuseConnection);
|
||||
jdbcProtocol.getPassword(), databaseUrl, timeout);
|
||||
switch (jdbcProtocol.getQueryType()) {
|
||||
case QUERY_TYPE_ONE_ROW -> queryOneRow(statement, jdbcProtocol.getSql(), metrics.getAliasFields(), builder, startTime);
|
||||
case QUERY_TYPE_MULTI_ROW -> queryMultiRow(statement, jdbcProtocol.getSql(), metrics.getAliasFields(), builder, startTime);
|
||||
@@ -143,20 +142,11 @@ public class JdbcCommonCollect extends AbstractCollect {
|
||||
builder.setMsg("Query Error: " + errorMessage);
|
||||
} finally {
|
||||
if (statement != null) {
|
||||
Connection connection = null;
|
||||
try {
|
||||
connection = statement.getConnection();
|
||||
statement.close();
|
||||
} catch (Exception e) {
|
||||
log.error("Jdbc close statement error: {}", e.getMessage());
|
||||
}
|
||||
try {
|
||||
if (!reuseConnection && connection != null) {
|
||||
connection.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Jdbc close connection error: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,40 +157,38 @@ public class JdbcCommonCollect extends AbstractCollect {
|
||||
}
|
||||
|
||||
|
||||
private Statement getConnection(String username, String password, String url, Integer timeout, boolean reuseConnection) throws Exception {
|
||||
private Statement getConnection(String username, String password, String url, Integer timeout) throws Exception {
|
||||
CacheIdentifier identifier = CacheIdentifier.builder()
|
||||
.ip(url)
|
||||
.username(username).password(password).build();
|
||||
Optional<AbstractConnection<?>> cacheOption = connectionCommonCache.getCache(identifier, true);
|
||||
Statement statement = null;
|
||||
if (reuseConnection) {
|
||||
Optional<AbstractConnection<?>> cacheOption = connectionCommonCache.getCache(identifier, true);
|
||||
if (cacheOption.isPresent()) {
|
||||
JdbcConnect jdbcConnect = (JdbcConnect) cacheOption.get();
|
||||
if (cacheOption.isPresent()) {
|
||||
JdbcConnect jdbcConnect = (JdbcConnect) cacheOption.get();
|
||||
try {
|
||||
statement = jdbcConnect.getConnection().createStatement();
|
||||
// set query timeout
|
||||
int timeoutSecond = timeout / 1000;
|
||||
timeoutSecond = timeoutSecond <= 0 ? 1 : timeoutSecond;
|
||||
statement.setQueryTimeout(timeoutSecond);
|
||||
// set query max row number
|
||||
statement.setMaxRows(1000);
|
||||
} catch (Exception e) {
|
||||
log.info("The jdbc connect from cache, create statement error: {}", e.getMessage());
|
||||
try {
|
||||
statement = jdbcConnect.getConnection().createStatement();
|
||||
// set query timeout
|
||||
int timeoutSecond = timeout / 1000;
|
||||
timeoutSecond = timeoutSecond <= 0 ? 1 : timeoutSecond;
|
||||
statement.setQueryTimeout(timeoutSecond);
|
||||
// set query max row number
|
||||
statement.setMaxRows(1000);
|
||||
} catch (Exception e) {
|
||||
log.info("The jdbc connect from cache, create statement error: {}", e.getMessage());
|
||||
try {
|
||||
if (statement != null) {
|
||||
statement.close();
|
||||
}
|
||||
jdbcConnect.close();
|
||||
} catch (Exception e2) {
|
||||
log.error(e2.getMessage());
|
||||
if (statement != null) {
|
||||
statement.close();
|
||||
}
|
||||
statement = null;
|
||||
connectionCommonCache.removeCache(identifier);
|
||||
jdbcConnect.close();
|
||||
} catch (Exception e2) {
|
||||
log.error(e2.getMessage());
|
||||
}
|
||||
statement = null;
|
||||
connectionCommonCache.removeCache(identifier);
|
||||
}
|
||||
if (statement != null) {
|
||||
return statement;
|
||||
}
|
||||
}
|
||||
if (statement != null) {
|
||||
return statement;
|
||||
}
|
||||
// renew connection when failed
|
||||
Connection connection = DriverManager.getConnection(url, username, password);
|
||||
@@ -210,10 +198,8 @@ public class JdbcCommonCollect extends AbstractCollect {
|
||||
timeoutSecond = timeoutSecond <= 0 ? 1 : timeoutSecond;
|
||||
statement.setQueryTimeout(timeoutSecond);
|
||||
statement.setMaxRows(1000);
|
||||
if (reuseConnection) {
|
||||
JdbcConnect jdbcConnect = new JdbcConnect(connection);
|
||||
connectionCommonCache.addCache(identifier, jdbcConnect);
|
||||
}
|
||||
JdbcConnect jdbcConnect = new JdbcConnect(connection);
|
||||
connectionCommonCache.addCache(identifier, jdbcConnect);
|
||||
return statement;
|
||||
}
|
||||
|
||||
|
||||
-67
@@ -84,8 +84,6 @@ public class SnmpCollectImpl extends AbstractCollect {
|
||||
+ "{1,choice,0#|1#1 hour, |1<{1,number,integer} hours, }"
|
||||
+ "{2,choice,0#|1#1 minute, |1<{2,number,integer} minutes, }"
|
||||
+ "{3,choice,0#|1#1 second, |1<{3,number,integer} seconds }";
|
||||
private static final String DATE_AND_TIME_PATTERN = "%04d-%02d-%02d,%02d:%02d:%02d.%d";
|
||||
private static final String TIME_ZONE_PATTERN = "%c%02d:%02d";
|
||||
|
||||
private final Map<Integer, Snmp> versionSnmpService = new ConcurrentHashMap<>(3);
|
||||
|
||||
@@ -307,9 +305,6 @@ public class SnmpCollectImpl extends AbstractCollect {
|
||||
CharBuffer res = decoder.decode(ByteBuffer.wrap(bytes));
|
||||
return res.toString();
|
||||
} catch (Exception e) {
|
||||
if (isDateAndTimeOctetString(binding)) {
|
||||
return parseDateAndTime(clearHexStr);
|
||||
}
|
||||
return new String(bytes);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@@ -320,68 +315,6 @@ public class SnmpCollectImpl extends AbstractCollect {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isDateAndTimeOctetString(VariableBinding binding) {
|
||||
if (!(binding.getVariable() instanceof OctetString)) {
|
||||
return false;
|
||||
}
|
||||
byte[] bytes = HexFormat.of().parseHex(binding.toValueString().replaceAll(HEX_SPLIT, ""));
|
||||
if (bytes.length != 8 && bytes.length != 11) return false;
|
||||
|
||||
int year = ((bytes[0] & 0xFF) << 8) | (bytes[1] & 0xFF);
|
||||
if (year < 1970 || year > 3000) return false;
|
||||
|
||||
int month = bytes[2] & 0xFF;
|
||||
if (month < 1 || month > 12) return false;
|
||||
|
||||
int day = bytes[3] & 0xFF;
|
||||
if (day < 1 || day > 31) return false;
|
||||
|
||||
int hour = bytes[4] & 0xFF;
|
||||
if (hour > 23) return false;
|
||||
|
||||
int minute = bytes[5] & 0xFF;
|
||||
if (minute > 59) return false;
|
||||
|
||||
int second = bytes[6] & 0xFF;
|
||||
if (second > 59) return false;
|
||||
|
||||
int deciSecond = bytes[7] & 0xFF;
|
||||
if (deciSecond > 99) return false;
|
||||
|
||||
if (bytes.length == 11) {
|
||||
int tzSign = bytes[8] & 0xFF;
|
||||
if (tzSign != 0x2B && tzSign != 0x2D) return false;
|
||||
|
||||
int tzHour = bytes[9] & 0xFF;
|
||||
if (tzHour > 23) return false;
|
||||
|
||||
int tzMinute = bytes[10] & 0xFF;
|
||||
if (tzMinute > 59) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static String parseDateAndTime(String hexString) {
|
||||
byte[] bytes = HexFormat.of().parseHex(hexString);
|
||||
int year = ((bytes[0] & 0xFF) << 8) | (bytes[1] & 0xFF);
|
||||
int month = bytes[2] & 0xFF;
|
||||
int day = bytes[3] & 0xFF;
|
||||
int hour = bytes[4] & 0xFF;
|
||||
int minute = bytes[5] & 0xFF;
|
||||
int second = bytes[6] & 0xFF;
|
||||
int deciSeconds = bytes[7] & 0xFF;
|
||||
String dateTime = String.format(DATE_AND_TIME_PATTERN,
|
||||
year, month, day, hour, minute, second, deciSeconds);
|
||||
if (bytes.length == 11) {
|
||||
char sign = (char) bytes[8];
|
||||
int tzHour = bytes[9] & 0xFF;
|
||||
int tzMinute = bytes[10] & 0xFF;
|
||||
dateTime += String.format(" " + TIME_ZONE_PATTERN, sign, tzHour, tzMinute);
|
||||
}
|
||||
return dateTime;
|
||||
}
|
||||
|
||||
|
||||
private void snmpClose(Snmp snmp, int version) throws IOException {
|
||||
snmp.close();
|
||||
versionSnmpService.remove(version);
|
||||
|
||||
-2
@@ -267,8 +267,6 @@ public class KafkaCollectImpl extends AbstractCollect {
|
||||
break;
|
||||
}
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
builder.setCode(CollectRep.Code.FAIL);
|
||||
builder.setMsg("Kafka collect error: " + e.getMessage());
|
||||
log.error("Kafka collect error", e);
|
||||
}
|
||||
}
|
||||
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.common.constants;
|
||||
|
||||
/**
|
||||
* Import/Export task constants
|
||||
*/
|
||||
|
||||
public interface ImExportTaskConstant {
|
||||
|
||||
/**
|
||||
* If the number of tasks exceeds 100, progress information will broadcast
|
||||
*/
|
||||
Integer IMPORT_TASK_PROCESS_THRESHOLD = 100;
|
||||
}
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.common.constants;
|
||||
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* Import/Export task status
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
@ToString
|
||||
public enum ImportTaskStatusEnum {
|
||||
|
||||
/**
|
||||
* In progress
|
||||
*/
|
||||
IN_PROGRESS("IN_PROGRESS"),
|
||||
|
||||
/**
|
||||
* Completed
|
||||
*/
|
||||
COMPLETED("COMPLETED"),
|
||||
|
||||
/**
|
||||
* Failed
|
||||
*/
|
||||
FAILED("FAILED");
|
||||
|
||||
private final String value;
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.common.constants;
|
||||
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* Manager Event Type Enum
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
@ToString
|
||||
public enum ManagerEventTypeEnum {
|
||||
|
||||
/**
|
||||
* IMPORT_TASK_EVENT
|
||||
*/
|
||||
IMPORT_TASK_EVENT("IMPORT_TASK_EVENT");
|
||||
|
||||
private final String value;
|
||||
}
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.common.constants;
|
||||
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* Notify Level Enum
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
@ToString
|
||||
public enum NotifyLevelEnum {
|
||||
|
||||
SUCCESS("SUCCESS"),
|
||||
ERROR("ERROR"),
|
||||
INFO("INFO"),
|
||||
WARNING("WARNING"),
|
||||
BLANK("BLANK");
|
||||
|
||||
private final String value;
|
||||
}
|
||||
+2
-5
@@ -23,13 +23,10 @@ package org.apache.hertzbeat.common.constants;
|
||||
public interface SmsConstants {
|
||||
// Tencent cloud SMS
|
||||
String TENCENT = "tencent";
|
||||
|
||||
|
||||
// Alibaba Cloud SMS
|
||||
String ALIBABA = "alibaba";
|
||||
|
||||
|
||||
// UniSMS
|
||||
String UNISMS = "unisms";
|
||||
|
||||
// Smslocal SMS
|
||||
String SMSLOCAL = "smslocal";
|
||||
}
|
||||
|
||||
-1
@@ -63,7 +63,6 @@ public class GroupAlert {
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "Group Key", example = "HighCPUUsage{alertname=\"HighCPUUsage\", instance=\"server1\"}")
|
||||
@Column(length = 2048)
|
||||
private String groupKey;
|
||||
|
||||
@Schema(title = "Status", example = "resolved")
|
||||
|
||||
+2
-4
@@ -59,9 +59,8 @@ public class SingleAlert {
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Schema(title = "Threshold Id", example = "87584674384", accessMode = READ_ONLY)
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "Fingerprint", example = "alertname:demo")
|
||||
@Column(length = 2048)
|
||||
|
||||
@Schema(title = "Fingerprint", example = "dxsdfdsf")
|
||||
private String fingerprint;
|
||||
|
||||
@Schema(title = "Labels", example = "{\"alertname\": \"HighCPUUsage\", \"priority\": \"critical\", \"instance\": \"343483943\"}")
|
||||
@@ -75,7 +74,6 @@ public class SingleAlert {
|
||||
private Map<String, String> annotations;
|
||||
|
||||
@Schema(title = "Content", example = "CPU usage is above 80% for the last 5 minutes on instance server1.example.com.")
|
||||
@Column(length = 4096)
|
||||
private String content;
|
||||
|
||||
@Schema(title = "Status", example = "firing|resolved")
|
||||
|
||||
-79
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.common.entity.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.apache.hertzbeat.common.constants.ImportTaskStatusEnum;
|
||||
import org.apache.hertzbeat.common.constants.ManagerEventTypeEnum;
|
||||
import org.apache.hertzbeat.common.constants.NotifyLevelEnum;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Import task message
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class ImportTaskMessage extends ManagerMessage {
|
||||
|
||||
/**
|
||||
* Task name
|
||||
*/
|
||||
@NotNull
|
||||
private String taskName;
|
||||
|
||||
/**
|
||||
* Progress, expressed as a percentage
|
||||
*/
|
||||
@Nullable
|
||||
private Integer progress;
|
||||
|
||||
/**
|
||||
* Task Status,
|
||||
* @see ImportTaskStatusEnum
|
||||
*/
|
||||
@NotNull
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* If Fail, the error message
|
||||
*/
|
||||
@Nullable
|
||||
private String errMsg;
|
||||
|
||||
public ImportTaskMessage(String notifyLevel, String managerEventType, String taskName, @Nullable Integer progress, String status, @Nullable String errMsg){
|
||||
super(notifyLevel, managerEventType);
|
||||
this.taskName = taskName;
|
||||
this.progress = progress;
|
||||
this.status = status;
|
||||
this.errMsg = errMsg;
|
||||
}
|
||||
|
||||
public static ManagerMessage createInProgressMessage(String taskName, Integer process){
|
||||
return new ImportTaskMessage(NotifyLevelEnum.INFO.getValue(), ManagerEventTypeEnum.IMPORT_TASK_EVENT.getValue(), taskName, process, ImportTaskStatusEnum.IN_PROGRESS.getValue(), null);
|
||||
}
|
||||
|
||||
public static ManagerMessage createCompletedMessage(String taskName){
|
||||
return new ImportTaskMessage(NotifyLevelEnum.SUCCESS.getValue(), ManagerEventTypeEnum.IMPORT_TASK_EVENT.getValue(), taskName, null, ImportTaskStatusEnum.COMPLETED.getValue(), null);
|
||||
}
|
||||
|
||||
public static ManagerMessage createFailedMessage(String taskName, String errMsg){
|
||||
return new ImportTaskMessage(NotifyLevelEnum.ERROR.getValue(), ManagerEventTypeEnum.IMPORT_TASK_EVENT.getValue(), taskName, null, ImportTaskStatusEnum.FAILED.getValue(), errMsg);
|
||||
}
|
||||
}
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.common.entity.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* Manager Message Entity
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ManagerMessage {
|
||||
/**
|
||||
* Notify Level
|
||||
* @see org.apache.hertzbeat.common.constants.NotifyLevelEnum
|
||||
*/
|
||||
private String notifyLevel;
|
||||
|
||||
/**
|
||||
* Manager Event Type
|
||||
* @see org.apache.hertzbeat.common.constants.ManagerEventTypeEnum
|
||||
*/
|
||||
private String managerEventType;
|
||||
}
|
||||
+1
-4
@@ -71,10 +71,7 @@ public class JdbcProtocol implements CommonRequestProtocol, Protocol {
|
||||
* DATABASE LINK URL eg: jdbc:mysql://localhost:3306/usthe
|
||||
*/
|
||||
private String url;
|
||||
/**
|
||||
* reuse connection session
|
||||
*/
|
||||
private String reuseConnection = "true";
|
||||
|
||||
/**
|
||||
* ssh tunnel
|
||||
*/
|
||||
|
||||
-7
@@ -567,13 +567,6 @@ public final class CollectRep {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if(!(o instanceof Field))
|
||||
return false;
|
||||
Field other = (Field)o;
|
||||
return other.name.equals(this.name);
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private final Field instance;
|
||||
|
||||
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.common.entity.message;
|
||||
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* Test case for {@link CollectRep}
|
||||
*/
|
||||
public class CollectRepTest {
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource(value = {
|
||||
"name, name, true",
|
||||
"name1, name3, false",
|
||||
})
|
||||
void testFieldEquals(String name1, String name2, boolean result) {
|
||||
CollectRep.Field field1 = new CollectRep.Field();
|
||||
field1.setName(name1);
|
||||
CollectRep.Field field2 = new CollectRep.Field();
|
||||
field2.setName(name2);
|
||||
|
||||
assertEquals(field1.equals(field2), result);
|
||||
}
|
||||
|
||||
}
|
||||
-88
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.manager.config;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.common.constants.ManagerEventTypeEnum;
|
||||
import org.apache.hertzbeat.common.entity.dto.ImportTaskMessage;
|
||||
import org.apache.hertzbeat.common.entity.dto.ManagerMessage;
|
||||
import org.apache.hertzbeat.common.util.JsonUtil;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Manager SSE
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class ManagerSseManager {
|
||||
private final Map<Long, SseEmitter> emitters = new ConcurrentHashMap<>();
|
||||
|
||||
public SseEmitter createEmitter(Long clientId) {
|
||||
SseEmitter emitter = new SseEmitter(Long.MAX_VALUE);
|
||||
emitter.onCompletion(() -> removeEmitter(clientId));
|
||||
emitter.onTimeout(() -> removeEmitter(clientId));
|
||||
emitters.put(clientId, emitter);
|
||||
return emitter;
|
||||
}
|
||||
|
||||
@Async
|
||||
public void broadcast(String eventName, String data) {
|
||||
emitters.forEach((clientId, emitter) -> {
|
||||
try {
|
||||
emitter.send(SseEmitter.event()
|
||||
.id(String.valueOf(System.currentTimeMillis()))
|
||||
.name(eventName)
|
||||
.data(data));
|
||||
} catch (IOException | IllegalStateException e) {
|
||||
emitter.complete();
|
||||
removeEmitter(clientId);
|
||||
} catch (Exception exception) {
|
||||
log.error("Failed to broadcast manager message data to client: {}", exception.getMessage());
|
||||
emitter.complete();
|
||||
removeEmitter(clientId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void broadcastImportTaskInProgress(String taskName, Integer progress){
|
||||
ManagerMessage managerMessage = ImportTaskMessage.createInProgressMessage(taskName, progress);
|
||||
broadcast(ManagerEventTypeEnum.IMPORT_TASK_EVENT.getValue(), JsonUtil.toJson(managerMessage));
|
||||
}
|
||||
|
||||
public void broadcastImportTaskSuccess(String taskName){
|
||||
ManagerMessage managerMessage = ImportTaskMessage.createCompletedMessage(taskName);
|
||||
broadcast(ManagerEventTypeEnum.IMPORT_TASK_EVENT.getValue(), JsonUtil.toJson(managerMessage));
|
||||
}
|
||||
|
||||
public void broadcastImportTaskFail(String taskName, String errMsg){
|
||||
ManagerMessage managerMessage = ImportTaskMessage.createFailedMessage(taskName, errMsg);
|
||||
broadcast(ManagerEventTypeEnum.IMPORT_TASK_EVENT.getValue(), JsonUtil.toJson(managerMessage));
|
||||
}
|
||||
|
||||
private void removeEmitter(Long clientId) {
|
||||
emitters.remove(clientId);
|
||||
}
|
||||
}
|
||||
-50
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.manager.controller;
|
||||
|
||||
import org.apache.hertzbeat.common.util.SnowFlakeIdGenerator;
|
||||
import org.apache.hertzbeat.manager.config.ManagerSseManager;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
|
||||
import static org.springframework.http.MediaType.TEXT_EVENT_STREAM_VALUE;
|
||||
|
||||
|
||||
/**
|
||||
* SSE controller for manager
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(path = "/api/manager/sse", produces = {TEXT_EVENT_STREAM_VALUE})
|
||||
public class ManagerSseController {
|
||||
|
||||
private final ManagerSseManager emitterManager;
|
||||
|
||||
public ManagerSseController(ManagerSseManager emitterManager) {
|
||||
this.emitterManager = emitterManager;
|
||||
}
|
||||
|
||||
@GetMapping(path = "/subscribe")
|
||||
public SseEmitter subscribe() {
|
||||
Long clientId = SnowFlakeIdGenerator.generateId();
|
||||
return emitterManager.createEmitter(clientId);
|
||||
}
|
||||
}
|
||||
-2
@@ -39,7 +39,5 @@ public class SmsNoticeSender {
|
||||
|
||||
private SmsUniSmsConfig unisms;
|
||||
|
||||
private SmslocalConfig smslocal;
|
||||
|
||||
private boolean enable = true;
|
||||
}
|
||||
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.manager.pojo.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
|
||||
/**
|
||||
* Smslocal SMS configuration
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SmslocalConfig {
|
||||
/**
|
||||
* Smslocal api key
|
||||
*/
|
||||
private String apiKey;
|
||||
}
|
||||
+1
-2
@@ -29,10 +29,9 @@ public interface ImExportService {
|
||||
|
||||
/**
|
||||
* Import Configuration
|
||||
* @param taskName task name
|
||||
* @param is input stream
|
||||
*/
|
||||
void importConfig(String taskName, InputStream is);
|
||||
void importConfig(InputStream is);
|
||||
|
||||
/**
|
||||
* Export Configuration
|
||||
|
||||
+43
-44
@@ -22,20 +22,6 @@ import cn.afterturn.easypoi.excel.annotation.ExcelTarget;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.common.constants.ImExportTaskConstant;
|
||||
import org.apache.hertzbeat.common.entity.manager.Monitor;
|
||||
import org.apache.hertzbeat.common.entity.manager.Param;
|
||||
import org.apache.hertzbeat.manager.config.ManagerSseManager;
|
||||
import org.apache.hertzbeat.manager.pojo.dto.MonitorDto;
|
||||
import org.apache.hertzbeat.manager.service.ImExportService;
|
||||
import org.apache.hertzbeat.manager.service.MonitorService;
|
||||
import org.apache.hertzbeat.manager.service.TagService;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.time.LocalDate;
|
||||
@@ -43,6 +29,17 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.common.entity.manager.Monitor;
|
||||
import org.apache.hertzbeat.common.entity.manager.Param;
|
||||
import org.apache.hertzbeat.manager.pojo.dto.MonitorDto;
|
||||
import org.apache.hertzbeat.manager.service.ImExportService;
|
||||
import org.apache.hertzbeat.manager.service.MonitorService;
|
||||
import org.apache.hertzbeat.manager.service.TagService;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* class AbstractImExportServiceImpl
|
||||
@@ -57,30 +54,27 @@ public abstract class AbstractImExportServiceImpl implements ImExportService {
|
||||
@Resource
|
||||
private TagService tagService;
|
||||
|
||||
@Resource
|
||||
private ManagerSseManager managerSseManager;
|
||||
|
||||
@Override
|
||||
public void importConfig(String taskName, InputStream is) {
|
||||
var formList = parseImport(is).stream().map(this::convert).toList();
|
||||
public void importConfig(InputStream is) {
|
||||
var formList = parseImport(is)
|
||||
.stream()
|
||||
.map(this::convert)
|
||||
.toList();
|
||||
if (!CollectionUtils.isEmpty(formList)) {
|
||||
int totalElements = formList.size();
|
||||
int progressInterval = Math.max(1, totalElements / 10);
|
||||
for (int i = 0; i < totalElements; i++) {
|
||||
MonitorDto monitorDto = formList.get(i);
|
||||
formList.forEach(monitorDto -> {
|
||||
monitorService.validate(monitorDto, false);
|
||||
monitorService.addMonitor(monitorDto.getMonitor(), monitorDto.getParams(), monitorDto.getCollector(), monitorDto.getGrafanaDashboard());
|
||||
if (totalElements >= ImExportTaskConstant.IMPORT_TASK_PROCESS_THRESHOLD && ((i + 1) % progressInterval == 0) && (i + 1 < totalElements)) {
|
||||
managerSseManager.broadcastImportTaskInProgress(taskName, (int) ((i + 1) * 100.0 / totalElements));
|
||||
}
|
||||
}
|
||||
managerSseManager.broadcastImportTaskSuccess(taskName);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exportConfig(OutputStream os, List<Long> configList) {
|
||||
var monitorList = configList.stream().map(it -> monitorService.getMonitorDto(it)).filter(Objects::nonNull).map(this::convert).toList();
|
||||
var monitorList = configList.stream()
|
||||
.map(it -> monitorService.getMonitorDto(it))
|
||||
.filter(Objects::nonNull)
|
||||
.map(this::convert)
|
||||
.toList();
|
||||
writeOs(monitorList, os);
|
||||
}
|
||||
|
||||
@@ -105,13 +99,15 @@ public abstract class AbstractImExportServiceImpl implements ImExportService {
|
||||
var monitor = new MonitorDTO();
|
||||
BeanUtils.copyProperties(dto.getMonitor(), monitor);
|
||||
exportMonitor.setMonitor(monitor);
|
||||
exportMonitor.setParams(dto.getParams().stream().map(it -> {
|
||||
var param = new ParamDTO();
|
||||
param.setField(it.getField());
|
||||
param.setType(it.getType());
|
||||
param.setValue(it.getParamValue());
|
||||
return param;
|
||||
}).toList());
|
||||
exportMonitor.setParams(dto.getParams().stream()
|
||||
.map(it -> {
|
||||
var param = new ParamDTO();
|
||||
param.setField(it.getField());
|
||||
param.setType(it.getType());
|
||||
param.setValue(it.getParamValue());
|
||||
return param;
|
||||
})
|
||||
.toList());
|
||||
exportMonitor.getMonitor().setCollector(dto.getCollector());
|
||||
return exportMonitor;
|
||||
}
|
||||
@@ -124,7 +120,7 @@ public abstract class AbstractImExportServiceImpl implements ImExportService {
|
||||
var monitorDto = new MonitorDto();
|
||||
var monitor = new Monitor();
|
||||
log.debug("exportMonitor.monitor{}", exportMonitor.monitor);
|
||||
if (exportMonitor.monitor != null) {
|
||||
if (exportMonitor.monitor != null) {
|
||||
// Add one more null check
|
||||
BeanUtils.copyProperties(exportMonitor.monitor, monitor);
|
||||
}
|
||||
@@ -133,13 +129,15 @@ public abstract class AbstractImExportServiceImpl implements ImExportService {
|
||||
monitorDto.setCollector(exportMonitor.getMonitor().getCollector());
|
||||
}
|
||||
if (exportMonitor.params != null) {
|
||||
monitorDto.setParams(exportMonitor.params.stream().map(it -> {
|
||||
var param = new Param();
|
||||
param.setField(it.field);
|
||||
param.setType(it.type);
|
||||
param.setParamValue(it.value);
|
||||
return param;
|
||||
}).toList());
|
||||
monitorDto.setParams(exportMonitor.params.stream()
|
||||
.map(it -> {
|
||||
var param = new Param();
|
||||
param.setField(it.field);
|
||||
param.setType(it.type);
|
||||
param.setParamValue(it.value);
|
||||
return param;
|
||||
})
|
||||
.toList());
|
||||
} else {
|
||||
monitorDto.setParams(Collections.emptyList());
|
||||
}
|
||||
@@ -205,4 +203,5 @@ public abstract class AbstractImExportServiceImpl implements ImExportService {
|
||||
@Excel(name = "Value")
|
||||
private String value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-13
@@ -54,7 +54,6 @@ import org.apache.hertzbeat.common.util.JsonUtil;
|
||||
import org.apache.hertzbeat.common.util.SdMonitorOperator;
|
||||
import org.apache.hertzbeat.common.util.SnowFlakeIdGenerator;
|
||||
import org.apache.hertzbeat.grafana.service.DashboardService;
|
||||
import org.apache.hertzbeat.manager.config.ManagerSseManager;
|
||||
import org.apache.hertzbeat.manager.dao.CollectorDao;
|
||||
import org.apache.hertzbeat.manager.dao.CollectorMonitorBindDao;
|
||||
import org.apache.hertzbeat.manager.dao.MonitorBindDao;
|
||||
@@ -139,8 +138,6 @@ public class MonitorServiceImpl implements MonitorService {
|
||||
private WarehouseService warehouseService;
|
||||
@Autowired
|
||||
private DashboardService dashboardService;
|
||||
@Autowired
|
||||
private ManagerSseManager managerSseManager;
|
||||
|
||||
public MonitorServiceImpl(List<ImExportService> imExportServiceList) {
|
||||
imExportServiceList.forEach(it -> imExportServiceMap.put(it.type(), it));
|
||||
@@ -186,21 +183,17 @@ public class MonitorServiceImpl implements MonitorService {
|
||||
|
||||
@Override
|
||||
public void importConfig(MultipartFile file) throws Exception {
|
||||
|
||||
var fileName = FileUtil.getFileName(file);
|
||||
var type = FileUtil.getFileType(file);
|
||||
try {
|
||||
if (!imExportServiceMap.containsKey(type)) {
|
||||
String errMsg = ExportFileConstants.FILE + " " + fileName + " is not supported.";
|
||||
throw new RuntimeException(errMsg);
|
||||
}
|
||||
var imExportService = imExportServiceMap.get(type);
|
||||
imExportService.importConfig(fileName, file.getInputStream());
|
||||
} catch (Exception e){
|
||||
managerSseManager.broadcastImportTaskFail(fileName, e.getMessage());
|
||||
throw e;
|
||||
if (!imExportServiceMap.containsKey(type)) {
|
||||
throw new RuntimeException(ExportFileConstants.FILE + " " + fileName + " is not supported.");
|
||||
}
|
||||
var imExportService = imExportServiceMap.get(type);
|
||||
imExportService.importConfig(file.getInputStream());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public void validate(MonitorDto monitorDto, Boolean isModify) throws IllegalArgumentException {
|
||||
|
||||
@@ -225,8 +225,6 @@ alerter:
|
||||
access-key-secret: YOUR_ACCESS_KEY_SECRET
|
||||
signature: YOUR_SMS_SIGNATURE
|
||||
template-id: YOUR_TEMPLATE_ID
|
||||
smslocal:
|
||||
api-key: YOUR_API_KEY_HERE
|
||||
|
||||
scheduler:
|
||||
server:
|
||||
@@ -249,4 +247,4 @@ ai:
|
||||
# api key
|
||||
api-key:
|
||||
#At present, only IFLYTEK large model needs to be filled in
|
||||
api-secret:
|
||||
api-secret:
|
||||
|
||||
@@ -1,100 +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: llm
|
||||
# The monitoring type eg: linux windows tomcat mysql aws...
|
||||
app: deepseek
|
||||
# The monitoring i18n name
|
||||
name:
|
||||
zh-CN: Deepseek
|
||||
en-US: Deepseek
|
||||
# The description and help of this monitoring type
|
||||
help:
|
||||
zh-CN: Hertzbeat 对 Deepseek Api进行测量监控。<br>您可以点击 “<i>新建 Deepseek</i>” 并进行配置,或者选择“<i>更多操作</i>”,导入已有配置。
|
||||
en-US: Hertzbeat monitors Deepseek Api. You could click the "<i>New Deepseek</i>" button and proceed with the configuration or import an existing setup through the "<i>More Actions</i>" menu.
|
||||
zh-TW: Hertzbeat對Deepseek Api進行量測監控。<br>您可以點擊“<i>Deepseek</i>”並進行配寘,或者選擇“<i>更多操作</i>”,導入已有配寘。
|
||||
helpLink:
|
||||
zh-CN: https://hertzbeat.apache.org/zh-cn/docs/help/deepseek
|
||||
en-US: https://hertzbeat.apache.org/docs/help/deepseek
|
||||
# Input params define for monitoring(render web ui by the definition)
|
||||
params:
|
||||
# field-param field key
|
||||
- field: token
|
||||
# name-param field display i18n name
|
||||
name:
|
||||
zh-CN: 会话密钥
|
||||
en-US: Session Key
|
||||
# type-param field type(most mapping the html input type)
|
||||
type: text
|
||||
# required-true or false
|
||||
required: true
|
||||
|
||||
# collect metrics config list
|
||||
metrics:
|
||||
# metrics - auth
|
||||
- name: billing
|
||||
i18n:
|
||||
zh-CN: 计费
|
||||
en-US: Billing
|
||||
# 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-metric name, type-metric type(0-number,1-string), unit-metric unit('%','ms','MB'), label-whether it is a metrics label field
|
||||
- field: currency
|
||||
type: 1
|
||||
i18n:
|
||||
zh-CN: 货币
|
||||
en-US: Currency
|
||||
- field: total_balance
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 可用余额
|
||||
en-US: Available Balance
|
||||
- field: granted_balance
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 未过期的赠金余额
|
||||
en-US: Unexpired Gift Balance
|
||||
- field: topped_up_balance
|
||||
type: 0
|
||||
i18n:
|
||||
zh-CN: 充值的余额
|
||||
en-US: Topped Up Balance
|
||||
# the protocol used for monitoring, eg: sql, ssh, http, telnet, wmi, snmp, sdk
|
||||
protocol: http
|
||||
# the config content when protocol is http
|
||||
http:
|
||||
# http host: ipv4 ipv6 domain
|
||||
host: api.deepseek.com
|
||||
# http port
|
||||
port: 443
|
||||
# http url
|
||||
url: /user/balance
|
||||
# http method: GET POST PUT DELETE PATCH
|
||||
method: GET
|
||||
# if enabled https
|
||||
ssl: true
|
||||
# http auth
|
||||
authorization:
|
||||
# http auth type: Basic Auth, Digest Auth, Bearer Token
|
||||
type: Bearer Token
|
||||
bearerTokenToken: ^_^token^_^
|
||||
# http response data parse type: default-hertzbeat rule, jsonpath-jsonpath script, website-for website monitoring, prometheus-prometheus exporter rule
|
||||
parseType: jsonPath
|
||||
parseScript: '$.balance_infos.*'
|
||||
@@ -64,13 +64,6 @@ params:
|
||||
required: false
|
||||
hide: true
|
||||
defaultValue: 6000
|
||||
- field: reuseConnection
|
||||
name:
|
||||
zh-CN: 复用连接
|
||||
en-US: Reuse Connection
|
||||
type: boolean
|
||||
required: false
|
||||
defaultValue: true
|
||||
- field: database
|
||||
name:
|
||||
zh-CN: 服务名
|
||||
@@ -165,7 +158,6 @@ metrics:
|
||||
password: ^_^password^_^
|
||||
database: ^_^database^_^
|
||||
timeout: ^_^timeout^_^
|
||||
reuseConnection: ^_^reuseConnection^_^
|
||||
# SQL Query Method:oneRow, multiRow, columns
|
||||
queryType: oneRow
|
||||
# sql
|
||||
@@ -221,8 +213,8 @@ metrics:
|
||||
password: ^_^password^_^
|
||||
database: ^_^database^_^
|
||||
timeout: ^_^timeout^_^
|
||||
reuseConnection: ^_^reuseConnection^_^
|
||||
queryType: multiRow
|
||||
|
||||
sql: select file_id, file_name, tablespace_name, status, bytes / 1024 / 1024 as bytes, blocks from dba_data_files
|
||||
url: ^_^url^_^
|
||||
|
||||
@@ -246,7 +238,6 @@ metrics:
|
||||
password: ^_^password^_^
|
||||
database: ^_^database^_^
|
||||
timeout: ^_^timeout^_^
|
||||
reuseConnection: ^_^reuseConnection^_^
|
||||
queryType: oneRow
|
||||
sql: select count(*) as count from v$session
|
||||
url: ^_^url^_^
|
||||
@@ -271,7 +262,6 @@ metrics:
|
||||
password: ^_^password^_^
|
||||
database: ^_^database^_^
|
||||
timeout: ^_^timeout^_^
|
||||
reuseConnection: ^_^reuseConnection^_^
|
||||
queryType: oneRow
|
||||
sql: select count(*) as count from v$session where username is not null and status = 'ACTIVE'
|
||||
url: ^_^url^_^
|
||||
@@ -296,7 +286,6 @@ metrics:
|
||||
password: ^_^password^_^
|
||||
database: ^_^database^_^
|
||||
timeout: ^_^timeout^_^
|
||||
reuseConnection: ^_^reuseConnection^_^
|
||||
queryType: oneRow
|
||||
sql: select count(*) as count from v$session where username is null
|
||||
url: ^_^url^_^
|
||||
@@ -327,7 +316,6 @@ metrics:
|
||||
password: ^_^password^_^
|
||||
database: ^_^database^_^
|
||||
timeout: ^_^timeout^_^
|
||||
reuseConnection: ^_^reuseConnection^_^
|
||||
queryType: oneRow
|
||||
sql: SELECT username, count( username ) as count FROM v$session WHERE username IS NOT NULL GROUP BY username
|
||||
url: ^_^url^_^
|
||||
@@ -373,7 +361,6 @@ metrics:
|
||||
password: ^_^password^_^
|
||||
database: ^_^database^_^
|
||||
timeout: ^_^timeout^_^
|
||||
reuseConnection: ^_^reuseConnection^_^
|
||||
queryType: columns
|
||||
sql: select metric_name, value from gv$sysmetric where metric_name = 'I/O Megabytes per Second' or metric_name = 'User Transaction Per Sec' or metric_name = 'I/O Requests per Second'
|
||||
url: ^_^url^_^
|
||||
@@ -427,7 +414,6 @@ metrics:
|
||||
password: ^_^password^_^
|
||||
database: ^_^database^_^
|
||||
timeout: ^_^timeout^_^
|
||||
reuseConnection: ^_^reuseConnection^_^
|
||||
queryType: multiRow
|
||||
# DBA_TABLESPACE_USAGE_METRICS可以查出表空间used_max值,它的大小计算单位是block,1kb=8block,把block*8/1024转化为MB单位
|
||||
sql: "SELECT tablespace_name,ROUND ( (TABLESPACE_SIZE * 8 / 1024), 0) AS total,ROUND ( (USED_SPACE * 8 / 1024), 0) AS used,ROUND ( ( (TABLESPACE_SIZE * 8 / 1024) - (USED_SPACE * 8 / 1024)), 0) AS free,ROUND ( (USED_PERCENT), 0) AS used_percentage,100 - ROUND ( (USED_PERCENT), 0) AS free_percentage FROM sys.dba_tablespace_usage_metrics ORDER BY used_percent DESC"
|
||||
@@ -453,7 +439,6 @@ metrics:
|
||||
password: ^_^password^_^
|
||||
database: ^_^database^_^
|
||||
timeout: ^_^timeout^_^
|
||||
reuseConnection: ^_^reuseConnection^_^
|
||||
queryType: oneRow
|
||||
sql: select count(*) as process_count from v$process
|
||||
url: ^_^url^_^
|
||||
@@ -491,7 +476,6 @@ metrics:
|
||||
password: ^_^password^_^
|
||||
database: ^_^database^_^
|
||||
timeout: ^_^timeout^_^
|
||||
reuseConnection: ^_^reuseConnection^_^
|
||||
queryType: columns
|
||||
sql: select metric_name, value from gv$sysmetric where metric_name = 'User Commits Per Sec' or metric_name = 'User Rollbacks Per Sec'
|
||||
url: ^_^url^_^
|
||||
@@ -577,7 +561,6 @@ metrics:
|
||||
password: ^_^password^_^
|
||||
database: ^_^database^_^
|
||||
timeout: ^_^timeout^_^
|
||||
reuseConnection: ^_^reuseConnection^_^
|
||||
queryType: columns
|
||||
sql: select wait_class, sum(time_waited) total_wait_time from v$active_session_history where session_state = 'WAITING' GROUP BY wait_class ORDER BY total_wait_time DESC
|
||||
url: ^_^url^_^
|
||||
@@ -608,7 +591,6 @@ metrics:
|
||||
password: ^_^password^_^
|
||||
database: ^_^database^_^
|
||||
timeout: ^_^timeout^_^
|
||||
reuseConnection: ^_^reuseConnection^_^
|
||||
queryType: multiRow
|
||||
sql: select stat_name as type, value as num from v$osstat where stat_name like '%CPU%' or stat_name like '%TIME'
|
||||
url: ^_^url^_^
|
||||
@@ -639,7 +621,6 @@ metrics:
|
||||
password: ^_^password^_^
|
||||
database: ^_^database^_^
|
||||
timeout: ^_^timeout^_^
|
||||
reuseConnection: ^_^reuseConnection^_^
|
||||
queryType: multiRow
|
||||
sql: select stat_name as type, value as num from v$osstat where stat_name like '%BYTES'
|
||||
url: ^_^url^_^
|
||||
@@ -675,7 +656,6 @@ metrics:
|
||||
password: ^_^password^_^
|
||||
database: ^_^database^_^
|
||||
timeout: ^_^timeout^_^
|
||||
reuseConnection: ^_^reuseConnection^_^
|
||||
queryType: columns
|
||||
sql: select metric_name, value from gv$sysmetric where metric_name like '%Cache Hit Ratio' order by end_time asc
|
||||
url: ^_^url^_^
|
||||
@@ -753,7 +733,6 @@ metrics:
|
||||
password: ^_^password^_^
|
||||
database: ^_^database^_^
|
||||
timeout: ^_^timeout^_^
|
||||
reuseConnection: ^_^reuseConnection^_^
|
||||
queryType: multiRow
|
||||
sql: SELECT * FROM (SELECT sql_id, child_number, executions, ROUND(CASE WHEN executions = 0 THEN NULL ELSE elapsed_time / (executions*1000000) END,4) AS per_secs, cpu_time / 1000000 AS cpu_secs, buffer_gets, disk_reads, fetches, parse_calls, optimizer_cost, sql_text FROM v$sql ) where rownum <= 10 ORDER BY per_secs DESC
|
||||
url: ^_^url^_^
|
||||
|
||||
@@ -78,7 +78,6 @@ excludedResource:
|
||||
- /api/apps/hierarchy===get
|
||||
- /api/push/**===*
|
||||
- /api/status/page/public/**===*
|
||||
- /api/manager/sse/**===*
|
||||
# web ui resource
|
||||
- /===get
|
||||
- /assets/**===get
|
||||
|
||||
+4
-7
@@ -73,13 +73,10 @@ public class DataStorageDispatch {
|
||||
if (metricsData == null) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
calculateMonitorStatus(metricsData);
|
||||
historyDataWriter.ifPresent(dataWriter -> dataWriter.saveData(metricsData));
|
||||
pluginRunner.pluginExecute(PostCollectPlugin.class, ((postCollectPlugin, pluginContext) -> postCollectPlugin.execute(metricsData, pluginContext)));
|
||||
} finally {
|
||||
realTimeDataWriter.saveData(metricsData);
|
||||
}
|
||||
calculateMonitorStatus(metricsData);
|
||||
historyDataWriter.ifPresent(dataWriter -> dataWriter.saveData(metricsData));
|
||||
pluginRunner.pluginExecute(PostCollectPlugin.class, ((postCollectPlugin, pluginContext) -> postCollectPlugin.execute(metricsData, pluginContext)));
|
||||
realTimeDataWriter.saveData(metricsData);
|
||||
} catch (InterruptedException interruptedException) {
|
||||
Thread.currentThread().interrupt();
|
||||
} catch (Exception e) {
|
||||
|
||||
-1
@@ -70,7 +70,6 @@ public class MemoryDataStorage extends AbstractRealTimeDataStorage {
|
||||
Long monitorId = metricsData.getId();
|
||||
String metrics = metricsData.getMetrics();
|
||||
if (metricsData.getCode() != CollectRep.Code.SUCCESS) {
|
||||
metricsData.close();
|
||||
return;
|
||||
}
|
||||
Map<String, CollectRep.MetricsData> metricsDataMap =
|
||||
|
||||
-1
@@ -63,7 +63,6 @@ public class RedisDataStorage extends AbstractRealTimeDataStorage {
|
||||
String hashKey = metricsData.getMetrics();
|
||||
if (metricsData.getCode() == CollectRep.Code.SUCCESS) {
|
||||
redisCommandDelegate.operate().hset(key, hashKey, metricsData, future -> future.thenAccept(response -> {
|
||||
metricsData.close();
|
||||
if (response) {
|
||||
log.debug("[warehouse] redis add new data {}:{}.", key, hashKey);
|
||||
} else {
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
---
|
||||
title: GSOC Google Summer of Code 2025 Recruitment is Underway | We Look Forward to Your Proposals
|
||||
author: zhangshenghang
|
||||
author_title: zhangshenghang
|
||||
author_url: https://github.com/zhangshenghang
|
||||
author_image_url: https://avatars.githubusercontent.com/u/29418975?s=400&v=4
|
||||
tags: [opensource, practice]
|
||||
keywords: [open source monitoring system, alerting system]
|
||||
---
|
||||
|
||||
## The Origin and Purpose of GSOC
|
||||
|
||||
GSOC, namely Google Summer of Code, is a global initiative launched by Google. It aims to encourage students to participate in the development of open-source software projects. Here is a detailed introduction:
|
||||
|
||||
- GSOC started in 2005. Initially, it was a project established by Google to promote the development of the open-source community and encourage more students to engage in the development and innovation of open-source software. Through this project, Google hopes to inject fresh blood into the open-source world, enabling students to enhance their technical capabilities through practice, and at the same time, bring new ideas and contributions to open-source projects.
|
||||
|
||||
## Task: An AI Agent for Monitoring Information Interaction Based on the MCP Protocol
|
||||
|
||||
**Website**: `https://hertzbeat.apache.org/`
|
||||
|
||||
**Github**: `http://github.com/apache/hertzbeat/`
|
||||
|
||||
### Background
|
||||
|
||||
Apache HertzBeat is an open-source real-time monitoring tool that supports a wide range of monitoring targets, including web services, databases, middleware, and more. It is characterized by high performance, scalability, and security.
|
||||
|
||||
With the continuous advancement of artificial intelligence (AI) technology, integrating AI with monitoring systems can significantly improve their usability and interactivity. By developing an AI agent based on the Model Context Protocol (MCP), we aim to enable conversational interaction for querying monitoring information, adding new monitoring tasks, and retrieving monitoring metrics. This will provide a more user-friendly and intelligent monitoring management experience.
|
||||
|
||||
## Functional Requirements
|
||||
|
||||
### Query Monitoring and Alarm Information
|
||||
|
||||
1. **Monitoring Item Status Monitoring**
|
||||
Be able to obtain the status of monitoring items through natural language;
|
||||
For example: Which monitoring items are currently abnormal? It should inform the user which monitoring items are abnormal and the time when the abnormality occurred.
|
||||
|
||||
2. **Search for Metric Data**
|
||||
Be able to obtain metric data through natural language;
|
||||
For example: a. Which servers currently have a CPU usage rate exceeding 80%?
|
||||
b. Display the CPU usage of server 192.168.1.1 in the last day in the form of a chart.
|
||||
|
||||
3. **Alarm Data**
|
||||
Obtain alarm data through natural language;
|
||||
For example: Which monitoring alarms have been more frequent recently?
|
||||
|
||||
### Add New Monitoring Tasks
|
||||
|
||||
1. **Add New Monitoring Targets**
|
||||
Be able to add new monitoring targets through natural language;
|
||||
For example: a. I want to monitor the response time of the web service.
|
||||
b. Please help me add monitoring for the database connection pool.
|
||||
2. **Configure Alarm Thresholds**
|
||||
Be able to configure alarm thresholds through natural language;
|
||||
For example: a. Trigger an alarm when the web service response time exceeds 5 seconds.
|
||||
b. Send a notification when the database connection pool usage rate exceeds 90%.
|
||||
|
||||
### Considerations During Design
|
||||
|
||||
1. There are many data sources supported by the underlying storage. How to monitor? For example: Natural language -> SQL -> Query data source -> Large language model.
|
||||
2. Compatibility with large language models, supporting commonly used models.
|
||||
3. The usability of the solution, making it convenient for users to use.
|
||||
|
||||
### Requirement Analysis
|
||||
|
||||
- **Apache HertzBeat**: As the core backend of the monitoring system, it provides data collection, storage, and management functions.
|
||||
- **MCP Protocol**: An open protocol that enables seamless integration between large language model (LLM) applications and external data sources and tools.
|
||||
- **Front-end Interaction**: Develop a user-friendly interface that supports voice or text input and displays monitoring information and interaction results.
|
||||
|
||||
### Recommended Skills
|
||||
|
||||
- **Java + TypeScript**: Apache HertzBeat is developed based on this technology stack. Therefore, mastering these technologies is crucial for integrating with HertzBeat.
|
||||
- **SpringAi**: It is recommended to use SpringAi to build the AI agent.
|
||||
- **LLM + MCP**: You need to understand large language models (LLM) and the MCP protocol. SpringAi seems to support the MCP protocol, or you can consider using the mcp-sdk directly.
|
||||
|
||||
### Scale
|
||||
|
||||
- **Difficulty**: Difficult
|
||||
- **Project Scale**: Approximately 350 hours
|
||||
|
||||
### Mentors
|
||||
|
||||
If you are interested, you can send an email to the mentors, including your solution and ideas.
|
||||
|
||||
- **Gong Chao**: `gongchao@apache.org`
|
||||
- **Zhang Shenghang**: `shenghang@apache.org`
|
||||
|
||||
## How Can I Increase My Chances of Being Selected as a GSoC Contributor?
|
||||
|
||||
1. After the list of organizations is announced, please visit the program website to view these organizations and find several organizations that interest you.
|
||||
2. Carefully read the "Project Ideas" list of these organizations.
|
||||
3. If you see an idea that interests you, please contact the organization through the organization's preferred communication method (listed on the organization's page on the GSoC website).
|
||||
4. Communicate with the mentors and community members to determine whether this project idea is something you are willing to implement during the program. If what you do is not something you are interested in, it will not be a pleasant summer vacation for you and your mentor.
|
||||
5. During the communication with the mentors and other members of the organization's community, you have obtained some information. Use this information to write a proposal.
|
||||
6. Please submit the proposal as early as possible so that the mentors have time to provide feedback. You need to have time to make revisions based on their feedback and resubmit it before the deadline. Do not wait until the last minute to submit the proposal!
|
||||
|
||||
## 2025 Google Summer of Code Timeline
|
||||
|
||||
All times are Coordinated Universal Time (UTC)
|
||||
|
||||
1. **January 27th - 18:00**: Mentor organizations can start submitting applications to Google.
|
||||
2. **February 11th - 18:00**: Deadline for mentor organization applications.
|
||||
3. **February 11th to 26th**: Google program administrators review organization applications.
|
||||
4. **February 27th - 18:00**: Release the list of approved mentor organizations.
|
||||
5. **February 27th to March 24th**: Potential GSoC contributors discuss proposal ideas with the mentoring organizations.
|
||||
6. **March 24th - 18:00**: Start accepting applications from Google Summer of Code contributors (i.e., GSoC contributors).
|
||||
7. **April 8th - 18:00**: Deadline for GSoC contributor applications.
|
||||
8. **April 29th - 18:00**: Organization administrators need to determine the ranking of GSoC contributor proposals.
|
||||
9. **May 8th - 18:00**: Announce the accepted GSoC contributor projects.
|
||||
10. **May 8th to June 1st**: Community interaction period. Participating Google Summer of Code contributors (GSoC contributors) get to know the mentors, read the documentation, learn relevant information, and prepare for starting the project work.
|
||||
11. **June 2nd**: Start coding officially!
|
||||
12. **July 14th - 18:00**: Mentors and Google Summer of Code contributors can start submitting mid-term evaluations (applicable to standard 12-week programming projects).
|
||||
13. **July 18th - 18:00**: Deadline for mid-term evaluations (standard coding cycle).
|
||||
14. **July 14th to August 25th**: Working stage. Under the guidance of the mentors, GSoC contributors carry out the projects.
|
||||
15. **August 25th to September 1st - 18:00**: Final week. GSoC contributors submit the final results and the final mentor evaluations (standard coding cycle).
|
||||
16. **September 1st to 8th - 18:00**: Mentors submit the final evaluation results of GSoC contributors (standard coding cycle).
|
||||
17. **September 1st to November 9th**: GSoC contributors with an extended schedule can continue coding.
|
||||
18. **November 10th - 18:00**: Deadline for all Google Summer of Code contributors to submit the final results and final evaluations.
|
||||
19. **November 17th - 18:00**: Final date for mentors to submit evaluations for GSoC contributor projects with an extended deadline.
|
||||
|
||||
## Frequently Asked Questions about Google Summer of Code
|
||||
|
||||
[https://developers.google.com/open-source/gsoc/faq?hl=zh-cn](https://developers.google.com/open-source/gsoc/faq?hl=zh-cn)
|
||||
@@ -20,6 +20,6 @@ WeChat Public : Search ID `usthecom`.
|
||||
|
||||
[Reddit Community](https://www.reddit.com/r/hertzbeat/)
|
||||
|
||||
[Follow Us Twitter](https://x.com/hertzbeat1024)
|
||||
[Follow Us Twitter](https://twitter.com/hertzbeat1024)
|
||||
|
||||
[Subscribe YouTube](https://www.youtube.com/channel/UCri75zfWX0GHqJFPENEbLow)
|
||||
|
||||
@@ -68,9 +68,11 @@ Even small corrections to typos are very welcome :)
|
||||
|
||||
4. Install Dependencies: `yarn install` or `yarn install --registry=https://registry.npmmirror.com` in `web-app`
|
||||
|
||||
5. After the local backend is started, start the local frontend in the web-app directory: `yarn start`
|
||||
5. Install angular-cli globally: `yarn global add @angular/cli@15` or `yarn global add @angular/cli@15 --registry=https://registry.npmmirror.com`
|
||||
|
||||
6. Browser access to localhost:4200 to start, default account/password is *admin/hertzbeat*
|
||||
6. After the local backend is started, start the local frontend in the web-app directory: `ng serve --open`
|
||||
|
||||
7. Browser access to localhost:4200 to start, default account/password is *admin/hertzbeat*
|
||||
|
||||
### Find tasks
|
||||
|
||||
|
||||
@@ -28,9 +28,11 @@ sidebar_label: Development
|
||||
|
||||
4. Install Dependencies: `yarn install` or `yarn install --registry=https://registry.npmmirror.com` in `web-app`
|
||||
|
||||
5. After the local backend is started, start the local frontend in the web-app directory: `yarn start`
|
||||
5. Install angular-cli globally: `yarn global add @angular/cli@15` or `yarn global add @angular/cli@15 --registry=https://registry.npmmirror.com`
|
||||
|
||||
6. Browser access to localhost:4200 to start, default account/password is *admin/hertzbeat*
|
||||
6. After the local backend is started, start the local frontend in the web-app directory: `ng serve --open`
|
||||
|
||||
7. Browser access to localhost:4200 to start, default account/password is *admin/hertzbeat*
|
||||
|
||||
## Build HertzBeat binary package
|
||||
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
---
|
||||
id: alert_sms
|
||||
title: Alert SMS notification
|
||||
sidebar_label: Alert SMS notification
|
||||
keywords: [open source monitoring tool, open source alerter, open source SMS alert notification]
|
||||
---
|
||||
|
||||
> After the threshold is triggered send alarm information and notify the recipient by SMS.
|
||||
|
||||
## SMS Service Configuration
|
||||
|
||||
Only when you successfully configure your own SMS service will the alert SMS triggered within the monitoring system be sent correctly.
|
||||
HertzBeat provides two ways to configure the SMS service: modifying the `application.yml` configuration file directly or configuring it through the HertzBeat frontend interface (Settings > Message Server Setting).
|
||||
|
||||
> ⚠️ Note: Only one method can be effective at a time. If both methods are configured and enabled, HertzBeat will prioritize the SMS service configured in the frontend interface.
|
||||
|
||||
### Tencent Cloud SMS Configuration
|
||||
|
||||
Add/Fill in the following Tencent Cloud SMS server configuration to `application.yml` (replace parameters with your own SMS server configuration):
|
||||
|
||||
```yaml
|
||||
alerter:
|
||||
sms:
|
||||
enable: true # Whether to enable
|
||||
type: tencent # SMS provider type, supports "tencent"
|
||||
tencent: # Tencent Cloud SMS configuration
|
||||
secret-id: AKIDbQ4VhdMr89wDedFrIcgU2PaaMvOuBCzY
|
||||
secret-key: PaXGl0ziY9UcWFjUyiFlCPMr77rLkJYlyA
|
||||
app-id: 1435441637
|
||||
sign-name: HertzBeat
|
||||
template-id: 1343434
|
||||
```
|
||||
|
||||
1. Create a signature (sign-name) in Tencent Cloud SMS
|
||||

|
||||
|
||||
2. Create a message template (template-id) in Tencent Cloud SMS
|
||||
|
||||
```text
|
||||
Monitor: {1}, Alert Level: {2}. Content: {3}
|
||||
```
|
||||
|
||||

|
||||
|
||||
3. Create an application (app-id) in Tencent Cloud SMS
|
||||

|
||||
|
||||
4. Obtain Tencent Cloud Access Management credentials (secret-id, secret-key)
|
||||

|
||||
|
||||
### Alibaba Cloud SMS Configuration
|
||||
|
||||
To activate and use Alibaba Cloud SMS service, you can refer to the official Alibaba Cloud documentation: [SMS Getting Started Guide](https://help.aliyun.com/zh/sms/getting-started/get-started-with-sms)
|
||||
|
||||
You can configure the Alibaba Cloud SMS service either through the graphical interface or in the `application.yml` file.
|
||||
To use `application.yml`, add/fill in the following Alibaba Cloud SMS configuration (replace parameters with your own SMS server configuration):
|
||||
|
||||
```yaml
|
||||
alerter:
|
||||
sms:
|
||||
enable: true # Whether to enable
|
||||
type: alibaba # SMS provider type, supports "alibaba"
|
||||
alibaba: # Alibaba Cloud SMS configuration
|
||||
access-key-id: # Your AccessKey ID
|
||||
access-key-secret: # Your AccessKey Secret
|
||||
sign-name: # SMS signature
|
||||
template-code: # SMS template code
|
||||
```
|
||||
|
||||
1. Create an Alibaba Cloud account and activate SMS service
|
||||
- Visit [Alibaba Cloud SMS Console](https://dysms.console.aliyun.com/)
|
||||
- Activate SMS service
|
||||
|
||||
2. Create a signature (sign-name)
|
||||
- Log in to [SMS Console](https://dysms.console.aliyun.com/)
|
||||
- Select Domestic/International SMS service
|
||||
- Go to "Signature Management" page and click "Add Signature"
|
||||
- Fill in signature information and submit for review
|
||||
- Wait for signature approval
|
||||
|
||||
3. Create a message template (template-code)
|
||||
- Go to "Template Management" page
|
||||
- Click "Add Template"
|
||||
- Create a template with the following format:
|
||||
|
||||
```text
|
||||
Monitor: ${instance}, Alert Level: ${priority}. Content: ${content}
|
||||
```
|
||||
|
||||
- Submit the template for review
|
||||
|
||||
4. Obtain Access Key credentials (access-key-id, access-key-secret)
|
||||
:::tip
|
||||
Alibaba Cloud officially recommends using RAM user AccessKey with minimal permissions.
|
||||
:::
|
||||
- [Go to RAM Access Control](https://ram.console.aliyun.com/users) to manage RAM users
|
||||
- Create user and select "Access Key for API Access"
|
||||
- Securely save the AccessKey ID and AccessKey Secret
|
||||
- Grant SMS service permission "AliyunDysmsFullAccess" to the user
|
||||
|
||||
Now you can configure this information in your hertzbeat application.
|
||||
|
||||
### UniSMS Configuration
|
||||
|
||||
UniSMS is an aggregated SMS service platform. You can refer to [UniSMS Documentation](https://unisms.apistd.com/docs/tutorials) for configuration.
|
||||
|
||||
Add/Fill in the following UniSMS configuration to `application.yml` (replace parameters with your own SMS server configuration):
|
||||
|
||||
```yaml
|
||||
alerter:
|
||||
sms:
|
||||
enable: true # Whether to enable
|
||||
type: unisms # SMS provider type, set to unisms
|
||||
unisms: # UniSMS configuration
|
||||
# auth-mode: simple or hmac
|
||||
auth-mode: simple
|
||||
access-key-id: YOUR_ACCESS_KEY_ID
|
||||
# hmac mode need to fill in access-key-secret
|
||||
access-key-secret: YOUR_ACCESS_KEY_SECRET
|
||||
signature: YOUR_SMS_SIGNATURE
|
||||
template-id: YOUR_TEMPLATE_ID
|
||||
```
|
||||
|
||||
1. Register UniSMS account
|
||||
- Visit [UniSMS website](https://unisms.apistd.com/)
|
||||
|
||||
2. Create signature
|
||||
- Log in to [UniSMS Console](https://unisms.apistd.com/console/)
|
||||
- Go to "SMS Filing - Signature Management" page
|
||||
- Click "Add Signature"
|
||||
- Fill in signature information and submit for review
|
||||
- Wait for signature approval
|
||||
|
||||
3. Create message template
|
||||
- Go to "SMS Filing - Template Management" page
|
||||
- Click "Add Template"
|
||||
- Create a template with the following format:
|
||||
|
||||
```text
|
||||
Monitor: {instance}, Alert Level: {priority}. Content: {content}
|
||||
```
|
||||
|
||||
- Submit the template for review
|
||||
|
||||
4. Obtain `access-key-id` and `access-key-secret`
|
||||
- Log in to [UniSMS Console](https://unisms.apistd.com/console/)
|
||||
- Go to "Credential Management" page
|
||||
- Get AccessKey ID and AccessKey Secret
|
||||
- Securely save the AccessKey ID and AccessKey Secret
|
||||
|
||||
:::note
|
||||
UniSMS provides two authentication methods for developers to choose from, which can be set in Console - Credential Management, with Simple Mode as default.
|
||||
- Simple Mode [Default]: This mode only verifies AccessKey ID without request parameter signature, making it easier for developers to integrate quickly.
|
||||
- HMAC Mode: This mode requires signing request parameters with AccessKey Secret to enhance the security and authenticity of requests.
|
||||
:::
|
||||
|
||||
Now you can configure this information in your hertzbeat application.
|
||||
|
||||
### Smslocal SMS Configuration
|
||||
|
||||
SMSLocal is an all-in-one SMS service for businesses, with features like multi-way sending, strong security, and 24/7 support. You can refer to smslocal's [Developer Documentation](https://www.smslocal.com/developer/) for configuration.
|
||||
|
||||
Add/Fill in the following Smslocal configuration to `application.yml` (replace parameters with your own SMS server configuration):
|
||||
|
||||
```yaml
|
||||
alerter:
|
||||
sms:
|
||||
enable: true # Whether to enable
|
||||
type: smslocal # SMS provider type, set to smslocal
|
||||
smslocal: # Smslocal configuration
|
||||
api-key: YOUR_API_KEY_HERE
|
||||
```
|
||||
|
||||
1. Register smslocal account
|
||||
- Visit [Smslocal Website](https://www.smslocal.com/)
|
||||
|
||||
2. Obtain `api-key`
|
||||
- Log in to [Smslocal Api Access](https://secure.smslocal.com/cpaas/pages/profile/settings/api-reference)
|
||||
- Go to "API Access" page
|
||||
- Click the eye button
|
||||
- Copy the displayed access key
|
||||
- Then you can configure the `application.yml` file
|
||||
|
||||
Now you can configure this information in your hertzbeat application.
|
||||
|
||||
## Operation steps
|
||||
|
||||
1. **【Alarm notification】->【Add new recipient】 ->【Select SMS notification method】**
|
||||
|
||||
2. **Configure the associated alarm notification strategy⚠️ 【Add new notification strategy】-> 【Associate the recipient just set】-> 【Confirm】**
|
||||
|
||||
> **Note⚠️ Adding a new recipient does not mean that it is effective to receive alarm information. It is also necessary to configure the associated alarm notification strategy, that is, to specify which messages are sent to which recipients.**
|
||||
|
||||
If you have any issues, please provide feedback through the communication group or ISSUE!
|
||||
@@ -1,35 +0,0 @@
|
||||
---
|
||||
id: deepseek
|
||||
title: Monitoring Deepseek Account Status
|
||||
sidebar_label: Deepseek Account Status
|
||||
keywords: [Open Source Monitoring System, Open Source Network Monitoring, Deepseek Account Monitoring]
|
||||
---
|
||||
|
||||
### Preparation
|
||||
|
||||
#### Obtain Session Key
|
||||
|
||||
Log in to the Deepseek backend and visit the `https://platform.deepseek.com/api_keys` page to obtain the session key.
|
||||
|
||||
### Configuration Parameters
|
||||
|
||||
| Parameter Name | Parameter Description |
|
||||
| ------------- | --------------------- |
|
||||
| Monitoring Host | Enter `api.deepseek.com` here. |
|
||||
| Task Name | The name that identifies this monitoring task, which must be unique. |
|
||||
| Session Key | The session key obtained in the preparation step. |
|
||||
| Collector | Configure which collector is used to schedule data collection for this monitoring. |
|
||||
| Monitoring Interval | The interval for periodically collecting data, in seconds. The minimum interval that can be set is 30 seconds. |
|
||||
| Bound Tags | Tags for categorizing and managing monitoring resources. |
|
||||
| Description/Remarks | Additional remarks to identify and describe this monitoring. Users can add notes here. |
|
||||
|
||||
### Collection Metrics
|
||||
|
||||
#### Metric Set: Billing
|
||||
|
||||
| Metric Name | Metric Unit | Metric Description |
|
||||
| ---------- | ---------- | ----------------- |
|
||||
| Currency | None | Currency, either RMB or USD. |
|
||||
| Available Balance | RMB/USD | Total available balance, including bonus and recharge balance. |
|
||||
| Unexpired Bonus Balance | RMB/USD | Unexpired bonus balance. |
|
||||
| Recharge Balance | RMB/USD | Recharge balance. |
|
||||
@@ -9,7 +9,7 @@ slug: /
|
||||
|
||||
[](https://discord.gg/Fb6M73htGr)
|
||||
[](https://www.reddit.com/r/hertzbeat/)
|
||||
[](https://x.com/hertzbeat1024)
|
||||
[](https://twitter.com/hertzbeat1024)
|
||||
[](https://www.bestpractices.dev/projects/8139)
|
||||
[](https://hub.docker.com/r/apache/hertzbeat)
|
||||
[](https://artifacthub.io/packages/search?repo=hertzbeat)
|
||||
|
||||
@@ -4,7 +4,7 @@ title: Advanced Params Config
|
||||
sidebar_label: Advanced Params Config
|
||||
---
|
||||
|
||||
Here it describes how to configure custom parameters for alerts, etc.
|
||||
This describes how to configure the SMS server, the number of built-in availability alarm triggers, etc.
|
||||
|
||||
**Configuration file `application.yml` of `hertzbeat`**
|
||||
|
||||
@@ -14,7 +14,48 @@ Configuring the HertzBeat configuration file:
|
||||
- **Docker Deployment:** ⚠️ When using a Docker container, the `application.yml` file must be mounted to the host machine
|
||||
- **Installation Package Deployment:** Extract the package and modify the configuration file located at `hertzbeat/config/application.yml`
|
||||
|
||||
## 1. Configuring Custom Alert Parameters
|
||||
## 1. Configuring the SMS Sending Service
|
||||
|
||||
Only when you successfully configure your own SMS service will the alert SMS triggered within the monitoring system be sent correctly.
|
||||
HertzBeat provides two ways to configure the SMS service: modifying the `application.yml` configuration file directly or configuring it through the HertzBeat frontend interface (Settings > Message Server Setting).
|
||||
|
||||
> ⚠️ Note: Only one method can be effective at a time. If both methods are configured and enabled, HertzBeat will prioritize the SMS service configured in the frontend interface.
|
||||
|
||||
### 1.1 Tencent Cloud SMS Configuration
|
||||
|
||||
Add the following Tencent Cloud SMS server configuration to `application.yml` (replace parameters with your own SMS server configuration):
|
||||
|
||||
```yaml
|
||||
alerter:
|
||||
sms:
|
||||
enable: true # Whether to enable
|
||||
type: tencent # SMS provider type, supports "tencent"
|
||||
tencent: # Tencent Cloud SMS configuration
|
||||
secret-id: AKIDbQ4VhdMr89wDedFrIcgU2PaaMvOuBCzY
|
||||
secret-key: PaXGl0ziY9UcWFjUyiFlCPMr77rLkJYlyA
|
||||
app-id: 1435441637
|
||||
sign-name: HertzBeat
|
||||
template-id: 1343434
|
||||
```
|
||||
|
||||
1. Create a signature (sign-name) in Tencent Cloud SMS
|
||||

|
||||
|
||||
2. Create a message template (template-id) in Tencent Cloud SMS
|
||||
|
||||
```text
|
||||
Monitor: {1}, Alert Level: {2}. Content: {3}
|
||||
```
|
||||
|
||||

|
||||
|
||||
3. Create an application (app-id) in Tencent Cloud SMS
|
||||

|
||||
|
||||
4. Obtain Tencent Cloud Access Management credentials (secret-id, secret-key)
|
||||

|
||||
|
||||
## 2. Configuring Custom Alert Parameters
|
||||
|
||||
```yaml
|
||||
alerter:
|
||||
@@ -22,7 +63,7 @@ alerter:
|
||||
console-url: https://console.tancloud.io
|
||||
```
|
||||
|
||||
## 2. Using an External Redis Instead of In-Memory Storage for Real-Time Metric Data
|
||||
## 3. Using an External Redis Instead of In-Memory Storage for Real-Time Metric Data
|
||||
|
||||
> By default, real-time metric data is stored in memory. You can configure Redis as a replacement using the settings below.
|
||||
|
||||
|
||||
@@ -213,7 +213,7 @@ module.exports = {
|
||||
className: 'header-github-link'
|
||||
},
|
||||
{
|
||||
href: 'https://x.com/hertzbeat1024',
|
||||
href: 'https://twitter.com/hertzbeat1024',
|
||||
position: 'right',
|
||||
className: 'header-twitter-link'
|
||||
},
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
---
|
||||
title: GSOC谷歌编程之夏2025招募中|期待您的提案
|
||||
author: zhangshenghang
|
||||
author_title: zhangshenghang
|
||||
author_url: https://github.com/zhangshenghang
|
||||
author_image_url: https://avatars.githubusercontent.com/u/29418975?s=400&v=4
|
||||
tags: [opensource, practice]
|
||||
keywords: [open source monitoring system, alerting system]
|
||||
---
|
||||
|
||||
## GSOC的起源与目的
|
||||
|
||||
GSOC 即 Google Summer of Code(谷歌编程之夏),是谷歌公司发起的一项全球性活动,旨在鼓励学生参与开源软件项目的开发,以下是其详细介绍:
|
||||
|
||||
- GSOC 始于 2005 年,最初是谷歌为了促进开源社区的发展,鼓励更多学生投身于开源软件的开发和创新而设立的项目。通过该项目,谷歌希望能够为开源世界注入新鲜血液,让学生们在实践中提升技术能力,同时也为开源项目带来新的思路和贡献。
|
||||
|
||||
## 任务:基于MCP协议的用于监控信息交互的AI代理
|
||||
|
||||
**网站**: `https://hertzbeat.apache.org/`
|
||||
|
||||
**Github**: `http://github.com/apache/hertzbeat/`
|
||||
|
||||
### 背景
|
||||
|
||||
Apache HertzBeat是一款开源的实时监控工具,支持广泛的监控目标,包括Web服务、数据库、中间件等等。它具有高性能、可扩展性和安全性的特点。
|
||||
|
||||
随着人工智能(AI)技术的不断进步,将人工智能与监控系统集成可以显著提高其可用性和交互性。通过开发一个基于模型上下文协议(MCP)的AI代理,我们旨在实现对话式交互,以便查询监控信息、添加新的监控任务以及检索监控指标。这将提供更加用户友好和智能的监控管理体验。
|
||||
|
||||
## 功能需求
|
||||
|
||||
### 查询监控和报警信息
|
||||
|
||||
1. **监控项状态监控**
|
||||
|
||||
通过自然语言能够获取监控项的状态;
|
||||
|
||||
如:现在哪些监控项存在异常?应该告诉用户哪些监控项存在异常,并且异常发生时间。
|
||||
|
||||
2. **搜索指标数据**
|
||||
|
||||
通过自然语言能够获取指标的数据;
|
||||
|
||||
如:a. 现在哪些服务器 CPU 使用率超过 80%
|
||||
|
||||
b. 服务器 192.168.1.1 最近一天 CPU 使用情况,用图表方式显示出来
|
||||
|
||||
3. **报警数据**
|
||||
通过自然语言获取报警数据;
|
||||
如:最近哪些监控报警比较多?
|
||||
|
||||
### 添加新的监控任务
|
||||
|
||||
1. **添加新的监控目标**
|
||||
通过自然语言能够添加新的监控目标;
|
||||
如:a. 我要监控Web服务的响应时间
|
||||
b. 请帮我添加数据库连接池的监控
|
||||
2. **配置警报阈值**
|
||||
通过自然语言能够配置警报阈值;
|
||||
如:a. 当Web服务响应时间超过5秒时触发警报
|
||||
b. 数据库连接池使用率超过90%时发送通知
|
||||
|
||||
### 设计时需要考虑的事项
|
||||
|
||||
1. 底层存储支持数据源比较多,如何监控? 比如:自然语言 -> SQL -> 查询数据源 -> 大模型
|
||||
2. 大模型的兼容性,支持常用模型
|
||||
3. 方案的易用性,让用户能够方便使用
|
||||
|
||||
### 需求分析
|
||||
|
||||
- **Apache HertzBeat**:作为监控系统的核心后端,它提供数据收集、存储和管理功能。
|
||||
- **MCP协议**:一种开放协议,可实现大语言模型(LLM)应用程序与外部数据源和工具之间的无缝集成。
|
||||
- **前端交互**:开发一个用户友好的界面,支持语音或文本输入,并显示监控信息和交互结果。
|
||||
|
||||
### 推荐技能
|
||||
|
||||
- **Java + TypeScript**:Apache HertzBeat是基于此技术栈开发的。因此,掌握这些技术对于与HertzBeat集成至关重要。
|
||||
- **SpringAi**:建议使用SpringAi来构建AI代理。
|
||||
- **LLM + MCP**:你需要了解大语言模型(LLM)和MCP协议。SpringAi似乎支持MCP协议,或者可以考虑直接使用mcp-sdk。
|
||||
|
||||
### 规模
|
||||
|
||||
- **难度**:困难
|
||||
- **项目规模**:约350小时
|
||||
|
||||
### 导师
|
||||
|
||||
如果您有意向可邮件发送给导师,带上您的方案和想法。
|
||||
|
||||
- **宫超**:`gongchao@apache.org`
|
||||
- **张圣航**:`shenghang@apache.org`
|
||||
|
||||
## 我该怎么做才能提高被选为 GSoC 贡献者的几率?
|
||||
|
||||
1. 在组织名单公布后,请访问计划网站查看这些组织,并找到几个您感兴趣的组织。
|
||||
2. 仔细阅读这些组织的“项目想法”列表。
|
||||
3. 如果您看到了感兴趣的想法,请通过组织的首选沟通方式(列在 GSoC 网站上的组织页面上)与该组织联系。
|
||||
4. 与导师和社区成员沟通,确定这个项目想法是否是你在该计划期间乐于着手实施的。如果您所做的不是自己感兴趣的事情,那么对您和您的导师来说,这将不会是一个愉快的暑假。
|
||||
5. 在与导师和其他组织社区成员沟通期间,您获得了一些信息,请利用这些信息撰写提案。
|
||||
6. 请尽早提交提案,以便导师有时间提供反馈。您需要有时间根据他们的反馈进行修改,并在截止日期之前重新提交。请勿等到最后一刻才提交提案!
|
||||
|
||||
## 2025年Google编程之夏时间轴
|
||||
|
||||
所有时间均为世界协调时间(UTC)
|
||||
|
||||
1. **1月27日 - 18:00**:导师组织可以开始向Google提交申请。
|
||||
2. **2月11日 - 18:00**:导师组织申请截止日期。
|
||||
3. **2月11日至26日**:Google计划管理员审核组织申请。
|
||||
4. **2月27日 - 18:00**:发布已获批准的导师组织列表。
|
||||
5. **2月27日至3月24日**:潜在的GSoC贡献者与指导组织讨论提案想法。
|
||||
6. **3月24日 - 18:00**:开始接受Google全球服务学习贡献者(即GSoC贡献者)申请。
|
||||
7. **4月8日 - 18:00**:GSoC贡献者申请截止日期。
|
||||
8. **4月29日 - 18:00**:组织管理员需要确定GSoC贡献者提案排名。
|
||||
9. **5月8日 - 18:00**:公布已接受的GSoC贡献者项目。
|
||||
10. **5月8日至6月1日**:社区互动期。参与Google开放式项目贡献者(GSoC贡献者)结识导师、阅读文档,了解相关信息,为开始项目工作做准备。
|
||||
11. **6月2日**:正式开始编码!
|
||||
12. **7月14日 - 18:00**:导师和Google开放式项目贡献者可以开始提交中期评估(适用于标准12周编程项目)。
|
||||
13. **7月18日 - 18:00**:中期评估截止日期(标准编码周期)。
|
||||
14. **7月14日至8月25日**:工作阶段。在导师的指导下,GSoC贡献者开展项目。
|
||||
15. **8月25日至9月1日 - 18:00**:最后一周。GSoC贡献者提交最终成果和最终导师评估(标准编码周期)。
|
||||
16. **9月1日至8日 - 18:00**:导师提交最终的GSoC贡献者评估结果(标准编码周期)。
|
||||
17. **9月1日至11月9日**:有延长时间表的GSoC贡献者可以继续编码。
|
||||
18. **11月10日 - 18:00**:所有Google开放式课程贡献者提交最终成果和最终评估的截止日期。
|
||||
19. **11月17日 - 18:00**:导师针对延长截止日期的GSoC贡献者项目提交评估的最终日期 。
|
||||
|
||||
## Google 编程之夏常见问题解答
|
||||
|
||||
[https://developers.google.com/open-source/gsoc/faq?hl=zh-cn](https://developers.google.com/open-source/gsoc/faq?hl=zh-cn)
|
||||
@@ -20,6 +20,6 @@ sidebar_label: 交流联系
|
||||
|
||||
[Reddit Community](https://www.reddit.com/r/hertzbeat/)
|
||||
|
||||
[Follow Us Twitter](https://x.com/hertzbeat1024)
|
||||
[Follow Us Twitter](https://twitter.com/hertzbeat1024)
|
||||
|
||||
[Subscribe YouTube](https://www.youtube.com/channel/UCri75zfWX0GHqJFPENEbLow)
|
||||
|
||||
@@ -72,9 +72,11 @@ limitations under the License.
|
||||
|
||||
4. 在前端工程目录 `web-app` 下执行: `yarn install` or `yarn install --registry=https://registry.npmmirror.com` in `web-app`
|
||||
|
||||
5. 待本地后端启动后,在 web-app 目录下启动本地前端 `yarn start`
|
||||
5. 全局安装 `angular-cli`: `yarn global add @angular/cli@15` or `yarn global add @angular/cli@15 --registry=https://registry.npmmirror.com`
|
||||
|
||||
6. 浏览器访问 localhost:4200 即可开始,默认账号密码 **admin/hertzbeat**
|
||||
6. 待本地后端启动后,在 web-app 目录下启动本地前端 `ng serve --open`
|
||||
|
||||
7. 浏览器访问 localhost:4200 即可开始,默认账号密码 **admin/hertzbeat**
|
||||
|
||||
### 寻找任务
|
||||
|
||||
|
||||
@@ -31,9 +31,11 @@ sidebar_label: 运行编译
|
||||
|
||||
4. 在前端工程目录 `web-app` 下执行: `yarn install` 或者 `yarn install --registry=https://registry.npmmirror.com`
|
||||
|
||||
5. 待本地后端启动后,在web-app目录下启动本地前端 `yarn start`
|
||||
5. 全局安装 `angular-cli`: `yarn global add @angular/cli@15` or `yarn global add @angular/cli@15 --registry=https://registry.npmmirror.com`
|
||||
|
||||
6. 浏览器访问 localhost:4200 即可开始,默认账号密码 admin/hertzbeat
|
||||
6. 待本地后端启动后,在web-app目录下启动本地前端 `ng serve --open`
|
||||
|
||||
7. 浏览器访问 localhost:4200 即可开始,默认账号密码 admin/hertzbeat
|
||||
|
||||
## 生成二进制包
|
||||
|
||||
|
||||
@@ -1,193 +0,0 @@
|
||||
---
|
||||
id: alert_sms
|
||||
title: 告警短信通知
|
||||
sidebar_label: 告警短信通知
|
||||
keywords: [开源监控系统, 开源告警系统, 开源短信告警通知]
|
||||
---
|
||||
|
||||
> 当阈值触发后发送告警信息,通过短信方式通知接收人。
|
||||
|
||||
## 短信服务配置
|
||||
|
||||
只有成功配置了您自己的短信服务,监控系统内触发的告警短信才会正常发送。
|
||||
hertzbeat有两种方式配置短信服务,一种是直接修改`application.yml`配置文件,另一种是通过hertzbeat前端界面(系统设置 > 消息服务配置)配置。
|
||||
> 注意⚠️:两种方式配置的短信服务只能选择一种生效,当两种方式都配置并且开启时,hertzbeat将会优先使用前端界面配置的短信服务。
|
||||
|
||||
### 腾讯云短信配置
|
||||
|
||||
在`application.yml`新增/填写如下腾讯平台短信服务器配置(参数需替换为您的短信服务器配置)
|
||||
|
||||
```yaml
|
||||
alerter:
|
||||
sms:
|
||||
enable: true # 是否启用
|
||||
type: tencent # 短信服务商类型,支持tencent、
|
||||
tencent: # 腾讯云短信配置
|
||||
secret-id: AKIDbQ4VhdMr89wDedFrIcgU2PaaMvOuBCzY
|
||||
secret-key: PaXGl0ziY9UcWFjUyiFlCPMr77rLkJYlyA
|
||||
app-id: 1435441637
|
||||
sign-name: 赫兹跳动
|
||||
template-id: 1343434
|
||||
```
|
||||
|
||||
1. 腾讯云短信创建签名(sign-name)
|
||||

|
||||
|
||||
2. 腾讯云短信创建正文模板(template-id)
|
||||
|
||||
```text
|
||||
监控:{1},告警级别:{2}。内容:{3}
|
||||
```
|
||||
|
||||

|
||||
|
||||
3. 腾讯云短信创建应用(app-id)
|
||||

|
||||
|
||||
4. 腾讯云访问管理(secret-id、secret-key)
|
||||

|
||||
|
||||
### 阿里云短信配置
|
||||
|
||||
开通使用阿里云短信服务,您可参考阿里云官方文档:[短信新手操作指引](https://help.aliyun.com/zh/sms/getting-started/get-started-with-sms)
|
||||
|
||||
您可以使用图形化界面配置阿里云短信服务,也可以在`application.yml`中配置阿里云短信服务。
|
||||
使用`application.yml`需要新增/填写如下阿里云短信配置(参数需替换为您的短信服务器配置)
|
||||
|
||||
```yaml
|
||||
alerter:
|
||||
sms:
|
||||
enable: true # 启用配置
|
||||
type: alibaba # 短信服务商类型,设置为alibaba
|
||||
alibaba: # 填写阿里云短信配置
|
||||
access-key-id: # 您的AccessKey ID
|
||||
access-key-secret: # 您的AccessKey Secret
|
||||
sign-name: # 短信签名
|
||||
template-code: # 短信模板CODE
|
||||
```
|
||||
|
||||
1. 创建阿里云账号并开通短信服务
|
||||
- 访问[阿里云短信服务控制台](https://dysms.console.aliyun.com/)
|
||||
- 开通短信服务
|
||||
|
||||
2. 创建短信签名(sign-name)
|
||||
- 登录[短信服务控制台](https://dysms.console.aliyun.com/)
|
||||
- 选择国内/国际短信服务
|
||||
- 进入"签名管理"页面,点击"添加签名"
|
||||
- 填写签名信息并提交审核
|
||||
- 等待签名审核通过
|
||||
|
||||
3. 创建短信模板(template-code)
|
||||
- 进入"模板管理"页面
|
||||
- 点击"添加模板"
|
||||
- 创建如下格式的模板:
|
||||
|
||||
```text
|
||||
监控项:${instance},告警级别:${priority}。内容:${content}
|
||||
```
|
||||
|
||||
- 提交模板等待审核
|
||||
|
||||
4. 获取访问密钥(access-key-id、access-key-secret)
|
||||
:::tip
|
||||
阿里云官方建议使用 RAM 用户 AccessKey,并进行最小化授权。
|
||||
:::
|
||||
- 进入[RAM访问控制](https://ram.console.aliyun.com/users)管理RAM用户
|
||||
- 创建用户并选择"使用永久 AccessKey 访问"
|
||||
- 安全保存AccessKey ID和AccessKey Secret
|
||||
- 为用户授权短信服务权限"AliyunDysmsFullAccess"
|
||||
|
||||
现在您可以把这些信息配置到您的hertzbeat应用中。
|
||||
|
||||
### uni-sms配置
|
||||
|
||||
uni-sms是一个聚合短信服务平台,您可以参考[UniSMS合一短信文档](https://unisms.apistd.com/docs/tutorials)进行配置。
|
||||
|
||||
在`application.yml`新增/填写如下uni-sms短信服务配置(参数需替换为您的短信服务器配置)
|
||||
|
||||
```yaml
|
||||
alerter:
|
||||
sms:
|
||||
enable: true # 启用配置
|
||||
type: unisms # 短信服务商类型,设置为unisms
|
||||
unisms: # 填写uni-sms短信配置
|
||||
# auth-mode: simple or hmac
|
||||
auth-mode: simple
|
||||
access-key-id: YOUR_ACCESS_KEY_ID
|
||||
# hmac mode need to fill in access-key-secret
|
||||
access-key-secret: YOUR_ACCESS_KEY_SECRET
|
||||
signature: YOUR_SMS_SIGNATURE
|
||||
template-id: YOUR_TEMPLATE_ID
|
||||
```
|
||||
|
||||
1. 注册uni-sms账号
|
||||
- 访问[uni-sms官网](https://unisms.apistd.com/)
|
||||
|
||||
2. 创建短信签名(signature)
|
||||
- 登录[uni-sms控制台](https://unisms.apistd.com/console/)
|
||||
- 进入"短信报备-签名管理"页面
|
||||
- 点击"添加签名"
|
||||
- 填写签名信息并提交审核
|
||||
- 等待签名审核通过
|
||||
|
||||
3. 创建短信模板(template-id)
|
||||
- 进入"短信报备-模板管理"页面
|
||||
- 点击"添加模板"
|
||||
- 创建如下格式的模板:
|
||||
|
||||
```text
|
||||
监控项:{instance},告警级别:{priority}。内容:{content}
|
||||
```
|
||||
|
||||
- 提交模板等待审核
|
||||
|
||||
4. 获取`access-key-id`和`access-key-secret`
|
||||
- 登录[uni-sms控制台](https://unisms.apistd.com/console/)
|
||||
- 进入"凭证管理"页面
|
||||
- 获取AccessKey ID和AccessKey Secret
|
||||
- 安全保存AccessKey ID和AccessKey Secret
|
||||
|
||||
:::note
|
||||
UniSMS 提供以下两种鉴权方式共开发者选择,可在控制台-凭证管理中设置,默认为简易模式。
|
||||
- 简易模式 [默认]:此模式仅核验 AccessKey ID,不对请求参数进行验签,方便开发者快速接入。
|
||||
- HMAC模式:此模式要求使用 AccessKey Secret 对请求参数进行验签,以加强保障请求的安全与真实性。
|
||||
:::
|
||||
|
||||
现在您可以把这些信息配置到您的hertzbeat应用中。
|
||||
|
||||
### smslocal短信配置
|
||||
|
||||
smslocal是一款面向企业的一体化短信服务平台,具备诸如多种发送方式、强大的安全性以及全天候支持等特性。你可以参考 smslocal 的[开发者文档](https://www.smslocal.com/developer/)来进行配置。
|
||||
|
||||
在 `application.yml` 中添加/填写以下 smslocal 配置内容(请用你自己的短信服务器配置参数替换相关参数):
|
||||
|
||||
```yaml
|
||||
alerter:
|
||||
sms:
|
||||
enable: true # 是否启用
|
||||
type: smslocal # 短信服务提供商类型,设置为smslocal
|
||||
smslocal: # smslocal配置
|
||||
api-key: 在此处填入你的API密钥
|
||||
```
|
||||
|
||||
1. 注册 smslocal 账号
|
||||
- 访问 [smslocal官网](https://www.smslocal.com/)
|
||||
|
||||
2. 获取 `api-key`
|
||||
- 登录 [smslocal API accessKey访问页面](https://secure.smslocal.com/cpaas/pages/profile/settings/api-reference)
|
||||
- 进入 “API 访问” 页面
|
||||
- 点击眼睛图标按钮
|
||||
- 复制显示的访问密钥
|
||||
- 然后你就可以配置 `application.yml` 文件了
|
||||
|
||||
现在你可以在你的 Hertzbeat 应用程序中配置这些信息。
|
||||
|
||||
## 操作步骤
|
||||
|
||||
1. **【告警通知】->【新增接收人】 ->【选择短信通知方式】**
|
||||
|
||||
2. **配置关联的告警通知策略⚠️ 【新增通知策略】-> 【关联刚才设置的接收人】-> 【确认】**
|
||||
|
||||
> **注意⚠️ 新增接收人并不代表就生效能收到告警信息,还需要配置关联的告警通知策略,即指定哪些消息发给哪些接收人。**
|
||||
|
||||
如有问题可通过交流群ISSUE反馈!
|
||||
@@ -1,35 +0,0 @@
|
||||
---
|
||||
id: deepseek
|
||||
title: 监控:Deepseek 账户情况
|
||||
sidebar_label: Deepseek 账户情况
|
||||
keywords: [开源监控系统, 开源网络监控, Deepseek账户监控]
|
||||
---
|
||||
|
||||
### 准备工作
|
||||
|
||||
#### 获取会话密钥
|
||||
|
||||
登录 Deepseek 后台,访问 `https://platform.deepseek.com/api_keys` 页面,获取会话密钥。
|
||||
|
||||
### 配置参数
|
||||
|
||||
| 参数名称 | 参数帮助描述 |
|
||||
|-------|---------------------------------|
|
||||
| 监控Host | 此处填写 api.deepseek.com 。 |
|
||||
| 任务名称 | 标识此监控的名称,名称需要保证唯一性。 |
|
||||
| 会话密钥 | 即准备工作中获取的会话密钥。 |
|
||||
| 采集器 | 配置此监控使用哪台采集器调度采集。 |
|
||||
| 监控周期 | 监控周期性采集数据间隔时间,单位秒,可设置的最小间隔为30秒。 |
|
||||
| 绑定标签 | 对监控资源的分类管理标签。 |
|
||||
| 描述备注 | 更多标识和描述此监控的备注信息,用户可以在这里备注信息。 |
|
||||
|
||||
### 采集指标
|
||||
|
||||
#### 指标集合:计费
|
||||
|
||||
| 指标名称 | 指标单位 | 指标帮助描述 |
|
||||
|---------|--------|-----------|
|
||||
| 货币 | 无 | 货币,人民币或美元 |
|
||||
| 可用余额 | 人民币/美元 | 总的可用余额,包括赠金和充值余额 |
|
||||
| 未过期的赠金余额 | 人民币/美元 | 未过期的赠金余额 |
|
||||
| 充值的余额 | 人民币/美元 | 充值余额 |
|
||||
@@ -23,15 +23,15 @@ keywords: [开源监控系统, 开源网络监控, OpenAI账户监控]
|
||||
|
||||
### 配置参数
|
||||
|
||||
| 参数名称 | 参数帮助描述 |
|
||||
|----------|--------------------------------|
|
||||
| 监控Host | 此处填写 api.openai.com 。 |
|
||||
| 任务名称 | 标识此监控的名称,名称需要保证唯一性。 |
|
||||
| 会话密钥 | 即准备工作中获取的会话密钥。 |
|
||||
| 采集器 | 配置此监控使用哪台采集器调度采集。 |
|
||||
| 参数名称 | 参数帮助描述 |
|
||||
|:-------|---------------------------------|---|
|
||||
| 监控Host | 此处填写 api.openai.com 。 |
|
||||
| 任务名称 | 标识此监控的名称,名称需要保证唯一性。 | |
|
||||
| 会话密钥 | 即准备工作中获取的会话密钥。 | |
|
||||
| 采集器 | 配置此监控使用哪台采集器调度采集。 |
|
||||
| 监控周期 | 监控周期性采集数据间隔时间,单位秒,可设置的最小间隔为30秒。 |
|
||||
| 绑定标签 | 对监控资源的分类管理标签。 |
|
||||
| 描述备注 | 更多标识和描述此监控的备注信息,用户可以在这里备注信息。 |
|
||||
| 绑定标签 | 对监控资源的分类管理标签。 |
|
||||
| 描述备注 | 更多标识和描述此监控的备注信息,用户可以在这里备注信息。 |
|
||||
|
||||
### 采集指标
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ slug: /
|
||||
|
||||
[](https://discord.gg/Fb6M73htGr)
|
||||
[](https://www.reddit.com/r/hertzbeat/)
|
||||
[](https://x.com/hertzbeat1024)
|
||||
[](https://twitter.com/hertzbeat1024)
|
||||
[](https://www.bestpractices.dev/projects/8139)
|
||||
[](https://hub.docker.com/r/apache/hertzbeat)
|
||||
[](https://artifacthub.io/packages/search?repo=hertzbeat)
|
||||
|
||||
@@ -4,7 +4,7 @@ title: 常见参数配置
|
||||
sidebar_label: 常见参数配置
|
||||
---
|
||||
|
||||
这里描述了如何配置告警自定义参数等。
|
||||
这里描述了如何配置短信服务,内置可用性告警触发次数等。
|
||||
|
||||
**`hertzbeat`的配置文件`application.yml`**
|
||||
|
||||
@@ -14,7 +14,47 @@ sidebar_label: 常见参数配置
|
||||
- **Docker部署:** ⚠️docker容器方式需要将 `application.yml` 文件挂载到主机本地
|
||||
- **安装包方式:** 解压修改位于 `hertzbeat/config/application.yml` 的配置文件即可
|
||||
|
||||
## 1. 配置告警自定义参数
|
||||
## 1. 配置短信发送服务
|
||||
|
||||
只有成功配置了您自己的短信服务,监控系统内触发的告警短信才会正常发送。
|
||||
hertzbeat有两种方式配置短信服务,一种是直接修改`application.yml`配置文件,另一种是通过hertzbeat前端界面(系统设置 > 消息服务配置)配置。
|
||||
> 注意⚠️:两种方式配置的短信服务只能选择一种生效,当两种方式都配置并且开启时,hertzbeat将会优先使用前端界面配置的短信服务。
|
||||
|
||||
### 1.1 腾讯云短信配置
|
||||
|
||||
在`application.yml`新增如下腾讯平台短信服务器配置(参数需替换为您的短信服务器配置)
|
||||
|
||||
```yaml
|
||||
alerter:
|
||||
sms:
|
||||
enable: true # 是否启用
|
||||
type: tencent # 短信服务商类型,支持tencent、
|
||||
tencent: # 腾讯云短信配置
|
||||
secret-id: AKIDbQ4VhdMr89wDedFrIcgU2PaaMvOuBCzY
|
||||
secret-key: PaXGl0ziY9UcWFjUyiFlCPMr77rLkJYlyA
|
||||
app-id: 1435441637
|
||||
sign-name: 赫兹跳动
|
||||
template-id: 1343434
|
||||
```
|
||||
|
||||
1. 腾讯云短信创建签名(sign-name)
|
||||

|
||||
|
||||
2. 腾讯云短信创建正文模板(template-id)
|
||||
|
||||
```text
|
||||
监控:{1},告警级别:{2}。内容:{3}
|
||||
```
|
||||
|
||||

|
||||
|
||||
3. 腾讯云短信创建应用(app-id)
|
||||

|
||||
|
||||
4. 腾讯云访问管理(secret-id、secret-key)
|
||||

|
||||
|
||||
## 2. 配置告警自定义参数
|
||||
|
||||
```yaml
|
||||
alerter:
|
||||
@@ -22,7 +62,7 @@ alerter:
|
||||
console-url: https://console.tancloud.io
|
||||
```
|
||||
|
||||
## 2. 使用外置redis代替内存存储实时指标数据
|
||||
## 3. 使用外置redis代替内存存储实时指标数据
|
||||
|
||||
> 默认我们的指标实时数据存储在内存中,可以配置如下来使用redis代替内存存储。
|
||||
|
||||
|
||||
@@ -20,6 +20,6 @@ sidebar_label: 交流联系
|
||||
|
||||
[Reddit Community](https://www.reddit.com/r/hertzbeat/)
|
||||
|
||||
[Follow Us Twitter](https://x.com/hertzbeat1024)
|
||||
[Follow Us Twitter](https://twitter.com/hertzbeat1024)
|
||||
|
||||
[Subscribe YouTube](https://www.youtube.com/channel/UCri75zfWX0GHqJFPENEbLow)
|
||||
|
||||
@@ -9,7 +9,7 @@ slug: /
|
||||
|
||||
[](https://discord.gg/Fb6M73htGr)
|
||||
[](https://www.reddit.com/r/hertzbeat/)
|
||||
[](https://x.com/hertzbeat1024)
|
||||
[](https://twitter.com/hertzbeat1024)
|
||||
[](https://www.bestpractices.dev/projects/8139)
|
||||
[](https://hub.docker.com/r/apache/hertzbeat)
|
||||
[](https://artifacthub.io/packages/search?repo=hertzbeat)
|
||||
|
||||
@@ -260,7 +260,6 @@
|
||||
"label": "notice",
|
||||
"items": [
|
||||
"help/alert_email",
|
||||
"help/alert_sms",
|
||||
"help/alert_webhook",
|
||||
"help/alert_discord",
|
||||
"help/alert_slack",
|
||||
|
||||
@@ -445,9 +445,6 @@ export default function () {
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/myangle1120"><img src="https://avatars.githubusercontent.com/u/19237013?v=4?s=100" width="100px;" alt="myangle1120"/><br /><sub><b>myangle1120</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=myangle1120" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yasminvo"><img src="https://avatars.githubusercontent.com/u/107528848?v=4?s=100" width="100px;" alt="yasminvo"/><br /><sub><b>yasminvo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yasminvo" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/notbugggg"><img src="https://avatars.githubusercontent.com/u/147966331?v=4?s=100" width="100px;" alt="不关银渐层的事哦"/><br /><sub><b>不关银渐层的事哦</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=notbugggg" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yyahang"><img src="https://avatars.githubusercontent.com/u/90464876?v=4?s=100" width="100px;" alt="yyahang"/><br /><sub><b>yyahang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yyahang" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -123,11 +123,6 @@
|
||||
"githubId": "61108539",
|
||||
"gitUrl": "https://github.com/zuobiao-zhou",
|
||||
"name": "Yuxuan Zhang"
|
||||
},
|
||||
{
|
||||
"githubId": "91836599",
|
||||
"gitUrl": "https://github.com/yunfan24",
|
||||
"name": "Lixin Diao"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -20,6 +20,6 @@ WeChat Public : Search ID `usthecom`.
|
||||
|
||||
[Reddit Community](https://www.reddit.com/r/hertzbeat/)
|
||||
|
||||
[Follow Us Twitter](https://x.com/hertzbeat1024)
|
||||
[Follow Us Twitter](https://twitter.com/hertzbeat1024)
|
||||
|
||||
[Subscribe YouTube](https://www.youtube.com/channel/UCri75zfWX0GHqJFPENEbLow)
|
||||
|
||||
@@ -9,7 +9,7 @@ slug: /
|
||||
|
||||
[](https://discord.gg/Fb6M73htGr)
|
||||
[](https://www.reddit.com/r/hertzbeat/)
|
||||
[](https://x.com/hertzbeat1024)
|
||||
[](https://twitter.com/hertzbeat1024)
|
||||
[](https://www.bestpractices.dev/projects/8139)
|
||||
[](https://hub.docker.com/r/apache/hertzbeat)
|
||||
[](https://artifacthub.io/packages/search?repo=hertzbeat)
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
<!-- hertzbeat related modules -->
|
||||
<hertzbeat.version>2.0-SNAPSHOT</hertzbeat.version>
|
||||
|
||||
<springdoc.version>2.8.5</springdoc.version>
|
||||
<springdoc.version>2.3.0</springdoc.version>
|
||||
<spring-boot-starter-sureness.version>1.1.0</spring-boot-starter-sureness.version>
|
||||
<javaparser.version>3.26.1</javaparser.version>
|
||||
<nekohtml.version>1.9.22</nekohtml.version>
|
||||
|
||||
@@ -224,8 +224,6 @@ alerter:
|
||||
access-key-secret: YOUR_ACCESS_KEY_SECRET
|
||||
signature: YOUR_SMS_SIGNATURE
|
||||
template-id: YOUR_TEMPLATE_ID
|
||||
smslocal:
|
||||
api-key: YOUR_API_KEY_HERE
|
||||
|
||||
scheduler:
|
||||
server:
|
||||
|
||||
@@ -17,11 +17,3 @@
|
||||
./home/i18n/zh-cn/docusaurus-plugin-content-docs/version-v1.5.x/help/sqlserver.md
|
||||
./home/i18n/zh-cn/docusaurus-plugin-content-docs/version-v1.5.x/start/tdengine-init.md
|
||||
./home/i18n/zh-cn/docusaurus-plugin-content-docs/current/start/tdengine-init.md
|
||||
./home/versioned_docs/version-v1.5.x/introduce.md
|
||||
./home/versioned_docs/version-v1.5.x/community/contact.md
|
||||
./home/i18n/zh-cn/docusaurus-plugin-content-docs/current/introduce.md
|
||||
./home/i18n/zh-cn/docusaurus-plugin-content-docs/current/community/contact.md
|
||||
./home/i18n/zh-cn/docusaurus-plugin-content-docs/version-v1.5.x/community/contact.md
|
||||
./home/i18n/zh-cn/docusaurus-plugin-content-docs/version-v1.5.x/introduce.md
|
||||
./home/docs/introduce.md
|
||||
./home/docs/community/contact.md
|
||||
@@ -14,7 +14,6 @@
|
||||
"aliveStatusCodes": [
|
||||
0,
|
||||
200,
|
||||
400,
|
||||
401,
|
||||
403
|
||||
]
|
||||
|
||||
@@ -191,8 +191,6 @@ alerter:
|
||||
access-key-secret: YOUR_ACCESS_KEY_SECRET
|
||||
signature: YOUR_SMS_SIGNATURE
|
||||
template-id: YOUR_TEMPLATE_ID
|
||||
smslocal:
|
||||
api-key: YOUR_API_KEY_HERE
|
||||
|
||||
scheduler:
|
||||
server:
|
||||
|
||||
@@ -78,7 +78,6 @@ excludedResource:
|
||||
- /api/apps/hierarchy===get
|
||||
- /api/push/**===*
|
||||
- /api/status/page/public/**===*
|
||||
- /api/manager/sse/**===*
|
||||
# web ui resource
|
||||
- /===get
|
||||
- /assets/**===get
|
||||
|
||||
@@ -187,8 +187,6 @@ alerter:
|
||||
access-key-secret: YOUR_ACCESS_KEY_SECRET
|
||||
signature: YOUR_SMS_SIGNATURE
|
||||
template-id: YOUR_TEMPLATE_ID
|
||||
smslocal:
|
||||
api-key: YOUR_API_KEY_HERE
|
||||
|
||||
scheduler:
|
||||
server:
|
||||
|
||||
@@ -78,7 +78,6 @@ excludedResource:
|
||||
- /api/apps/hierarchy===get
|
||||
- /api/push/**===*
|
||||
- /api/status/page/public/**===*
|
||||
- /api/manager/sse/**===*
|
||||
# web ui resource
|
||||
- /===get
|
||||
- /assets/**===get
|
||||
|
||||
@@ -185,8 +185,6 @@ alerter:
|
||||
access-key-secret: YOUR_ACCESS_KEY_SECRET
|
||||
signature: YOUR_SMS_SIGNATURE
|
||||
template-id: YOUR_TEMPLATE_ID
|
||||
smslocal:
|
||||
api-key: YOUR_API_KEY_HERE
|
||||
|
||||
scheduler:
|
||||
server:
|
||||
|
||||
@@ -78,7 +78,6 @@ excludedResource:
|
||||
- /api/apps/hierarchy===get
|
||||
- /api/push/**===*
|
||||
- /api/status/page/public/**===*
|
||||
- /api/manager/sse/**===*
|
||||
# web ui resource
|
||||
- /===get
|
||||
- /assets/**===get
|
||||
|
||||
@@ -184,8 +184,6 @@ alerter:
|
||||
access-key-secret: YOUR_ACCESS_KEY_SECRET
|
||||
signature: YOUR_SMS_SIGNATURE
|
||||
template-id: YOUR_TEMPLATE_ID
|
||||
smslocal:
|
||||
api-key: YOUR_API_KEY_HERE
|
||||
|
||||
scheduler:
|
||||
server:
|
||||
|
||||
@@ -78,7 +78,6 @@ excludedResource:
|
||||
- /api/apps/hierarchy===get
|
||||
- /api/push/**===*
|
||||
- /api/status/page/public/**===*
|
||||
- /api/manager/sse/**===*
|
||||
# web ui resource
|
||||
- /===get
|
||||
- /assets/**===get
|
||||
|
||||
@@ -78,7 +78,6 @@ excludedResource:
|
||||
- /api/apps/hierarchy===get
|
||||
- /api/push/**===*
|
||||
- /api/status/page/public/**===*
|
||||
- /api/manager/sse/**===*
|
||||
# web ui resource
|
||||
- /===get
|
||||
- /assets/**===get
|
||||
|
||||
+3
-2
@@ -9,8 +9,9 @@
|
||||
|
||||
1. Need `Node Yarn` Environment, Make sure `Node.js >= 18`
|
||||
2. Install yarn if not existed `npm install -g yarn`
|
||||
3. Execute `yarn install` or `yarn install --registry=https://registry.npmmirror.com` in `web-app`
|
||||
4. Start After Backend Server Available : `yarn start`
|
||||
3. Execute `yarn install` or `yarn install --registry=https://registry.npmmirror.com` in `web-app`
|
||||
4. Install angular-cli : `yarn global add @angular/cli@15` or `yarn global add @angular/cli@15 --registry=https://registry.npmmirror.com`
|
||||
5. Start After Backend Server Available : `yarn start`
|
||||
|
||||
|
||||
### Build HertzBeat Install Package
|
||||
|
||||
@@ -81,11 +81,4 @@ describe('Service: I18n', () => {
|
||||
expect(lang).toBe('en-US');
|
||||
});
|
||||
});
|
||||
it('should be trigger notify when changed language', () => {
|
||||
genModule();
|
||||
srv.use('pt-BR', {});
|
||||
srv.change.subscribe(lang => {
|
||||
expect(lang).toBe('pt-BR');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,7 +3,6 @@ import { registerLocaleData } from '@angular/common';
|
||||
import { HttpHeaders } from '@angular/common/http';
|
||||
import ngEn from '@angular/common/locales/en';
|
||||
import ngJa from '@angular/common/locales/ja';
|
||||
import ngPt from '@angular/common/locales/pt';
|
||||
import ngZh from '@angular/common/locales/zh';
|
||||
import ngZhTw from '@angular/common/locales/zh-Hant';
|
||||
import { Injectable } from '@angular/core';
|
||||
@@ -18,16 +17,9 @@ import {
|
||||
ja_JP as delonJaJP
|
||||
} from '@delon/theme';
|
||||
import { AlainConfigService } from '@delon/util/config';
|
||||
import { enUS as dfEn, zhCN as dfZhCn, zhTW as dfZhTw, ja as dfJa, ptBR as dfPtBR } from 'date-fns/locale';
|
||||
import { enUS as dfEn, zhCN as dfZhCn, zhTW as dfZhTw, ja as dfJa } from 'date-fns/locale';
|
||||
import { NzSafeAny } from 'ng-zorro-antd/core/types';
|
||||
import {
|
||||
en_US as zorroEnUS,
|
||||
NzI18nService,
|
||||
zh_CN as zorroZhCN,
|
||||
zh_TW as zorroZhTW,
|
||||
ja_JP as zorroJaJP,
|
||||
pt_BR as zorroPtBR
|
||||
} from 'ng-zorro-antd/i18n';
|
||||
import { en_US as zorroEnUS, NzI18nService, zh_CN as zorroZhCN, zh_TW as zorroZhTW, ja_JP as zorroJaJP } from 'ng-zorro-antd/i18n';
|
||||
import { Observable, zip } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
@@ -75,14 +67,6 @@ const LANGS: { [key: string]: LangConfigData } = {
|
||||
date: dfJa,
|
||||
delon: delonJaJP,
|
||||
abbr: '🇯🇵'
|
||||
},
|
||||
'pt-BR': {
|
||||
text: 'Português (Brasil)',
|
||||
ng: ngPt,
|
||||
zorro: zorroPtBR,
|
||||
date: dfPtBR,
|
||||
delon: delonEnUS, // Usando en-US como fallback (ou crie um locale personalizado)
|
||||
abbr: '🇧🇷'
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ import { GeneralConfigService } from '../../../service/general-config.service';
|
||||
ngClass="alain-default__nav-item-icon"
|
||||
(click)="toggleMute($event)"
|
||||
nz-tooltip
|
||||
[nzTooltipTitle]="(mute.mute ? 'common.unmute' : 'common.mute') | i18n"
|
||||
[nzTooltipTitle]="'common.mute' | i18n"
|
||||
></i>
|
||||
</nz-badge>
|
||||
</div>
|
||||
@@ -156,17 +156,13 @@ export class HeaderNotifyComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
);
|
||||
this.loadData();
|
||||
this.initAlertSSEConnection();
|
||||
this.initManagerSSEConnection();
|
||||
this.initSSEConnection();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
if (this.refreshInterval) {
|
||||
clearInterval(this.refreshInterval);
|
||||
}
|
||||
if (this.eventSource) {
|
||||
this.eventSource.close();
|
||||
}
|
||||
}
|
||||
|
||||
onPopoverVisibleChange(visible: boolean): void {
|
||||
@@ -232,6 +228,24 @@ export class HeaderNotifyComponent implements OnInit, OnDestroy {
|
||||
);
|
||||
}
|
||||
|
||||
updateAlertsStatus(alertIds: Set<number>, status: string) {
|
||||
const markAlertsStatus$ = this.alertSvc.applyGroupAlertsStatus(alertIds, status).subscribe(
|
||||
message => {
|
||||
markAlertsStatus$.unsubscribe();
|
||||
if (message.code === 0) {
|
||||
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.mark-success'), '');
|
||||
this.loadData();
|
||||
} else {
|
||||
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.mark-fail'), message.msg);
|
||||
}
|
||||
},
|
||||
error => {
|
||||
markAlertsStatus$.unsubscribe();
|
||||
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.mark-fail'), error.msg);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
gotoAlertCenter(): void {
|
||||
this.popoverVisible = false;
|
||||
this.router.navigateByUrl(`/alert/center`);
|
||||
@@ -272,7 +286,7 @@ export class HeaderNotifyComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
private initAlertSSEConnection(): void {
|
||||
private initSSEConnection(): void {
|
||||
const sseUrl = '/api/alert/sse/subscribe';
|
||||
|
||||
this.eventSource = new EventSource(sseUrl);
|
||||
@@ -300,37 +314,7 @@ export class HeaderNotifyComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
this.eventSource.onerror = error => {
|
||||
console.error('SSE connection error:', error);
|
||||
this.eventSource.close();
|
||||
};
|
||||
}
|
||||
|
||||
private initManagerSSEConnection(): void {
|
||||
const sseUrl = '/api/manager/sse/subscribe';
|
||||
this.eventSource = new EventSource(sseUrl);
|
||||
this.eventSource.addEventListener('IMPORT_TASK_EVENT', (evt: MessageEvent) => {
|
||||
let msg = JSON.parse(evt.data);
|
||||
if (msg.notifyLevel === 'SUCCESS') {
|
||||
this.notifySvc.success(
|
||||
this.i18nSvc.fanyi('common.notice'),
|
||||
this.i18nSvc.fanyi('common.notify.import-success-detail', { taskName: msg.taskName })
|
||||
);
|
||||
} else if (msg.notifyLevel === 'ERROR') {
|
||||
this.notifySvc.error(
|
||||
this.i18nSvc.fanyi('common.notice'),
|
||||
this.i18nSvc.fanyi('common.notify.import-fail-detail', { taskName: msg.taskName, errMsg: msg.errMsg })
|
||||
);
|
||||
} else if (msg.notifyLevel === 'INFO') {
|
||||
this.notifySvc.info(
|
||||
this.i18nSvc.fanyi('common.notice'),
|
||||
this.i18nSvc.fanyi('common.notify.import-progress', { taskName: msg.taskName, progress: msg.progress })
|
||||
);
|
||||
} else {
|
||||
console.error('Parse message error, msg:', evt.data);
|
||||
}
|
||||
});
|
||||
this.eventSource.onerror = error => {
|
||||
console.error('Manager SSE connection error:', error);
|
||||
this.eventSource.close();
|
||||
setTimeout(() => this.initSSEConnection(), 3000);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
*/
|
||||
|
||||
import { AlibabaSmsConfig } from './AlibabaSmsConfig';
|
||||
import { SmslocalSmsConfig } from './SmslocalSmsConfig';
|
||||
import { TencentSmsConfig } from './TencentSmsConfig';
|
||||
import { UniSmsConfig } from './UniSmsConfig';
|
||||
import { SmsType } from './enums/sms-type.enum';
|
||||
@@ -29,7 +28,6 @@ export class SmsNoticeSender {
|
||||
tencent: TencentSmsConfig = new TencentSmsConfig();
|
||||
alibaba: AlibabaSmsConfig = new AlibabaSmsConfig();
|
||||
unisms: UniSmsConfig = new UniSmsConfig();
|
||||
smslocal: SmslocalSmsConfig = new SmslocalSmsConfig();
|
||||
enable: boolean = false;
|
||||
creator!: string;
|
||||
modifier!: string;
|
||||
|
||||
@@ -1,22 +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.
|
||||
*/
|
||||
|
||||
export class SmslocalSmsConfig {
|
||||
apiKey!: string;
|
||||
}
|
||||
@@ -20,8 +20,7 @@
|
||||
export enum SmsType {
|
||||
TENCENT = 'tencent',
|
||||
ALIBABA = 'alibaba',
|
||||
UNISMS = 'unisms',
|
||||
SMSLOCAL = 'smslocal'
|
||||
UNISMS = 'unisms'
|
||||
}
|
||||
|
||||
export enum UniSmsAuthMode {
|
||||
|
||||
@@ -144,9 +144,7 @@ export class MonitorEditComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
define.name = this.i18nSvc.fanyi(`monitor.app.${this.monitor.app}.param.${define.field}`);
|
||||
if (define.placeholder == null && this.i18nSvc.fanyi(`monitor.${define.field}.tip`) != `monitor.${define.field}.tip`) {
|
||||
define.placeholder = this.i18nSvc.fanyi(`monitor.${define.field}.tip`);
|
||||
}
|
||||
define.placeholder = define.placeholder && this.i18nSvc.fanyi(`monitor.${define.field}.tip`);
|
||||
if (define.hide) {
|
||||
advancedParams.push(param);
|
||||
advancedParamDefines.push(define);
|
||||
|
||||
@@ -169,7 +169,7 @@
|
||||
<tbody>
|
||||
<tr *ngFor="let data of fixedTable.data">
|
||||
<td nzAlign="center" nzLeft [nzChecked]="checkedMonitorIds.has(data.id)" (nzCheckedChange)="onItemChecked(data.id, $event)"></td>
|
||||
<td nzAlign="center" nzEllipsis>
|
||||
<td nzAlign="center">
|
||||
<button nz-button nzSize="default" nzType="link" [routerLink]="['/monitors/' + data.id]">
|
||||
{{ data.name }}
|
||||
<span nz-icon nzType="area-chart"></span>
|
||||
@@ -189,7 +189,7 @@
|
||||
<span>{{ 'monitor.status.down' | i18n }}</span>
|
||||
</nz-tag>
|
||||
</td>
|
||||
<td nzAlign="center" nzEllipsis>
|
||||
<td nzAlign="center">
|
||||
<button
|
||||
nz-button
|
||||
nzSize="default"
|
||||
|
||||
@@ -265,20 +265,15 @@ export class MonitorListComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
onImportMonitors(info: NzUploadChangeParam): void {
|
||||
console.log(info.type);
|
||||
if (info.type === 'start') {
|
||||
this.notifySvc.info(
|
||||
this.i18nSvc.fanyi('common.notice'),
|
||||
this.i18nSvc.fanyi('common.notify.import-submitted', { taskName: info.file.name })
|
||||
);
|
||||
}
|
||||
if (info.type === 'success' && info.file.response) {
|
||||
if (info.file.response) {
|
||||
this.tableLoading = true;
|
||||
const message = info.file.response;
|
||||
if (message.code === 0) {
|
||||
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.import-success'), '');
|
||||
this.loadMonitorTable();
|
||||
} else {
|
||||
this.tableLoading = false;
|
||||
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.import-fail'), message.msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,9 +112,7 @@ export class MonitorNewComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
define.name = this.i18nSvc.fanyi(`monitor.app.${this.monitor.app}.param.${define.field}`);
|
||||
if (define.placeholder == null && this.i18nSvc.fanyi(`monitor.${define.field}.tip`) != `monitor.${define.field}.tip`) {
|
||||
define.placeholder = this.i18nSvc.fanyi(`monitor.${define.field}.tip`);
|
||||
}
|
||||
define.placeholder = define.placeholder && this.i18nSvc.fanyi(`monitor.${define.field}.tip`);
|
||||
if (define.hide) {
|
||||
advancedParams.push(param);
|
||||
advancedParamDefines.push(define);
|
||||
|
||||
+1
-20
@@ -139,7 +139,7 @@
|
||||
</div>
|
||||
</nz-modal>
|
||||
|
||||
<!-- sms server model -->
|
||||
<!-- sms server modal -->
|
||||
<nz-modal
|
||||
[(nzVisible)]="isSmsServerModalVisible"
|
||||
[nzTitle]="'settings.server.sms.setting' | i18n"
|
||||
@@ -158,12 +158,9 @@
|
||||
<nz-option [nzValue]="SmsType.TENCENT" nzLabel="{{ 'alert.notice.sender.sms.type.tencent' | i18n }}"></nz-option>
|
||||
<nz-option [nzValue]="SmsType.ALIBABA" nzLabel="{{ 'alert.notice.sender.sms.type.alibaba' | i18n }}"></nz-option>
|
||||
<nz-option [nzValue]="SmsType.UNISMS" nzLabel="{{ 'alert.notice.sender.sms.type.unisms' | i18n }}"></nz-option>
|
||||
<nz-option [nzValue]="SmsType.SMSLOCAL" nzLabel="{{ 'alert.notice.sender.sms.type.smslocal' | i18n }}"></nz-option>
|
||||
</nz-select>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
|
||||
<!-- Tencent SMS -->
|
||||
<ng-container *ngIf="smsType === SmsType.TENCENT">
|
||||
<nz-form-item>
|
||||
<nz-form-label [nzSpan]="7" nzFor="secretId" nzRequired="true">
|
||||
@@ -204,8 +201,6 @@
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
</ng-container>
|
||||
|
||||
<!-- Alibaba SMS -->
|
||||
<ng-container *ngIf="smsType === SmsType.ALIBABA">
|
||||
<nz-form-item>
|
||||
<nz-form-label [nzSpan]="7" nzFor="accessKeyId" nzRequired="true">
|
||||
@@ -261,8 +256,6 @@
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
</ng-container>
|
||||
|
||||
<!-- UniSMS -->
|
||||
<ng-container *ngIf="smsType === SmsType.UNISMS">
|
||||
<nz-form-item>
|
||||
<nz-form-label [nzSpan]="7" nzFor="accessKeyId" nzRequired="true">
|
||||
@@ -324,18 +317,6 @@
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
</ng-container>
|
||||
|
||||
<!-- Smslocal SMS -->
|
||||
<ng-container *ngIf="smsType === SmsType.SMSLOCAL">
|
||||
<nz-form-item>
|
||||
<nz-form-label [nzSpan]="7" nzFor="apiKey" nzRequired="true">
|
||||
{{ 'alert.notice.sender.sms.smslocal.apiKey' | i18n }}
|
||||
</nz-form-label>
|
||||
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
|
||||
<input [(ngModel)]="smsNoticeSender.smslocal.apiKey" nz-input required name="apiKey" type="password" id="apiKey" />
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
</ng-container>
|
||||
<nz-form-item>
|
||||
<nz-form-label nzSpan="7" nzFor="smsEnable" nzRequired="true">{{ 'common.enable' | i18n }}</nz-form-label>
|
||||
<nz-form-control nzSpan="12">
|
||||
|
||||
@@ -31,7 +31,6 @@ import { UniSmsConfig } from 'src/app/pojo/UniSmsConfig';
|
||||
import { SmsType, UniSmsAuthMode } from 'src/app/pojo/enums/sms-type.enum';
|
||||
|
||||
import { EmailNoticeSender } from '../../../../pojo/EmailNoticeSender';
|
||||
import { SmslocalSmsConfig } from '../../../../pojo/SmslocalSmsConfig';
|
||||
import { GeneralConfigService } from '../../../../service/general-config.service';
|
||||
|
||||
@Component({
|
||||
@@ -143,7 +142,6 @@ export class MessageServerComponent implements OnInit {
|
||||
this.smsNoticeSender.tencent = { ...new TencentSmsConfig(), ...message.data.tencent };
|
||||
this.smsNoticeSender.alibaba = { ...new AlibabaSmsConfig(), ...message.data.alibaba };
|
||||
this.smsNoticeSender.unisms = { ...new UniSmsConfig(), ...message.data.unisms };
|
||||
this.smsNoticeSender.smslocal = { ...new SmslocalSmsConfig(), ...message.data.smslocal };
|
||||
this.smsType = message.data.type || 'tencent';
|
||||
} else {
|
||||
this.smsNoticeSender = new SmsNoticeSender();
|
||||
@@ -167,8 +165,7 @@ export class MessageServerComponent implements OnInit {
|
||||
...this.smsNoticeSender,
|
||||
tencent: { ...this.smsNoticeSender.tencent },
|
||||
alibaba: { ...this.smsNoticeSender.alibaba },
|
||||
unisms: { ...this.smsNoticeSender.unisms },
|
||||
smslocal: { ...this.smsNoticeSender.smslocal }
|
||||
unisms: { ...this.smsNoticeSender.unisms }
|
||||
};
|
||||
this.isSmsServerModalVisible = true;
|
||||
}
|
||||
@@ -179,8 +176,7 @@ export class MessageServerComponent implements OnInit {
|
||||
...this.tempSmsNoticeSender,
|
||||
tencent: { ...this.tempSmsNoticeSender.tencent },
|
||||
alibaba: { ...this.tempSmsNoticeSender.alibaba },
|
||||
unisms: { ...this.tempSmsNoticeSender.unisms },
|
||||
smslocal: { ...this.tempSmsNoticeSender.smslocal }
|
||||
unisms: { ...this.tempSmsNoticeSender.unisms }
|
||||
};
|
||||
this.isSmsServerModalVisible = false;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
<nz-option [nzValue]="'zh_CN'" [nzLabel]="'settings.system-config.locale.zh_CN' | i18n"></nz-option>
|
||||
<nz-option [nzValue]="'zh_TW'" [nzLabel]="'settings.system-config.locale.zh_TW' | i18n"></nz-option>
|
||||
<nz-option [nzValue]="'ja_JP'" [nzLabel]="'settings.system-config.locale.ja-JP' | i18n"></nz-option>
|
||||
<nz-option [nzValue]="'pt_BR'" [nzLabel]="'settings.system-config.locale.pt_BR' | i18n"></nz-option>
|
||||
</nz-select>
|
||||
</se>
|
||||
<se [label]="'settings.system-config.timezone' | i18n" [error]="'validation.required' | i18n">
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
"alert.center.filter-priority": "Alert Priority",
|
||||
"alert.center.filter-status": "Alert Status",
|
||||
"alert.center.first-time": "Start Time",
|
||||
"alert.center.labels": "Labels",
|
||||
"alert.center.labels": "Tags",
|
||||
"alert.center.last-time": "Active Time",
|
||||
"alert.center.monitor": "Belong Monitor",
|
||||
"alert.center.no-deal": "Mark Pending",
|
||||
@@ -124,8 +124,8 @@
|
||||
"alert.notice.rule.period.no-limit": "Unlimited",
|
||||
"alert.notice.rule.priority": "Priority Match",
|
||||
"alert.notice.rule.priority.placeholder": "Select Priorities",
|
||||
"alert.notice.rule.tag": "Label Match",
|
||||
"alert.notice.rule.tag.placeholder": "Select Labels",
|
||||
"alert.notice.rule.tag": "Tag Match",
|
||||
"alert.notice.rule.tag.placeholder": "Select Tags",
|
||||
"alert.notice.rule.time": "Notification Time",
|
||||
"alert.notice.rule.time-end": "End time",
|
||||
"alert.notice.rule.time-start": "Start time",
|
||||
@@ -153,12 +153,10 @@
|
||||
"alert.notice.sender.sms.unisms.signature": "UniSMS Signature",
|
||||
"alert.notice.sender.sms.unisms.templateId": "UniSMS TemplateId",
|
||||
"alert.notice.sender.sms.unisms.authMode": "UniSMS Authentication Mode",
|
||||
"alert.notice.sender.sms.smslocal.apiKey": "Smslocal ApiKey",
|
||||
"alert.notice.sender.sms.type": "Sms Type",
|
||||
"alert.notice.sender.sms.type.alibaba": "Alibaba Sms",
|
||||
"alert.notice.sender.sms.type.tencent": "Tencent Sms",
|
||||
"alert.notice.sender.sms.type.unisms": "UniSMS",
|
||||
"alert.notice.sender.sms.type.smslocal": "Smslocal Sms",
|
||||
"alert.notice.template": "Notice Template",
|
||||
"alert.notice.template.content": "Template Content",
|
||||
"alert.notice.template.delete": "Delete Template",
|
||||
@@ -312,7 +310,7 @@
|
||||
"alert.severity.all": "All Severity",
|
||||
"alert.silence.delete": "Delete Silence Strategy",
|
||||
"alert.silence.edit": "Edit Silence Strategy",
|
||||
"alert.silence.labels": "Label Match",
|
||||
"alert.silence.labels": "Tag Match",
|
||||
"alert.silence.match-all": "Match All",
|
||||
"alert.silence.name": "Silence Strategy Name",
|
||||
"alert.silence.new": "New Silence Strategy",
|
||||
@@ -439,7 +437,6 @@
|
||||
"common.file.select": "Select File",
|
||||
"common.ignore": "Ignore",
|
||||
"common.mute": "Mute",
|
||||
"common.unmute": "Unmute",
|
||||
"common.name": "Metric Name",
|
||||
"common.new-time": "Create Time",
|
||||
"common.no": "No",
|
||||
@@ -462,10 +459,6 @@
|
||||
"common.notify.export-success": "Export Success!",
|
||||
"common.notify.import-fail": "Import Failed!",
|
||||
"common.notify.import-success": "Import Success!",
|
||||
"common.notify.import-fail-detail": "Import [{{taskName}}] Failed: [{{errMsg}}]",
|
||||
"common.notify.import-success-detail": "Import [{{taskName}}] Success!",
|
||||
"common.notify.import-submitted": "Import [{{taskName}}] Submitted!",
|
||||
"common.notify.import-progress": "Importing [{{taskName}}], progress: {{progress}}%",
|
||||
"common.notify.mark-fail": "Mark Failed!",
|
||||
"common.notify.mark-success": "Mark Success!",
|
||||
"common.notify.new-fail": "Add Failed!",
|
||||
@@ -779,7 +772,6 @@
|
||||
"settings.system-config.locale.zh_CN": "Simplified Chinese(zh_CN)",
|
||||
"settings.system-config.locale.zh_TW": "Traditional Chinese(zh_TW)",
|
||||
"settings.system-config.locale.ja-JP": "Japanese(ja_JP)",
|
||||
"settings.system-config.locale.pt_BR": "Portuguese(pt_BR)",
|
||||
"settings.system-config.ok": "Confirm Update",
|
||||
"settings.system-config.theme": "System Theme",
|
||||
"settings.system-config.theme.compact": "Compact Theme",
|
||||
@@ -805,7 +797,7 @@
|
||||
"status.component.state.0": "Normal",
|
||||
"status.component.state.1": "Abnormal",
|
||||
"status.component.state.2": "Unknown",
|
||||
"status.component.tag": "Match Label",
|
||||
"status.component.tag": "Match Tag",
|
||||
"status.component.tag.tip": "Status calculation associates the label, and uses all monitoring availability status associated with the label as data to calculate the service status of this component.",
|
||||
"status.help": "Quickly build a powerful status page based on HertzBeat to easily communicate the real-time status of your services to users. For example, the status page provided by Github <a href='https://www.githubstatus.com'> https://www.githubstatus.com</a>. <br>Supports linkage and synchronization of status page component status and monitoring status, fault event maintenance and management mechanism, etc. Improve your transparency, professionalism and user trust, and reduce communication costs.",
|
||||
"status.help.link": "https://hertzbeat.apache.org/docs/help/status",
|
||||
@@ -854,7 +846,7 @@
|
||||
"status.public.to-component": "Status Page",
|
||||
"status.public.to-incident": "Incident History",
|
||||
"status.public.today": "Today",
|
||||
"tag": "Label",
|
||||
"tag": "Tag",
|
||||
"validation.confirm-password.required": "Please confirm your password!",
|
||||
"validation.date.required": "Please select the start and end date",
|
||||
"validation.email.invalid": "Invalid email!",
|
||||
|
||||
@@ -153,12 +153,10 @@
|
||||
"alert.notice.sender.sms.unisms.signature": "UniSMS Signature",
|
||||
"alert.notice.sender.sms.unisms.templateId": "UniSMS TemplateId",
|
||||
"alert.notice.sender.sms.unisms.authMode": "UniSMS認証モード",
|
||||
"alert.notice.sender.sms.smslocal.apiKey": "Smslocal ApiKey",
|
||||
"alert.notice.sender.sms.type": "SMSタイプ",
|
||||
"alert.notice.sender.sms.type.alibaba": "Alibaba Sms",
|
||||
"alert.notice.sender.sms.type.tencent": "Tencent Sms",
|
||||
"alert.notice.sender.sms.type.unisms": "UniSMS",
|
||||
"alert.notice.sender.sms.type.smslocal": "Smslocal Sms",
|
||||
"alert.notice.template": "通知テンプレート",
|
||||
"alert.notice.template.content": "テンプレート内容",
|
||||
"alert.notice.template.delete": "テンプレートを削除",
|
||||
@@ -439,7 +437,6 @@
|
||||
"common.file.select": "ファイルを選択",
|
||||
"common.ignore": "無視",
|
||||
"common.mute": "ミュート",
|
||||
"common.unmute": "ミュート解除",
|
||||
"common.name": "メトリック名",
|
||||
"common.new-time": "作成時間",
|
||||
"common.no": "いいえ",
|
||||
@@ -462,10 +459,6 @@
|
||||
"common.notify.export-success": "エクスポートに成功しました!",
|
||||
"common.notify.import-fail": "インポートに失敗しました!",
|
||||
"common.notify.import-success": "インポートに成功しました!",
|
||||
"common.notify.import-fail-detail": "[{{taskName}}]のインポートに失敗しました: [{{errMsg}}]",
|
||||
"common.notify.import-success-detail": "[{{taskName}}]のインポートが成功しました!",
|
||||
"common.notify.import-submitted": "インポートタスク[{{taskName}}]が送信されました!",
|
||||
"common.notify.import-progress": "[{{taskName}}]のインポート中、進捗状況: {{progress}}%",
|
||||
"common.notify.mark-fail": "マークに失敗しました!",
|
||||
"common.notify.mark-success": "マークに成功しました!",
|
||||
"common.notify.new-fail": "追加に失敗しました!",
|
||||
@@ -779,7 +772,6 @@
|
||||
"settings.system-config.locale.zh_CN": "簡体字中国語(zh_CN)",
|
||||
"settings.system-config.locale.zh_TW": "繁体字中国語(zh_TW)",
|
||||
"settings.system-config.locale.ja-JP": "日本語(ja_JP)",
|
||||
"settings.system-config.locale.pt_BR": "Português(pt_BR)",
|
||||
"settings.system-config.ok": "更新を確認",
|
||||
"settings.system-config.theme": "システムテーマ",
|
||||
"settings.system-config.theme.compact": "コンパクトテーマ",
|
||||
|
||||
@@ -1,770 +0,0 @@
|
||||
{
|
||||
"menu": {
|
||||
"main": "Principal",
|
||||
"lang": "Idioma",
|
||||
"dashboard": "Painel",
|
||||
"search.placeholder": "Pesquisar: Tarefa de Monitoramento: Nome, Host, etc",
|
||||
"fullscreen": "Tela Cheia",
|
||||
"fullscreen.exit": "Sair",
|
||||
"clear.local.storage": "Limpar Armazenamento Local",
|
||||
"monitor": {
|
||||
"": "Monitoramento",
|
||||
"center": "Centro de Monitoramento",
|
||||
"bulletin": "Boletim",
|
||||
"service": "Monitor de Serviço",
|
||||
"db": "Monitor de Banco de Dados",
|
||||
"os": "Monitor de Sistema Operacional",
|
||||
"mid": "Monitor de Middleware",
|
||||
"cn": "Nativo da Nuvem",
|
||||
"network": "Monitor de Rede",
|
||||
"custom": "Monitor Personalizado",
|
||||
"prometheus": "Tarefa Prometheus",
|
||||
"program": "Monitor de Programa",
|
||||
"webserver": "Monitor de Servidor Web",
|
||||
"cache": "Monitor de Cache",
|
||||
"bigdata": "Monitor de Big Data",
|
||||
"promql": "Consulta de Dados",
|
||||
"llm": "AI LLM",
|
||||
"server": "Monitor de Servidor"
|
||||
},
|
||||
"account": {
|
||||
"": "Pessoal",
|
||||
"center": "Centro Pessoal",
|
||||
"settings": "Configurações da Conta",
|
||||
"security": "Configurações de Segurança",
|
||||
"binding": "Vinculação de Conta",
|
||||
"trigger": "Disparar Erro",
|
||||
"logout": "Sair"
|
||||
},
|
||||
"alert": {
|
||||
"": "Alertas",
|
||||
"center": "Centro de Alarmes",
|
||||
"converge": "Convergência de Alarmes",
|
||||
"setting": "Regra de Limite",
|
||||
"silence": "Silenciar Alarme",
|
||||
"dispatch": "Notificação"
|
||||
},
|
||||
"advanced": {
|
||||
"": "Avançado",
|
||||
"collector": "Cluster de Coletores",
|
||||
"tags": "Gerenciar Tags",
|
||||
"define": "Modelo de Monitoramento",
|
||||
"status": "Página de Status",
|
||||
"plugins": "Gerenciar Plugins"
|
||||
},
|
||||
"extras": {
|
||||
"": "Mais",
|
||||
"help": "Centro de Ajuda",
|
||||
"setting": "Configuração",
|
||||
"settings": "Configurações",
|
||||
"about": "Sobre"
|
||||
},
|
||||
"more": "Mais"
|
||||
},
|
||||
"monitor": {
|
||||
"": "Monitor",
|
||||
"availability": "Disponibilidade do Monitor",
|
||||
"name": "Nome da Tarefa",
|
||||
"name.tip": "Nome da tarefa de monitoramento",
|
||||
"host": "Host de Destino",
|
||||
"host.tip": "O IP ou domínio do peer monitorado",
|
||||
"description": "Descrição",
|
||||
"description.tip": "Descrição e observações",
|
||||
"intervals": "Intervalos",
|
||||
"intervals.tip": "Intervalo de tempo para coleta periódica de dados, em segundos",
|
||||
"collector": "Coletor",
|
||||
"collector.tip": "Escolha qual coletor despachar para este monitoramento",
|
||||
"collector.system.default": "Despacho Padrão do Sistema",
|
||||
"collector.status.online": "Online",
|
||||
"collector.status.offline": "Offline",
|
||||
"category": {
|
||||
"": "Categoria",
|
||||
"server": "Monitor de Servidor",
|
||||
"service": "Serviço",
|
||||
"db": "Banco de Dados",
|
||||
"os": "Sistema Operacional",
|
||||
"mid": "Middleware",
|
||||
"cn": "Nativo da Nuvem",
|
||||
"network": "Rede",
|
||||
"custom": "Personalizado",
|
||||
"program": "Aplicação",
|
||||
"webserver": "Servidor Web",
|
||||
"cache": "Cache",
|
||||
"bigdata": "Big Data",
|
||||
"auto": "Tarefa Automática"
|
||||
},
|
||||
"app": {
|
||||
"": "Tipo de Monitor",
|
||||
"website": "Monitor de Site",
|
||||
"api": "API HTTP",
|
||||
"http": "API HTTP",
|
||||
"ping": "Conexão PING",
|
||||
"port": "Porta Disponível",
|
||||
"mysql": "MySQL",
|
||||
"oracle": "Oracle",
|
||||
"redis": "Redis",
|
||||
"fullsite": "Monitor de Mapa do Site"
|
||||
},
|
||||
"status": {
|
||||
"": "Status da Tarefa",
|
||||
"all": "Todos os Status",
|
||||
"up": "Ativo",
|
||||
"down": "Inativo",
|
||||
"unreachable": "Inacessível",
|
||||
"paused": "Pausado"
|
||||
},
|
||||
"grafana": {
|
||||
"enabled.tip": "está habilitado, os dados de monitoramento serão exibidos no Grafana",
|
||||
"enabled.label": "Habilitar Grafana",
|
||||
"upload.tip": "Carregar arquivo de modelo do Grafana, suporta arquivo .json",
|
||||
"upload.label": "Carregar Modelo do Grafana"
|
||||
}
|
||||
},
|
||||
"alert": {
|
||||
"": "Alerta",
|
||||
"status": {
|
||||
"": "Status do Alerta",
|
||||
"all": "Todos os Status",
|
||||
"0": "Pendente",
|
||||
"2": "Restaurado",
|
||||
"3": "Processado"
|
||||
},
|
||||
"priority": {
|
||||
"": "Prioridade do Alarme",
|
||||
"all": "Todas as Prioridades",
|
||||
"0": "Emergência",
|
||||
"1": "Crítico",
|
||||
"2": "Aviso"
|
||||
}
|
||||
},
|
||||
"bulletin": {
|
||||
"new": "Novo Boletim",
|
||||
"edit": "Editar Boletim",
|
||||
"delete": "Excluir Boletim",
|
||||
"batch.delete": "Excluir Boletins em Lote",
|
||||
"name": "Nome do Boletim",
|
||||
"name.placeholder": "Digite um nome personalizado para o boletim",
|
||||
"monitor.type": "Tipo de Monitor",
|
||||
"monitor.name": "Nome da Tarefa de Monitoramento",
|
||||
"monitor.metrics": "Métricas de Monitoramento",
|
||||
"help.content": "Boletim de monitoramento personalizado (beta), exibindo métricas selecionadas de um monitor específico em forma de tabela",
|
||||
"help.link": ""
|
||||
},
|
||||
"question.link": "https://hertzbeat.apache.org/docs/help/issue/",
|
||||
"alert.setting.new": "Nova Regra de Limite",
|
||||
"alert.setting.edit": "Editar Regra de Limite",
|
||||
"alert.setting.delete": "Excluir Regra de Limite",
|
||||
"alert.setting.export": "Exportar Regra",
|
||||
"alert.setting.import": "Importar Regra",
|
||||
"alert.setting.target": "Métrica Alvo",
|
||||
"alert.setting.target.place-holder": "Pesquise ou selecione a métrica alvo",
|
||||
"alert.setting.expr": "Expressão de Disparo do Limite",
|
||||
"alert.setting.trigger": "Disparar alarmes e atualizar o status do monitor",
|
||||
"alert.setting.rule": "Regra de Limite",
|
||||
"alert.setting.number": "Numérico",
|
||||
"alert.setting.string": "Texto",
|
||||
"alert.setting.time": "Tempo",
|
||||
"alert.setting.rule.label": "Configuração gráfica de regras de limite de alarme, suporta múltiplas regras &&",
|
||||
"alert.setting.rule.metric.place-holder": "Selecione a métrica",
|
||||
"alert.setting.rule.switch-expr.0": "Limite de Modelo",
|
||||
"alert.setting.rule.switch-expr.1": "Limite de Codificação",
|
||||
"alert.setting.rule.operator": "Operador",
|
||||
"alert.setting.rule.operator.str-equals": "igual",
|
||||
"alert.setting.rule.operator.str-no-equals": "não igual",
|
||||
"alert.setting.rule.operator.str-contains": "contém",
|
||||
"alert.setting.rule.operator.str-no-contains": "não contém",
|
||||
"alert.setting.rule.operator.str-matches": "corresponde",
|
||||
"alert.setting.rule.operator.str-no-matches": "não corresponde",
|
||||
"alert.setting.rule.operator.exists": "valor existe",
|
||||
"alert.setting.rule.operator.no-exists": "valor não existe",
|
||||
"alert.setting.rule.string-value.place-holder": "Digite o texto",
|
||||
"alert.setting.rule.numeric-value.place-holder": "Digite o número",
|
||||
"alert.setting.times": "Número de Disparos",
|
||||
"alert.setting.times.tip": "Defina quantas vezes o limite deve ser disparado antes de enviar um alerta",
|
||||
"alert.setting.template": "Modelo de Notificação",
|
||||
"alert.setting.template.tip": "Variáveis de ambiente de modelo de notificação suportadas",
|
||||
"alert.setting.template.label": "O modelo de informação de notificação enviado após o disparo do alarme, veja as variáveis de ambiente do modelo acima",
|
||||
"alert.setting.template.example": "Digite o modelo de notificação. Ex: ${app}.${metrics}.${metric} valor está muito alto",
|
||||
"alert.setting.template.monitor-type": "Nome do Tipo de Monitor",
|
||||
"alert.setting.template.metrics-name": "Nome da Métrica",
|
||||
"alert.setting.template.metric-name": "Nome da Métrica",
|
||||
"alert.setting.template.metric-value": "Valor da Métrica",
|
||||
"alert.setting.template.other-value": "Outro Valor da Métrica",
|
||||
"alert.setting.default": "Padrão Global",
|
||||
"alert.setting.default.tip": "Se esta configuração de limite de alarme se aplica a todos os monitoramentos deste tipo globalmente",
|
||||
"alert.setting.enable": "Habilitar Limite",
|
||||
"alert.setting.enable.tip": "Esta configuração de limite de alarme está habilitada ou desabilitada",
|
||||
"alert.setting.recover-notice": "Notificação de Recuperação",
|
||||
"alert.setting.recover-notice.tip": "Se deve enviar a notificação correspondente quando o alarme for resolvido sob esta regra de limite",
|
||||
"alert.setting.connect": "Associar Monitores ao Limite de Alarme",
|
||||
"alert.setting.connect.left": "Não Associado",
|
||||
"alert.setting.connect.right": "Associado",
|
||||
"alert.setting.expr.tip": "Variáveis de ambiente e operadores suportados na expressão de disparo do limite",
|
||||
"alert.setting.expr.label": "Calcule e julgue se o limite foi disparado de acordo com esta expressão. As variáveis de ambiente e operadores da expressão são mostrados acima.",
|
||||
"alert.setting.expr.example": "Calcule se o limite foi disparado de acordo com esta expressão. Ex",
|
||||
"alert.setting.priority.tip": "O nível de alarme que dispara o limite, do baixo para o alto: Aviso, Crítico, Emergência",
|
||||
"alert.setting.target.tip": "O objeto métrico selecionado",
|
||||
"alert.setting.target.other": "Outros objetos métricos da linha",
|
||||
"alert.setting.target.system_value_row_count": "Contagem de linhas de valor do Sistema-Métricas",
|
||||
"alert.setting.operator": "Funções de operador suportadas",
|
||||
"alert.setting.search": "Pesquisar Limite",
|
||||
"alert.silence.new": "Nova Estratégia de Silêncio",
|
||||
"alert.silence.edit": "Editar Estratégia de Silêncio",
|
||||
"alert.silence.delete": "Excluir Estratégia de Silêncio",
|
||||
"alert.silence.name": "Nome da Estratégia de Silêncio",
|
||||
"alert.silence.match-all": "Corresponder a Todos",
|
||||
"alert.silence.priority": "Corresponder Prioridade",
|
||||
"alert.silence.type.once": "Silêncio Único",
|
||||
"alert.silence.type.cyc": "Silêncio Periódico",
|
||||
"alert.silence.type": "Tipo de Silêncio",
|
||||
"alert.silence.tags": "Corresponder Tags",
|
||||
"alert.silence.time": "Período de Silêncio",
|
||||
"alert.silence.times": "Número de Alertas Silenciados",
|
||||
"alert.silence.enable": "Habilitar Silêncio",
|
||||
"alert.converge.new": "Nova Estratégia de Convergência",
|
||||
"alert.converge.edit": "Editar Estratégia de Convergência",
|
||||
"alert.converge.delete": "Excluir Estratégia de Convergência",
|
||||
"alert.converge.name": "Nome da Estratégia",
|
||||
"alert.converge.match-all": "Corresponder a Todos",
|
||||
"alert.converge.priority": "Corresponder Prioridade",
|
||||
"alert.converge.tags": "Corresponder Tags",
|
||||
"alert.converge.repeat": "Critério de Repetição de Alerta",
|
||||
"alert.converge.repeat-rule": "As tags e a prioridade do alerta são as mesmas",
|
||||
"alert.converge.eval-interval": "Intervalo de Convergência de Repetição de Alerta (s)",
|
||||
"alert.converge.enable": "Habilitar Convergência",
|
||||
"alert.center.delete": "Excluir Alertas",
|
||||
"alert.center.clear": "Limpar Tudo",
|
||||
"alert.center.deal": "Marcar como Processado",
|
||||
"alert.center.no-deal": "Marcar como Pendente",
|
||||
"alert.center.search": "Pesquisar Conteúdo do Alerta",
|
||||
"alert.center.filter-status": "Status do Alerta",
|
||||
"alert.center.filter-priority": "Prioridade do Alerta",
|
||||
"alert.center.target": "Métrica Alvo",
|
||||
"alert.center.monitor": "Monitor Pertence",
|
||||
"alert.center.priority": "Prioridade",
|
||||
"alert.center.content": "Conteúdo do Alerta",
|
||||
"alert.center.tags": "Tags",
|
||||
"alert.center.status": "Status",
|
||||
"alert.center.time": "Hora do Alerta",
|
||||
"alert.center.time.tip": "Alertas foram disparados {{times}} vezes durante este período de alerta",
|
||||
"alert.center.first-time": "Hora de Início",
|
||||
"alert.center.last-time": "Última Hora",
|
||||
"alert.center.confirm.delete": "Confirme se deseja excluir!",
|
||||
"alert.center.confirm.clear-all": "Confirme se deseja limpar todos os alertas!",
|
||||
"alert.center.notify.no-mark": "Nenhum item selecionado para marcação!",
|
||||
"alert.center.confirm.mark-done-batch": "Confirme se deseja marcar como processado em lote!",
|
||||
"alert.center.confirm.mark-done": "Confirme se deseja marcar como processado!",
|
||||
"alert.center.confirm.mark-no-batch": "Confirme se deseja marcar como pendente em lote!",
|
||||
"alert.center.confirm.mark-no": "Confirme se deseja marcar como pendente!",
|
||||
"alert.help.notice": "A notificação é usada para configurar o destinatário da mensagem de alarme e o método de recebimento. A mensagem de alarme será enviada ao destinatário de forma especificada (suporta email, discord, webhook, etc). <a href='https://hertzbeat.apache.org/zh-cn/docs/help/alert_webhook'>Clique aqui para ver os passos de configuração.</a>.<br>“<i>Modelo de Notificação</i>” é o modelo de estrutura de conteúdo da mensagem. O modelo embutido é usado por padrão ou você pode personalizar o modelo para personalizar a estrutura de notificação da mensagem.<br><span class='help_module_span'>Nota⚠\uFE0F: Após configurar o “<i>Destinatário</i>”, você também precisa configurar a “<i>Política de Notificação</i>” para especificar quais mensagens são enviadas para quais destinatários.</span><a href='https://hertzbeat.apache.org/docs/help/alert_email'> Clique aqui para ver possíveis problemas</a>.",
|
||||
"alert.help.notice.link": "https://hertzbeat.apache.org/docs/help/alert_email",
|
||||
"alert.help.converge": "A Convergência de Alarmes suporta a deduplicação e convergência de mensagens de alarme repetidas dentro de um período de tempo especificado. <br> Clique em \"<i>Nova Estratégia de Convergência</i>\" e configure o período de tempo para evitar um grande número de alarmes repetitivos que podem anestesiar o destinatário do alarme.",
|
||||
"alert.help.converge.link": "https://hertzbeat.apache.org",
|
||||
"alert.help.center": "O Centro de Alarmes é o centro de processamento de notificações para todas as mensagens de alarme disparadas, incluindo alarmes disparados por limites internos do sistema e informações de alarme acessadas através de canais de alarme externos de terceiros. <br> O Hertzbeat suporta operações em lote, como consulta de alarmes, marcação de processamento, não processados, exclusão de alarmes e limpeza.",
|
||||
"alert.help.center.link": "https://hertzbeat.apache.org/docs/help/guide",
|
||||
"alert.help.setting": "As Regras de Limite são usadas para o gerenciamento de regras de limite de alarme para métricas. Clique em \"<i>Novo Limite</i>\" para configurar o limite de alarme para métricas de monitoramento. O Hertzbeat disparará alarmes com base no limite e nos dados das métricas.<br>Nota⚠\uFE0F: A mensagem de alarme que foi disparada pode ser verificada no [Centro de Alarmes], e você também pode configurar o método de notificação e os destinatários em [Notificação].",
|
||||
"alert.help.setting.link": "https://hertzbeat.apache.org/docs/help/alert_threshold",
|
||||
"alert.help.silence": "O gerenciamento de Silêncio de Alarmes é usado quando você não quer ser perturbado durante a manutenção do sistema ou nos fins de semana. <br> Clique em \"<i>Nova Estratégia de Silêncio</i>\" e configure o período de tempo para bloquear mensagens para que você não seja perturbado durante os intervalos.",
|
||||
"alert.help.silence.link": "https://hertzbeat.apache.org/docs",
|
||||
"alert.notice.template": "Modelo de Notificação",
|
||||
"alert.notice.template.new": "Novo Modelo",
|
||||
"alert.notice.template.edit": "Editar Modelo",
|
||||
"alert.notice.template.show": "Ver Conteúdo do Modelo",
|
||||
"alert.notice.template.delete": "Excluir Modelo",
|
||||
"alert.notice.template.name": "Nome do Modelo",
|
||||
"alert.notice.template.type": "Tipo de Notificação",
|
||||
"alert.notice.template.preset": "Tipo de Modelo",
|
||||
"alert.notice.template.preset.true": "Pré-definido pelo Sistema",
|
||||
"alert.notice.template.preset.false": "Personalizado pelo Usuário",
|
||||
"alert.notice.template.content": "Conteúdo do Modelo",
|
||||
"alert.notice.template.placeholder": "Selecione um modelo",
|
||||
"alert.notice.receiver": "Destinatário da Notificação",
|
||||
"alert.notice.receiver.new": "Novo Destinatário",
|
||||
"alert.notice.receiver.edit": "Editar Destinatário",
|
||||
"alert.notice.receiver.delete": "Excluir Destinatário",
|
||||
"alert.notice.receiver.people": "Destinatário",
|
||||
"alert.notice.receiver.people.placeholder": "Selecione um destinatário",
|
||||
"alert.notice.receiver.people.name": "Nome do Destinatário",
|
||||
"alert.notice.receiver.type": "Tipo de Notificação",
|
||||
"alert.notice.receiver.type.placeholder": "Selecione um tipo de notificação",
|
||||
"alert.notice.receiver.setting": "Configuração",
|
||||
"alert.notice.receiver.next": "Por favor, configure sua [Política de Notificação de Alerta] no próximo passo!",
|
||||
"alert.notice.type.sms": "SMS",
|
||||
"alert.notice.type.phone": "Telefone",
|
||||
"alert.notice.type.email": "Email",
|
||||
"alert.notice.type.userId": "ID do Usuário",
|
||||
"alert.notice.type.url": "URL",
|
||||
"alert.notice.type.wechat": "Abrir WeChat",
|
||||
"alert.notice.type.wechat-id": "WeChat OPENID",
|
||||
"alert.notice.type.WeCom-robot": "Robô WeCom",
|
||||
"alert.notice.type.WeCom-robot-key": "Chave do Robô WeCom",
|
||||
"alert.notice.type.access-token": "Token de Acesso do Robô",
|
||||
"alert.notice.type.ding": "Robô DingDing",
|
||||
"alert.notice.type.fei-shu": "Robô FeiShu",
|
||||
"alert.notice.type.fei-shu-key": "Chave do Robô FeiShu",
|
||||
"alert.notice.type.telegram-bot": "Bot do Telegram",
|
||||
"alert.notice.type.telegram-bot-token": "Token do Bot do Telegram",
|
||||
"alert.notice.type.telegram-bot-user-id": "ID do Usuário do Telegram",
|
||||
"alert.notice.type.slack": "WebHook do Slack",
|
||||
"alert.notice.type.slack-webHook-url": "URL do WebHook do Slack",
|
||||
"alert.notice.type.discord": "Bot do Discord",
|
||||
"alert.notice.type.discord-bot-token": "Token do Bot do Discord",
|
||||
"alert.notice.type.discord-channel-id": "ID do Canal do Discord",
|
||||
"alert.notice.type.WeComApp": "App WeCom",
|
||||
"alert.notice.type.WeComApp-corpId": "ID da Corporação do App WeCom",
|
||||
"alert.notice.type.WeComApp-agentId": "ID do App WeCom",
|
||||
"alert.notice.type.WeComApp-appSecret": "Segredo do App WeCom",
|
||||
"alert.notice.type.WeComApp-userId": "ID do Usuário (separado por |)",
|
||||
"alert.notice.type.WeComApp-partyId": "ID do Partido (separado por |)",
|
||||
"alert.notice.type.WeComApp-tagId": "ID da Tag (separado por |)",
|
||||
"alert.notice.type.smn": "SMN da Nuvem Huawei",
|
||||
"alert.notice.type.smn-ak": "AK",
|
||||
"alert.notice.type.smn-sk": "SK",
|
||||
"alert.notice.type.smn-projectId": "ID do Projeto",
|
||||
"alert.notice.type.smn-region": "Região",
|
||||
"alert.notice.type.smn-topicUrn": "TopicUrn",
|
||||
"alert.notice.type.serverchan": "ServerChan",
|
||||
"alert.notice.type.serverchan-token": "Token do ServerChan",
|
||||
"alert.notice.type.gotify": "Gotify",
|
||||
"alert.notice.type.gotify-token": "Token do Gotify",
|
||||
"alert.notice.rule": "Política de Notificação",
|
||||
"alert.notice.rule.new": "Nova Política de Notificação",
|
||||
"alert.notice.rule.edit": "Editar Política de Notificação",
|
||||
"alert.notice.rule.delete": "Excluir Política de Notificação",
|
||||
"alert.notice.rule.name": "Nome da Política",
|
||||
"alert.notice.rule.all": "Despachar Todos",
|
||||
"alert.notice.rule.enable": "Habilitar",
|
||||
"alert.notice.rule.tag": "Corresponder Tags",
|
||||
"alert.notice.rule.tag.placeholder": "Selecione Tags",
|
||||
"alert.notice.rule.priority": "Corresponder Prioridades",
|
||||
"alert.notice.rule.priority.placeholder": "Selecione Prioridades",
|
||||
"alert.notice.rule.period": "Período de Tempo",
|
||||
"alert.notice.rule.period-chose": "Escolher Data",
|
||||
"alert.notice.rule.period.no-limit": "Ilimitado",
|
||||
"alert.notice.rule.period.custom": "Personalizado",
|
||||
"alert.notice.rule.time": "Hora da Notificação",
|
||||
"alert.notice.rule.time-start": "Hora de Início",
|
||||
"alert.notice.rule.time-end": "Hora de Término",
|
||||
"alert.notice.send-test": "Enviar Mensagem de Teste de Alerta",
|
||||
"alert.notice.send-test.notify.success": "Envio de Teste de Alerta Bem-sucedido!",
|
||||
"alert.notice.send-test.notify.failed": "Envio de Teste de Alerta Falhou!",
|
||||
"alert.notice.sender.enable": "está Habilitado",
|
||||
"alert.notice.sender.mail.host": "Endereço do Servidor de Email",
|
||||
"alert.notice.sender.mail.username": "Conta de Email",
|
||||
"alert.notice.sender.mail.password": "Senha do Email",
|
||||
"alert.notice.sender.mail.port": "Porta do Email",
|
||||
"alert.notice.sender.mail.ssl": "Habilitar SSL",
|
||||
"alert.notice.sender.mail.starttls": "Habilitar STARTTLS",
|
||||
"alert.notice.sender.mail.enable": "Habilitar Configuração de Email",
|
||||
"alert.notice.sender.sms.type": "Tipo de SMS",
|
||||
"alert.notice.sender.sms.type.tencent": "SMS Tencent",
|
||||
"alert.notice.sender.sms.type.alibaba": "SMS Alibaba",
|
||||
"alert.notice.sender.sms.tencent.secretId": "SecretId do SMS Tencent",
|
||||
"alert.notice.sender.sms.tencent.secretKey": "SecretKey do SMS Tencent",
|
||||
"alert.notice.sender.sms.tencent.signName": "Nome de Assinatura do SMS Tencent",
|
||||
"alert.notice.sender.sms.tencent.appId": "AppId do SMS Tencent",
|
||||
"alert.notice.sender.sms.tencent.templateId": "ID do Modelo do SMS Tencent",
|
||||
"alert.export.switch-type": "Selecione o formato do arquivo de exportação!",
|
||||
"alert.export.use-type": "Exportar regras no formato de arquivo {{type}}",
|
||||
"dashboard.alerts.title": "Lista de Alarmes Recentes",
|
||||
"dashboard.alerts.title-no": "Alarmes Pendentes Recentes",
|
||||
"dashboard.alerts.no": "Nenhum Alarme Pendente",
|
||||
"dashboard.alerts.enter": "Ir para o Centro de Alarmes",
|
||||
"dashboard.alerts.distribute": "A Distribuição dos Alarmes",
|
||||
"dashboard.alerts.num": "Número de Alarmes",
|
||||
"dashboard.alerts.deal": "Tratamento de Alarmes",
|
||||
"dashboard.alerts.deal-percent": "Taxa de Tratamento",
|
||||
"dashboard.monitors.total": "Total de Monitores",
|
||||
"dashboard.monitors.title": "Visão Geral do Monitoramento",
|
||||
"dashboard.monitors.sub-title": "A Distribuição dos Monitores",
|
||||
"dashboard.monitors.formatter": " Monitores ",
|
||||
"dashboard.monitors.distribute": "Distribuição do Monitor",
|
||||
"menu.link.question": "FAQ",
|
||||
"menu.link.guild": "Guia do Usuário",
|
||||
"monitor_icon.center": "laptop",
|
||||
"monitor_icon.service": "appstore",
|
||||
"monitor_icon.db": "console-sql",
|
||||
"monitor_icon.os": "windows",
|
||||
"monitor_icon.mid": "cluster",
|
||||
"monitor_icon.cn": "cloud-server",
|
||||
"monitor_icon.network": "global",
|
||||
"monitor_icon.custom": "project",
|
||||
"monitor_icon.program": "code",
|
||||
"monitor_icon.cache": "group",
|
||||
"monitor_icon.bigdata": "dot-chart",
|
||||
"monitor_icon.webserver": "database",
|
||||
"monitors.center.help": "O Centro de Monitoramento é o portal de gerenciamento de recursos de monitoramento do HertzBeat. Exibe os monitores atualmente adicionados em forma de lista e suporta agrupamento por tags, filtragem de consulta e acesso para visualizar detalhes de monitoramento. <br> Você pode adicionar, modificar, excluir, pausar monitoramento, importar/exportar, gerenciar em lote e outras operações nos monitores.",
|
||||
"monitors.center.help.link": "https://hertzbeat.apache.org/docs/",
|
||||
"monitors.center.search.placeholder": "Pesquisar tipo de monitor para adicionar: Linux, Redis",
|
||||
"monitors.list": "Lista de Monitores",
|
||||
"monitors.spinning-tip.detecting": "Detecção Disponível",
|
||||
"monitors.new": "Novo",
|
||||
"monitors.new-monitor": "Novo Monitor",
|
||||
"monitors.new.success": "Novo Monitor Bem-sucedido",
|
||||
"monitors.new.failed": "Novo Monitor Falhou",
|
||||
"monitors.edit": "Editar",
|
||||
"monitors.edit.success": "Atualização do Monitor Bem-sucedida",
|
||||
"monitors.edit.failed": "Atualização do Monitor Falhou",
|
||||
"monitors.not-found": "Este Monitor Não Encontrado",
|
||||
"monitors.delete": "Excluir",
|
||||
"monitors.edit-monitor": "Editar Monitor",
|
||||
"monitors.delete-monitor": "Excluir Monitor",
|
||||
"monitors.enable": "Retomar Monitor",
|
||||
"monitors.cancel": "Pausar Monitor",
|
||||
"monitors.export": "Exportar Monitor",
|
||||
"monitors.export.switch-type": "Selecione o formato do arquivo de exportação!",
|
||||
"monitors.export.use-type": "Exportar monitores no formato de arquivo {{type}}",
|
||||
"monitors.import": "Importar Monitor",
|
||||
"monitors.search.placeholder": "Pesquisar Monitor",
|
||||
"monitors.search.tag": "Filtrar por Tag",
|
||||
"monitors.search.app": "Filtrar por Tipo",
|
||||
"monitors.total": "Total",
|
||||
"monitors.advanced": "Avançado",
|
||||
"monitors.advanced.tip": "Parâmetros de Configuração Avançada",
|
||||
"monitors.detect": "Detectar",
|
||||
"monitors.detect.success": "Detecção Bem-sucedida",
|
||||
"monitors.detect.failed": "Detecção Falhou",
|
||||
"monitors.detect.tip": "Verificar e detectar o status de disponibilidade do monitor",
|
||||
"monitors.detail.time-series.unavailable": "Incapaz de fornecer gráfico histórico, configure o banco de dados de séries temporais",
|
||||
"monitors.detail": "Detalhes do Monitor",
|
||||
"monitors.detail.auto-refresh": "Atualização Automática Após {{time}} s",
|
||||
"monitors.detail.config-refresh": "Definir Atualização Automática para {{time}} s",
|
||||
"monitors.detail.close-refresh": "Fechar Atualização Automática",
|
||||
"monitors.detail.show-basic": "Mostrar Básico do Monitor",
|
||||
"monitors.detail.name": "Nome",
|
||||
"monitors.detail.port": "Porta",
|
||||
"monitors.detail.description": "Descrição",
|
||||
"monitors.detail.status": "Status",
|
||||
"monitors.detail.basic": "Básico do Monitoramento",
|
||||
"monitors.detail.realtime": "Detalhes em Tempo Real do Monitor",
|
||||
"monitors.detail.history": "Detalhes do Gráfico Histórico do Monitor",
|
||||
"monitors.collect.time": "Tempo de Coleta",
|
||||
"monitors.collect.time.tip": "Último Tempo de Coleta",
|
||||
"monitors.detail.chart.zoom": "Ampliar",
|
||||
"monitors.detail.chart.back": "Restaurar Zoom",
|
||||
"monitors.detail.chart.save": "Salvar como Imagem",
|
||||
"monitors.detail.chart.query-1h": "Consultar 1 Hora",
|
||||
"monitors.detail.chart.query-6h": "Consultar 6 Horas",
|
||||
"monitors.detail.chart.query-1d": "Consultar 1 Dia",
|
||||
"monitors.detail.chart.query-1w": "Consultar 1 Semana",
|
||||
"monitors.detail.chart.query-1m": "Consultar 1 Mês",
|
||||
"monitors.detail.chart.query-3m": "Consultar 3 Meses",
|
||||
"monitors.detail.chart.no-data": "Nenhum Dado de Métrica",
|
||||
"monitors.detail.chart.unit": "Unidade",
|
||||
"monitors.detail.value.null": "Nenhum Valor",
|
||||
"common.name": "Nome da Métrica",
|
||||
"common.value": "Valor da Métrica",
|
||||
"common.search": "Pesquisar",
|
||||
"common.refresh": "Atualizar",
|
||||
"common.notice": "Notificação",
|
||||
"common.ignore": "Ignorar",
|
||||
"common.edit-time": "Tempo de Atualização",
|
||||
"common.new-time": "Tempo de Criação",
|
||||
"common.edit": "Operar",
|
||||
"common.total": "Total",
|
||||
"common.yes": "Sim",
|
||||
"common.no": "Não",
|
||||
"common.enable": "Habilitar",
|
||||
"common.disable": "Desabilitar",
|
||||
"common.copy": "Copiar para a Área de Transferência",
|
||||
"common.copy.button": "Copiar",
|
||||
"common.notify.no-select-edit": "Nenhum item selecionado para edição!",
|
||||
"common.notify.one-select-edit": "Apenas uma seleção pode ser editada!",
|
||||
"common.confirm.delete": "Confirme se deseja excluir!",
|
||||
"common.notify.no-select-delete": "Nenhum item selecionado para exclusão!",
|
||||
"common.notify.no-select-export": "Nenhum item selecionado para exportação!",
|
||||
"common.confirm.delete-batch": "Confirme se deseja excluir em lote!",
|
||||
"common.notify.delete-success": "Exclusão Bem-sucedida!",
|
||||
"common.notify.delete-fail": "Exclusão Falhou!",
|
||||
"common.notify.new-success": "Adição Bem-sucedida!",
|
||||
"common.notify.new-fail": "Adição Falhou!",
|
||||
"common.notify.apply-success": "Aplicação Bem-sucedida!",
|
||||
"common.notify.apply-fail": "Aplicação Falhou!",
|
||||
"common.notify.operate-success": "Operação Bem-sucedida!",
|
||||
"common.notify.operate-fail": "Operação Falhou!",
|
||||
"common.notify.monitor-fail": "Consulta do Monitor Falhou!",
|
||||
"common.notify.edit-success": "Edição Bem-sucedida!",
|
||||
"common.notify.edit-fail": "Edição Falhou!",
|
||||
"common.notify.no-select-cancel": "Nenhum item selecionado para cancelamento!",
|
||||
"common.confirm.cancel-batch": "Confirme se deseja cancelar o monitor em lote!",
|
||||
"common.confirm.cancel": "Confirme se deseja cancelar o monitor!",
|
||||
"common.notify.cancel-success": "Cancelamento Bem-sucedido!",
|
||||
"common.notify.cancel-fail": "Cancelamento Falhou!",
|
||||
"common.notify.mark-success": "Marca Bem-sucedida!",
|
||||
"common.notify.mark-fail": "Marca Falhou!",
|
||||
"common.notify.no-select-enable": "Nenhum item selecionado para habilitar!",
|
||||
"common.confirm.enable-batch": "Confirme se deseja habilitar o monitor em lote!",
|
||||
"common.confirm.enable": "Confirme se deseja habilitar o monitor!",
|
||||
"common.notify.enable-success": "Habilitação Bem-sucedida!",
|
||||
"common.notify.enable-fail": "Habilitação Falhou!",
|
||||
"common.confirm.clear-cache": "Confirme se deseja limpar o cache!",
|
||||
"common.notify.clear-success": "Limpeza Bem-sucedida!",
|
||||
"common.notify.clear-fail": "Limpeza Falhou!",
|
||||
"common.notify.export-success": "Exportação Bem-sucedida!",
|
||||
"common.notify.export-fail": "Exportação Falhou!",
|
||||
"common.notify.import-success": "Importação Bem-sucedida!",
|
||||
"common.notify.import-fail": "Importação Falhou!",
|
||||
"common.notify.copy-success": "Cópia Bem-sucedida!",
|
||||
"common.button.ok": "OK",
|
||||
"common.button.cancel": "Cancelar",
|
||||
"common.button.return": "Retornar",
|
||||
"common.button.help": "Ajuda",
|
||||
"common.button.edit": "Editar",
|
||||
"common.button.setting": "Configuração",
|
||||
"common.button.delete": "Excluir",
|
||||
"common.button.detect": "Detectar",
|
||||
"common.week.7": "Domingo",
|
||||
"common.week.1": "Segunda-feira",
|
||||
"common.week.2": "Terça-feira",
|
||||
"common.week.3": "Quarta-feira",
|
||||
"common.week.4": "Quinta-feira",
|
||||
"common.week.5": "Sexta-feira",
|
||||
"common.week.6": "Sábado",
|
||||
"common.time.unit.second": "Segundos",
|
||||
"common.file.select": "Selecionar Arquivo",
|
||||
"validation.email.invalid": "Email inválido!",
|
||||
"validation.phone.invalid": "Número de telefone inválido!",
|
||||
"validation.verification-code.invalid": "Código de verificação inválido, deve ter 6 dígitos!",
|
||||
"validation.required": "Por favor, preencha os campos obrigatórios! ",
|
||||
"app.theme.default": "Tema Claro",
|
||||
"app.theme.dark": "Tema Escuro",
|
||||
"app.theme.compact": "Tema Compacto",
|
||||
"app.role.admin": "administrador",
|
||||
"app.lock": "Desbloquear",
|
||||
"app.lock.placeholder": "Digite qualquer coisa para desbloquear",
|
||||
"app.passport.desc": "Um Sistema de Monitoramento em Tempo Real de Código Aberto",
|
||||
"app.passport.intro-1": "Código Aberto, Distribuído",
|
||||
"app.passport.intro-2": "Monitoramento em Tempo Real",
|
||||
"app.login.message-need-identifier": "Por favor, insira seu nome de usuário",
|
||||
"app.login.message-need-credential": "Por favor, insira a senha",
|
||||
"app.login.message-invalid-credentials": "Nome de usuário ou senha inválidos",
|
||||
"app.login.need-change-password": "Por favor, atualize a senha inicial padrão em tempo hábil!",
|
||||
"app.login.tab-login-credentials": "Entrar no HertzBeat",
|
||||
"app.login.remember-me": "Lembrar de mim",
|
||||
"app.login.login": "Entrar",
|
||||
"app.login.notify": "Por favor, faça login!",
|
||||
"app.login.explore.cloud": "Explorar Nuvem",
|
||||
"app.login.explore.cloud.detail": "Clique para Explorar a Nuvem HertzBeat",
|
||||
"tag.new": "Nova Tag",
|
||||
"tag.edit": "Editar Tag",
|
||||
"tag.search": "Pesquisar Tag",
|
||||
"tag.delete": "Excluir Tag",
|
||||
"tag": "Tag",
|
||||
"tag.setting": "Tags",
|
||||
"tag.id": "ID",
|
||||
"tag.name": "Nome da Tag",
|
||||
"tag.value": "Valor da Tag",
|
||||
"tag.color": "Cor",
|
||||
"tag.description": "Descrição",
|
||||
"tag.update-time": "Tempo de Atualização",
|
||||
"tag.display": "Exibir",
|
||||
"tag.bind": "Vincular Tags",
|
||||
"tag.bind.tip": "Você pode usar tags para gerenciamento de classificação. Ex: atribuir tags a recursos em ambiente de produção e teste.",
|
||||
"tag.help": "As tags estão em todos os lugares no HertzBeat. Podemos aplicar tags no agrupamento de recursos, correspondência de tags sob regras e outros. [Gerenciamento de Tags] é usado para gerenciamento unificado de tags, incluindo adição, exclusão, edição, etc. <br>Você pode usar tags para classificar e gerenciar recursos de monitoramento, como vincular etiquetas para ambientes de produção e teste separadamente.",
|
||||
"tag.help.link": "https://hertzbeat.apache.org/zh-cn/docs/",
|
||||
"plugin.help": "No HertzBeat, podemos usar o mecanismo de plugin para realizar algumas outras operações após o alarme, exceto notificação. O gerenciamento de plugins é usado para gerenciamento unificado de plugins, incluindo upload e operações de habilitar/desabilitar.<br>Por exemplo, você pode usar o mecanismo de plugin para executar scripts específicos ou SQL após a ocorrência do alarme.",
|
||||
"plugin.help.link": "https://hertzbeat.apache.org/docs/help/plugin",
|
||||
"plugin.upload": "Carregar Plugin",
|
||||
"plugin.name": "Nome do Plugin",
|
||||
"plugin.type": "Tipo do Plugin",
|
||||
"plugin.status": "Status Habilitado",
|
||||
"plugin.jar.file": "Arquivo Jar",
|
||||
"plugin.delete": "Excluir Plugin",
|
||||
"plugin.type.POST_ALERT": "PÓS ALERTA",
|
||||
"plugin.type.POST_COLLECT": "PÓS COLETA",
|
||||
"plugin.search": "Pesquisar plugins",
|
||||
"plugin.edit": "Editar plugin",
|
||||
"plugin.param.edit": "Editar Parâmetros",
|
||||
"define.help": "Os modelos de monitoramento definem cada tipo de monitoramento, variável de parâmetro, informações de métricas, protocolo de coleta, etc. Você pode selecionar um modelo de monitoramento existente no menu suspenso e fazer modificações de acordo com suas próprias necessidades. A área inferior esquerda é a área de comparação e a área inferior direita é o local de edição. <br> Você também pode clicar em \"Novo Tipo de Monitor\" para definir um novo tipo personalizado. Atualmente, os protocolos suportados incluem<a href='https://hertzbeat.apache.org/zh-cn/docs/advanced/extend-http'> HTTP</a>, <a href='https://hertzbeat.apache.org/zh-cn/docs/advanced/extend-jdbc'>JDBC</a>, <a href='https://hertzbeat.apache.org/zh-cn/docs/advanced/extend-ssh'>SSH</a>, <a href='https://hertzbeat.apache.org/zh-cn/docs/advanced/extend-jmx'>JMX</a>, <a href='https://hertzbeat.apache.org/zh-cn/docs/advanced/extend-snmp'> SNMP</a>. <a class='help_module_content' href='https://hertzbeat.apache.org/zh-cn/docs/template'>Modelos de Monitoramento</a>.",
|
||||
"define.help.link": "https://hertzbeat.apache.org/zh-cn/docs/advanced/extend-point/",
|
||||
"define.save-apply": "Salvar e Aplicar",
|
||||
"define.delete": "Excluir {{app}}",
|
||||
"define.delete.confirm": "Confirme se deseja excluir o tipo de monitoramento {{app}}? Este tipo de monitoramento não poderá ser adicionado após a exclusão.",
|
||||
"define.new": "Novo Tipo de Monitor",
|
||||
"define.new.code": "# Por favor, defina um novo tipo de monitoramento escrevendo o conteúdo YML aqui, consulte o documento: https://hertzbeat.apache.org/docs/advanced/extend-point ",
|
||||
"define.save-apply.no-code": "O conteúdo da definição do tipo de monitoramento não pode estar vazio.",
|
||||
"define.save-apply.confirm": "Confirme se deseja atualizar e aplicar a definição do monitor? Isso afetará o que você monitora.",
|
||||
"define.hide-true.tip": "Não exibido no menu principal, se deseja exibi-lo",
|
||||
"define.hide-true.confirm": "Confirme se deseja exibir este menu?",
|
||||
"define.hide-false.tip": "Já exibido no menu principal, se deseja ocultá-lo",
|
||||
"define.hide-false.confirm": "Confirme se deseja ocultar este menu?",
|
||||
"settings.server": "Configuração do Servidor de Mensagens",
|
||||
"settings.server.email": "Servidor de Email",
|
||||
"settings.server.email.setting": "Configurar Servidor de Email",
|
||||
"settings.server.sms": "Servidor de SMS",
|
||||
"settings.server.sms.setting": "Configurar Servidor de SMS",
|
||||
"settings.system-config": "Configuração do Sistema",
|
||||
"settings.system-config.locale": "Idioma do Sistema",
|
||||
"settings.system-config.locale.zh_CN": "Chinês Simplificado(zh_CN)",
|
||||
"settings.system-config.locale.zh_TW": "Chinês Tradicional(zh_TW)",
|
||||
"settings.system-config.locale.en_US": "Inglês(en_US)",
|
||||
"settings.system-config.locale.pt_BR": "Português(pt_BR)",
|
||||
"settings.system-config.timezone": "Fuso Horário do Sistema",
|
||||
"settings.system-config.theme": "Tema do Sistema",
|
||||
"settings.system-config.theme.default": "Tema Padrão",
|
||||
"settings.system-config.theme.dark": "Tema Escuro",
|
||||
"settings.system-config.theme.compact": "Tema Compacto",
|
||||
"settings.system-config.ok": "Confirmar Atualização",
|
||||
"settings.object-store": "Configuração do Servidor de Arquivos",
|
||||
"settings.object-store.type": "Provedor do Servidor de Arquivos",
|
||||
"settings.object-store.type.file": "Arquivo local (padrão)",
|
||||
"settings.object-store.type.database": "Banco de dados local",
|
||||
"settings.object-store.type.obs": "HUAWEI CLOUD OBS",
|
||||
"settings.object-store.obs.accessKey": "AccessKey",
|
||||
"settings.object-store.obs.accessKey.placeholder": "Access Key ID da HUAWEI CLOUD",
|
||||
"settings.object-store.obs.secretKey": "SecretKey",
|
||||
"settings.object-store.obs.secretKey.placeholder": "Access Key Secret da HUAWEI CLOUD",
|
||||
"settings.object-store.obs.bucketName": "Bucket",
|
||||
"settings.object-store.obs.bucketName.placeholder": "O nome do bucket que você criou na HUAWEI CLOUD OBS",
|
||||
"settings.object-store.obs.endpoint": "EndPoint",
|
||||
"settings.object-store.obs.endpoint.placeholder": "Domínio da HUAWEI CLOUD OBS, excluindo o nome do bucket",
|
||||
"settings.object-store.obs.savePath": "Caminho de Salvamento",
|
||||
"settings.object-store.obs.savePath.placeholder": "Caminho para salvar o arquivo de backup, O valor padrão é hertzbeat.",
|
||||
"collector": "Coletor",
|
||||
"collector.name": "Nome do Coletor",
|
||||
"collector.name.placeholder": "Por favor, configure o nome único do coletor",
|
||||
"collector.status": "Status Online",
|
||||
"collector.mode": "Modo de Execução",
|
||||
"collector.mode.public": "Cluster Público",
|
||||
"collector.mode.private": "Nuvem-Private Edge",
|
||||
"collector.task": "Total de Tarefas",
|
||||
"collector.start-time": "Hora de Início",
|
||||
"collector.ip": "Endereço IP",
|
||||
"collector.version": "Versão",
|
||||
"collector.node": "Nome do Nó",
|
||||
"collector.pinned": "Tarefas Fixadas",
|
||||
"collector.dispatched": "Tarefas Despachadas",
|
||||
"collector.delete": "Excluir Coletor",
|
||||
"collector.deploy": "Implantar Coletor",
|
||||
"collector.deploy.identity": "Token do Coletor (IDENTIDADE)",
|
||||
"collector.deploy.identity.tip": "Por favor, note que este token é único, mantenha-o seguro.",
|
||||
"collector.deploy.ok": "Gerar Token e Comandos de Implantação",
|
||||
"collector.deploy.close": "Fechar - Eu Salvei o Token",
|
||||
"collector.deploy.docker": "Implantar via Docker",
|
||||
"collector.deploy.docker.help": "# Execute o seguinte comando no ambiente Docker",
|
||||
"collector.deploy.docker.help.1": "# docker run -d : Inicie um contêiner em execução em segundo plano através do Docker",
|
||||
"collector.deploy.docker.help.2": "# -e IDENTITY=xxx : Defina o token de identidade do coletor",
|
||||
"collector.deploy.docker.help.3": "# -e MANAGER_HOST=127.0.0.1 : Defina o endereço do serviço principal do HertzBeat para conexão",
|
||||
"collector.deploy.docker.help.4": "# -e MODE=public : Defina o modo de execução (público ou privado), cluster público ou nuvem-private edge.",
|
||||
"collector.deploy.docker.help.5": "# --name hertzbeat-collector: Nomeie o contêiner como hertzbeat-collector",
|
||||
"collector.deploy.docker.help.6": "# apache/hertzbeat-collector: Fonte oficial da imagem do aplicativo, ou use quay.io/tancloud/hertzbeat-collector quando houver timeout",
|
||||
"collector.deploy.package": "Implantar via Pacote",
|
||||
"collector.deploy.package.github": "Baixar do Github",
|
||||
"collector.deploy.package.gitee": "Baixar do Gitee",
|
||||
"collector.deploy.package.help": "# Baixe o pacote de lançamento correspondente ao sistema hertzbeat-collector-xx.tar.gz",
|
||||
"collector.deploy.package.help.1": "# Descompacte e configure o arquivo hertzbeat-collector/config/application.yml",
|
||||
"collector.deploy.package.help.2": "# Substitua os parâmetros IDENTITY MANAGER_HOST MODE no arquivo como segue.",
|
||||
"collector.deploy.package.help.3": "# Execute bin/startup.sh ou startup.bat(windows) para iniciar o coletor.",
|
||||
"collector.online": "Coletor Online",
|
||||
"collector.offline": "Coletor Offline",
|
||||
"collector.confirm.online": "Confirme se deseja colocar este coletor online!",
|
||||
"collector.confirm.offline": "Confirme se deseja colocar este coletor offline!",
|
||||
"collector.confirm.online-batch": "Confirme se deseja colocar o coletor online em lote!",
|
||||
"collector.confirm.offline-batch": "Confirme se deseja colocar o coletor offline em lote!",
|
||||
"collector.notify.no-select-online": "Nenhum item selecionado para coletor online!",
|
||||
"collector.notify.no-select-offline": "Nenhum item selecionado para coletor offline!",
|
||||
"collector.help": "O Cluster de Coletores é usado para gerenciar nós de cluster de coletores registrados, exibir o status atual do coletor e a distribuição de tarefas de agendamento, e suporta operações como implantação, exclusão, offline de coletores.<br>Além de usar o coletor embutido, você pode registrar vários coletores para uso em cenários de <strong>Cluster de Alto Desempenho</strong> ou <strong>Colaboração Nuvem-Edge</strong>.",
|
||||
"collector.help.link": "https://hertzbeat.apache.org/docs/help/guide",
|
||||
"about.title": "Um sistema de monitoramento em tempo real de código aberto, sem agente, cluster, compatível com prometheus, personalizado e página de status.",
|
||||
"about.point.1": "Monitoramento-alerta-notificação tudo em um, suporta web, banco de dados, sistema operacional, middleware, rede, etc.",
|
||||
"about.point.2": "Fácil de usar, operações totalmente baseadas na web com apenas um clique do mouse.",
|
||||
"about.point.3": "Capacidades poderosas de modelo de monitoramento, monitoramento personalizado de qualquer métrica que você desejar.",
|
||||
"about.point.4": "Alto desempenho, suporta cluster de coletores, rede multi-isolada e nuvem-edge.",
|
||||
"about.point.5": "Regras de limite de alarme flexíveis, notificação oportuna via discord, slack, telegram, etc.",
|
||||
"about.point.6": "Construa facilmente uma página de status poderosa para comunicar o status em tempo real aos usuários.",
|
||||
"about.help": "A poderosa personalização do HertzBeat, suporte a vários tipos, alto desempenho e fácil expansão, visa ajudar os usuários a construir rapidamente seu próprio sistema de monitoramento.",
|
||||
"about.github": "Github",
|
||||
"about.gitee": "Gitee",
|
||||
"about.issue": "Feedback",
|
||||
"about.pr": "Contribuir",
|
||||
"about.discuss": "Discutir",
|
||||
"about.doc": "Documento",
|
||||
"about.upgrade": "Atualizar",
|
||||
"about.star": "Estrela",
|
||||
"status.page": "Página de Status",
|
||||
"status.org.name": "Nome da Organização",
|
||||
"status.org.name.tip": "O nome da equipe da organização exibido na página de status, como TanCloud",
|
||||
"status.org.desc": "Introdução",
|
||||
"status.org.desc.tip": "Introdução às informações da organização exibidas na página de status",
|
||||
"status.org.logo": "Imagem do Logo",
|
||||
"status.org.logo.tip": "Por favor, configure o endereço URL da imagem do logo da organização, sugere svg",
|
||||
"status.org.home": "Link do Site",
|
||||
"status.org.home.tip": "Por favor, configure o endereço da página inicial do site da organização",
|
||||
"status.org.feedback": "Link de Feedback",
|
||||
"status.org.feedback.tip": "Por favor, configure o endereço de contato de feedback dos usuários",
|
||||
"status.org.color": "Cor do Tema",
|
||||
"status.org.color.tip": "Por favor, configure a cor do tema da página de status",
|
||||
"status.org.state": "Estado da Organização",
|
||||
"status.public.feedback": "FEEDBACK DE PROBLEMAS",
|
||||
"status.public.org.state.0": "Todos os Sistemas Operacionais",
|
||||
"status.public.org.state.1": "Alguns Sistemas Anormais",
|
||||
"status.public.org.state.2": "Todos os Sistemas Anormais",
|
||||
"status.public.today": "Hoje",
|
||||
"status.public.30-day": "30 dias atrás",
|
||||
"status.public.power-by": "Desenvolvido por Apache HertzBeat. Dê-nos uma estrela!",
|
||||
"status.public.to-incident": "Histórico de Incidentes",
|
||||
"status.public.to-component": "Página de Status",
|
||||
"status.incident": "Incidente",
|
||||
"status.incident.name": "Nome do Incidente",
|
||||
"status.incident.name.tip": "Por favor, descreva brevemente o título do incidente atual",
|
||||
"status.incident.history": "Histórico de Incidentes",
|
||||
"status.incident.state": "Status do Incidente",
|
||||
"status.incident.state.0": "Investigando",
|
||||
"status.incident.state.1": "Identificado",
|
||||
"status.incident.state.2": "Monitorando",
|
||||
"status.incident.state.3": "Resolvido",
|
||||
"status.incident.message": "Publicar Mensagem",
|
||||
"status.incident.message.tip.0": "Estamos investigando este incidente, por favor, verifique novamente mais tarde para atualizações.",
|
||||
"status.incident.message.tip.1": "Confirmamos a causa da falha e estamos processando.",
|
||||
"status.incident.message.tip.2": "Estamos monitorando este evento e observando o efeito do processamento",
|
||||
"status.incident.message.tip.3": "Este incidente foi resolvido, obrigado pela compreensão e apoio.",
|
||||
"status.incident.message-latest": "Última Mensagem",
|
||||
"status.incident.component": "Componente Afetado",
|
||||
"status.incident.new": "Publicar Incidente",
|
||||
"status.incident.update": "Atualizar Incidente",
|
||||
"status.incident.delete": "Excluir Incidente",
|
||||
"status.incident.public.start-at": "Iniciar em",
|
||||
"status.incident.public.update-at": "Atualizar em",
|
||||
"status.incident.public.process-time": "Tempo de Processamento",
|
||||
"status.component": "Componente",
|
||||
"status.component.name": "Componente de Serviço",
|
||||
"status.component.name.tip": "Configurar o nome do componente de serviço exibido, como Gateway",
|
||||
"status.component.desc": "Descrição do Componente",
|
||||
"status.component.desc.tip": "Configurar informações de descrição do componente de serviço",
|
||||
"status.component.state": "Estado do Componente",
|
||||
"status.component.new": "Novo Componente",
|
||||
"status.component.edit": "Editar Componente",
|
||||
"status.component.delete": "Excluir Componente",
|
||||
"status.component.tag": "Corresponder Tag",
|
||||
"status.component.tag.tip": "O cálculo do status associa a etiqueta e usa todos os status de disponibilidade de monitoramento associados à etiqueta como dados para calcular o status do serviço deste componente.",
|
||||
"status.component.method": "Modo de Cálculo do Status",
|
||||
"status.component.method.tip": "A forma de calcular o status do serviço do componente é calcular automaticamente a disponibilidade com base no monitoramento de associação de tags ou configurar manualmente o status.",
|
||||
"status.component.method.0": "Cálculo Automático",
|
||||
"status.component.method.1": "Configuração Manual",
|
||||
"status.component.config-state": "Estado de Configuração",
|
||||
"status.component.config-state.tip": "Quando o modo de cálculo do status é manual, o estado do serviço do componente configurado.",
|
||||
"status.component.state.0": "Normal",
|
||||
"status.component.state.1": "Anormal",
|
||||
"status.component.state.2": "Desconhecido",
|
||||
"status.component.notify.need-org": "Por favor, configure as informações da sua organização primeiro!",
|
||||
"status.help": "Construa rapidamente uma página de status poderosa com base no HertzBeat para comunicar facilmente o status em tempo real dos seus serviços aos usuários. Por exemplo, a página de status fornecida pelo Github <a href='https://www.githubstatus.com'> https://www.githubstatus.com</a>. <br>Suporta vinculação e sincronização do status do componente da página de status e status de monitoramento, manutenção e gerenciamento de eventos de falha, etc. Melhore sua transparência, profissionalismo e confiança do usuário, e reduza os custos de comunicação.",
|
||||
"status.help.link": "https://hertzbeat.apache.org/docs/help/status",
|
||||
"validation.email.required": "Por favor, insira seu email!",
|
||||
"validation.email.wrong-format": "O endereço de email está no formato errado!",
|
||||
"validation.password.required": "Por favor, insira sua senha!",
|
||||
"validation.password.twice": "As senhas inseridas duas vezes não coincidem!",
|
||||
"validation.password.strength.msg": "Por favor, insira pelo menos 6 caracteres e não use senhas fáceis de adivinhar.",
|
||||
"validation.password.strength.strong": "Força: forte",
|
||||
"validation.password.strength.medium": "Força: média",
|
||||
"validation.password.strength.short": "Força: muito curta",
|
||||
"validation.confirm-password.required": "Por favor, confirme sua senha!",
|
||||
"validation.phone-number.required": "Por favor, insira seu número de telefone!",
|
||||
"validation.phone-number.wrong-format": "Número de telefone mal formatado!",
|
||||
"validation.verification-code.required": "Por favor, insira o código de verificação!",
|
||||
"validation.title.required": "Por favor, insira um título",
|
||||
"validation.date.required": "Por favor, selecione a data de início e término",
|
||||
"validation.goal.required": "Por favor, insira uma descrição do objetivo",
|
||||
"validation.standard.required": "Por favor, insira uma métrica",
|
||||
"expand": "Expandir",
|
||||
"collapse": "Recolher"
|
||||
}
|
||||
@@ -153,12 +153,10 @@
|
||||
"alert.notice.sender.sms.unisms.signature": "合一短信Signature",
|
||||
"alert.notice.sender.sms.unisms.templateId": "合一短信TemplateId",
|
||||
"alert.notice.sender.sms.unisms.authMode": "合一短信鉴权方式",
|
||||
"alert.notice.sender.sms.smslocal.apiKey": "Smslocal短信鉴权方式",
|
||||
"alert.notice.sender.sms.type": "短信类型",
|
||||
"alert.notice.sender.sms.type.alibaba": "阿里短信",
|
||||
"alert.notice.sender.sms.type.tencent": "腾讯短信",
|
||||
"alert.notice.sender.sms.type.unisms": "合一短信(UniSMS)",
|
||||
"alert.notice.sender.sms.type.smslocal": "当地短信(Smslocal)",
|
||||
"alert.notice.template": "通知模板",
|
||||
"alert.notice.template.content": "模板内容",
|
||||
"alert.notice.template.delete": "删除通知模板",
|
||||
@@ -439,7 +437,6 @@
|
||||
"common.file.select": "选择文件",
|
||||
"common.ignore": "忽略",
|
||||
"common.mute": "静音",
|
||||
"common.unmute": "取消静音",
|
||||
"common.name": "指标名",
|
||||
"common.new-time": "创建时间",
|
||||
"common.no": "否",
|
||||
@@ -462,10 +459,6 @@
|
||||
"common.notify.export-success": "导出成功!",
|
||||
"common.notify.import-fail": "导入失败!",
|
||||
"common.notify.import-success": "导入成功!",
|
||||
"common.notify.import-fail-detail": "导入 [{{taskName}}] 失败: [{{errMsg}}]",
|
||||
"common.notify.import-success-detail": "导入 [{{taskName}}] 成功!",
|
||||
"common.notify.import-submitted": "导入任务 [{{taskName}}] 已提交!",
|
||||
"common.notify.import-progress": "正在导入 [{{taskName}}], 进度: {{progress}}%",
|
||||
"common.notify.mark-fail": "标记失败!",
|
||||
"common.notify.mark-success": "标记成功!",
|
||||
"common.notify.new-fail": "新增失败!",
|
||||
@@ -779,7 +772,6 @@
|
||||
"settings.system-config.locale.zh_CN": "简体中文(zh_CN)",
|
||||
"settings.system-config.locale.zh_TW": "繁体中文(zh_TW)",
|
||||
"settings.system-config.locale.ja-JP": "日语(ja_JP)",
|
||||
"settings.system-config.locale.pt_BR": "Português(pt_BR)",
|
||||
"settings.system-config.ok": "确认更新",
|
||||
"settings.system-config.theme": "系统主题",
|
||||
"settings.system-config.theme.compact": "紧凑主题",
|
||||
|
||||
@@ -153,12 +153,10 @@
|
||||
"alert.notice.sender.sms.unisms.signature": "合一簡訊Signature",
|
||||
"alert.notice.sender.sms.unisms.templateId": "合一簡訊TemplateId",
|
||||
"alert.notice.sender.sms.unisms.authMode": "合一簡訊驗證方式",
|
||||
"alert.notice.sender.sms.smslocal.authMode": "Smslocal短訊ApiKey",
|
||||
"alert.notice.sender.sms.type": "騰訊類型",
|
||||
"alert.notice.sender.sms.type.alibaba": "阿裏短訊",
|
||||
"alert.notice.sender.sms.type.tencent": "騰訊短訊",
|
||||
"alert.notice.sender.sms.type.unisms": "合一簡訊(UniSMS)",
|
||||
"alert.notice.sender.sms.type.smslocal": "当地短訊(Smslocal)",
|
||||
"alert.notice.template": "通知模板",
|
||||
"alert.notice.template.content": "模板内容",
|
||||
"alert.notice.template.delete": "刪除通知模板",
|
||||
@@ -439,7 +437,6 @@
|
||||
"common.file.select": "選擇文件",
|
||||
"common.ignore": "忽略",
|
||||
"common.mute": "靜音",
|
||||
"common.unmute": "取消靜音",
|
||||
"common.name": "指標名",
|
||||
"common.new-time": "創建時間",
|
||||
"common.no": "否",
|
||||
@@ -462,10 +459,6 @@
|
||||
"common.notify.export-success": "導出成功!",
|
||||
"common.notify.import-fail": "導入失敗!",
|
||||
"common.notify.import-success": "導入成功!",
|
||||
"common.notify.import-fail-detail": "導入 [{{taskName}}] 失敗: [{{errMsg}}]",
|
||||
"common.notify.import-success-detail": "導入 [{{taskName}}] 成功!",
|
||||
"common.notify.import-submitted": "導入任務 [{{taskName}}] 已提交!",
|
||||
"common.notify.import-progress": "正在導入 [{{taskName}}], 進度: {{progress}}%",
|
||||
"common.notify.mark-fail": "標記失敗!",
|
||||
"common.notify.mark-success": "標記成功!",
|
||||
"common.notify.new-fail": "新增失敗!",
|
||||
@@ -779,7 +772,6 @@
|
||||
"settings.system-config.locale.zh_CN": "簡體中文(zh_CN)",
|
||||
"settings.system-config.locale.zh_TW": "繁體中文(zh_TW)",
|
||||
"settings.system-config.locale.ja-JP": "日語(ja_JP)",
|
||||
"settings.system-config.locale.pt_BR": "Português(pt_BR)",
|
||||
"settings.system-config.ok": "確認更新",
|
||||
"settings.system-config.theme": "系統主題",
|
||||
"settings.system-config.theme.compact": "緊湊主題",
|
||||
|
||||
Reference in New Issue
Block a user