diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle b/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle index 272e36bbc9f..de4db46bda7 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle @@ -102,6 +102,7 @@ dependencies { optional("org.flywaydb:flyway-core") optional("org.glassfish.jersey.core:jersey-server") optional("org.glassfish.jersey.containers:jersey-container-servlet-core") + optional("org.glassfish.jersey.ext:jersey-micrometer") optional("org.hibernate.orm:hibernate-core") optional("org.hibernate.orm:hibernate-micrometer") optional("org.hibernate.validator:hibernate-validator") diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/jersey/JerseyServerMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/jersey/JerseyServerMetricsAutoConfiguration.java index 27d9729cc80..6615a69c900 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/jersey/JerseyServerMetricsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/jersey/JerseyServerMetricsAutoConfiguration.java @@ -20,13 +20,16 @@ import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import io.micrometer.core.instrument.MeterRegistry; -import io.micrometer.core.instrument.binder.jersey.server.AnnotationFinder; -import io.micrometer.core.instrument.binder.jersey.server.DefaultJerseyTagsProvider; -import io.micrometer.core.instrument.binder.jersey.server.JerseyTagsProvider; -import io.micrometer.core.instrument.binder.jersey.server.MetricsApplicationEventListener; +import io.micrometer.core.instrument.Tag; import io.micrometer.core.instrument.config.MeterFilter; +import org.glassfish.jersey.micrometer.server.AnnotationFinder; +import org.glassfish.jersey.micrometer.server.DefaultJerseyTagsProvider; +import org.glassfish.jersey.micrometer.server.JerseyTagsProvider; +import org.glassfish.jersey.micrometer.server.MetricsApplicationEventListener; import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.server.monitoring.RequestEvent; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties; import org.springframework.boot.actuate.autoconfigure.metrics.OnlyOnceLoggingDenyMeterFilter; @@ -66,17 +69,22 @@ public class JerseyServerMetricsAutoConfiguration { } @Bean - @ConditionalOnMissingBean(JerseyTagsProvider.class) + @SuppressWarnings("deprecation") + @ConditionalOnMissingBean({ JerseyTagsProvider.class, + io.micrometer.core.instrument.binder.jersey.server.JerseyTagsProvider.class }) public DefaultJerseyTagsProvider jerseyTagsProvider() { return new DefaultJerseyTagsProvider(); } @Bean + @SuppressWarnings("deprecation") public ResourceConfigCustomizer jerseyServerMetricsResourceConfigCustomizer(MeterRegistry meterRegistry, - JerseyTagsProvider tagsProvider) { + ObjectProvider tagsProvider, + ObjectProvider micrometerTagsProvider) { String metricName = this.observationProperties.getHttp().getServer().getRequests().getName(); - return (config) -> config.register(new MetricsApplicationEventListener(meterRegistry, tagsProvider, metricName, - true, new AnnotationUtilsAnnotationFinder())); + return (config) -> config.register(new MetricsApplicationEventListener(meterRegistry, + tagsProvider.getIfAvailable(() -> new JerseyTagsProviderAdapter(micrometerTagsProvider.getObject())), + metricName, true, new AnnotationUtilsAnnotationFinder())); } @Bean @@ -101,4 +109,26 @@ public class JerseyServerMetricsAutoConfiguration { } + @SuppressWarnings("deprecation") + static final class JerseyTagsProviderAdapter implements JerseyTagsProvider { + + private final io.micrometer.core.instrument.binder.jersey.server.JerseyTagsProvider delegate; + + private JerseyTagsProviderAdapter( + io.micrometer.core.instrument.binder.jersey.server.JerseyTagsProvider delegate) { + this.delegate = delegate; + } + + @Override + public Iterable httpRequestTags(RequestEvent event) { + return this.delegate.httpRequestTags(event); + } + + @Override + public Iterable httpLongRequestTags(RequestEvent event) { + return this.delegate.httpLongRequestTags(event); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/jersey/JerseyServerMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/jersey/JerseyServerMetricsAutoConfigurationTests.java index a7b1a6326ea..612db1b2b51 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/jersey/JerseyServerMetricsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/jersey/JerseyServerMetricsAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -17,22 +17,25 @@ package org.springframework.boot.actuate.autoconfigure.metrics.jersey; import java.net.URI; +import java.util.Set; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Tag; import io.micrometer.core.instrument.Timer; -import io.micrometer.core.instrument.binder.jersey.server.DefaultJerseyTagsProvider; -import io.micrometer.core.instrument.binder.jersey.server.JerseyTagsProvider; -import io.micrometer.core.instrument.binder.jersey.server.MetricsApplicationEventListener; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; +import org.assertj.core.api.InstanceOfAssertFactories; +import org.glassfish.jersey.micrometer.server.DefaultJerseyTagsProvider; +import org.glassfish.jersey.micrometer.server.JerseyTagsProvider; +import org.glassfish.jersey.micrometer.server.MetricsApplicationEventListener; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.server.monitoring.RequestEvent; import org.junit.jupiter.api.Test; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.metrics.jersey.JerseyServerMetricsAutoConfiguration.JerseyTagsProviderAdapter; import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; @@ -87,6 +90,22 @@ class JerseyServerMetricsAutoConfigurationTests { .run((context) -> assertThat(context).hasSingleBean(CustomJerseyTagsProvider.class)); } + @Test + @Deprecated(since = "3.3.0", forRemoval = true) + void shouldHonorExistingMicrometerTagProvider() { + this.webContextRunner.withUserConfiguration(CustomMicrometerJerseyTagsProviderConfiguration.class) + .run((context) -> { + assertThat(context).hasSingleBean(CustomMicrometerJerseyTagsProvider.class); + ResourceConfig config = new ResourceConfig(); + context.getBean(ResourceConfigCustomizer.class).customize(config); + Set instances = config.getInstances(); + assertThat(instances).hasSize(1) + .first(InstanceOfAssertFactories.type(MetricsApplicationEventListener.class)) + .satisfies((listener) -> assertThat(listener).extracting("tagsProvider") + .isInstanceOf(JerseyTagsProviderAdapter.class)); + }); + } + @Test void httpRequestsAreTimed() { this.webContextRunner.run((context) -> { @@ -161,4 +180,31 @@ class JerseyServerMetricsAutoConfigurationTests { } + @SuppressWarnings("deprecation") + @Configuration(proxyBeanMethods = false) + static class CustomMicrometerJerseyTagsProviderConfiguration { + + @Bean + io.micrometer.core.instrument.binder.jersey.server.JerseyTagsProvider customJerseyTagsProvider() { + return new CustomMicrometerJerseyTagsProvider(); + } + + } + + @SuppressWarnings("deprecation") + static class CustomMicrometerJerseyTagsProvider + implements io.micrometer.core.instrument.binder.jersey.server.JerseyTagsProvider { + + @Override + public Iterable httpRequestTags(RequestEvent event) { + return null; + } + + @Override + public Iterable httpLongRequestTags(RequestEvent event) { + return null; + } + + } + }