From 602f52fffc63d71e4ab16e3da11c17e24aa4df69 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 14 May 2018 13:26:01 +0200 Subject: [PATCH] Add support for configuring common tags declaratively Closes gh-12933 --- .../metrics/MetricsProperties.java | 9 ++++++++ .../metrics/PropertiesMeterFilter.java | 23 ++++++++++++++++++- ...ricsAutoConfigurationIntegrationTests.java | 13 +++++++++++ .../appendix-application-properties.adoc | 1 + .../asciidoc/production-ready-features.adoc | 15 ++++++++++++ 5 files changed, 60 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsProperties.java index a69a2b50c91..f24cce63747 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsProperties.java @@ -44,6 +44,11 @@ public class MetricsProperties { */ private Map enable = new LinkedHashMap<>(); + /** + * Common tags that are applied to every meter. + */ + private final Map tags = new LinkedHashMap<>(); + private final Web web = new Web(); private final Distribution distribution = new Distribution(); @@ -65,6 +70,10 @@ public class MetricsProperties { this.enable = enable; } + public Map getTags() { + return this.tags; + } + public Web getWeb() { return this.web; } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/PropertiesMeterFilter.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/PropertiesMeterFilter.java index 130b1f7db2b..85b40cab78b 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/PropertiesMeterFilter.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/PropertiesMeterFilter.java @@ -19,9 +19,12 @@ package org.springframework.boot.actuate.autoconfigure.metrics; import java.util.Arrays; import java.util.Map; import java.util.Objects; +import java.util.stream.Collectors; import io.micrometer.core.instrument.Meter; import io.micrometer.core.instrument.Meter.Id; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.Tags; import io.micrometer.core.instrument.config.MeterFilter; import io.micrometer.core.instrument.config.MeterFilterReply; import io.micrometer.core.instrument.distribution.DistributionStatisticConfig; @@ -35,17 +38,30 @@ import org.springframework.util.StringUtils; * * @author Jon Schneider * @author Phillip Webb + * @author Stephane Nicoll * @since 2.0.0 */ public class PropertiesMeterFilter implements MeterFilter { private static final ServiceLevelAgreementBoundary[] EMPTY_SLA = {}; - private MetricsProperties properties; + private final MetricsProperties properties; + + private final MeterFilter mapFilter; public PropertiesMeterFilter(MetricsProperties properties) { Assert.notNull(properties, "Properties must not be null"); this.properties = properties; + this.mapFilter = createMapFilter(properties.getTags()); + } + + private static MeterFilter createMapFilter(Map tags) { + if (tags.isEmpty()) { + return new MeterFilter() { }; + } + Tags commonTags = Tags.of(tags.entrySet().stream().map((entry) -> + Tag.of(entry.getKey(), entry.getValue())).collect(Collectors.toList())); + return MeterFilter.commonTags(commonTags); } @Override @@ -54,6 +70,11 @@ public class PropertiesMeterFilter implements MeterFilter { return (enabled ? MeterFilterReply.NEUTRAL : MeterFilterReply.DENY); } + @Override + public Id map(Id id) { + return this.mapFilter.map(id); + } + @Override public DistributionStatisticConfig configure(Meter.Id id, DistributionStatisticConfig config) { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationIntegrationTests.java index 0c9784b5d27..18999833803 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationIntegrationTests.java @@ -55,6 +55,19 @@ public class MetricsAutoConfigurationIntegrationTests { }); } + @Test + public void propertyBasedCommonTagsIsAutoConfigured() { + this.contextRunner.withPropertyValues("management.metrics.tags.region=test", + "management.metrics.tags.origin=local") + .run((context) -> { + MeterRegistry registry = context.getBean(MeterRegistry.class); + registry.counter("my.counter", "env", "qa"); + assertThat(registry.find("my.counter").tags("env", "qa") + .tags("region", "test").tags("origin", "local").counter()) + .isNotNull(); + }); + } + @Test public void simpleMeterRegistryIsUsedAsAFallback() { this.contextRunner diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index fd4cfdb7bcc..74e200d0773 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -1432,6 +1432,7 @@ content into your application. Rather, pick only the properties that you need. management.metrics.export.wavefront.step=10s # Step size (i.e. reporting frequency) to use. management.metrics.export.wavefront.uri=https://longboard.wavefront.com # URI to ship metrics to. management.metrics.use-global-registry=true # Whether auto-configured MeterRegistry implementations should be bound to the global static registry on Metrics. + management.metrics.tags.*= # Common tags that are applied to every meter. management.metrics.web.client.max-uri-tags=100 # Maximum number of unique URI tag values allowed. After the max number of tag values is reached, metrics with additional tag values are denied by filter. management.metrics.web.client.requests-metric-name=http.client.requests # Name of the metric for sent requests. management.metrics.web.server.auto-time-requests=true # Whether requests handled by Spring MVC or WebFlux should be automatically timed. diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index 52664dd22bd..4639c986505 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -1846,6 +1846,21 @@ all meter IDs beginning with `com.example`, you can do the following: include::{code-examples}/actuate/metrics/MetricsFilterBeanExample.java[tag=configuration] ---- +[[production-ready-metrics-common-tags]] +==== Common tags +Common tag are generally used for dimensional drill-down on the operating environment like +host, instance, region, stack, etc. Commons tags applied to all meters and can be +configured as shown in the following example: + +[source,properties,indent=0] +---- + management.metrics.tags.region=us-east-1 + management.metrics.tags.stack=prod +---- + +The example above adds a `region` and `stack` tags to all meters with a value of +`us-east-1` and `prod` respectively. + ==== Per-meter properties