diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricExportAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricExportAutoConfiguration.java index 2380b2c1a69..9900b840c33 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricExportAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricExportAutoConfiguration.java @@ -29,6 +29,7 @@ import org.springframework.boot.actuate.metrics.export.MetricExportProperties; import org.springframework.boot.actuate.metrics.export.MetricExporters; import org.springframework.boot.actuate.metrics.reader.CompositeMetricReader; import org.springframework.boot.actuate.metrics.reader.MetricReader; +import org.springframework.boot.actuate.metrics.statsd.StatsdMetricWriter; import org.springframework.boot.actuate.metrics.writer.MetricWriter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -45,6 +46,7 @@ import org.springframework.util.CollectionUtils; * {@link EnableAutoConfiguration Auto-configuration} for metrics export. * * @author Dave Syer + * @author Simon Buettner * @since 1.3.0 */ @Configuration @@ -92,6 +94,16 @@ public class MetricExportAutoConfiguration { return exporters; } + @Bean + @ExportMetricWriter + @ConditionalOnMissingBean + @ConditionalOnProperty(prefix = "spring.metrics.export.statsd", name = "host") + public StatsdMetricWriter statsdMetricWriter() { + MetricExportProperties.Statsd statsdProperties = this.properties.getStatsd(); + return new StatsdMetricWriter(statsdProperties.getPrefix(), + statsdProperties.getHost(), statsdProperties.getPort()); + } + @Configuration protected static class MetricExportPropertiesConfiguration { diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/export/MetricExportProperties.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/export/MetricExportProperties.java index 539f0e8c2e4..fb2bc15920d 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/export/MetricExportProperties.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/export/MetricExportProperties.java @@ -29,6 +29,7 @@ import org.springframework.util.PatternMatchUtils; * Configuration properties for metrics export. * * @author Dave Syer + * @author Simon Buettner * @since 1.3.0 */ @ConfigurationProperties("spring.metrics.export") @@ -43,6 +44,8 @@ public class MetricExportProperties extends TriggerProperties { private Redis redis = new Redis(); + private Statsd statsd = new Statsd(); + @PostConstruct public void setUpDefaults() { TriggerProperties defaults = this; @@ -79,10 +82,6 @@ public class MetricExportProperties extends TriggerProperties { return this.triggers; } - public Redis getRedis() { - return this.redis; - } - public Aggregate getAggregate() { return this.aggregate; } @@ -91,10 +90,22 @@ public class MetricExportProperties extends TriggerProperties { this.aggregate = aggregate; } + public Redis getRedis() { + return this.redis; + } + public void setRedis(Redis redis) { this.redis = redis; } + public Statsd getStatsd() { + return this.statsd; + } + + public void setStatsd(Statsd statsd) { + this.statsd = statsd; + } + /** * Find a matching trigger configuration. * @param name the bean name to match @@ -205,4 +216,50 @@ public class MetricExportProperties extends TriggerProperties { } + /** + * Statsd properties. + */ + public static class Statsd { + + /** + * Host of a statsd server to receive exported metrics. + */ + private String host; + + /** + * Port of a statsd server to receive exported metrics. + */ + private int port = 8125; + + /** + * Prefix for statsd exported metrics. + */ + private String prefix; + + public String getHost() { + return this.host; + } + + public void setHost(String host) { + this.host = host; + } + + public int getPort() { + return this.port; + } + + public void setPort(int port) { + this.port = port; + } + + public String getPrefix() { + return this.prefix; + } + + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + } + } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/MetricExportAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/MetricExportAutoConfigurationTests.java index 4adcc708135..2a7e9145ded 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/MetricExportAutoConfigurationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/MetricExportAutoConfigurationTests.java @@ -17,16 +17,21 @@ package org.springframework.boot.actuate.autoconfigure; import org.junit.After; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.mockito.Matchers; import org.mockito.Mockito; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.boot.actuate.endpoint.MetricsEndpointMetricReader; import org.springframework.boot.actuate.metrics.GaugeService; import org.springframework.boot.actuate.metrics.Metric; import org.springframework.boot.actuate.metrics.export.MetricCopyExporter; import org.springframework.boot.actuate.metrics.export.MetricExporters; +import org.springframework.boot.actuate.metrics.statsd.StatsdMetricWriter; import org.springframework.boot.actuate.metrics.writer.MetricWriter; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.test.EnvironmentTestUtils; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -36,16 +41,22 @@ import org.springframework.messaging.MessageHandler; import org.springframework.messaging.MessagingException; import org.springframework.messaging.SubscribableChannel; +import static org.hamcrest.Matchers.notNullValue; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; /** * Tests for {@link MetricExportAutoConfiguration}. * * @author Phillip Webb * @author Dave Syer + * @author Simon Buettner */ public class MetricExportAutoConfigurationTests { + @Rule + public ExpectedException thrown = ExpectedException.none(); + private AnnotationConfigApplicationContext context; @After @@ -100,16 +111,43 @@ public class MetricExportAutoConfigurationTests { Mockito.verify(reader, Mockito.atLeastOnce()).findAll(); } + @Test + public void statsdMissingHost() throws Exception { + this.context = new AnnotationConfigApplicationContext(); + this.context.register(WriterConfig.class, MetricEndpointConfiguration.class, + MetricExportAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class); + this.context.refresh(); + this.thrown.expect(NoSuchBeanDefinitionException.class); + this.context.getBean(StatsdMetricWriter.class); + } + + @Test + public void statsdWithHost() throws Exception { + this.context = new AnnotationConfigApplicationContext(); + EnvironmentTestUtils.addEnvironment(this.context, + "spring.metrics.export.statsd.host=localhost"); + this.context.register(WriterConfig.class, MetricEndpointConfiguration.class, + MetricExportAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class); + this.context.refresh(); + assertThat(this.context.getBean(StatsdMetricWriter.class), notNullValue()); + } + @Configuration public static class MessageChannelConfiguration { + @Bean public SubscribableChannel metricsChannel() { return new FixedSubscriberChannel(new MessageHandler() { + @Override public void handleMessage(Message message) throws MessagingException { } + }); } + } @Configuration diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 94237518eb0..f525b414cc5 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -790,6 +790,9 @@ content into your application; rather pick only the properties that you need. spring.metrics.export.excludes= # list of patterns for metric names to exclude. Applied after the includes spring.metrics.export.redis.prefix=spring.metrics # prefix for redis repository if active spring.metrics.export.redis.key=keys.spring.metrics # key for redis repository export (if active) + spring.metrics.export.statsd.host= # host of the statsd server + spring.metrics.export.statsd.port=8125 # port of the statsd server + spring.metrics.export.statsd.prefix= # prefix for exported metrics spring.metrics.export.triggers.*= # specific trigger properties per MetricWriter bean name # SENDGRID ({sc-spring-boot-autoconfigure}/sendgrid/SendGridAutoConfiguration.{sc-ext}[SendGridAutoConfiguration]) diff --git a/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index 490303d4825..29fbe33750f 100644 --- a/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -1142,28 +1142,28 @@ curl localhost:4242/api/query?start=1h-ago&m=max:counter.status.200.root [[production-ready-metric-writers-export-to-statsd]] ==== Example: Export to Statsd -If you provide a `@Bean` of type `StatsdMetricWriter` and mark it `@ExportMetricWriter` the metrics are exported to a -statsd server: +To export metrics to Statsd add a `spring.metrics.export.statsd.host` value to your +`application.properties` file. Connections will be opened to port `8125` unless a +`spring.metrics.export.statsd.port` override is provided. You can use +`spring.metrics.export.statsd.prefix` if you want a custom prefix. + +Alternatively, you can provide a `@Bean` of type `StatsdMetricWriter` and mark it +`@ExportMetricWriter`: [source,java,indent=0] ---- @Value("${spring.application.name:application}.${random.value:0000}") private String prefix = "metrics"; -@Value("${statsd.host:localhost}") -private String host = "localhost"; - -@Value("${statsd.port:8125}") -private int port; - @Bean @ExportMetricWriter MetricWriter metricWriter() { - return new StatsdMetricWriter(prefix, host, port); + return new StatsdMetricWriter(prefix, "localhost", "8125"); } ---- + [[production-ready-metric-writers-export-to-jmx]] ==== Example: Export to JMX If you provide a `@Bean` of type `JmxMetricWriter` marked `@ExportMetricWriter` the metrics are exported as MBeans to