Skip to content

Commit 37fbcce

Browse files
authored
Add JSON format support for the /debugging/config/dump status API (#13263)
1 parent 80da79e commit 37fbcce

File tree

5 files changed

+108
-41
lines changed

5 files changed

+108
-41
lines changed

docs/en/changes/changes.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
* Add Ztunnel component in the topology.
2121
* [Break Change] Change `compomentId` to `componentIds` in the K8SServiceRelation Scope.
2222
* Adapt the mesh metrics if detect the ambient mesh in the eBPF access log receiver.
23+
* Add JSON format support for the `/debugging/config/dump` status API.
24+
* Enhance status APIs to support multiple `accept` header values, e.g. `Accept: application/json; charset=utf-8`.
2325

2426
#### UI
2527

docs/en/debugging/config_dump.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,30 @@ core.default.serviceCacheRefreshInterval=10
3535

3636
All booting configurations with their runtime values are listed, including the selected provider for each module.
3737

38+
This API also provides the response in JSON format, which is more friendly for programmatic usage.
39+
40+
```shell
41+
> curl -X GET 'http://127.0.0.1:12800/debugging/config/dump' \
42+
-H 'Accept: application/json'
43+
44+
// The following JSON is manually formatted for better readability.
45+
46+
{
47+
"core.default.autocompleteTagKeysQueryMaxSize":"100",
48+
"receiver-sharing-server.default.gRPCPort":"0",
49+
"aws-firehose.default.port":"12801",
50+
"core.default.restPort":"12800",
51+
"receiver-sharing-server.default.gRPCSslCertChainPath":"",
52+
"agent-analyzer.default.meterAnalyzerActiveFiles":"datasource,threadpool,satellite,go-runtime,python-runtime,continuous-profiling,java-agent,go-agent",
53+
"agent-analyzer.default.traceSamplingPolicySettingsFile":"trace-sampling-policy-settings.yml",
54+
"core.default.gRPCSslTrustedCAPath":"",
55+
"configuration-discovery.default.disableMessageDigest":"false",
56+
"core.default.serviceNameMaxLength":"70",
57+
"aws-firehose.default.tlsCertChainPath":"",
58+
....
59+
}
60+
```
61+
3862
## Protect The Secrets
3963

4064
Some of the configurations contain sensitive values, such as username, password, token, etc. These values would be

oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/status/ServerStatusService.java

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818

1919
package org.apache.skywalking.oap.server.core.status;
2020

21+
import com.google.gson.Gson;
22+
import io.vavr.Tuple2;
23+
import java.util.ArrayList;
2124
import java.util.List;
2225
import java.util.concurrent.CopyOnWriteArrayList;
2326
import lombok.Getter;
@@ -84,20 +87,18 @@ public void registerWatcher(ServerStatusWatcher watcher) {
8487
/**
8588
* @return a complete list of booting configurations with effected values.
8689
* @since 9.7.0
90+
* @since 10.3.0 return ConfigList instead of String, to support raw configurations.
8791
*/
88-
public String dumpBootingConfigurations(String keywords4MaskingSecretsOfConfig) {
92+
public ConfigList dumpBootingConfigurations(String keywords4MaskingSecretsOfConfig) {
93+
ConfigList configList = new ConfigList();
8994
if (configurations == null || configurations.isEmpty()) {
90-
return "No available booting configurations.";
95+
return configList;
9196
}
9297
final String[] keywords = keywords4MaskingSecretsOfConfig.split(",");
93-
StringBuilder configList = new StringBuilder();
9498
for (ApplicationConfiguration.ModuleConfiguration configuration : configurations) {
9599
final String moduleName = configuration.getModuleName();
96100
if (configuration.getProviders().size() == 1) {
97-
configList.append(moduleName)
98-
.append(".provider=")
99-
.append(configuration.getProviders().keySet().iterator().next())
100-
.append("\n");
101+
configList.add(moduleName + ".provider", configuration.getProviders().keySet().iterator().next());
101102
}
102103
configuration.getProviders().forEach(
103104
(providerName, providerConfiguration) ->
@@ -108,19 +109,41 @@ public String dumpBootingConfigurations(String keywords4MaskingSecretsOfConfig)
108109
value = "******";
109110
}
110111
}
111-
112-
configList.append(moduleName)
113-
.append(".")
114-
.append(providerName)
115-
.append(".")
116-
.append(key)
117-
.append("=")
118-
.append(value)
119-
.append("\n");
112+
configList.add(moduleName + "." + providerName + "." + key, value.toString());
120113
}
121114
)
122115
);
123116
}
124-
return configList.toString();
117+
return configList;
118+
}
119+
120+
public static class ConfigList {
121+
private final static Gson GSON = new Gson();
122+
private List<Tuple2> configurations = new ArrayList<>(200);
123+
124+
public void add(String key, String value) {
125+
configurations.add(new Tuple2<>(key, value));
126+
}
127+
128+
@Override
129+
public String toString() {
130+
StringBuilder configList = new StringBuilder();
131+
for (Tuple2 tuple : configurations) {
132+
configList.append(tuple._1)
133+
.append("=")
134+
.append(tuple._2)
135+
.append("\n");
136+
}
137+
return configList.toString();
138+
}
139+
140+
public String toJsonString() {
141+
return GSON.toJson(configurations.stream()
142+
.collect(
143+
java.util.stream.Collectors.toMap(
144+
tuple -> tuple._1.toString(),
145+
tuple -> tuple._2.toString()
146+
)));
147+
}
125148
}
126149
}

