Auto-configure Micrometer's New Relic and SignalFX support

Closes gh-11803
This commit is contained in:
Andy Wilkinson 2018-02-09 15:09:20 +00:00
parent 1b156fc2c3
commit 037b6d8ba2
13 changed files with 698 additions and 0 deletions

View File

@ -117,11 +117,21 @@
<artifactId>micrometer-registry-jmx</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-new-relic</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-signalfx</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-statsd</artifactId>

View File

@ -0,0 +1,69 @@
/*
* Copyright 2012-2018 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
*
* http://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.newrelic;
import io.micrometer.core.instrument.Clock;
import io.micrometer.newrelic.NewRelicConfig;
import io.micrometer.newrelic.NewRelicMeterRegistry;
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.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to New Relic.
*
* @author Jon Schneider
* @author Andy Wilkinson
* @since 2.0.0
*/
@Configuration
@AutoConfigureBefore(SimpleMetricsExportAutoConfiguration.class)
@AutoConfigureAfter(MetricsAutoConfiguration.class)
@ConditionalOnBean(Clock.class)
@ConditionalOnClass(NewRelicMeterRegistry.class)
@EnableConfigurationProperties(NewRelicProperties.class)
public class NewRelicMetricsExportAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public Clock micrometerClock() {
return Clock.SYSTEM;
}
@Bean
@ConditionalOnMissingBean
public NewRelicConfig newRelicConfig(NewRelicProperties props) {
return new NewRelicPropertiesConfigAdapter(props);
}
@Bean
@ConditionalOnMissingBean
public NewRelicMeterRegistry newRelicMeterRegistry(NewRelicConfig config,
Clock clock) {
return new NewRelicMeterRegistry(config, clock);
}
}

View File

