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.sh...@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);

Reply via email to