diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml
index 3768e9f4f2..4068c27685 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml
@@ -179,6 +179,11 @@
micrometer-registry-statsd
true
+
+ io.micrometer
+ micrometer-registry-stackdriver
+ true
+
io.micrometer
micrometer-registry-wavefront
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/stackdriver/StackdriverMetricsExportAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/stackdriver/StackdriverMetricsExportAutoConfiguration.java
new file mode 100644
index 0000000000..458892d87a
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/stackdriver/StackdriverMetricsExportAutoConfiguration.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012-2020 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.autoconfigure.metrics.export.stackdriver;
+
+import io.micrometer.core.instrument.Clock;
+import io.micrometer.stackdriver.StackdriverConfig;
+import io.micrometer.stackdriver.StackdriverMeterRegistry;
+import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration;
+import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
+import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.AutoConfigureBefore;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to Stackdriver.
+ *
+ * @author Johannes Graf
+ */
+@Configuration(proxyBeanMethods = false)
+@AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class })
+@AutoConfigureAfter(MetricsAutoConfiguration.class)
+@ConditionalOnBean(Clock.class)
+@ConditionalOnClass(StackdriverMeterRegistry.class)
+@ConditionalOnProperty(prefix = "management.metrics.export.stackdriver", name = "enabled", havingValue = "true",
+ matchIfMissing = true
+)
+@EnableConfigurationProperties(StackdriverProperties.class)
+public class StackdriverMetricsExportAutoConfiguration {
+ private final StackdriverProperties properties;
+
+ public StackdriverMetricsExportAutoConfiguration(StackdriverProperties stackdriverProperties) {
+ this.properties = stackdriverProperties;
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public StackdriverConfig stackdriverConfig() {
+ return new StackdriverPropertiesConfigAdapter(this.properties);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public StackdriverMeterRegistry StackdriverMeterRegistry(StackdriverConfig stackdriverConfig, Clock clock) {
+ return StackdriverMeterRegistry.builder(stackdriverConfig)
+ .clock(clock)
+ .build();
+ }
+}
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/stackdriver/StackdriverProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/stackdriver/StackdriverProperties.java
new file mode 100644
index 0000000000..944a2437d2
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/stackdriver/StackdriverProperties.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2012-2020 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.autoconfigure.metrics.export.stackdriver;
+
+import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryProperties;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+
+/**
+ * {@link ConfigurationProperties @ConfigurationProperties} for configuring Stackdriver metrics
+ * export.
+ *
+ * @author Johannes Graf
+ */
+@ConfigurationProperties(prefix = "management.metrics.export.stackdriver")
+public class StackdriverProperties extends StepRegistryProperties {
+
+ /**
+ * The ID of your google cloud platform project
+ */
+ private String projectId;
+
+ /**
+ * The resource type of the metrics
+ */
+ private String resourceType = "global";
+
+ public String getProjectId() {
+ return projectId;
+ }
+
+ public void setProjectId(String projectId) {
+ this.projectId = projectId;
+ }
+
+ public String getResourceType() {
+ return resourceType;
+ }
+
+ public void setResourceType(String resourceType) {
+ this.resourceType = resourceType;
+ }
+}
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/stackdriver/StackdriverPropertiesConfigAdapter.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/stackdriver/StackdriverPropertiesConfigAdapter.java
new file mode 100644
index 0000000000..ce605e8133
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/stackdriver/StackdriverPropertiesConfigAdapter.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2012-2020 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.autoconfigure.metrics.export.stackdriver;
+
+import io.micrometer.stackdriver.StackdriverConfig;
+import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryPropertiesConfigAdapter;
+
+/**
+ * Adapter to convert {@link StackdriverProperties} to a {@link StackdriverConfig}.
+ *
+ * @author Johannes Graf
+ */
+public class StackdriverPropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapter implements StackdriverConfig {
+
+ public StackdriverPropertiesConfigAdapter(StackdriverProperties properties) {
+ super(properties);
+ }
+
+ @Override
+ public String projectId() {
+ return get(StackdriverProperties::getProjectId, StackdriverConfig.super::projectId);
+ }
+
+ @Override
+ public String resourceType() {
+ return get(StackdriverProperties::getResourceType, StackdriverConfig.super::resourceType);
+ }
+}
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/stackdriver/package-info.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/stackdriver/package-info.java
new file mode 100644
index 0000000000..df40a7adb9
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/stackdriver/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2012-2020 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Support for exporting actuator metrics to Stackdriver.
+ */
+package org.springframework.boot.actuate.autoconfigure.metrics.export.stackdriver;
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/stackdriver/StackdriverMetricsExportAutoConfigurationTest.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/stackdriver/StackdriverMetricsExportAutoConfigurationTest.java
new file mode 100644
index 0000000000..46f3183f80
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/stackdriver/StackdriverMetricsExportAutoConfigurationTest.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2012-2020 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.autoconfigure.metrics.export.stackdriver;
+
+import io.micrometer.core.instrument.Clock;
+import io.micrometer.stackdriver.StackdriverConfig;
+import io.micrometer.stackdriver.StackdriverMeterRegistry;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.autoconfigure.AutoConfigurations;
+import org.springframework.boot.test.context.runner.ApplicationContextRunner;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests for {@link StackdriverMetricsExportAutoConfiguration}.
+ *
+ * @author Johannes Graf
+ */
+class StackdriverMetricsExportAutoConfigurationTest {
+
+ private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
+ .withConfiguration(AutoConfigurations.of(StackdriverMetricsExportAutoConfiguration.class));
+
+ @Test
+ void backsOffWithoutAClock() {
+ this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(StackdriverMeterRegistry.class));
+ }
+
+ @Test
+ void failsWithoutAnProjectId() {
+ this.contextRunner.withUserConfiguration(BaseConfiguration.class)
+ .run((context) -> assertThat(context).hasFailed());
+ }
+
+ @Test
+ void autoConfiguresConfigAndMeterRegistry() {
+ this.contextRunner.withUserConfiguration(BaseConfiguration.class)
+ .withPropertyValues("management.metrics.export.stackdriver.project-id=qwert")
+ .run((context) -> assertThat(context).hasSingleBean(StackdriverMeterRegistry.class)
+ .hasSingleBean(StackdriverConfig.class));
+ }
+
+ @Test
+ void autoConfigurationCanBeDisabled() {
+ this.contextRunner.withUserConfiguration(BaseConfiguration.class)
+ .withPropertyValues("management.metrics.export.stackdriver.enabled=false")
+ .run((context) -> assertThat(context).doesNotHaveBean(StackdriverMeterRegistry.class)
+ .doesNotHaveBean(StackdriverConfig.class));
+ }
+
+ @Test
+ void allowsCustomConfigToBeUsed() {
+ this.contextRunner.withUserConfiguration(CustomConfigConfiguration.class).run((context) -> assertThat(context)
+ .hasSingleBean(StackdriverMeterRegistry.class).hasSingleBean(StackdriverConfig.class).hasBean("customConfig"));
+ }
+
+ @Test
+ void allowsCustomRegistryToBeUsed() {
+ this.contextRunner.withUserConfiguration(CustomRegistryConfiguration.class)
+ .withPropertyValues("management.metrics.export.stackdriver.project-id=qwert")
+ .run((context) -> assertThat(context).hasSingleBean(StackdriverMeterRegistry.class)
+ .hasBean("customRegistry").hasSingleBean(StackdriverConfig.class));
+ }
+
+ @Test
+ void stopsMeterRegistryWhenContextIsClosed() {
+ this.contextRunner.withUserConfiguration(BaseConfiguration.class)
+ .withPropertyValues("management.metrics.export.stackdriver.project-id=qwert").run((context) -> {
+ StackdriverMeterRegistry registry = context.getBean(StackdriverMeterRegistry.class);
+ assertThat(registry.isClosed()).isFalse();
+ context.close();
+ assertThat(registry.isClosed()).isTrue();
+ });
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ static class BaseConfiguration {
+
+ @Bean
+ Clock clock() {
+ return Clock.SYSTEM;
+ }
+
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @Import(BaseConfiguration.class)
+ static class CustomConfigConfiguration {
+
+ @Bean
+ StackdriverConfig customConfig() {
+ return (key) -> {
+ if ("stackdriver.projectId".equals(key)) {
+ return "qwert";
+ }
+ return null;
+ };
+ }
+
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @Import(BaseConfiguration.class)
+ static class CustomRegistryConfiguration {
+
+ @Bean
+ StackdriverMeterRegistry customRegistry(StackdriverConfig config, Clock clock) {
+ return new StackdriverMeterRegistry(config, clock);
+ }
+
+ }
+}
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/stackdriver/StackdriverPropertiesConfigAdapterTest.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/stackdriver/StackdriverPropertiesConfigAdapterTest.java
new file mode 100644
index 0000000000..c48aa14c35
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/stackdriver/StackdriverPropertiesConfigAdapterTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2012-2020 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.autoconfigure.metrics.export.stackdriver;
+
+
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests for {@link StackdriverPropertiesConfigAdapter}.
+ *
+ * @author Johannes Graf
+ */
+class StackdriverPropertiesConfigAdapterTest {
+
+ @Test
+ void whenPropertiesProjectIdIsSetAdapterProjectIdReturnsIt() {
+ StackdriverProperties properties = new StackdriverProperties();
+ properties.setProjectId("my-gcp-project-id");
+ assertThat(new StackdriverPropertiesConfigAdapter(properties).projectId()).isEqualTo("my-gcp-project-id");
+ }
+ @Test
+ void whenPropertiesResourceTypeIsSetAdapterResourceTypeReturnsIt() {
+ StackdriverProperties properties = new StackdriverProperties();
+ properties.setResourceType("my-resource-type");
+ assertThat(new StackdriverPropertiesConfigAdapter(properties).resourceType()).isEqualTo("my-resource-type");
+ }
+}
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/stackdriver/StackdriverPropertiesTest.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/stackdriver/StackdriverPropertiesTest.java
new file mode 100644
index 0000000000..98a6a981d0
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/stackdriver/StackdriverPropertiesTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2012-2020 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.autoconfigure.metrics.export.stackdriver;
+
+
+import io.micrometer.stackdriver.StackdriverConfig;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryPropertiesTests;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests for {@link StackdriverProperties}.
+ *
+ * @author Johannes Graf
+ */
+class StackdriverPropertiesTest extends StepRegistryPropertiesTests {
+
+ @Test
+ void defaultValuesAreConsistent() {
+ StackdriverProperties properties = new StackdriverProperties();
+ StackdriverConfig config = (key) -> null;
+ assertStepRegistryDefaultValues(properties, config);
+ assertThat(properties.getResourceType()).isEqualTo(config.resourceType());
+ }
+}