@ -0,0 +1,71 @@
/*
* Copyright 2012-2018 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
*
* http://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.newrelic;
import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* {@link ConfigurationProperties} for configuring New Relic metrics export.
*
* @author Jon Schneider
* @author Andy Wilkinson
* @since 2.0.0
*/
@ConfigurationProperties(prefix = "management.metrics.export.newrelic")
public class NewRelicProperties extends StepRegistryProperties {
/**
* New Relic API key.
*/
private String apiKey;
/**
* New Relic account ID.
*/
private String accountId;
/**
* Optional custom URI for the New Relic Insights API.
*/
private String uri;
public String getApiKey() {
return this.apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
public String getAccountId() {
return this.accountId;
}
public void setAccountId(String accountId) {
this.accountId = accountId;
}
public String getUri() {
return this.uri;
}
public void setUri(String uri) {
this.uri = uri;
}
}

View File

@ -0,0 +1,52 @@
/*
* Copyright 2012-2018 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
*
* http://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.newrelic;
import io.micrometer.newrelic.NewRelicConfig;
import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryPropertiesConfigAdapter;
/**
* Adapter to convert {@link NewRelicProperties} to a {@link NewRelicConfig}.
*
* @author Jon Schneider
* @since 2.0.0
*/
public class NewRelicPropertiesConfigAdapter
extends StepRegistryPropertiesConfigAdapter<NewRelicProperties>
implements NewRelicConfig {
public NewRelicPropertiesConfigAdapter(NewRelicProperties properties) {
super(properties);
}
@Override
public String apiKey() {
return get(NewRelicProperties::getApiKey, NewRelicConfig.super::apiKey);
}
@Override
public String accountId() {
return get(NewRelicProperties::getAccountId, NewRelicConfig.super::accountId);
}
@Override
public String uri() {
return get(NewRelicProperties::getUri, NewRelicConfig.super::uri);
}
}

View File

@ -0,0 +1,20 @@
/*
* Copyright 2012-2018 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
*
* http://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 New Relic.
*/
package org.springframework.boot.actuate.autoconfigure.metrics.export.newrelic;

View File

@ -0,0 +1,69 @@
/*
* Copyright 2012-2018 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
*
* http://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.signalfx;
import io.micrometer.core.instrument.Clock;
import io.micrometer.signalfx.SignalFxConfig;
import io.micrometer.signalfx.SignalFxMeterRegistry;
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.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to SignalFX.
*
* @author Jon Schneider
* @author Andy Wilkinson
* @since 2.0.0
*/
@Configuration
@AutoConfigureBefore(SimpleMetricsExportAutoConfiguration.class)
@AutoConfigureAfter(MetricsAutoConfiguration.class)
@ConditionalOnBean(Clock.class)
@ConditionalOnClass(SignalFxMeterRegistry.class)
@EnableConfigurationProperties(SignalFxProperties.class)
public class SignalFxMetricsExportAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public SignalFxConfig signalfxConfig(SignalFxProperties props) {
return new SignalFxPropertiesConfigAdapter(props);
}
@Bean
@ConditionalOnMissingBean
public SignalFxMeterRegistry signalFxMeterRegistry(SignalFxConfig config,
Clock clock) {
return new SignalFxMeterRegistry(config, clock);
}
@Bean
@ConditionalOnMissingBean
public Clock micrometerClock() {
return Clock.SYSTEM;
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright 2012-2018 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
*
* http://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.signalfx;
import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* {@link ConfigurationProperties} for configuring metrics export to SignalFX.
*
* @author Jon Schneider
* @author Andy Wilkinson
* @since 2.0.0
*/
@ConfigurationProperties(prefix = "management.metrics.export.signalfx")
public class SignalFxProperties extends StepRegistryProperties {
/**
* SignalFX access token.
*/
private String accessToken;
/**
* Optional custom URI for the SignalFX API.
*/
private String uri;
public String getAccessToken() {
return this.accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public String getUri() {
return this.uri;
}
public void setUri(String uri) {
this.uri = uri;
}
}

View File

@ -0,0 +1,47 @@
/*
* Copyright 2012-2018 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
*
* http://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.signalfx;
import io.micrometer.signalfx.SignalFxConfig;
import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryPropertiesConfigAdapter;
/**
* Adapter to convert {@link SignalFxProperties} to a {@link SignalFxConfig}.
*
* @author Jon Schneider
* @since 2.0.0
*/
public class SignalFxPropertiesConfigAdapter
extends StepRegistryPropertiesConfigAdapter<SignalFxProperties>
implements SignalFxConfig {
public SignalFxPropertiesConfigAdapter(SignalFxProperties properties) {
super(properties);
}
@Override
public String accessToken() {
return get(SignalFxProperties::getAccessToken, SignalFxConfig.super::accessToken);
}
@Override
public String uri() {
return get(SignalFxProperties::getUri, SignalFxConfig.super::uri);
}
}

View File

@ -0,0 +1,20 @@
/*
* Copyright 2012-2018 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
*
* http://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 SignalFX.
*/
package org.springframework.boot.actuate.autoconfigure.metrics.export.signalfx;

View File

@ -42,8 +42,10 @@ org.springframework.boot.actuate.autoconfigure.metrics.export.ganglia.GangliaMet
org.springframework.boot.actuate.autoconfigure.metrics.export.graphite.GraphiteMetricsExportAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.metrics.export.influx.InfluxMetricsExportAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.metrics.export.jmx.JmxMetricsExportAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.metrics.export.newrelic.NewRelicMetricsExportAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.metrics.export.prometheus.PrometheusMetricsExportAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.metrics.export.signalfx.SignalFxMetricsExportAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.metrics.export.statsd.StatsdMetricsExportAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.metrics.jdbc.DataSourcePoolMetricsAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.metrics.web.client.RestTemplateMetricsAutoConfiguration,\

View File

@ -0,0 +1,143 @@
/*
* Copyright 2012-2018 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
*
* http://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.newrelic;
import io.micrometer.core.instrument.Clock;
import io.micrometer.newrelic.NewRelicConfig;
import io.micrometer.newrelic.NewRelicMeterRegistry;
import org.junit.Test;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
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 static org.assertj.core.api.Assertions.assertThat;
/**
*
* Tests for {@link NewRelicMetricsExportAutoConfiguration}.
*
* @author Andy Wilkinson
*/
public class NewRelicMetricsExportAutoConfigurationTests {
private final ApplicationContextRunner runner = new ApplicationContextRunner()
.withConfiguration(
AutoConfigurations.of(NewRelicMetricsExportAutoConfiguration.class,
MetricsAutoConfiguration.class));
@Test
public void failsWithoutAnApiKey() {
this.runner
.withPropertyValues("management.metrics.export.newrelic.account-id=12345")
.run((context) -> assertThat(context).hasFailed());
}
@Test
public void failsWithoutAnAccountId() {
this.runner
.withConfiguration(AutoConfigurations.of(
NewRelicMetricsExportAutoConfiguration.class,
MetricsAutoConfiguration.class))
.withPropertyValues("management.metrics.export.newrelic.api-key=abcde")
.run((context) -> assertThat(context).hasFailed());
}
@Test
public void autoConfiguresWithAccountIdAndApiKey() {
this.runner
.withPropertyValues("management.metrics.export.newrelic.api-key=abcde",
"management.metrics.export.newrelic.account-id=12345")
.run((context) -> assertThat(context)
.hasSingleBean(NewRelicMeterRegistry.class)
.hasSingleBean(Clock.class).hasSingleBean(NewRelicConfig.class));
}
@Test
public void allowsClockToBeCustomized() {
this.runner.withUserConfiguration(CustomClockConfiguration.class)
.withPropertyValues("management.metrics.export.newrelic.api-key=abcde",
"management.metrics.export.newrelic.account-id=12345")
.run((context) -> assertThat(context).hasSingleBean(Clock.class)
.hasBean("customClock"));
}
@Test
public void allowsConfigToBeCustomized() {
this.runner.withUserConfiguration(CustomConfigConfiguration.class)
.withPropertyValues("management.metrics.export.newrelic.api-key=abcde",
"management.metrics.export.newrelic.account-id=12345")
.run((context) -> assertThat(context).hasSingleBean(NewRelicConfig.class)
.hasBean("customConfig"));
}
@Test
public void allowsRegistryToBeCustomized() {
this.runner.withUserConfiguration(CustomRegistryConfiguration.class)
.withPropertyValues("management.metrics.export.newrelic.api-key=abcde",
"management.metrics.export.newrelic.account-id=12345")
.run((context) -> assertThat(context)
.hasSingleBean(NewRelicMeterRegistry.class)
.hasBean("customRegistry"));
}
@Configuration
static class CustomClockConfiguration {
@Bean
public Clock customClock() {
return Clock.SYSTEM;
}
}
@Configuration
static class CustomConfigConfiguration {
@Bean
public NewRelicConfig customConfig() {
return new NewRelicConfig() {
@Override
public String get(String k) {
if ("newrelic.accountId".equals(k)) {
return "abcde";
}
if ("newrelic.apiKey".equals(k)) {
return "12345";
}
return null;
}
};
}
}
@Configuration
static class CustomRegistryConfiguration {
@Bean
public NewRelicMeterRegistry customRegistry(NewRelicConfig config, Clock clock) {
return new NewRelicMeterRegistry(config, clock);
}
}
}

View File

@ -0,0 +1,132 @@
/*
* Copyright 2012-2018 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
*
* http://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.signalfx;
import io.micrometer.core.instrument.Clock;
import io.micrometer.signalfx.SignalFxConfig;
import io.micrometer.signalfx.SignalFxMeterRegistry;
import org.junit.Test;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
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 static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link SignalFxMetricsExportAutoConfiguration}.
*
* @author Andy Wilkinson
*/
public class SignalFxMetricsExportAutoConfigurationTests {
private final ApplicationContextRunner runner = new ApplicationContextRunner()
.withConfiguration(
AutoConfigurations.of(SignalFxMetricsExportAutoConfiguration.class,
MetricsAutoConfiguration.class));
@Test
public void failsWithoutAnAccessToken() {
this.runner.run((context) -> assertThat(context).hasFailed());
}
@Test
public void autoConfiguresWithAnAccessToken() {
this.runner
.withPropertyValues(
"management.metrics.export.signalfx.access-token=abcde")
.run((context) -> assertThat(context)
.hasSingleBean(SignalFxMeterRegistry.class)
.hasSingleBean(Clock.class).hasSingleBean(SignalFxConfig.class));
}
@Test
public void allowsClockToBeCustomized() {
this.runner
.withPropertyValues(
"management.metrics.export.signalfx.access-token=abcde")
.withUserConfiguration(CustomClockConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(Clock.class)
.hasBean("customClock"));
}
@Test
public void allowsConfigToBeCustomized() {
this.runner
.withPropertyValues(
"management.metrics.export.signalfx.access-token=abcde")
.withUserConfiguration(CustomConfigConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(Clock.class)
.hasSingleBean(SignalFxMeterRegistry.class)
.hasSingleBean(SignalFxConfig.class).hasBean("customConfig"));
}
@Test
public void allowsRegistryToBeCustomized() {
this.runner
.withPropertyValues(
"management.metrics.export.signalfx.access-token=abcde")
.withUserConfiguration(CustomRegistryConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(Clock.class)
.hasSingleBean(SignalFxConfig.class)
.hasSingleBean(SignalFxMeterRegistry.class)
.hasBean("customRegistry"));
}
@Configuration
static class CustomClockConfiguration {
@Bean
public Clock customClock() {
return Clock.SYSTEM;
}
}
@Configuration
static class CustomConfigConfiguration {
@Bean
public SignalFxConfig customConfig() {
return new SignalFxConfig() {
@Override
public String get(String k) {
if ("signalfx.accessToken".equals(k)) {
return "abcde";
}
return null;
}
};
}
}
@Configuration
static class CustomRegistryConfiguration {
@Bean
public SignalFxMeterRegistry customRegistry(SignalFxConfig config, Clock clock) {
return new SignalFxMeterRegistry(config, clock);
}
}
}

View File

@ -893,6 +893,11 @@
<artifactId>micrometer-registry-prometheus</artifactId>
<version>${micrometer.version}</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-signalfx</artifactId>
<version>${micrometer.version}</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-statsd</artifactId>