oap-server/server-query-plugin/status-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/DebuggingHTTPHandler.java

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
import com.google.common.reflect.TypeToken;
2727
import com.google.gson.Gson;
2828
import com.linecorp.armeria.common.AggregatedHttpResponse;
29+
import com.linecorp.armeria.common.HttpHeaderNames;
30+
import com.linecorp.armeria.common.HttpRequest;
2931
import com.linecorp.armeria.server.annotation.Default;
3032
import com.linecorp.armeria.server.annotation.ExceptionHandler;
3133
import com.linecorp.armeria.server.annotation.Get;
@@ -38,7 +40,6 @@
3840
import java.util.stream.Collectors;
3941
import lombok.SneakyThrows;
4042
import lombok.extern.slf4j.Slf4j;
41-
import org.apache.skywalking.oap.server.core.query.mqe.ExpressionResult;
4243
import org.apache.skywalking.oap.query.debug.log.DebuggingQueryLogsRsp;
4344
import org.apache.skywalking.oap.query.debug.mqe.DebuggingMQERsp;
4445
import org.apache.skywalking.oap.query.debug.topology.DebuggingQueryEndpointTopologyRsp;
@@ -67,6 +68,7 @@
6768
import org.apache.skywalking.oap.server.core.query.input.LogQueryCondition;
6869
import org.apache.skywalking.oap.server.core.query.input.TraceQueryCondition;
6970
import org.apache.skywalking.oap.server.core.query.input.TraceScopeCondition;
71+
import org.apache.skywalking.oap.server.core.query.mqe.ExpressionResult;
7072
import org.apache.skywalking.oap.server.core.query.type.EndpointTopology;
7173
import org.apache.skywalking.oap.server.core.query.type.Logs;
7274
import org.apache.skywalking.oap.server.core.query.type.Pagination;
@@ -77,8 +79,8 @@
7779
import org.apache.skywalking.oap.server.core.query.type.Trace;
7880
import org.apache.skywalking.oap.server.core.query.type.TraceBrief;
7981
import org.apache.skywalking.oap.server.core.query.type.TraceState;
80-
import org.apache.skywalking.oap.server.core.query.type.debugging.DebuggingTrace;
8182
import org.apache.skywalking.oap.server.core.query.type.debugging.DebuggingSpan;
83+
import org.apache.skywalking.oap.server.core.query.type.debugging.DebuggingTrace;
8284
import org.apache.skywalking.oap.server.core.query.type.debugging.DebuggingTraceContext;
8385
import org.apache.skywalking.oap.server.core.status.ServerStatusService;
8486
import org.apache.skywalking.oap.server.library.module.ModuleManager;
@@ -109,8 +111,13 @@ public DebuggingHTTPHandler(final ModuleManager manager, final StatusQueryConfig
109111
}
110112

