You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2025/05/26 02:39:11 UTC
(skywalking) 01/01: Add JSON format support for the `/debugging/config/dump` status API
This is an automated email from the ASF dual-hosted git repository.
wusheng pushed a commit to branch api-json
in repository https://gitbox.apache.org/repos/asf/skywalking.git
commit fb8bc981353caee6dbbdbe1ae831d3549c2e6a4b
Author: Wu Sheng <wu...@foxmail.com>
AuthorDate: Mon May 26 10:39:00 2025 +0800
Add JSON format support for the `/debugging/config/dump` status API
---
docs/en/changes/changes.md | 1 +
docs/en/debugging/config_dump.md | 24 +++++++++
.../server/core/status/ServerStatusService.java | 57 ++++++++++++++------
.../oap/query/debug/DebuggingHTTPHandler.java | 62 ++++++++++++++--------
4 files changed, 104 insertions(+), 40 deletions(-)
diff --git a/docs/en/changes/changes.md b/docs/en/changes/changes.md
index 09a199d4aa..cb8f3bb73a 100644
--- a/docs/en/changes/changes.md
+++ b/docs/en/changes/changes.md
@@ -20,6 +20,7 @@
* Add Ztunnel component in the topology.
* [Break Change] Change `compomentId` to `componentIds` in the K8SServiceRelation Scope.
* Adapt the mesh metrics if detect the ambient mesh in the eBPF access log receiver.
+* Add JSON format support for the `/debugging/config/dump` status API.
#### UI
diff --git a/docs/en/debugging/config_dump.md b/docs/en/debugging/config_dump.md
index 4f5bad7b8d..c416719c50 100644
--- a/docs/en/debugging/config_dump.md
+++ b/docs/en/debugging/config_dump.md
@@ -35,6 +35,30 @@ core.default.serviceCacheRefreshInterval=10
All booting configurations with their runtime values are listed, including the selected provider for each module.
+This API also provides the response in JSON format, which is more friendly for programmatic usage.
+
+```shell
+> curl -X GET 'http://127.0.0.1:12800/debugging/config/dump' \
+ -H 'Accept: application/json'
+
+// The following JSON is manually formatted for better readability.
+
+{
+ "core.default.autocompleteTagKeysQueryMaxSize":"100",
+ "receiver-sharing-server.default.gRPCPort":"0",
+ "aws-firehose.default.port":"12801",
+ "core.default.restPort":"12800",
+ "receiver-sharing-server.default.gRPCSslCertChainPath":"",
+ "agent-analyzer.default.meterAnalyzerActiveFiles":"datasource,threadpool,satellite,go-runtime,python-runtime,continuous-profiling,java-agent,go-agent",
+ "agent-analyzer.default.traceSamplingPolicySettingsFile":"trace-sampling-policy-settings.yml",
+ "core.default.gRPCSslTrustedCAPath":"",
+ "configuration-discovery.default.disableMessageDigest":"false",
+ "core.default.serviceNameMaxLength":"70",
+ "aws-firehose.default.tlsCertChainPath":"",
+ ....
+}
+```
+
## Protect The Secrets
Some of the configurations contain sensitive values, such as username, password, token, etc. These values would be
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/status/ServerStatusService.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/status/ServerStatusService.java
index a6dea09e2f..0a498877be 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/status/ServerStatusService.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/status/ServerStatusService.java
@@ -18,6 +18,9 @@
package org.apache.skywalking.oap.server.core.status;
+import com.google.gson.Gson;
+import io.vavr.Tuple2;
+import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import lombok.Getter;
@@ -84,20 +87,18 @@ public class ServerStatusService implements Service {
/**
* @return a complete list of booting configurations with effected values.
* @since 9.7.0
+ * @since 10.3.0 return ConfigList instead of String, to support raw configurations.
*/
- public String dumpBootingConfigurations(String keywords4MaskingSecretsOfConfig) {
+ public ConfigList dumpBootingConfigurations(String keywords4MaskingSecretsOfConfig) {
+ ConfigList configList = new ConfigList();
if (configurations == null || configurations.isEmpty()) {
- return "No available booting configurations.";
+ return configList;
}
final String[] keywords = keywords4MaskingSecretsOfConfig.split(",");
- StringBuilder configList = new StringBuilder();
for (ApplicationConfiguration.ModuleConfiguration configuration : configurations) {
final String moduleName = configuration.getModuleName();
if (configuration.getProviders().size() == 1) {
- configList.append(moduleName)
- .append(".provider=")
- .append(configuration.getProviders().keySet().iterator().next())
- .append("\n");
+ configList.add(moduleName + ".provider", configuration.getProviders().keySet().iterator().next());
}
configuration.getProviders().forEach(
(providerName, providerConfiguration) ->
@@ -108,19 +109,41 @@ public class ServerStatusService implements Service {
value = "******";
}
}
-
- configList.append(moduleName)
- .append(".")
- .append(providerName)
- .append(".")
- .append(key)
- .append("=")
- .append(value)
- .append("\n");
+ configList.add(moduleName + "." + providerName + "." + key, value.toString());
}
)
);
}
- return configList.toString();
+ return configList;
+ }
+
+ public static class ConfigList {
+ private final static Gson GSON = new Gson();
+ private List<Tuple2> configurations = new ArrayList<>(200);
+
+ public void add(String key, String value) {
+ configurations.add(new Tuple2<>(key, value));
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder configList = new StringBuilder();
+ for (Tuple2 tuple : configurations) {
+ configList.append(tuple._1)
+ .append("=")
+ .append(tuple._2)
+ .append("\n");
+ }
+ return configList.toString();
+ }
+
+ public String toJsonString() {
+ return GSON.toJson(configurations.stream()
+ .collect(
+ java.util.stream.Collectors.toMap(
+ tuple -> tuple._1.toString(),
+ tuple -> tuple._2.toString()
+ )));
+ }
}
}
diff --git a/oap-server/server-query-plugin/status-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/DebuggingHTTPHandler.java b/oap-server/server-query-plugin/status-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/DebuggingHTTPHandler.java
index cd03825648..901588ff36 100644
--- a/oap-server/server-query-plugin/status-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/DebuggingHTTPHandler.java
+++ b/oap-server/server-query-plugin/status-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/DebuggingHTTPHandler.java
@@ -26,6 +26,8 @@ import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.linecorp.armeria.common.AggregatedHttpResponse;
+import com.linecorp.armeria.common.HttpHeaderNames;
+import com.linecorp.armeria.common.HttpRequest;
import com.linecorp.armeria.server.annotation.Default;
import com.linecorp.armeria.server.annotation.ExceptionHandler;
import com.linecorp.armeria.server.annotation.Get;
@@ -38,7 +40,6 @@ import java.util.Optional;
import java.util.stream.Collectors;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
-import org.apache.skywalking.oap.server.core.query.mqe.ExpressionResult;
import org.apache.skywalking.oap.query.debug.log.DebuggingQueryLogsRsp;
import org.apache.skywalking.oap.query.debug.mqe.DebuggingMQERsp;
import org.apache.skywalking.oap.query.debug.topology.DebuggingQueryEndpointTopologyRsp;
@@ -67,6 +68,7 @@ import org.apache.skywalking.oap.server.core.query.input.Entity;
import org.apache.skywalking.oap.server.core.query.input.LogQueryCondition;
import org.apache.skywalking.oap.server.core.query.input.TraceQueryCondition;
import org.apache.skywalking.oap.server.core.query.input.TraceScopeCondition;
+import org.apache.skywalking.oap.server.core.query.mqe.ExpressionResult;
import org.apache.skywalking.oap.server.core.query.type.EndpointTopology;
import org.apache.skywalking.oap.server.core.query.type.Logs;
import org.apache.skywalking.oap.server.core.query.type.Pagination;
@@ -77,8 +79,8 @@ import org.apache.skywalking.oap.server.core.query.type.Topology;
import org.apache.skywalking.oap.server.core.query.type.Trace;
import org.apache.skywalking.oap.server.core.query.type.TraceBrief;
import org.apache.skywalking.oap.server.core.query.type.TraceState;
-import org.apache.skywalking.oap.server.core.query.type.debugging.DebuggingTrace;
import org.apache.skywalking.oap.server.core.query.type.debugging.DebuggingSpan;
+import org.apache.skywalking.oap.server.core.query.type.debugging.DebuggingTrace;
import org.apache.skywalking.oap.server.core.query.type.debugging.DebuggingTraceContext;
import org.apache.skywalking.oap.server.core.status.ServerStatusService;
import org.apache.skywalking.oap.server.library.module.ModuleManager;
@@ -109,8 +111,12 @@ public class DebuggingHTTPHandler {
}
@Get("/debugging/config/dump")
- public String dumpConfigurations() {
- return serverStatusService.dumpBootingConfigurations(config.getKeywords4MaskingSecretsOfConfig());
+ public String dumpConfigurations(HttpRequest request) {
+ if ("application/json".equalsIgnoreCase(request.headers().get(HttpHeaderNames.ACCEPT))) {
+ return serverStatusService.dumpBootingConfigurations(config.getKeywords4MaskingSecretsOfConfig())
+ .toJsonString();
+ }
+ return serverStatusService.dumpBootingConfigurations(config.getKeywords4MaskingSecretsOfConfig()).toString();
}
@SneakyThrows
@@ -150,7 +156,8 @@ public class DebuggingHTTPHandler {
duration.setEnd(endTime);
duration.setStep(Step.valueOf(step));
coldStage.ifPresent(duration::setColdStage);
- ExpressionResult expressionResult = mqeQuery.execExpression(expression, entity, duration, true, dumpStorageRsp).join();
+ ExpressionResult expressionResult = mqeQuery.execExpression(expression, entity, duration, true, dumpStorageRsp)
+ .join();
DebuggingTrace execTrace = expressionResult.getDebuggingTrace();
DebuggingMQERsp result = new DebuggingMQERsp(
expressionResult.getType(), expressionResult.getResults(), expressionResult.getError(),
@@ -279,8 +286,10 @@ public class DebuggingHTTPHandler {
);
List<List<Span>> traces = new ArrayList<>();
if (response.status().code() == 200) {
- traces = new Gson().fromJson(response.contentUtf8(), new TypeToken<ArrayList<ArrayList<Span>>>() {
- }.getType());
+ traces = new Gson().fromJson(
+ response.contentUtf8(), new TypeToken<ArrayList<ArrayList<Span>>>() {
+ }.getType()
+ );
}
DebuggingZipkinQueryTracesRsp result = new DebuggingZipkinQueryTracesRsp(
traces, transformTrace(traceContext.getExecTrace()));
@@ -300,11 +309,15 @@ public class DebuggingHTTPHandler {
AggregatedHttpResponse response = zipkinQueryHandler.getTraceById(traceId);
List<Span> trace = new ArrayList<>();
if (response.status().code() == 200) {
- trace = new Gson().fromJson(response.contentUtf8(), new TypeToken<ArrayList<Span>>() {
- }.getType());
+ trace = new Gson().fromJson(
+ response.contentUtf8(), new TypeToken<ArrayList<Span>>() {
+ }.getType()
+ );
}
- DebuggingZipkinQueryTraceRsp result = new DebuggingZipkinQueryTraceRsp(trace, transformTrace(
- traceContext.getExecTrace()));
+ DebuggingZipkinQueryTraceRsp result = new DebuggingZipkinQueryTraceRsp(
+ trace, transformTrace(
+ traceContext.getExecTrace())
+ );
return transToYAMLStringZipkin(result);
} finally {
traceContext.stopTrace();
@@ -315,10 +328,10 @@ public class DebuggingHTTPHandler {
@SneakyThrows
@Get("/debugging/query/topology/getGlobalTopology")
public String getGlobalTopology(@Param("startTime") String startTime,
- @Param("endTime") String endTime,
- @Param("step") String step,
- @Param("coldStage") Optional<Boolean> coldStage,
- @Param("serviceLayer") Optional<String> serviceLayer) {
+ @Param("endTime") String endTime,
+ @Param("step") String step,
+ @Param("coldStage") Optional<Boolean> coldStage,
+ @Param("serviceLayer") Optional<String> serviceLayer) {
Duration duration = new Duration();
duration.setStart(startTime);
duration.setEnd(endTime);
@@ -333,11 +346,11 @@ public class DebuggingHTTPHandler {
@SneakyThrows
@Get("/debugging/query/topology/getServicesTopology")
public String getServicesTopology(@Param("startTime") String startTime,
- @Param("endTime") String endTime,
- @Param("step") String step,
- @Param("coldStage") Optional<Boolean> coldStage,
- @Param("serviceLayer") String serviceLayer,
- @Param("services") String services) {
+ @Param("endTime") String endTime,
+ @Param("step") String step,
+ @Param("coldStage") Optional<Boolean> coldStage,
+ @Param("serviceLayer") String serviceLayer,
+ @Param("services") String services) {
Duration duration = new Duration();
duration.setStart(startTime);
duration.setEnd(endTime);
@@ -367,9 +380,12 @@ public class DebuggingHTTPHandler {
duration.setEnd(endTime);
duration.setStep(Step.valueOf(step));
coldStage.ifPresent(duration::setColdStage);
- String clientServiceId = IDManager.ServiceID.buildId(clientService, Layer.nameOf(clientServiceLayer).isNormal());
- String serverServiceId = IDManager.ServiceID.buildId(serverService, Layer.nameOf(serverServiceLayer).isNormal());
- ServiceInstanceTopology topology = topologyQuery.getServiceInstanceTopology(clientServiceId, serverServiceId, duration, true).join();
+ String clientServiceId = IDManager.ServiceID.buildId(
+ clientService, Layer.nameOf(clientServiceLayer).isNormal());
+ String serverServiceId = IDManager.ServiceID.buildId(
+ serverService, Layer.nameOf(serverServiceLayer).isNormal());
+ ServiceInstanceTopology topology = topologyQuery.getServiceInstanceTopology(
+ clientServiceId, serverServiceId, duration, true).join();
DebuggingQueryInstanceTopologyRsp result = new DebuggingQueryInstanceTopologyRsp(
topology.getNodes(), topology.getCalls(), transformTrace(topology.getDebuggingTrace()));
return transToYAMLString(result);