Skip to content

Commit 2526cf6

Browse files
committed
New diagnostic REST resource
1 parent 7433ffc commit 2526cf6

File tree

13 files changed

+135
-34
lines changed

13 files changed

+135
-34
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
* [new] The `SEEDSTACK_PROFILES` environment variable can now be used to specify comma-separated configuration profiles
77
to enable. These profiles will be added to the profiles already defined in the `seedstack.profiles` system property if
88
any.
9+
* [new] If config option `rest.diagnosticResource` is set to `true`, the diagnostic report will be available as a JSON
10+
representation at `/seedstack/diagnostic`. Do not enable permanently in production. Default is `false`.
911

1012
# Version 3.12.1 (2021-05-21)
1113

core/src/main/java/org/seedstack/seed/core/SeedRuntime.java

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,7 @@
88

99
package org.seedstack.seed.core;
1010

11-
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
1211
import io.nuun.kernel.api.Plugin;
13-
import java.io.IOException;
14-
import java.util.Collection;
15-
import java.util.HashMap;
16-
import java.util.HashSet;
17-
import java.util.Map;
18-
import java.util.ServiceLoader;
19-
import java.util.Set;
2012
import org.seedstack.coffig.Coffig;
2113
import org.seedstack.coffig.provider.CompositeProvider;
2214
import org.seedstack.coffig.provider.InMemoryProvider;
@@ -26,9 +18,15 @@
2618
import org.seedstack.seed.diagnostic.spi.DiagnosticInfoCollector;
2719
import org.seedstack.seed.spi.ConfigurationPriority;
2820

