From 7779056983aa089296564d65cfe08b92897945f6 Mon Sep 17 00:00:00 2001 From: Sherlock Yin Date: Thu, 15 May 2025 08:25:50 +0800 Subject: [PATCH] [feature] Support DNS Service Discovery (#3328) Signed-off-by: Sherlock Yin Co-authored-by: yinyijun Co-authored-by: yinyijun Co-authored-by: tomsun28 --- .../collect/sd/DnsSdCollectImpl.java | 181 ++++++++++++++++++ ...ertzbeat.collector.collect.AbstractCollect | 1 + .../collector/dispatch/DispatchConstants.java | 5 + .../hertzbeat/common/entity/job/Metrics.java | 8 +- .../entity/job/protocol/DnsSdProtocol.java | 41 ++++ .../common/entity/manager/Monitor.java | 2 +- hertzbeat-manager/pom.xml | 4 +- .../component/sd/ServiceDiscoveryWorker.java | 9 +- .../hertzbeat/manager/dao/MonitorBindDao.java | 2 + .../src/main/resources/define/app-dns_sd.yml | 106 ++++++++++ .../monitor-form/monitor-form.component.html | 1 + web-app/src/assets/i18n/en-US.json | 1 + web-app/src/assets/i18n/ja-JP.json | 1 + web-app/src/assets/i18n/pt-BR.json | 1 + web-app/src/assets/i18n/zh-CN.json | 1 + web-app/src/assets/i18n/zh-TW.json | 1 + 16 files changed, 358 insertions(+), 7 deletions(-) create mode 100644 hertzbeat-collector/hertzbeat-collector-basic/src/main/java/org/apache/hertzbeat/collector/collect/sd/DnsSdCollectImpl.java create mode 100644 hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/job/protocol/DnsSdProtocol.java create mode 100644 hertzbeat-manager/src/main/resources/define/app-dns_sd.yml diff --git a/hertzbeat-collector/hertzbeat-collector-basic/src/main/java/org/apache/hertzbeat/collector/collect/sd/DnsSdCollectImpl.java b/hertzbeat-collector/hertzbeat-collector-basic/src/main/java/org/apache/hertzbeat/collector/collect/sd/DnsSdCollectImpl.java new file mode 100644 index 0000000000..ba9186cc66 --- /dev/null +++ b/hertzbeat-collector/hertzbeat-collector-basic/src/main/java/org/apache/hertzbeat/collector/collect/sd/DnsSdCollectImpl.java @@ -0,0 +1,181 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hertzbeat.collector.collect.sd; + +import lombok.extern.slf4j.Slf4j; +import org.apache.hertzbeat.collector.collect.AbstractCollect; +import org.apache.hertzbeat.collector.dispatch.DispatchConstants; +import org.apache.hertzbeat.common.entity.job.Metrics; +import org.apache.hertzbeat.common.entity.message.CollectRep; +import org.apache.hertzbeat.common.util.CommonUtil; +import org.xbill.DNS.AAAARecord; +import org.xbill.DNS.ARecord; +import org.xbill.DNS.Lookup; +import org.xbill.DNS.MXRecord; +import org.xbill.DNS.NSRecord; +import org.xbill.DNS.Record; +import org.xbill.DNS.SRVRecord; +import org.xbill.DNS.SimpleResolver; +import org.xbill.DNS.TextParseException; +import org.xbill.DNS.Type; + +import java.time.Duration; +import java.util.Arrays; + +/** + * DNS SD collector supporting multiple record types + */ +@Slf4j +public class DnsSdCollectImpl extends AbstractCollect { + + private static final int DEFAULT_TIME_OUT = 3; + + @Override + public void preCheck(Metrics metrics) throws IllegalArgumentException { + if (metrics.getDns_sd() == null) { + throw new IllegalArgumentException("DNS SD configuration cannot be null"); + } + if (metrics.getDns_sd().getHost() == null || metrics.getDns_sd().getHost().isEmpty()) { + throw new IllegalArgumentException("DNS host cannot be null or empty"); + } + if (metrics.getDns_sd().getPort() == null || metrics.getDns_sd().getPort().isEmpty()) { + throw new IllegalArgumentException("DNS port cannot be null or empty"); + } + if (metrics.getDns_sd().getRecordType() == null || metrics.getDns_sd().getRecordType().isEmpty()) { + throw new IllegalArgumentException("DNS record type cannot be null or empty"); + } + if (metrics.getDns_sd().getRecordName() == null || metrics.getDns_sd().getRecordName().isEmpty()) { + throw new IllegalArgumentException("DNS record name cannot be null or empty"); + } + } + + @Override + public void collect(CollectRep.MetricsData.Builder builder, Metrics metrics) { + String hostName = metrics.getDns_sd().getHost(); + int type = Integer.parseInt(metrics.getDns_sd().getRecordType()); + Type.check(type); + String recordName = metrics.getDns_sd().getRecordName(); + try { + Lookup lookup = new Lookup(recordName, type); + SimpleResolver resolver = new SimpleResolver(metrics.getDns_sd().getHost()); + resolver.setPort(Integer.parseInt(metrics.getDns_sd().getPort())); + resolver.setTimeout(Duration.ofMillis(DEFAULT_TIME_OUT)); + lookup.setResolver(resolver); + lookup.setCache(null); + lookup.run(); + if (lookup.getResult() != Lookup.SUCCESSFUL) { + String msg = String.format("DNS lookup failed for: %s, error: %s", recordName, lookup.getErrorString()); + log.warn(msg); + builder.setCode(CollectRep.Code.FAIL); + builder.setMsg(msg); + return; + } + Record[] records = lookup.getAnswers(); + if (records == null || records.length == 0) { + log.info("No record type: {} records found for host: {}", type, hostName); + builder.setCode(CollectRep.Code.SUCCESS); + return; + } + processRecords(builder, records, type); + } catch (TextParseException e) { + String errorMsg = CommonUtil.getMessageFromThrowable(e); + log.warn("Failed to parse dns query... {}", errorMsg); + builder.setCode(CollectRep.Code.FAIL); + builder.setMsg(errorMsg); + } catch (Exception e) { + String errorMsg = CommonUtil.getMessageFromThrowable(e); + log.error("Failed to fetch dns sd...{}", errorMsg); + builder.setCode(CollectRep.Code.FAIL); + builder.setMsg(errorMsg); + } + } + + private void processRecords(CollectRep.MetricsData.Builder builder, Record[] records, int recordType) { + switch (recordType) { + case Type.A: + processARecords(builder, records); + break; + case Type.AAAA: + processAAAARecords(builder, records); + break; + case Type.SRV: + processSrvRecords(builder, records); + break; + case Type.MX: + processMxRecords(builder, records); + break; + case Type.NS: + processNsRecords(builder, records); + break; + default: + throw new IllegalStateException("Invalid record type: " + recordType); + } + } + + @SuppressWarnings({"checkstyle:AbbreviationAsWordInName", "checkstyle:LambdaParameterName"}) + private void processARecords(CollectRep.MetricsData.Builder builder, Record[] records) { + Arrays.stream(records).filter(ARecord.class::isInstance).map(ARecord.class::cast).forEach(aRecord -> { + CollectRep.ValueRow.Builder row = CollectRep.ValueRow.newBuilder(); + row.addColumn(aRecord.getAddress().getHostAddress()); + row.addColumn(""); //A record has no port + builder.addValueRow(row.build()); + }); + } + + @SuppressWarnings("checkstyle:AbbreviationAsWordInName") + private void processAAAARecords(CollectRep.MetricsData.Builder builder, Record[] records) { + Arrays.stream(records).filter(AAAARecord.class::isInstance).map(AAAARecord.class::cast).forEach(aaaaRecord -> { + CollectRep.ValueRow.Builder row = CollectRep.ValueRow.newBuilder(); + row.addColumn(aaaaRecord.getAddress().getHostAddress()); + row.addColumn(""); //AAAA record has no port + builder.addValueRow(row.build()); + }); + } + + private void processSrvRecords(CollectRep.MetricsData.Builder builder, Record[] records) { + Arrays.stream(records).filter(SRVRecord.class::isInstance).map(SRVRecord.class::cast).forEach(srvRecord -> { + CollectRep.ValueRow.Builder row = CollectRep.ValueRow.newBuilder(); + row.addColumn(srvRecord.getTarget().toString(true)); + row.addColumn(String.valueOf(srvRecord.getPort())); + builder.addValueRow(row.build()); + }); + } + + private void processMxRecords(CollectRep.MetricsData.Builder builder, Record[] records) { + Arrays.stream(records).filter(MXRecord.class::isInstance).map(MXRecord.class::cast).forEach(mxRecord -> { + CollectRep.ValueRow.Builder row = CollectRep.ValueRow.newBuilder(); + row.addColumn(mxRecord.getTarget().toString(true)); + row.addColumn(""); //MX record has no port + builder.addValueRow(row.build()); + }); + } + + private void processNsRecords(CollectRep.MetricsData.Builder builder, Record[] records) { + Arrays.stream(records).filter(NSRecord.class::isInstance).map(NSRecord.class::cast).forEach(nsRecord -> { + CollectRep.ValueRow.Builder row = CollectRep.ValueRow.newBuilder(); + row.addColumn(nsRecord.getTarget().toString(true)); + row.addColumn(""); //NS record has no port + builder.addValueRow(row.build()); + }); + } + + @Override + public String supportProtocol() { + return DispatchConstants.PROTOCOL_DNS_SD; + } +} diff --git a/hertzbeat-collector/hertzbeat-collector-collector/src/main/resources/META-INF/services/org.apache.hertzbeat.collector.collect.AbstractCollect b/hertzbeat-collector/hertzbeat-collector-collector/src/main/resources/META-INF/services/org.apache.hertzbeat.collector.collect.AbstractCollect index 39aae718e8..c9e7d2b3ae 100644 --- a/hertzbeat-collector/hertzbeat-collector-collector/src/main/resources/META-INF/services/org.apache.hertzbeat.collector.collect.AbstractCollect +++ b/hertzbeat-collector/hertzbeat-collector-collector/src/main/resources/META-INF/services/org.apache.hertzbeat.collector.collect.AbstractCollect @@ -29,6 +29,7 @@ org.apache.hertzbeat.collector.collect.mqtt.MqttCollectImpl org.apache.hertzbeat.collector.collect.ipmi2.IpmiCollectImpl org.apache.hertzbeat.collector.collect.kafka.KafkaCollectImpl org.apache.hertzbeat.collector.collect.sd.HttpSdCollectImpl +org.apache.hertzbeat.collector.collect.sd.DnsSdCollectImpl org.apache.hertzbeat.collector.collect.sd.EurekaSdCollectImpl org.apache.hertzbeat.collector.collect.sd.ConsulSdCollectImpl org.apache.hertzbeat.collector.collect.modbus.ModbusCollectImpl diff --git a/hertzbeat-collector/hertzbeat-collector-common/src/main/java/org/apache/hertzbeat/collector/dispatch/DispatchConstants.java b/hertzbeat-collector/hertzbeat-collector-common/src/main/java/org/apache/hertzbeat/collector/dispatch/DispatchConstants.java index 804fb54657..5e66be7202 100644 --- a/hertzbeat-collector/hertzbeat-collector-common/src/main/java/org/apache/hertzbeat/collector/dispatch/DispatchConstants.java +++ b/hertzbeat-collector/hertzbeat-collector-common/src/main/java/org/apache/hertzbeat/collector/dispatch/DispatchConstants.java @@ -127,10 +127,15 @@ public interface DispatchConstants { * protocol http sd */ String PROTOCOL_HTTP_SD = "http_sd"; + /** + * protocol dns sd + */ + String PROTOCOL_DNS_SD = "dns_sd"; /** * protocol eureka sd */ String PROTOCOL_EUREKA_SD = "eureka_sd"; + /** * protocol consul sd */ diff --git a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/job/Metrics.java b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/job/Metrics.java index fc69c95dbd..6df41c4979 100644 --- a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/job/Metrics.java +++ b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/job/Metrics.java @@ -30,9 +30,9 @@ import lombok.Data; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.hertzbeat.common.entity.job.protocol.DnsProtocol; +import org.apache.hertzbeat.common.entity.job.protocol.DnsSdProtocol; import org.apache.hertzbeat.common.entity.job.protocol.FtpProtocol; import org.apache.hertzbeat.common.entity.job.protocol.HttpProtocol; -import org.apache.hertzbeat.common.entity.job.protocol.HttpSdProtocol; import org.apache.hertzbeat.common.entity.job.protocol.EurekaSdProtocol; import org.apache.hertzbeat.common.entity.job.protocol.ConsulSdProtocol; import org.apache.hertzbeat.common.entity.job.protocol.ModbusProtocol; @@ -265,7 +265,11 @@ public class Metrics { /** * http sd protocol */ - private HttpSdProtocol http_sd; + private HttpProtocol http_sd; + /** + * dns sd protocol + */ + private DnsSdProtocol dns_sd; /** * eureka sd protocol */ diff --git a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/job/protocol/DnsSdProtocol.java b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/job/protocol/DnsSdProtocol.java new file mode 100644 index 0000000000..9597ac6f91 --- /dev/null +++ b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/job/protocol/DnsSdProtocol.java @@ -0,0 +1,41 @@ +/* + * 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.job.protocol; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Dns protocol + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class DnsSdProtocol implements Protocol { + + private String host; + + private String port; + + private String recordType; + + private String recordName; +} diff --git a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/manager/Monitor.java b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/manager/Monitor.java index 31cc545853..23e0ff338d 100644 --- a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/manager/Monitor.java +++ b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/manager/Monitor.java @@ -77,7 +77,7 @@ public class Monitor { @Size(max = 100) private String app; - @Schema(title = "Scrape type: static | http_sd", example = "static", accessMode = READ_WRITE) + @Schema(title = "Scrape type: static | http_sd | dns_sd", example = "static", accessMode = READ_WRITE) @Size(max = 100) private String scrape; diff --git a/hertzbeat-manager/pom.xml b/hertzbeat-manager/pom.xml index 022fbeb610..59cd25d180 100644 --- a/hertzbeat-manager/pom.xml +++ b/hertzbeat-manager/pom.xml @@ -47,7 +47,7 @@ org.apache.hertzbeat hertzbeat-base - + org.apache.hertzbeat @@ -409,5 +409,5 @@ - + diff --git a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/sd/ServiceDiscoveryWorker.java b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/sd/ServiceDiscoveryWorker.java index f783d34b22..e09057a46f 100644 --- a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/sd/ServiceDiscoveryWorker.java +++ b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/sd/ServiceDiscoveryWorker.java @@ -49,7 +49,7 @@ import org.springframework.stereotype.Component; @Slf4j @Component public class ServiceDiscoveryWorker implements InitializingBean { - + private static final String FILED_HOST = "host"; private static final String FILED_PORT = "port"; private final MonitorService monitorService; @@ -97,6 +97,11 @@ public class ServiceDiscoveryWorker implements InitializingBean { .stream().collect(Collectors.toMap(MonitorBind::getKeyStr, item -> item)); RowWrapper rowWrapper = metricsData.readRow(); Map fieldsValue = Maps.newHashMapWithExpectedSize(8); + String defaultPort = mainMonitorParams.stream() + .filter(param -> FILED_PORT.equals(param.getField())) + .findFirst() + .map(Param::getParamValue) + .orElse(""); while (rowWrapper.hasNextRow()) { rowWrapper = rowWrapper.nextRow(); fieldsValue.clear(); @@ -105,7 +110,7 @@ public class ServiceDiscoveryWorker implements InitializingBean { fieldsValue.put(cell.getField().getName(), value); }); final String host = fieldsValue.get(FILED_HOST); - final String port = fieldsValue.get(FILED_PORT); + final String port = fieldsValue.getOrDefault(FILED_PORT, defaultPort); final String keyStr = host + ":" + port; if (subMonitorBindMap.containsKey(keyStr)) { subMonitorBindMap.remove(keyStr); diff --git a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/dao/MonitorBindDao.java b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/dao/MonitorBindDao.java index 82eb54d4ed..a6300848a6 100644 --- a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/dao/MonitorBindDao.java +++ b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/dao/MonitorBindDao.java @@ -22,6 +22,7 @@ import org.apache.hertzbeat.common.entity.manager.MonitorBind; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Modifying; +import org.springframework.transaction.annotation.Transactional; /** * MonitorBind database operation @@ -33,5 +34,6 @@ public interface MonitorBindDao extends JpaRepository, JpaSpe void deleteByMonitorId(Long monitorId); @Modifying + @Transactional void deleteMonitorBindByBizIdAndMonitorId(Long bizId, Long monitorId); } diff --git a/hertzbeat-manager/src/main/resources/define/app-dns_sd.yml b/hertzbeat-manager/src/main/resources/define/app-dns_sd.yml new file mode 100644 index 0000000000..0fd80aa10e --- /dev/null +++ b/hertzbeat-manager/src/main/resources/define/app-dns_sd.yml @@ -0,0 +1,106 @@ +# 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: __system__ +# Monitoring application type name (consistent with file name) eg: linux windows tomcat mysql aws... +app: dns_sd +# The app api i18n name +name: + zh-CN: Dns Service Discovery + en-US: Dns Service Discovery +# Input params define for app api(render web ui by the definition) +params: + # field-param field key + - field: __sd_host__ + # name-param field display i18n name + name: + zh-CN: DNS地址 + en-US: DNS Host + # type-param field type(most mapping the html input type) + type: text + # required-true or false + required: true + # field-param field key + - field: __sd_port__ + # name-param field display i18n name + name: + zh-CN: DNS端口 + en-US: DNS Port + # type-param field type(most mapping the html input type) + type: text + # required-true or false + required: true + # default value + defaultValue: 53 + - field: __sd_record_type__ + # name-param field display i18n name + name: + zh-CN: 记录类型 + en-US: Record Type + # type-param field type(radio mapping the html radio tag) + type: radio + # required-true or false + required: true + # when type is radio checkbox, use option to show optional values {name1:value1,name2:value2} + options: + - label: SRV + value: 33 + - label: A + value: 1 + - label: AAAA + value: 28 + - label: MX + value: 15 + - label: NS + value: 2 + - field: __sd_record_name__ + # name-param field display i18n name + name: + zh-CN: 记录名 + en-US: Record Name + # type-param field type(most mapping the html input type) + type: text + # required-true or false + required: true +metrics: + - name: target + i18n: + zh-CN: 监控目标 + en-US: Monitor Target + # 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: host + type: 1 + i18n: + zh-CN: Host + en-US: Host + - field: port + type: 1 + i18n: + zh-CN: Port + en-US: Port + # the protocol used for monitoring, eg: sql, ssh, http, telnet, wmi, snmp, sdk + protocol: dns_sd + # the config content when protocol is dns_sd + dns_sd: + host: ^_^__sd_host__^_^ + port: ^_^__sd_port__^_^ + recordType: ^_^__sd_record_type__^_^ + recordName: ^_^__sd_record_name__^_^ diff --git a/web-app/src/app/routes/monitor/monitor-form/monitor-form.component.html b/web-app/src/app/routes/monitor/monitor-form/monitor-form.component.html index 448bc42cec..9f1ad2076c 100644 --- a/web-app/src/app/routes/monitor/monitor-form/monitor-form.component.html +++ b/web-app/src/app/routes/monitor/monitor-form/monitor-form.component.html @@ -31,6 +31,7 @@ > + diff --git a/web-app/src/assets/i18n/en-US.json b/web-app/src/assets/i18n/en-US.json index f1a3689c9b..b570c57db0 100644 --- a/web-app/src/assets/i18n/en-US.json +++ b/web-app/src/assets/i18n/en-US.json @@ -762,6 +762,7 @@ "monitor.sshPrivateKey.tip": "BEGIN RSA PRIVATE KEY", "monitor.scrape.type.static": "Static Scrape", "monitor.scrape.type.http_sd": "Http Service Discovery", + "monitor.scrape.type.dns_sd": "Dns Service Discovery", "monitor.scrape.type.eureka_sd": "Eureka Service Discovery", "monitor.scrape.type.consul_sd": "Consul Service Discovery", "placeholder.key": "Key", diff --git a/web-app/src/assets/i18n/ja-JP.json b/web-app/src/assets/i18n/ja-JP.json index ab7a2ae182..fad463cd59 100644 --- a/web-app/src/assets/i18n/ja-JP.json +++ b/web-app/src/assets/i18n/ja-JP.json @@ -761,6 +761,7 @@ "monitor.sshUsername.tip": "SSHトンネルオープン時に必要", "monitor.sshPrivateKey.tip": "RSA秘密鍵の起動", "monitor.scrape.type.static": "静的な設定", + "monitor.scrape.type.dns_sd": "Dns サービスディスカバリー", "monitor.scrape.type.http_sd": "Http サービスディスカバリー", "monitor.scrape.type.eureka_sd": "Eurekaサービスディスカバリー", "monitor.scrape.type.consul_sd": "Consulサービスディスカバリー", diff --git a/web-app/src/assets/i18n/pt-BR.json b/web-app/src/assets/i18n/pt-BR.json index 05eb348a0f..d6aed35183 100644 --- a/web-app/src/assets/i18n/pt-BR.json +++ b/web-app/src/assets/i18n/pt-BR.json @@ -573,6 +573,7 @@ "monitor.sshPrivateKey.tip": "Chave privada RSA", "monitor.scrape.type.static": "Estatico", "monitor.scrape.type.http_sd": "Http Service Discovery", + "monitor.scrape.type.dns_sd": "Dns Service Discovery", "monitor.scrape.type.eureka_sd": "Eureka Service Discovery", "monitor.scrape.type.consul_sd": "Consul Service Discovery", "common.name": "Nome da Métrica", diff --git a/web-app/src/assets/i18n/zh-CN.json b/web-app/src/assets/i18n/zh-CN.json index ed3cac810c..f9a07af276 100644 --- a/web-app/src/assets/i18n/zh-CN.json +++ b/web-app/src/assets/i18n/zh-CN.json @@ -762,6 +762,7 @@ "monitor.sshPrivateKey.tip": "启动RSA私钥", "monitor.scrape.type.static": "静态配置", "monitor.scrape.type.http_sd": "Http 服务发现", + "monitor.scrape.type.dns_sd": "Dns 服务发现", "monitor.scrape.type.eureka_sd": "Eureka 服务发现", "monitor.scrape.type.consul_sd": "Consul 服务发现", "placeholder.key": "键", diff --git a/web-app/src/assets/i18n/zh-TW.json b/web-app/src/assets/i18n/zh-TW.json index 14908c309b..e1ed05cd0d 100644 --- a/web-app/src/assets/i18n/zh-TW.json +++ b/web-app/src/assets/i18n/zh-TW.json @@ -761,6 +761,7 @@ "monitor.sshPrivateKey.tip": "啟動RSA私鑰", "monitor.scrape.type.static": "靜態配置", "monitor.scrape.type.http_sd": "Http 服務發現", + "monitor.scrape.type.dns_sd": "Dns 服務發現", "monitor.scrape.type.eureka_sd": "Eureka 服務發現", "monitor.scrape.type.consul_sd": "Consul 服務發現", "placeholder.key": "鍵",