Skip to content

Commit b906b18

Browse files
committed
Initiate GitProperties
This commit polish the new info contributor infrastructure by migrating `GitInfo` to `GitProperties`. `InfoProperties` provides an abstraction that exposes unstructured data in an immutable way. The `GitInfoContributor` now accepts a "mode" that determines if all data should be exposed or only a sub-set of known keys. Closes gh-2644
1 parent 474aed0 commit b906b18

File tree

15 files changed

+841
-202
lines changed

15 files changed

+841
-202
lines changed

spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/InfoContributorAutoConfiguration.java

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,17 @@
1616

1717
package org.springframework.boot.actuate.autoconfigure;
1818

19-
import java.io.IOException;
20-
2119
import org.springframework.boot.actuate.info.EnvironmentInfoContributor;
20+
import org.springframework.boot.actuate.info.GitInfoContributor;
2221
import org.springframework.boot.actuate.info.InfoContributor;
23-
import org.springframework.boot.actuate.info.SimpleInfoContributor;
2422
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
2523
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
2624
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
25+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2726
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
28-
import org.springframework.boot.autoconfigure.info.GitInfo;
2927
import org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration;
28+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
29+
import org.springframework.boot.info.GitProperties;
3030
import org.springframework.context.annotation.Bean;
3131
import org.springframework.context.annotation.Configuration;
3232
import org.springframework.core.Ordered;
@@ -44,13 +44,20 @@
4444
@Configuration
4545
@AutoConfigureAfter(ProjectInfoAutoConfiguration.class)
4646
@AutoConfigureBefore(EndpointAutoConfiguration.class)
47+
@EnableConfigurationProperties(InfoContributorProperties.class)
4748
public class InfoContributorAutoConfiguration {
4849

4950
/**
5051
* The default order for the core {@link InfoContributor} beans.
5152
*/
5253
public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 10;
5354

55+
private final InfoContributorProperties properties;
56+
57+
public InfoContributorAutoConfiguration(InfoContributorProperties properties) {
58+
this.properties = properties;
59+
}
60+
5461
@Bean
5562
@ConditionalOnEnabledInfoContributor("env")
5663
@Order(DEFAULT_ORDER)
@@ -61,10 +68,11 @@ public EnvironmentInfoContributor envInfoContributor(
6168

6269
@Bean
6370
@ConditionalOnEnabledInfoContributor("git")
64-
@ConditionalOnSingleCandidate(GitInfo.class)
71+
@ConditionalOnSingleCandidate(GitProperties.class)
72+
@ConditionalOnMissingBean
6573
@Order(DEFAULT_ORDER)
66-
public InfoContributor gitInfoContributor(GitInfo gitInfo) throws IOException {
67-
return new SimpleInfoContributor("git", gitInfo);
74+
public GitInfoContributor gitInfoContributor(GitProperties gitProperties) {
75+
return new GitInfoContributor(gitProperties, this.properties.getGit().getMode());
6876
}
6977

7078
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright 2012-2016 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure;
18+
19+
import org.springframework.boot.actuate.info.GitInfoContributor;
20+
import org.springframework.boot.context.properties.ConfigurationProperties;
21+
22+
/**
23+
* Configuration properties for core info contributors.
24+
*
25+
* @author Stephane Nicoll
26+
* @since 1.4.0
27+
*/
28+
@ConfigurationProperties("management.info")
29+
public class InfoContributorProperties {
30+
31+
private final Git git = new Git();
32+
33+
public Git getGit() {
34+
return this.git;
35+
}
36+
37+
public static class Git {
38+
39+
/**
40+
* Mode to use to expose git information.
41+
*/
42+
private GitInfoContributor.Mode mode = GitInfoContributor.Mode.SIMPLE;
43+
44+
public GitInfoContributor.Mode getMode() {
45+
return this.mode;
46+
}
47+
48+
public void setMode(GitInfoContributor.Mode mode) {
49+
this.mode = mode;
50+
}
51+
52+
}
53+
54+
}

spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/EnvironmentInfoContributor.java

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,29 +16,26 @@
1616

1717
package org.springframework.boot.actuate.info;
1818

19-
import java.util.Map;
20-
2119
import org.springframework.core.env.ConfigurableEnvironment;
2220

2321
/**
24-
* A {@link InfoContributor} that provides all environment entries prefixed with info.
22+
* An {@link InfoContributor} that provides all environment entries prefixed with info.
2523
*
2624
* @author Meang Akira Tanaka
2725
* @author Stephane Nicoll
2826
* @since 1.4.0
2927
*/
30-
public class EnvironmentInfoContributor extends AbstractEnvironmentInfoContributor {
28+
public class EnvironmentInfoContributor implements InfoContributor {
3129

32-
private final Map<String, Object> info;
30+
private final PropertySourcesBinder binder;
3331

3432
public EnvironmentInfoContributor(ConfigurableEnvironment environment) {
35-
super(environment);
36-
this.info = extract("info");
33+
this.binder = new PropertySourcesBinder(environment);
3734
}
3835

3936
@Override
4037
public void contribute(Info.Builder builder) {
41-
builder.withDetails(this.info);
38+
builder.withDetails(this.binder.extractAll("info"));
4239
}
4340

4441
}
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/*
2+
* Copyright 2012-2016 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.info;
18+
19+
import java.util.Collections;
20+
import java.util.Date;
21+
import java.util.Map;
22+
import java.util.Properties;
23+
24+
import org.apache.commons.logging.Log;
25+
import org.apache.commons.logging.LogFactory;
26+
27+
import org.springframework.boot.info.GitProperties;
28+
import org.springframework.core.env.MutablePropertySources;
29+
import org.springframework.core.env.PropertiesPropertySource;
30+
import org.springframework.core.env.PropertySource;
31+
import org.springframework.util.StringUtils;
32+
33+
/**
34+
* An {@link InfoContributor} that exposes {@link GitProperties}.
35+
*
36+
* @author Stephane Nicoll
37+
* @since 1.4.0
38+
*/
39+
public class GitInfoContributor implements InfoContributor {
40+
41+
private static final Log logger = LogFactory.getLog(GitInfoContributor.class);
42+
43+
private final GitProperties properties;
44+
45+
private final Mode mode;
46+
47+
public GitInfoContributor(GitProperties properties, Mode mode) {
48+
this.properties = properties;
49+
this.mode = mode;
50+
}
51+
52+
public GitInfoContributor(GitProperties properties) {
53+
this(properties, Mode.SIMPLE);
54+
}
55+
56+
protected final GitProperties getProperties() {
57+
return this.properties;
58+
}
59+
60+
protected final Mode getMode() {
61+
return this.mode;
62+
}
63+
64+
@Override
65+
public void contribute(Info.Builder builder) {
66+
builder.withDetail("git", extractContent());
67+
}
68+
69+
/**
70+
* Extract the content to contribute to the info endpoint.
71+
* @return the content to expose
72+
*/
73+
protected Map<String, Object> extractContent() {
74+
MutablePropertySources propertySources = new MutablePropertySources();
75+
propertySources.addFirst(toPropertySources());
76+
Map<String, Object> content = new PropertySourcesBinder(propertySources).extractAll("");
77+
postProcess(content);
78+
return content;
79+
}
80+
81+
/**
82+
* Post-process the content to expose. By default, well known keys representing dates
83+
* are converted to {@link Date} instances.
84+
* @param content the content to expose
85+
*/
86+
protected void postProcess(Map<String, Object> content) {
87+
coerceDate(getNestedMap(content, "commit"), "time");
88+
coerceDate(getNestedMap(content, "build"), "time");
89+
}
90+
91+
/**
92+
* Coerce the specified key if the value is a proper epoch time.
93+
* @param content the content to expose
94+
* @param key the property to coerce
95+
*/
96+
protected void coerceDate(Map<String, Object> content, String key) {
97+
Object value = content.get(key);
98+
if (value != null) {
99+
try {
100+
long epoch = Long.parseLong(value.toString());
101+
content.put(key, new Date(epoch));
102+
}
103+
catch (NumberFormatException ex) {
104+
logger.warn("Expected a date for '" + key + "'", ex);
105+
}
106+
}
107+
}
108+
109+
/**
110+
* Return the {@link PropertySource} to use.
111+
* @return the property source
112+
*/
113+
protected PropertySource<?> toPropertySources() {
114+
if (this.mode.equals(Mode.FULL)) {
115+
return this.properties.toPropertySource();
116+
}
117+
else {
118+
Properties props = new Properties();
119+
copyIfSet(this.properties, props, "branch");
120+
String commitId = this.properties.getShortCommitId();
121+
if (commitId != null) {
122+
props.put("commit.id", commitId);
123+
}
124+
copyIfSet(this.properties, props, "commit.time");
125+
return new PropertiesPropertySource("git", props);
126+
}
127+
}
128+
129+
private void copyIfSet(GitProperties source, Properties target, String key) {
130+
String value = source.get(key);
131+
if (StringUtils.hasText(value)) {
132+
target.put(key, value);
133+
}
134+
}
135+
136+
@SuppressWarnings("unchecked")
137+
private Map<String, Object> getNestedMap(Map<String, Object> map, String key) {
138+
Object o = map.get(key);
139+
if (o == null) {
140+
return Collections.emptyMap();
141+
}
142+
else {
143+
return (Map<String, Object>) o;
144+
}
145+
}
146+
147+
/**
148+
* Defines how git properties should be exposed.
149+
*/
150+
public enum Mode {
151+
152+
/**
153+
* Expose all available data, including custom properties.
154+
*/
155+
FULL,
156+
157+
/**
158+
* Expose a pre-defined set of core settings only.
159+
*/
160+
SIMPLE
161+
162+
}
163+
164+
}
Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,38 +21,43 @@
2121

2222
import org.springframework.boot.bind.PropertiesConfigurationFactory;
2323
import org.springframework.core.env.ConfigurableEnvironment;
24-
import org.springframework.core.env.Environment;
24+
import org.springframework.core.env.PropertySources;
25+
import org.springframework.util.StringUtils;
2526
import org.springframework.validation.BindException;
2627

2728
/**
28-
* A base {@link InfoContributor} implementation working on the {@link Environment}.
29+
* Helper extracting info from {@link PropertySources}.
2930
*
3031
* @author Stephane Nicoll
3132
* @since 1.4.0
3233
*/
33-
public abstract class AbstractEnvironmentInfoContributor implements InfoContributor {
34+
public class PropertySourcesBinder {
3435

35-
private final ConfigurableEnvironment environment;
36+
private final PropertySources propertySources;
3637

37-
protected AbstractEnvironmentInfoContributor(ConfigurableEnvironment environment) {
38-
this.environment = environment;
38+
public PropertySourcesBinder(PropertySources propertySources) {
39+
this.propertySources = propertySources;
3940
}
4041

41-
public final ConfigurableEnvironment getEnvironment() {
42-
return this.environment;
42+
public PropertySourcesBinder(ConfigurableEnvironment environment) {
43+
this(environment.getPropertySources());
44+
}
45+
46+
public final PropertySources getPropertySources() {
47+
return this.propertySources;
4348
}
4449

4550
/**
46-
* Extract the keys from the environment using the specified {@code prefix}. The
51+
* Extract the keys using the specified {@code prefix}. The
4752
* prefix won't be included.
4853
* <p>
4954
* Any key that starts with the {@code prefix} will be included
5055
* @param prefix the prefix to use
51-
* @return the keys from the environment matching the prefix
56+
* @return the keys matching the prefix
5257
*/
53-
protected Map<String, Object> extract(String prefix) {
58+
public Map<String, Object> extractAll(String prefix) {
5459
Map<String, Object> content = new LinkedHashMap<String, Object>();
55-
bindEnvironmentTo(prefix, content);
60+
bindTo(prefix, content);
5661
return content;
5762
}
5863

@@ -63,11 +68,13 @@ protected Map<String, Object> extract(String prefix) {
6368
* @param prefix the prefix to use
6469
* @param target the object to bind to
6570
*/
66-
protected void bindEnvironmentTo(String prefix, Object target) {
71+
public void bindTo(String prefix, Object target) {
6772
PropertiesConfigurationFactory<Object> factory = new PropertiesConfigurationFactory<Object>(
6873
target);
69-
factory.setTargetName(prefix);
70-
factory.setPropertySources(this.environment.getPropertySources());
74+
if (StringUtils.hasText(prefix)) {
75+
factory.setTargetName(prefix);
76+
}
77+
factory.setPropertySources(this.propertySources);
7178
try {
7279
factory.bindPropertiesToTarget();
7380
}

0 commit comments

Comments
 (0)