Use Jersey's ObservationRequestEventListener for Jersey observability
Closes gh-39633
This commit is contained in:
@@ -16,35 +16,25 @@
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.metrics.jersey;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
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 io.micrometer.observation.ObservationRegistry;
|
||||
import org.glassfish.jersey.micrometer.server.JerseyObservationConvention;
|
||||
import org.glassfish.jersey.micrometer.server.ObservationApplicationEventListener;
|
||||
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;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.observation.ObservationProperties;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
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.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.jersey.ResourceConfigCustomizer;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
/**
|
||||
@@ -53,13 +43,14 @@ import org.springframework.core.annotation.Order;
|
||||
* @author Michael Weirauch
|
||||
* @author Michael Simons
|
||||
* @author Andy Wilkinson
|
||||
* @author Moritz Halbritter
|
||||
* @since 2.1.0
|
||||
*/
|
||||
@AutoConfiguration(after = { MetricsAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class })
|
||||
@AutoConfiguration(after = { ObservationAutoConfiguration.class })
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
|
||||
@ConditionalOnClass({ ResourceConfig.class, MetricsApplicationEventListener.class })
|
||||
@ConditionalOnBean({ MeterRegistry.class, ResourceConfig.class })
|
||||
@EnableConfigurationProperties(MetricsProperties.class)
|
||||
@ConditionalOnClass({ ResourceConfig.class, ObservationApplicationEventListener.class })
|
||||
@ConditionalOnBean({ ResourceConfig.class, ObservationRegistry.class })
|
||||
@EnableConfigurationProperties({ MetricsProperties.class, ObservationProperties.class })
|
||||
public class JerseyServerMetricsAutoConfiguration {
|
||||
|
||||
private final ObservationProperties observationProperties;
|
||||
@@ -69,22 +60,11 @@ public class JerseyServerMetricsAutoConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
@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,
|
||||
ObjectProvider<JerseyTagsProvider> tagsProvider,
|
||||
ObjectProvider<io.micrometer.core.instrument.binder.jersey.server.JerseyTagsProvider> micrometerTagsProvider) {
|
||||
ResourceConfigCustomizer jerseyServerObservationResourceConfigCustomizer(ObservationRegistry observationRegistry,
|
||||
ObjectProvider<JerseyObservationConvention> jerseyObservationConvention) {
|
||||
String metricName = this.observationProperties.getHttp().getServer().getRequests().getName();
|
||||
return (config) -> config.register(new MetricsApplicationEventListener(meterRegistry,
|
||||
tagsProvider.getIfAvailable(() -> new JerseyTagsProviderAdapter(micrometerTagsProvider.getObject())),
|
||||
metricName, true, new AnnotationUtilsAnnotationFinder()));
|
||||
return (config) -> config.register(new ObservationApplicationEventListener(observationRegistry, metricName,
|
||||
jerseyObservationConvention.getIfAvailable()));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -97,38 +77,4 @@ public class JerseyServerMetricsAutoConfiguration {
|
||||
metricsProperties.getWeb().getServer().getMaxUriTags(), filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link AnnotationFinder} that uses {@link AnnotationUtils}.
|
||||
*/
|
||||
private static final class AnnotationUtilsAnnotationFinder implements AnnotationFinder {
|
||||
|
||||
@Override
|
||||
public <A extends Annotation> A findAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType) {
|
||||
return AnnotationUtils.findAnnotation(annotatedElement, annotationType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@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<Tag> httpRequestTags(RequestEvent event) {
|
||||
return this.delegate.httpRequestTags(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Tag> httpLongRequestTags(RequestEvent event) {
|
||||
return this.delegate.httpLongRequestTags(event);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,25 +17,18 @@
|
||||
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 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.micrometer.server.ObservationApplicationEventListener;
|
||||
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;
|
||||
@@ -58,6 +51,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*
|
||||
* @author Michael Weirauch
|
||||
* @author Michael Simons
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
class JerseyServerMetricsAutoConfigurationTests {
|
||||
|
||||
@@ -80,32 +74,10 @@ class JerseyServerMetricsAutoConfigurationTests {
|
||||
|
||||
@Test
|
||||
void shouldProvideAllNecessaryBeans() {
|
||||
this.webContextRunner.run((context) -> assertThat(context).hasSingleBean(DefaultJerseyTagsProvider.class)
|
||||
this.webContextRunner.run((context) -> assertThat(context).hasBean("jerseyMetricsUriTagFilter")
|
||||
.hasSingleBean(ResourceConfigCustomizer.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHonorExistingTagProvider() {
|
||||
this.webContextRunner.withUserConfiguration(CustomJerseyTagsProviderConfiguration.class)
|
||||
.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<Object> 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) -> {
|
||||
@@ -118,10 +90,9 @@ class JerseyServerMetricsAutoConfigurationTests {
|
||||
|
||||
@Test
|
||||
void noHttpRequestsTimedWhenJerseyInstrumentationMissingFromClasspath() {
|
||||
this.webContextRunner.withClassLoader(new FilteredClassLoader(MetricsApplicationEventListener.class))
|
||||
this.webContextRunner.withClassLoader(new FilteredClassLoader(ObservationApplicationEventListener.class))
|
||||
.run((context) -> {
|
||||
doRequest(context);
|
||||
|
||||
MeterRegistry registry = context.getBean(MeterRegistry.class);
|
||||
assertThat(registry.find("http.server.requests").timer()).isNull();
|
||||
});
|
||||
@@ -144,7 +115,7 @@ class JerseyServerMetricsAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Path("/users")
|
||||
public class TestResource {
|
||||
public static class TestResource {
|
||||
|
||||
@GET
|
||||
@Path("/{id}")
|
||||
@@ -156,55 +127,4 @@ class JerseyServerMetricsAutoConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class CustomJerseyTagsProviderConfiguration {
|
||||
|
||||
@Bean
|
||||
JerseyTagsProvider customJerseyTagsProvider() {
|
||||
return new CustomJerseyTagsProvider();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class CustomJerseyTagsProvider implements JerseyTagsProvider {
|
||||
|
||||
@Override
|
||||
public Iterable<Tag> httpRequestTags(RequestEvent event) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Tag> httpLongRequestTags(RequestEvent event) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@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<Tag> httpRequestTags(RequestEvent event) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Tag> httpLongRequestTags(RequestEvent event) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -815,7 +815,7 @@ By default, Jersey server metrics are tagged with the following information:
|
||||
| The request's URI template prior to variable substitution, if possible (for example, `/api/person/\{id}`)
|
||||
|===
|
||||
|
||||
To customize the tags, provide a `@Bean` that implements `JerseyTagsProvider`.
|
||||
To customize the tags, provide a `@Bean` that implements `JerseyObservationConvention`.
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user