Merge pull request #19528 from grafjo

* pr/19528:
  Polish "Add Stackdriver metrics export support"
  Add Stackdriver metrics export support

Closes gh-19528
pull/19578/head
Stephane Nicoll 5 years ago
commit 91151e0aac

@ -174,6 +174,11 @@
<artifactId>micrometer-registry-signalfx</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-stackdriver</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-statsd</artifactId>

@ -0,0 +1,73 @@
/*
* 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
* @author Stephane Nicoll
* @since 2.3.0
*/
@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();
}
}

@ -0,0 +1,59 @@
/*
* 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
* @author Stephane Nicoll
* @since 2.3.0
*/
@ConfigurationProperties(prefix = "management.metrics.export.stackdriver")
public class StackdriverProperties extends StepRegistryProperties {
/**
* Identifier of the Google Cloud project to monitor.
*/
private String projectId;
/**
* Monitored resource type.
*/
private String resourceType = "global";
public String getProjectId() {
return this.projectId;
}
public void setProjectId(String projectId) {
this.projectId = projectId;
}
public String getResourceType() {
return this.resourceType;
}
public void setResourceType(String resourceType) {
this.resourceType = resourceType;
}
}

@ -0,0 +1,46 @@
/*
* 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
* @since 2.3.0
*/
public class StackdriverPropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapter<StackdriverProperties>
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);
}
}

@ -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;

@ -0,0 +1,132 @@
/*
* 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=test-project")
.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=test-project")
.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=test-project").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 "test-project";
}
return null;
};
}
}
@Configuration(proxyBeanMethods = false)
@Import(BaseConfiguration.class)
static class CustomRegistryConfiguration {
@Bean
StackdriverMeterRegistry customRegistry(StackdriverConfig config, Clock clock) {
return new StackdriverMeterRegistry(config, clock);
}
}
}

@ -0,0 +1,44 @@
/*
* 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");
}
}

@ -0,0 +1,41 @@
/*
* 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());
}
}

@ -1038,6 +1038,17 @@
<artifactId>lettuce-core</artifactId>
<version>${lettuce.version}</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-stackdriver</artifactId>
<version>${micrometer.version}</version>
<exclusions>
<exclusion>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-bom</artifactId>

@ -1245,6 +1245,7 @@ Spring Boot Actuator provides dependency management and auto-configuration for h
- <<production-ready-metrics-export-prometheus,Prometheus>>
- <<production-ready-metrics-export-signalfx,SignalFx>>
- <<production-ready-metrics-export-simple,Simple (in-memory)>>
- <<production-ready-metrics-export-stackdriver,Stackdriver>>
- <<production-ready-metrics-export-statsd,StatsD>>
- <<production-ready-metrics-export-wavefront,Wavefront>>
@ -1584,6 +1585,25 @@ You can also disable it explicitly:
[[production-ready-metrics-export-stackdriver]]
==== Stackdriver
Stackdriver registry pushes metrics to https://cloud.google.com/stackdriver/[Stackdriver] periodically.
To export metrics to SaaS {micrometer-registry-docs}/stackdriver[Stackdriver], your Google Cloud project id must be provided:
[source,properties,indent=0,configprops]
----
management.metrics.export.stackdriver.project-id=my-project
----
You can also change the interval at which metrics are sent to Stackdriver:
[source,properties,indent=0,configprops]
----
management.metrics.export.stackdriver.step=30s
----
[[production-ready-metrics-export-statsd]]
==== StatsD
The StatsD registry pushes metrics over UDP to a StatsD agent eagerly.

Loading…
Cancel
Save