diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/amqp/RabbitMetricsConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/amqp/RabbitMetricsConfiguration.java index b0664076f6..c0ef6be866 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/amqp/RabbitMetricsConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/amqp/RabbitMetricsConfiguration.java @@ -20,7 +20,6 @@ import java.util.Map; import com.rabbitmq.client.ConnectionFactory; import io.micrometer.core.instrument.MeterRegistry; -import io.micrometer.core.instrument.Tag; import io.micrometer.core.instrument.Tags; import org.springframework.amqp.rabbit.connection.AbstractConnectionFactory; @@ -66,9 +65,11 @@ public class RabbitMetricsConfiguration { private void bindConnectionFactoryToRegistry(String beanName, AbstractConnectionFactory connectionFactory) { - Iterable tags = Tags.zip("name", getConnectionFactoryName(beanName)); - new RabbitMetrics(connectionFactory.getRabbitConnectionFactory(), this.metricName, - tags).bindTo(this.registry); + ConnectionFactory rabbitConnectionFactory = connectionFactory + .getRabbitConnectionFactory(); + String connectionFactoryName = getConnectionFactoryName(beanName); + new RabbitMetrics(rabbitConnectionFactory, this.metricName, + Tags.of("name", connectionFactoryName)).bindTo(this.registry); } /** diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/jdbc/DataSourcePoolMetricsConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/jdbc/DataSourcePoolMetricsConfiguration.java index 9d383cfa52..5353c15062 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/jdbc/DataSourcePoolMetricsConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/jdbc/DataSourcePoolMetricsConfiguration.java @@ -22,7 +22,6 @@ import java.util.Map; import javax.sql.DataSource; import io.micrometer.core.instrument.MeterRegistry; -import io.micrometer.core.instrument.Tag; import io.micrometer.core.instrument.Tags; import org.springframework.beans.factory.annotation.Autowired; @@ -68,9 +67,9 @@ public class DataSourcePoolMetricsConfiguration { } private void bindDataSourceToRegistry(String beanName, DataSource dataSource) { - Iterable tags = Tags.zip("name", getDataSourceName(beanName)); + String dataSourceName = getDataSourceName(beanName); new DataSourcePoolMetrics(dataSource, this.metadataProviders, this.metricName, - tags).bindTo(this.registry); + Tags.of("name", dataSourceName)).bindTo(this.registry); } /** diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/cache/CacheMetricsRegistrar.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/cache/CacheMetricsRegistrar.java index 2c4e7972cf..f2b71759a2 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/cache/CacheMetricsRegistrar.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/cache/CacheMetricsRegistrar.java @@ -16,10 +16,7 @@ package org.springframework.boot.actuate.metrics.cache; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; -import java.util.List; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Tag; @@ -69,8 +66,7 @@ public class CacheMetricsRegistrar { * @return {@code true} if the {@code cache} is supported and was registered */ public boolean bindCacheToRegistry(Cache cache, Tag... tags) { - List allTags = new ArrayList<>(Arrays.asList(tags)); - MeterBinder meterBinder = getMeterBinder(cache, allTags); + MeterBinder meterBinder = getMeterBinder(cache, Tags.of(tags)); if (meterBinder != null) { meterBinder.bindTo(this.registry); return true; @@ -79,8 +75,8 @@ public class CacheMetricsRegistrar { } @SuppressWarnings({ "unchecked", "rawtypes" }) - private MeterBinder getMeterBinder(Cache cache, Iterable tags) { - Iterable withAdditionalTags = Tags.concat(tags, getAdditionalTags(cache)); + private MeterBinder getMeterBinder(Cache cache, Tags tags) { + tags = tags.and(getAdditionalTags(cache)); for (CacheMeterBinderProvider binderProvider : this.binderProviders) { Class cacheType = ResolvableType .forClass(CacheMeterBinderProvider.class, binderProvider.getClass()) @@ -88,7 +84,7 @@ public class CacheMetricsRegistrar { if (cacheType.isInstance(cache)) { try { MeterBinder meterBinder = ((CacheMeterBinderProvider) binderProvider) - .getMeterBinder(cache, this.metricName, withAdditionalTags); + .getMeterBinder(cache, this.metricName, tags); if (meterBinder != null) { return meterBinder; } @@ -121,7 +117,7 @@ public class CacheMetricsRegistrar { * @return a list of additional tags to associate to that {@code cache}. */ protected Iterable getAdditionalTags(Cache cache) { - return Tags.zip("name", cache.getName()); + return Tags.of("name", cache.getName()); } } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/integration/SpringIntegrationMetrics.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/integration/SpringIntegrationMetrics.java index 5cb5ec6ca7..c85ad8d481 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/integration/SpringIntegrationMetrics.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/integration/SpringIntegrationMetrics.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * 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. @@ -45,7 +45,7 @@ import org.springframework.integration.support.management.PollableChannelManagem */ public class SpringIntegrationMetrics implements MeterBinder, SmartInitializingSingleton { - private final Iterable tags; + private final Tags tags; private Collection registries = new ArrayList<>(); @@ -56,9 +56,9 @@ public class SpringIntegrationMetrics implements MeterBinder, SmartInitializingS } public SpringIntegrationMetrics(IntegrationManagementConfigurer configurer, - Iterable tags) { + Iterable tags) { this.configurer = configurer; - this.tags = tags; + this.tags = Tags.of(tags); } @Override @@ -81,7 +81,7 @@ public class SpringIntegrationMetrics implements MeterBinder, SmartInitializingS private void addSourceMetrics(MeterRegistry registry) { for (String source : this.configurer.getSourceNames()) { MessageSourceMetrics sourceMetrics = this.configurer.getSourceMetrics(source); - Iterable tagsWithSource = Tags.concat(this.tags, "source", source); + Iterable tagsWithSource = this.tags.and("source", source); registerFunctionCounter(registry, sourceMetrics, tagsWithSource, "spring.integration.source.messages", "The number of successful handler calls", @@ -93,7 +93,7 @@ public class SpringIntegrationMetrics implements MeterBinder, SmartInitializingS for (String handler : this.configurer.getHandlerNames()) { MessageHandlerMetrics handlerMetrics = this.configurer .getHandlerMetrics(handler); - Iterable tagsWithHandler = Tags.concat(this.tags, "handler", handler); + Iterable tagsWithHandler = this.tags.and("handler", handler); registerTimedGauge(registry, handlerMetrics, tagsWithHandler, "spring.integration.handler.duration.max", "The maximum handler duration", @@ -116,7 +116,7 @@ public class SpringIntegrationMetrics implements MeterBinder, SmartInitializingS for (String channel : this.configurer.getChannelNames()) { MessageChannelMetrics channelMetrics = this.configurer .getChannelMetrics(channel); - Iterable tagsWithChannel = Tags.concat(this.tags, "channel", channel); + Iterable tagsWithChannel = this.tags.and("channel", channel); registerFunctionCounter(registry, channelMetrics, tagsWithChannel, "spring.integration.channel.sendErrors", "The number of failed sends (either throwing an exception or rejected by the channel)", diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/RouterFunctionMetrics.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/RouterFunctionMetrics.java index da1c9b869a..ef58527437 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/RouterFunctionMetrics.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/RouterFunctionMetrics.java @@ -16,17 +16,17 @@ package org.springframework.boot.actuate.metrics.web.reactive.server; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; import java.util.concurrent.TimeUnit; import java.util.function.BiFunction; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Tag; import io.micrometer.core.instrument.Tags; +import reactor.core.publisher.Mono; +import org.springframework.util.Assert; import org.springframework.web.reactive.function.server.HandlerFilterFunction; +import org.springframework.web.reactive.function.server.HandlerFunction; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; @@ -41,53 +41,53 @@ public class RouterFunctionMetrics { private final MeterRegistry registry; - private BiFunction> defaultTags = ( - ServerRequest request, ServerResponse response) -> response != null - ? Arrays.asList(method(request), status(response)) - : Collections.singletonList(method(request)); + private final BiFunction> defaultTags; public RouterFunctionMetrics(MeterRegistry registry) { + Assert.notNull(registry, "Registry must not be null"); this.registry = registry; + this.defaultTags = this::defaultTags; + } + + private RouterFunctionMetrics(MeterRegistry registry, + BiFunction> defaultTags) { + Assert.notNull(registry, "Registry must not be null"); + Assert.notNull(defaultTags, "DefaultTags must not be null"); + this.registry = registry; + this.defaultTags = defaultTags; + } + + private Iterable defaultTags(ServerRequest request, ServerResponse response) { + if (response == null) { + return Tags.of(getMethodTag(request)); + } + return Tags.of(getMethodTag(request), getStatusTag(response)); } /** - * Configures the default tags. + * Returns a new {@link RouterFunctionMetrics} instance with the specified default + * tags. * @param defaultTags Generate a list of tags to apply to the timer. * {@code ServerResponse} may be null. * @return {@code this} for further configuration */ public RouterFunctionMetrics defaultTags( - BiFunction> defaultTags) { - this.defaultTags = defaultTags; - return this; + BiFunction> defaultTags) { + return new RouterFunctionMetrics(this.registry, defaultTags); } public HandlerFilterFunction timer(String name) { - return timer(name, Collections.emptyList()); + return timer(name, Tags.empty()); } public HandlerFilterFunction timer(String name, String... tags) { - return timer(name, Tags.zip(tags)); + return timer(name, Tags.of(tags)); } public HandlerFilterFunction timer(String name, Iterable tags) { - return (request, next) -> { - final long start = System.nanoTime(); - return next.handle(request).doOnSuccess((response) -> { - Iterable allTags = Tags.concat(tags, - this.defaultTags.apply(request, response)); - this.registry.timer(name, allTags).record(System.nanoTime() - start, - TimeUnit.NANOSECONDS); - }).doOnError((error) -> { - // FIXME how do we get the response under an error condition? - Iterable allTags = Tags.concat(tags, - this.defaultTags.apply(request, null)); - this.registry.timer(name, allTags).record(System.nanoTime() - start, - TimeUnit.NANOSECONDS); - }); - }; + return new MetricsFilter(name, Tags.of(tags)); } /** @@ -95,7 +95,7 @@ public class RouterFunctionMetrics { * @param request The HTTP request. * @return A "method" tag whose value is a capitalized method (e.g. GET). */ - public static Tag method(ServerRequest request) { + public static Tag getMethodTag(ServerRequest request) { return Tag.of("method", request.method().toString()); } @@ -104,8 +104,48 @@ public class RouterFunctionMetrics { * @param response The HTTP response. * @return A "status" tag whose value is the numeric status code. */ - public static Tag status(ServerResponse response) { + public static Tag getStatusTag(ServerResponse response) { return Tag.of("status", response.statusCode().toString()); } + /** + * {@link HandlerFilterFunction} to handle calling micrometer. + */ + private class MetricsFilter + implements HandlerFilterFunction { + + private final String name; + + private final Tags tags; + + MetricsFilter(String name, Tags tags) { + this.name = name; + this.tags = tags; + } + + @Override + public Mono filter(ServerRequest request, + HandlerFunction next) { + long start = System.nanoTime(); + return next.handle(request).doOnSuccess((response) -> { + timer(start, request, response); + }).doOnError((error) -> { + // FIXME how do we get the response under an error condition? + timer(start, request, null); + }); + } + + private Iterable getDefaultTags(ServerRequest request, + ServerResponse response) { + return RouterFunctionMetrics.this.defaultTags.apply(request, response); + } + + private void timer(long start, ServerRequest request, ServerResponse response) { + Tags allTags = this.tags.and(getDefaultTags(request, response)); + RouterFunctionMetrics.this.registry.timer(this.name, allTags) + .record(System.nanoTime() - start, TimeUnit.NANOSECONDS); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetrics.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetrics.java index 3a7025490b..45eff57f5e 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetrics.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetrics.java @@ -34,7 +34,6 @@ import io.micrometer.core.annotation.Timed; import io.micrometer.core.annotation.TimedSet; import io.micrometer.core.instrument.LongTaskTimer; import io.micrometer.core.instrument.MeterRegistry; -import io.micrometer.core.instrument.Tag; import io.micrometer.core.instrument.Tags; import io.micrometer.core.instrument.Timer; import org.apache.commons.logging.Log; @@ -252,7 +251,7 @@ public class WebMvcMetrics { private final String name; - private final Iterable extraTags; + private final Tags extraTags; private final double[] percentiles; @@ -260,14 +259,14 @@ public class WebMvcMetrics { TimerConfig(String name, boolean histogram) { this.name = name; - this.extraTags = Collections.emptyList(); + this.extraTags = Tags.empty(); this.percentiles = new double[0]; this.histogram = histogram; } TimerConfig(Timed timed, Supplier name) { this.name = buildName(timed, name); - this.extraTags = Tags.zip(timed.extraTags()); + this.extraTags = Tags.of(timed.extraTags()); this.percentiles = timed.percentiles(); this.histogram = timed.histogram(); } @@ -285,7 +284,7 @@ public class WebMvcMetrics { return this.name; } - Iterable getExtraTags() { + Tags getExtraTags() { return this.extraTags; } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/amqp/RabbitMetricsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/amqp/RabbitMetricsTests.java index e16bce11fc..4b7457bc61 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/amqp/RabbitMetricsTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/amqp/RabbitMetricsTests.java @@ -43,7 +43,7 @@ public class RabbitMetricsTests { public void connectionFactoryWithTagsIsInstrumented() { ConnectionFactory connectionFactory = mockConnectionFactory(); SimpleMeterRegistry registry = new SimpleMeterRegistry(); - new RabbitMetrics(connectionFactory, "test", Tags.zip("env", "prod")) + new RabbitMetrics(connectionFactory, "test", Tags.of("env", "prod")) .bindTo(registry); assertThat(registry.get("test.connections").tags("env", "prod").meter()) .isNotNull();