21+
import java.util.Collection;
22+
import java.util.HashMap;
23+
import java.util.HashSet;
24+
import java.util.Map;
25+
import java.util.ServiceLoader;
26+
import java.util.Set;
27+
2928
public class SeedRuntime {
3029
private static final String SEED_PACKAGE_PREFIX = "org.seedstack.seed";
31-
private static final YAMLMapper yamlMapper = new YAMLMapper();
3230
private final Object context;
3331
private final DiagnosticManager diagnosticManager;
3432
private final Coffig configuration;
@@ -45,7 +43,7 @@ private SeedRuntime(Object context, DiagnosticManager diagnosticManager, Coffig
4543
this.configuration = configuration;
4644
this.seedVersion = seedVersion;
4745
this.businessVersion = businessVersion;
48-
this.diagnosticManager.registerDiagnosticInfoCollector("seed", new RuntimeDiagnosticCollector());
46+
this.diagnosticManager.registerDiagnosticInfoCollector("seedstack", new RuntimeDiagnosticCollector());
4947
this.prioritizedProvider = ((CompositeProvider) this.configuration.getProvider()).get(
5048
PrioritizedProvider.class);
5149
this.inMemoryProvider = new InMemoryProvider();
@@ -168,11 +166,6 @@ public Map<String, Object> collect() {
168166
result.put("businessVersion", businessVersion == null ? "UNKNOWN" : businessVersion);
169167
result.put("inconsistentPlugins", inconsistentPlugins);
170168
result.put("contextClass", context == null ? "NONE" : context.getClass().getName());
171-
try {
172-
result.put("configuration", yamlMapper.readValue(configuration.toString(), Map.class));
173-
} catch (IOException | RuntimeException e) {
174-
result.put("rawConfiguration", configuration.toString());
175-
}
176169

177170
return result;
178171
}

core/src/main/java/org/seedstack/seed/core/internal/configuration/ApplicationDiagnosticCollector.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,19 @@
77
*/
88
package org.seedstack.seed.core.internal.configuration;
99

10-
import java.util.HashMap;
11-
import java.util.Map;
10+
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
1211
import org.seedstack.seed.Application;
1312
import org.seedstack.seed.diagnostic.spi.DiagnosticInfoCollector;
13+
import org.slf4j.Logger;
14+
import org.slf4j.LoggerFactory;
15+
16+
import java.io.IOException;
17+
import java.util.HashMap;
18+
import java.util.Map;
1419

1520
class ApplicationDiagnosticCollector implements DiagnosticInfoCollector {
21+
private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationDiagnosticCollector.class);
22+
private final YAMLMapper yamlMapper = new YAMLMapper();
1623
private final Application application;
1724

1825
ApplicationDiagnosticCollector(Application application) {
@@ -30,6 +37,15 @@ public Map<String, Object> collect() {
3037
result.put("storage", application.getStorageLocation(""));
3138
}
3239

40+
try {
41+
result.put("configuration", yamlMapper.readValue(application.getConfiguration().toString(), Map.class));
42+
} catch (IOException | RuntimeException e) {
43+
LOGGER.warn("Error building diagnostic configuration, using toString() instead", e);
44+
result.put("configuration", application.getConfiguration().toString());
45+
}
46+
47+
result.put("configurationProfiles", application.getConfigurationProfiles());
48+
3349
return result;
3450
}
3551
}

core/src/main/java/org/seedstack/seed/core/internal/configuration/ApplicationImpl.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@
88
package org.seedstack.seed.core.internal.configuration;
99

1010
import com.google.inject.util.Types;
11+
1112
import java.io.File;
1213
import java.util.Collections;
1314
import java.util.Map;
15+
import java.util.Set;
16+
1417
import org.seedstack.coffig.Coffig;
1518
import org.seedstack.coffig.node.ValueNode;
1619
import org.seedstack.seed.Application;
@@ -77,6 +80,11 @@ public Coffig getConfiguration() {
7780
return coffig;
7881
}
7982

83+
@Override
84+
public Set<String> getConfigurationProfiles() {
85+
return ProfileProcessor.activeProfiles();
86+
}
87+
8088
@Override
8189
@SuppressWarnings("unchecked")
8290
public <T> ClassConfiguration<T> getConfiguration(Class<T> someClass) {

core/src/test/java/custom/CustomApplicationProvider.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import java.io.File;
1111
import java.util.Map;
12+
import java.util.Set;
1213
import javax.inject.Provider;
1314
import org.seedstack.coffig.Coffig;
1415
import org.seedstack.seed.Application;
@@ -50,6 +51,11 @@ public Coffig getConfiguration() {
5051
return null;
5152
}
5253

54+
@Override
55+
public Set<String> getConfigurationProfiles() {
56+
return null;
57+
}
58+
5359
@Override
5460
public <T> ClassConfiguration<T> getConfiguration(Class<T> someClass) {
5561
return null;

core/src/test/java/org/seedstack/seed/core/DiagnosticManagerIT.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,10 @@ public void seed_info_is_present() {
6868

6969
assertThat(diagnosticInfo).isNotNull();
7070

71-
Map<String, Object> seedInfo = (Map<String, Object>) diagnosticInfo.get("seed");
71+
Map<String, Object> seedInfo = (Map<String, Object>) diagnosticInfo.get("seedstack");
7272
assertThat((String) (seedInfo.get("version"))).isNotEmpty();
7373
assertThat((Set<String>) (seedInfo.get("inconsistentPlugins"))).isNotNull();
7474
assertThat((String) (seedInfo.get("contextClass"))).isNotEmpty();
75-
assertThat(seedInfo.get("configuration")).isNotNull();
7675
}
7776

7877
@Test
@@ -104,7 +103,9 @@ public void diagnostic_application_information_is_present() {
104103
assertThat(applicationInfo.get("id")).isNotNull();
105104
assertThat(applicationInfo.get("name")).isNotNull();
106105
assertThat(applicationInfo.get("version")).isNotNull();
107-
assertThat(applicationInfo.get("storage-location")).isNull();
106+
assertThat(applicationInfo.get("storage")).isNotNull(); // storage is automatically enabled during integration testing
107+
assertThat(applicationInfo.get("configuration")).isNotNull();
108+
assertThat(applicationInfo.get("configurationProfiles")).isNotNull();
108109
}
109110

110111
@Test
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright © 2013-2021, The SeedStack authors <http://seedstack.org>
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this
6+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
7+
*/
8+
package org.seedstack.seed.rest.internal;
9+
10+
import org.seedstack.seed.diagnostic.DiagnosticManager;
11+
import org.seedstack.seed.diagnostic.spi.DiagnosticInfoCollector;
12+
13+
import javax.inject.Inject;
14+
import javax.ws.rs.GET;
15+
import javax.ws.rs.Path;
16+
import javax.ws.rs.Produces;
17+
import javax.ws.rs.core.MediaType;
18+
import java.util.Map;
19+
20+
@Path("/seedstack/diagnostic")
21+
public class DiagnosticResource {
22+
@Inject
23+
private DiagnosticManager diagnosticManager;
24+
25+
@GET
26+
@Produces(MediaType.APPLICATION_JSON)
27+
public Map<String, Object> diag() {
28+
return diagnosticManager.getDiagnosticInfo(null);
29+
}
30+
}

rest/core/src/main/java/org/seedstack/seed/rest/internal/RestPlugin.java

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,6 @@
1515
import io.nuun.kernel.api.plugin.InitState;
1616
import io.nuun.kernel.api.plugin.context.InitContext;
1717
import io.nuun.kernel.api.plugin.request.ClasspathScanRequest;
18-
import java.util.Collection;
19-
import java.util.HashMap;
20-
import java.util.HashSet;
21-
import java.util.Locale;
22-
import java.util.Map;
23-
import java.util.Set;
24-
import java.util.function.Predicate;
25-
import javax.servlet.ServletContext;
26-
import javax.ws.rs.core.MediaType;
27-
import javax.ws.rs.core.Variant;
2818
import org.seedstack.seed.core.SeedRuntime;
2919
import org.seedstack.seed.core.internal.AbstractSeedPlugin;
3020
import org.seedstack.seed.core.internal.init.ValidationManager;
@@ -46,6 +36,17 @@
4636
import org.slf4j.Logger;
4737
import org.slf4j.LoggerFactory;
4838

39+
import javax.servlet.ServletContext;
40+
import javax.ws.rs.core.MediaType;
41+
import javax.ws.rs.core.Variant;
42+
import java.util.Collection;
43+
import java.util.HashMap;
44+
import java.util.HashSet;
45+
import java.util.Locale;
46+
import java.util.Map;
47+
import java.util.Set;
48+
import java.util.function.Predicate;
49+
4950
public class RestPlugin extends AbstractSeedPlugin implements RestProvider {
5051
private static final Logger LOGGER = LoggerFactory.getLogger(RestPlugin.class);
5152
private final Map<Variant, Class<? extends RootResource>> rootResourcesByVariant = new HashMap<>();
@@ -89,6 +90,7 @@ public InitState initialize(InitContext initContext) {
8990

9091
configureExceptionMappers();
9192
configureStreamSupport();
93+
configureDiagResource();
9294

9395
initializeHypermedia(servletContext.getContextPath());
9496

@@ -141,6 +143,15 @@ private boolean isDynamicValidationSupported() {
141143
return ValidationManager.get().getValidationLevel().compareTo(ValidationManager.ValidationLevel.LEVEL_1_1) >= 0;
142144
}
143145

146+
private void configureDiagResource() {
147+
if (!restConfig.isDiagnosticResource()) {
148+
resources.remove(DiagnosticResource.class);
149+
LOGGER.debug("Diagnostic resource disabled");
150+
} else {
151+
LOGGER.info("Diagnostic resource accessible at {}/{}", restConfig.getPath(), "seedstack/diag");
152+
}
153+
}
154+
144155
private void configureStreamSupport() {
145156
if (!restConfig.isStreamSupport()) {
146157
providers.remove(StreamMessageBodyReader.class);

rest/jersey2/src/test/java/org/seedstack/seed/rest/jersey2/Jersey2IT.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,7 @@
77
*/
88
package org.seedstack.seed.rest.jersey2;
99

10-
import static io.restassured.RestAssured.expect;
11-
import static org.assertj.core.api.Assertions.assertThat;
12-
1310
import io.restassured.response.Response;
14-
import javax.ws.rs.core.MediaType;
1511
import org.json.JSONException;
1612
import org.junit.Test;
1713
import org.junit.runner.RunWith;
@@ -20,6 +16,11 @@
2016
import org.seedstack.seed.undertow.LaunchWithUndertow;
2117
import org.skyscreamer.jsonassert.JSONAssert;
2218

19+
import javax.ws.rs.core.MediaType;
20+
21+
import static io.restassured.RestAssured.expect;
22+
import static org.assertj.core.api.Assertions.assertThat;
23+
2324
@RunWith(SeedITRunner.class)
2425
@LaunchWithUndertow
2526
public class Jersey2IT {
@@ -79,4 +80,10 @@ public void streamReading() {
7980
.asString();
8081
assertThat(result).isEqualTo("Hello world!");
8182
}
83+
84+
@Test
85+
public void diagnostic() {
86+
expect().statusCode(200).given()
87+
.get(baseUrl + "/seedstack/diagnostic");
88+
}
8289
}

rest/jersey2/src/test/resources/application.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,6 @@ rest:
2121
path<withPrefix>: /rest
2222
jsonHome: true
2323
jsonHome<withoutRootResource>: false
24+
diagnosticResource: true
2425

2526
textHome<withoutRootResource>: false

0 commit comments

Comments
 (0)