111113
@Get("/debugging/config/dump")
112-
public String dumpConfigurations() {
113-
return serverStatusService.dumpBootingConfigurations(config.getKeywords4MaskingSecretsOfConfig());
114+
public String dumpConfigurations(HttpRequest request) {
115+
final String acceptHeader = request.headers().get(HttpHeaderNames.ACCEPT);
116+
if (acceptHeader != null && acceptHeader.toLowerCase().contains("application/json")) {
117+
return serverStatusService.dumpBootingConfigurations(config.getKeywords4MaskingSecretsOfConfig())
118+
.toJsonString();
119+
}
120+
return serverStatusService.dumpBootingConfigurations(config.getKeywords4MaskingSecretsOfConfig()).toString();
114121
}
115122

116123
@SneakyThrows
@@ -150,7 +157,8 @@ public String execExpression(@Param("dumpDBRsp") boolean dumpStorageRsp,
150157
duration.setEnd(endTime);
151158
duration.setStep(Step.valueOf(step));
152159
coldStage.ifPresent(duration::setColdStage);
153-
ExpressionResult expressionResult = mqeQuery.execExpression(expression, entity, duration, true, dumpStorageRsp).join();
160+
ExpressionResult expressionResult = mqeQuery.execExpression(expression, entity, duration, true, dumpStorageRsp)
161+
.join();
154162
DebuggingTrace execTrace = expressionResult.getDebuggingTrace();
155163
DebuggingMQERsp result = new DebuggingMQERsp(
156164
expressionResult.getType(), expressionResult.getResults(), expressionResult.getError(),
@@ -279,8 +287,10 @@ public String queryZipkinTraces(@Param("serviceName") Optional<String> serviceNa
279287
);
280288
List<List<Span>> traces = new ArrayList<>();
281289
if (response.status().code() == 200) {
282-
traces = new Gson().fromJson(response.contentUtf8(), new TypeToken<ArrayList<ArrayList<Span>>>() {
283-
}.getType());
290+
traces = new Gson().fromJson(
291+
response.contentUtf8(), new TypeToken<ArrayList<ArrayList<Span>>>() {
292+
}.getType()
293+
);
284294
}
285295
DebuggingZipkinQueryTracesRsp result = new DebuggingZipkinQueryTracesRsp(
286296
traces, transformTrace(traceContext.getExecTrace()));
@@ -300,11 +310,15 @@ public String getZipkinTraceById(@Param("traceId") String traceId) {
300310
AggregatedHttpResponse response = zipkinQueryHandler.getTraceById(traceId);
301311
List<Span> trace = new ArrayList<>();
302312
if (response.status().code() == 200) {
303-
trace = new Gson().fromJson(response.contentUtf8(), new TypeToken<ArrayList<Span>>() {
304-
}.getType());
313+
trace = new Gson().fromJson(
314+
response.contentUtf8(), new TypeToken<ArrayList<Span>>() {
315+
}.getType()
316+
);
305317
}
306-
DebuggingZipkinQueryTraceRsp result = new DebuggingZipkinQueryTraceRsp(trace, transformTrace(
307-
traceContext.getExecTrace()));
318+
DebuggingZipkinQueryTraceRsp result = new DebuggingZipkinQueryTraceRsp(
319+
trace, transformTrace(
320+
traceContext.getExecTrace())
321+
);
308322
return transToYAMLStringZipkin(result);
309323
} finally {
310324
traceContext.stopTrace();
@@ -315,10 +329,10 @@ public String getZipkinTraceById(@Param("traceId") String traceId) {
315329
@SneakyThrows
316330
@Get("/debugging/query/topology/getGlobalTopology")
317331
public String getGlobalTopology(@Param("startTime") String startTime,
318-
@Param("endTime") String endTime,
319-
@Param("step") String step,
320-
@Param("coldStage") Optional<Boolean> coldStage,
321-
@Param("serviceLayer") Optional<String> serviceLayer) {
332+
@Param("endTime") String endTime,
333+
@Param("step") String step,
334+
@Param("coldStage") Optional<Boolean> coldStage,
335+
@Param("serviceLayer") Optional<String> serviceLayer) {
322336
Duration duration = new Duration();
323337
duration.setStart(startTime);
324338
duration.setEnd(endTime);
@@ -333,11 +347,11 @@ public String getGlobalTopology(@Param("startTime") String startTime,
333347
@SneakyThrows
334348
@Get("/debugging/query/topology/getServicesTopology")
335349
public String getServicesTopology(@Param("startTime") String startTime,
336-
@Param("endTime") String endTime,
337-
@Param("step") String step,
338-
@Param("coldStage") Optional<Boolean> coldStage,
339-
@Param("serviceLayer") String serviceLayer,
340-
@Param("services") String services) {
350+
@Param("endTime") String endTime,
351+
@Param("step") String step,
352+
@Param("coldStage") Optional<Boolean> coldStage,
353+
@Param("serviceLayer") String serviceLayer,
354+
@Param("services") String services) {
341355
Duration duration = new Duration();
342356
duration.setStart(startTime);
343357
duration.setEnd(endTime);
@@ -367,9 +381,12 @@ public String getServiceInstanceTopology(@Param("startTime") String startTime,
367381
duration.setEnd(endTime);
368382
duration.setStep(Step.valueOf(step));
369383
coldStage.ifPresent(duration::setColdStage);
370-
String clientServiceId = IDManager.ServiceID.buildId(clientService, Layer.nameOf(clientServiceLayer).isNormal());
371-
String serverServiceId = IDManager.ServiceID.buildId(serverService, Layer.nameOf(serverServiceLayer).isNormal());
372-
ServiceInstanceTopology topology = topologyQuery.getServiceInstanceTopology(clientServiceId, serverServiceId, duration, true).join();
384+
String clientServiceId = IDManager.ServiceID.buildId(
385+
clientService, Layer.nameOf(clientServiceLayer).isNormal());
386+
String serverServiceId = IDManager.ServiceID.buildId(
387+
serverService, Layer.nameOf(serverServiceLayer).isNormal());
388+
ServiceInstanceTopology topology = topologyQuery.getServiceInstanceTopology(
389+
clientServiceId, serverServiceId, duration, true).join();
373390
DebuggingQueryInstanceTopologyRsp result = new DebuggingQueryInstanceTopologyRsp(
374391
topology.getNodes(), topology.getCalls(), transformTrace(topology.getDebuggingTrace()));
375392
return transToYAMLString(result);

oap-server/server-query-plugin/status-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/TTLConfigQueryHandler.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ private TTLStatusQuery getTTLStatusQuery() {
5050

5151
@Get("/status/config/ttl")
5252
public HttpResponse affectedTTLConfigurations(HttpRequest request) {
53-
if ("application/json".equalsIgnoreCase(request.headers().get(HttpHeaderNames.ACCEPT))) {
53+
final String acceptHeader = request.headers().get(HttpHeaderNames.ACCEPT);
54+
if (acceptHeader != null && acceptHeader.toLowerCase().contains("application/json")) {
5455
return HttpResponse.of(MediaType.JSON_UTF_8, getTTLStatusQuery().getTTL().generateTTLDefinitionAsJSONStr());
5556
}
5657
return HttpResponse.of(MediaType.PLAIN_TEXT_UTF_8, getTTLStatusQuery().getTTL().generateTTLDefinition());

0 commit comments

Comments
 (0)