Skip to content

Commit 91151e0

Browse files
committed
Merge pull request #19528 from grafjo
* pr/19528: Polish "Add Stackdriver metrics export support" Add Stackdriver metrics export support Closes gh-19528
2 parents 10ba17c + 462442e commit 91151e0

File tree

10 files changed

+451
-0
lines changed

10 files changed

+451
-0
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,11 @@
174174
<artifactId>micrometer-registry-signalfx</artifactId>
175175
<optional>true</optional>
176176
</dependency>
177+
<dependency>
178+
<groupId>io.micrometer</groupId>
179+
<artifactId>micrometer-registry-stackdriver</artifactId>
180+
<optional>true</optional>
181+
</dependency>
177182
<dependency>
178183
<groupId>io.micrometer</groupId>
179184
<artifactId>micrometer-registry-statsd</artifactId>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright 2012-2020 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+
* https://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.metrics.export.stackdriver;
18+
19+
import io.micrometer.core.instrument.Clock;
20+
import io.micrometer.stackdriver.StackdriverConfig;
21+
import io.micrometer.stackdriver.StackdriverMeterRegistry;
22+
23+
import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration;
24+
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
25+
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
26+
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
27+
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
28+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
29+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
30+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
31+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
32+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
33+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
34+
import org.springframework.context.annotation.Bean;
35+
import org.springframework.context.annotation.Configuration;
36+
37+
/**
38+
* {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to
39+
* Stackdriver.
40+
*
41+
* @author Johannes Graf
42+
* @author Stephane Nicoll
43+
* @since 2.3.0
44+
*/
45+
@Configuration(proxyBeanMethods = false)
46+
@AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class })
47+
@AutoConfigureAfter(MetricsAutoConfiguration.class)
48+
@ConditionalOnBean(Clock.class)
49+
@ConditionalOnClass(StackdriverMeterRegistry.class)
50+
@ConditionalOnProperty(prefix = "management.metrics.export.stackdriver", name = "enabled", havingValue = "true",
51+
matchIfMissing = true)
52+
@EnableConfigurationProperties(StackdriverProperties.class)
53+
public class StackdriverMetricsExportAutoConfiguration {
54+
55+
private final StackdriverProperties properties;
56+
57+
public StackdriverMetricsExportAutoConfiguration(StackdriverProperties stackdriverProperties) {
58+
this.properties = stackdriverProperties;
59+
}
60+
61+
@Bean
62+
@ConditionalOnMissingBean
63+
public StackdriverConfig stackdriverConfig() {
64+
return new StackdriverPropertiesConfigAdapter(this.properties);
65+
}
66+
67+
@Bean
68+
@ConditionalOnMissingBean
69+
public StackdriverMeterRegistry stackdriverMeterRegistry(StackdriverConfig stackdriverConfig, Clock clock) {
70+
return StackdriverMeterRegistry.builder(stackdriverConfig).clock(clock).build();
71+
}
72+
73+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright 2012-2020 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+
* https://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.metrics.export.stackdriver;
18+
19+
import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryProperties;
20+
import org.springframework.boot.context.properties.ConfigurationProperties;
21+
22+
/**
23+
* {@link ConfigurationProperties @ConfigurationProperties} for configuring Stackdriver
24+
* metrics export.
25+
*
26+
* @author Johannes Graf
27+
* @author Stephane Nicoll
28+
* @since 2.3.0
29+
*/
30+
@ConfigurationProperties(prefix = "management.metrics.export.stackdriver")
31+
public class StackdriverProperties extends StepRegistryProperties {
32+
33+
/**
34+
* Identifier of the Google Cloud project to monitor.
35+
*/
36+
private String projectId;
37+
38+
/**
39+
* Monitored resource type.
40+
*/
41+
private String resourceType = "global";
42+
43+
public String getProjectId() {
44+
return this.projectId;
45+
}
46+
47+
public void setProjectId(String projectId) {
48+
this.projectId = projectId;
49+
}
50+
51+
public String getResourceType() {
52+
return this.resourceType;
53+
}
54+
55+
public void setResourceType(String resourceType) {
56+
this.resourceType = resourceType;
57+
}
58+
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2012-2020 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+
* https://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.metrics.export.stackdriver;
18+
19+
import io.micrometer.stackdriver.StackdriverConfig;
20+
21+
import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryPropertiesConfigAdapter;
22+
23+
/**
24+
* Adapter to convert {@link StackdriverProperties} to a {@link StackdriverConfig}.
25+
*
26+
* @author Johannes Graf
27+
* @since 2.3.0
28+
*/
29+
public class StackdriverPropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapter<StackdriverProperties>
30+
implements StackdriverConfig {
31+
32+
public StackdriverPropertiesConfigAdapter(StackdriverProperties properties) {
33+
super(properties);
34+
}
35+
36+
@Override
37+
public String projectId() {
38+
return get(StackdriverProperties::getProjectId, StackdriverConfig.super::projectId);
39+
}
40+
41+
@Override
42+
public String resourceType() {
43+
return get(StackdriverProperties::getResourceType, StackdriverConfig.super::resourceType);
44+
}
45+
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright 2012-2020 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+
* https://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+
/**
18+
* Support for exporting actuator metrics to Stackdriver.
19+
*/
20+
package org.springframework.boot.actuate.autoconfigure.metrics.export.stackdriver;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/*
2+
* Copyright 2012-2020 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+
* https://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.metrics.export.stackdriver;
18+
19+
import io.micrometer.core.instrument.Clock;
20+
import io.micrometer.stackdriver.StackdriverConfig;
21+
import io.micrometer.stackdriver.StackdriverMeterRegistry;
22+
import org.junit.jupiter.api.Test;
23+
24+
import org.springframework.boot.autoconfigure.AutoConfigurations;
25+
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
26+
import org.springframework.context.annotation.Bean;
27+
import org.springframework.context.annotation.Configuration;
28+
import org.springframework.context.annotation.Import;
29+
30+
import static org.assertj.core.api.Assertions.assertThat;
31+
32+
/**
33+
* Tests for {@link StackdriverMetricsExportAutoConfiguration}.
34+
*
35+
* @author Johannes Graf
36+
*/
37+
class StackdriverMetricsExportAutoConfigurationTest {
38+
39+
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
40+
.withConfiguration(AutoConfigurations.of(StackdriverMetricsExportAutoConfiguration.class));
41+
42+
@Test
43+
void backsOffWithoutAClock() {
44+
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(StackdriverMeterRegistry.class));
45+
}
46+
47+
@Test
48+
void failsWithoutAnProjectId() {
49+
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
50+
.run((context) -> assertThat(context).hasFailed());
51+
}
52+
53+
@Test
54+
void autoConfiguresConfigAndMeterRegistry() {
55+
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
56+
.withPropertyValues("management.metrics.export.stackdriver.project-id=test-project")
57+
.run((context) -> assertThat(context).hasSingleBean(StackdriverMeterRegistry.class)
58+
.hasSingleBean(StackdriverConfig.class));
59+
}
60+
61+
@Test
62+
void autoConfigurationCanBeDisabled() {
63+
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
64+
.withPropertyValues("management.metrics.export.stackdriver.enabled=false")
65+
.run((context) -> assertThat(context).doesNotHaveBean(StackdriverMeterRegistry.class)
66+
.doesNotHaveBean(StackdriverConfig.class));
67+
}
68+
69+
@Test
70+
void allowsCustomConfigToBeUsed() {
71+
this.contextRunner.withUserConfiguration(CustomConfigConfiguration.class)
72+
.run((context) -> assertThat(context).hasSingleBean(StackdriverMeterRegistry.class)
73+
.hasSingleBean(StackdriverConfig.class).hasBean("customConfig"));
74+
}
75+
76+
@Test
77+
void allowsCustomRegistryToBeUsed() {
78+
this.contextRunner.withUserConfiguration(CustomRegistryConfiguration.class)
79+
.withPropertyValues("management.metrics.export.stackdriver.project-id=test-project")
80+
.run((context) -> assertThat(context).hasSingleBean(StackdriverMeterRegistry.class)
81+
.hasBean("customRegistry").hasSingleBean(StackdriverConfig.class));
82+
}
83+
84+
@Test
85+
void stopsMeterRegistryWhenContextIsClosed() {
86+
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
87+
.withPropertyValues("management.metrics.export.stackdriver.project-id=test-project").run((context) -> {
88+
StackdriverMeterRegistry registry = context.getBean(StackdriverMeterRegistry.class);
89+
assertThat(registry.isClosed()).isFalse();
90+
context.close();
91+
assertThat(registry.isClosed()).isTrue();
92+
});
93+
}
94+
95+
@Configuration(proxyBeanMethods = false)
96+
static class BaseConfiguration {
97+
98+
@Bean
99+
Clock clock() {
100+
return Clock.SYSTEM;
101+
}
102+
103+
}
104+
105+
@Configuration(proxyBeanMethods = false)
106+
@Import(BaseConfiguration.class)
107+
static class CustomConfigConfiguration {
108+
109+
@Bean
110+
StackdriverConfig customConfig() {
111+
return (key) -> {
112+
if ("stackdriver.projectId".equals(key)) {
113+
return "test-project";
114+
}
115+
return null;
116+
};
117+
}
118+
119+
}
120+
121+
@Configuration(proxyBeanMethods = false)
122+
@Import(BaseConfiguration.class)
123+
static class CustomRegistryConfiguration {
124+
125+
@Bean
126+
StackdriverMeterRegistry customRegistry(StackdriverConfig config, Clock clock) {
127+
return new StackdriverMeterRegistry(config, clock);
128+
}
129+
130+
}
131+
132+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2012-2020 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+
* https://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.metrics.export.stackdriver;
18+
19+
import org.junit.jupiter.api.Test;
20+
21+
import static org.assertj.core.api.Assertions.assertThat;
22+
23+
/**
24+
* Tests for {@link StackdriverPropertiesConfigAdapter}.
25+
*
26+
* @author Johannes Graf
27+
*/
28+
class StackdriverPropertiesConfigAdapterTest {
29+
30+
@Test
31+
void whenPropertiesProjectIdIsSetAdapterProjectIdReturnsIt() {
32+
StackdriverProperties properties = new StackdriverProperties();
33+
properties.setProjectId("my-gcp-project-id");
34+
assertThat(new StackdriverPropertiesConfigAdapter(properties).projectId()).isEqualTo("my-gcp-project-id");
35+
}
36+
37+
@Test
38+
void whenPropertiesResourceTypeIsSetAdapterResourceTypeReturnsIt() {
39+
StackdriverProperties properties = new StackdriverProperties();
40+
properties.setResourceType("my-resource-type");
41+
assertThat(new StackdriverPropertiesConfigAdapter(properties).resourceType()).isEqualTo("my-resource-type");
42+
}
43+
44+
}

0 commit comments

Comments
 (0)