Skip to content

Commit c2c6f49

Browse files
committed
Improve output of /application/env/{propertyName}
This commit changes the output of a single property to mention the actual value in the environment as well as the property source that contributed to the value. Closes gh-10178
1 parent 5d05347 commit c2c6f49

File tree

5 files changed

+367
-154
lines changed

5 files changed

+367
-154
lines changed

spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/env/EnvironmentEndpointAutoConfigurationTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222

2323
import org.springframework.boot.actuate.env.EnvironmentEndpoint;
2424
import org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentDescriptor;
25-
import org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentDescriptor.PropertySourceDescriptor;
26-
import org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentDescriptor.PropertySourceDescriptor.PropertyValueDescriptor;
25+
import org.springframework.boot.actuate.env.EnvironmentEndpoint.PropertySourceDescriptor;
26+
import org.springframework.boot.actuate.env.EnvironmentEndpoint.PropertyValueDescriptor;
2727
import org.springframework.boot.autoconfigure.AutoConfigurations;
2828
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
2929
import org.springframework.boot.test.context.runner.ApplicationContextRunner;

spring-boot-actuator/src/main/java/org/springframework/boot/actuate/env/EnvironmentEndpoint.java

Lines changed: 171 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,15 @@
2525
import java.util.regex.Pattern;
2626
import java.util.stream.Stream;
2727

28+
import com.fasterxml.jackson.annotation.JsonInclude;
29+
2830
import org.springframework.boot.actuate.endpoint.Sanitizer;
2931
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
3032
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
3133
import org.springframework.boot.actuate.endpoint.annotation.Selector;
32-
import org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentDescriptor.PropertySourceDescriptor;
33-
import org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentDescriptor.PropertySourceDescriptor.PropertyValueDescriptor;
3434
import org.springframework.boot.context.properties.bind.PlaceholdersResolver;
3535
import org.springframework.boot.context.properties.bind.PropertySourcesPlaceholdersResolver;
36+
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
3637
import org.springframework.boot.origin.OriginLookup;
3738
import org.springframework.core.env.CompositePropertySource;
3839
import org.springframework.core.env.ConfigurableEnvironment;
@@ -54,6 +55,7 @@
5455
* @author Phillip Webb
5556
* @author Christian Dupuis
5657
* @author Madhura Bhave
58+
* @author Stephane Nicoll
5759
* @since 2.0.0
5860
*/
5961
@Endpoint(id = "env")
@@ -80,8 +82,8 @@ public EnvironmentDescriptor environment(String pattern) {
8082
}
8183

8284
@ReadOperation
83-
public EnvironmentDescriptor environmentEntry(@Selector String toMatch) {
84-
return getEnvironmentDescriptor(toMatch::equals);
85+
public EnvironmentEntryDescriptor environmentEntry(@Selector String toMatch) {
86+
return getEnvironmentEntryDescriptor(toMatch);
8587
}
8688

8789
private EnvironmentDescriptor getEnvironmentDescriptor(
@@ -99,6 +101,46 @@ private EnvironmentDescriptor getEnvironmentDescriptor(
99101
Arrays.asList(this.environment.getActiveProfiles()), propertySources);
100102
}
101103

104+
private EnvironmentEntryDescriptor getEnvironmentEntryDescriptor(
105+
String propertyName) {
106+
Map<String, PropertyValueDescriptor> descriptors = getPropertySourceDescriptors(
107+
propertyName);
108+
PropertySummaryDescriptor summary = getPropertySummaryDescriptor(descriptors);
109+
return new EnvironmentEntryDescriptor(summary,
110+
Arrays.asList(this.environment.getActiveProfiles()),
111+
toPropertySourceDescriptors(descriptors));
112+
}
113+
114+
private List<PropertySourceEntryDescriptor> toPropertySourceDescriptors(
115+
Map<String, PropertyValueDescriptor> descriptors) {
116+
List<PropertySourceEntryDescriptor> result = new ArrayList<>();
117+
for (Map.Entry<String, PropertyValueDescriptor> entry : descriptors.entrySet()) {
118+
result.add(new PropertySourceEntryDescriptor(entry.getKey(), entry.getValue()));
119+
}
120+
return result;
121+
}
122+
123+
private PropertySummaryDescriptor getPropertySummaryDescriptor(
124+
Map<String, PropertyValueDescriptor> descriptors) {
125+
for (Map.Entry<String, PropertyValueDescriptor> entry : descriptors.entrySet()) {
126+
if (entry.getValue() != null) {
127+
return new PropertySummaryDescriptor(entry.getKey(),
128+
entry.getValue().getValue());
129+
}
130+
}
131+
return null;
132+
}
133+
134+
private Map<String, PropertyValueDescriptor> getPropertySourceDescriptors(
135+
String propertyName) {
136+
Map<String, PropertyValueDescriptor> propertySources = new LinkedHashMap<>();
137+
PlaceholdersResolver resolver = getResolver();
138+
getPropertySourcesAsMap().forEach((sourceName, source) ->
139+
propertySources.put(sourceName, source.containsProperty(propertyName) ?
140+
describeValueOf(propertyName, source, resolver) : null));
141+
return propertySources;
142+
}
143+
102144
private PropertySourceDescriptor describeSource(String sourceName,
103145
EnumerablePropertySource<?> source, PlaceholdersResolver resolver,
104146
Predicate<String> namePredicate) {
@@ -109,7 +151,7 @@ private PropertySourceDescriptor describeSource(String sourceName,
109151
}
110152

111153
private PropertyValueDescriptor describeValueOf(String name,
112-
EnumerablePropertySource<?> source, PlaceholdersResolver resolver) {
154+
PropertySource<?> source, PlaceholdersResolver resolver) {
113155
Object resolved = resolver.resolvePlaceholders(source.getProperty(name));
114156
@SuppressWarnings("unchecked")
115157
String origin = (source instanceof OriginLookup)
@@ -125,7 +167,9 @@ private PlaceholdersResolver getResolver() {
125167
private Map<String, PropertySource<?>> getPropertySourcesAsMap() {
126168
Map<String, PropertySource<?>> map = new LinkedHashMap<>();
127169
for (PropertySource<?> source : getPropertySources()) {
128-
extract("", map, source);
170+
if (!ConfigurationPropertySources.isMainConfigurationPropertySource(source)) {
171+
extract("", map, source);
172+
}
129173
}
130174
return map;
131175
}
@@ -208,54 +252,141 @@ public List<PropertySourceDescriptor> getPropertySources() {
208252
return this.propertySources;
209253
}
210254

211-
/**
212-
* A description of a {@link PropertySource}.
213-
*/
214-
public static final class PropertySourceDescriptor {
255+
}
215256

216-
private final String name;
257+
/**
258+
* A description of an entry of the {@link Environment}.
259+
*/
260+
@JsonInclude(JsonInclude.Include.NON_NULL)
261+
public static final class EnvironmentEntryDescriptor {
217262

218-
private final Map<String, PropertyValueDescriptor> properties;
263+
private final PropertySummaryDescriptor property;
219264

220-
private PropertySourceDescriptor(String name,
221-
Map<String, PropertyValueDescriptor> properties) {
222-
this.name = name;
223-
this.properties = properties;
224-
}
265+
private final List<String> activeProfiles;
225266

226-
public String getName() {
227-
return this.name;
228-
}
267+
private final List<PropertySourceEntryDescriptor> propertySources;
229268

230-
public Map<String, PropertyValueDescriptor> getProperties() {
231-
return this.properties;
232-
}
269+
private EnvironmentEntryDescriptor(PropertySummaryDescriptor property,
270+
List<String> activeProfiles,
271+
List<PropertySourceEntryDescriptor> propertySources) {
272+
this.property = property;
273+
this.activeProfiles = activeProfiles;
274+
this.propertySources = propertySources;
275+
}
233276

234-
/**
235-
* A description of a property's value, including its origin if available.
236-
*/
237-
public static final class PropertyValueDescriptor {
277+
public PropertySummaryDescriptor getProperty() {
278+
return this.property;
279+
}
238280

239-
private final Object value;
281+
public List<String> getActiveProfiles() {
282+
return this.activeProfiles;
283+
}
240284

241-
private final String origin;
285+
public List<PropertySourceEntryDescriptor> getPropertySources() {
286+
return this.propertySources;
287+
}
242288

243-
private PropertyValueDescriptor(Object value, String origin) {
244-
this.value = value;
245-
this.origin = origin;
246-
}
289+
}
247290

248-
public Object getValue() {
249-
return this.value;
250-
}
291+
/**
292+
* A summary of a particular entry of the {@link Environment}.
293+
*/
294+
@JsonInclude(JsonInclude.Include.NON_NULL)
295+
public static final class PropertySummaryDescriptor {
251296

252-
public String getOrigin() {
253-
return this.origin;
254-
}
297+
private final String source;
255298

256-
}
299+
private final Object value;
300+
301+
public PropertySummaryDescriptor(String source, Object value) {
302+
this.source = source;
303+
this.value = value;
304+
}
305+
306+
public String getSource() {
307+
return this.source;
308+
}
309+
310+
public Object getValue() {
311+
return this.value;
312+
}
313+
314+
}
315+
316+
/**
317+
* A description of a particular entry of {@link PropertySource}.
318+
*/
319+
@JsonInclude(JsonInclude.Include.NON_NULL)
320+
public static final class PropertySourceEntryDescriptor {
321+
322+
private final String name;
323+
324+
private final PropertyValueDescriptor property;
325+
326+
private PropertySourceEntryDescriptor(String name,
327+
PropertyValueDescriptor property) {
328+
this.name = name;
329+
this.property = property;
330+
}
257331

332+
public String getName() {
333+
return this.name;
258334
}
335+
336+
public PropertyValueDescriptor getProperty() {
337+
return this.property;
338+
}
339+
340+
}
341+
342+
/**
343+
* A description of a {@link PropertySource}.
344+
*/
345+
public static final class PropertySourceDescriptor {
346+
347+
private final String name;
348+
349+
private final Map<String, PropertyValueDescriptor> properties;
350+
351+
private PropertySourceDescriptor(String name,
352+
Map<String, PropertyValueDescriptor> properties) {
353+
this.name = name;
354+
this.properties = properties;
355+
}
356+
357+
public String getName() {
358+
return this.name;
359+
}
360+
361+
public Map<String, PropertyValueDescriptor> getProperties() {
362+
return this.properties;
363+
}
364+
365+
}
366+
367+
/**
368+
* A description of a property's value, including its origin if available.
369+
*/
370+
@JsonInclude(JsonInclude.Include.NON_NULL)
371+
public static final class PropertyValueDescriptor {
372+
373+
private final Object value;
374+
375+
private final String origin;
376+
377+
private PropertyValueDescriptor(Object value, String origin) {
378+
this.value = value;
379+
this.origin = origin;
380+
}
381+
382+
public Object getValue() {
383+
return this.value;
384+
}
385+
386+
public String getOrigin() {
387+
return this.origin;
388+
}
389+
259390
}
260391

261392
/**

0 commit comments

Comments
 (0)