Skip to content

Commit 3a565e4

Browse files
committed
Use Jersey's ObservationRequestEventListener for Jersey observability
Closes gh-39633
1 parent 7e43d7b commit 3a565e4

File tree

3 files changed

+19
-153
lines changed

3 files changed

+19
-153
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/jersey/JerseyServerMetricsAutoConfiguration.java

+13-67
Original file line numberDiff line numberDiff line change
@@ -16,35 +16,25 @@
1616

1717
package org.springframework.boot.actuate.autoconfigure.metrics.jersey;
1818

19-
import java.lang.annotation.Annotation;
20-
import java.lang.reflect.AnnotatedElement;
21-
22-
import io.micrometer.core.instrument.MeterRegistry;
23-
import io.micrometer.core.instrument.Tag;
2419
import io.micrometer.core.instrument.config.MeterFilter;
25-
import org.glassfish.jersey.micrometer.server.AnnotationFinder;
26-
import org.glassfish.jersey.micrometer.server.DefaultJerseyTagsProvider;
27-
import org.glassfish.jersey.micrometer.server.JerseyTagsProvider;
28-
import org.glassfish.jersey.micrometer.server.MetricsApplicationEventListener;
20+
import io.micrometer.observation.ObservationRegistry;
21+
import org.glassfish.jersey.micrometer.server.JerseyObservationConvention;
22+
import org.glassfish.jersey.micrometer.server.ObservationApplicationEventListener;
2923
import org.glassfish.jersey.server.ResourceConfig;
30-
import org.glassfish.jersey.server.monitoring.RequestEvent;
3124

3225
import org.springframework.beans.factory.ObjectProvider;
33-
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
3426
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties;
3527
import org.springframework.boot.actuate.autoconfigure.metrics.OnlyOnceLoggingDenyMeterFilter;
36-
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
28+
import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration;
3729
import org.springframework.boot.actuate.autoconfigure.observation.ObservationProperties;
3830
import org.springframework.boot.autoconfigure.AutoConfiguration;
3931
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
4032
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
4133
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
42-
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
4334
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
4435
import org.springframework.boot.autoconfigure.jersey.ResourceConfigCustomizer;
4536
import org.springframework.boot.context.properties.EnableConfigurationProperties;
4637
import org.springframework.context.annotation.Bean;
47-
import org.springframework.core.annotation.AnnotationUtils;
4838
import org.springframework.core.annotation.Order;
4939

5040
/**
@@ -53,13 +43,14 @@
5343
* @author Michael Weirauch
5444
* @author Michael Simons
5545
* @author Andy Wilkinson
46+
* @author Moritz Halbritter
5647
* @since 2.1.0
5748
*/
58-
@AutoConfiguration(after = { MetricsAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class })
49+
@AutoConfiguration(after = { ObservationAutoConfiguration.class })
5950
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
60-
@ConditionalOnClass({ ResourceConfig.class, MetricsApplicationEventListener.class })
61-
@ConditionalOnBean({ MeterRegistry.class, ResourceConfig.class })
62-
@EnableConfigurationProperties(MetricsProperties.class)
51+
@ConditionalOnClass({ ResourceConfig.class, ObservationApplicationEventListener.class })
52+
@ConditionalOnBean({ ResourceConfig.class, ObservationRegistry.class })
53+
@EnableConfigurationProperties({ MetricsProperties.class, ObservationProperties.class })
6354
public class JerseyServerMetricsAutoConfiguration {
6455

6556
private final ObservationProperties observationProperties;
@@ -69,22 +60,11 @@ public JerseyServerMetricsAutoConfiguration(ObservationProperties observationPro
6960
}
7061

7162
@Bean
72-
@SuppressWarnings("deprecation")
73-
@ConditionalOnMissingBean({ JerseyTagsProvider.class,
74-
io.micrometer.core.instrument.binder.jersey.server.JerseyTagsProvider.class })
75-
public DefaultJerseyTagsProvider jerseyTagsProvider() {
76-
return new DefaultJerseyTagsProvider();
77-
}
78-
79-
@Bean
80-
@SuppressWarnings("deprecation")
81-
public ResourceConfigCustomizer jerseyServerMetricsResourceConfigCustomizer(MeterRegistry meterRegistry,
82-
ObjectProvider<JerseyTagsProvider> tagsProvider,
83-
ObjectProvider<io.micrometer.core.instrument.binder.jersey.server.JerseyTagsProvider> micrometerTagsProvider) {
63+
ResourceConfigCustomizer jerseyServerObservationResourceConfigCustomizer(ObservationRegistry observationRegistry,
64+
ObjectProvider<JerseyObservationConvention> jerseyObservationConvention) {
8465
String metricName = this.observationProperties.getHttp().getServer().getRequests().getName();
85-
return (config) -> config.register(new MetricsApplicationEventListener(meterRegistry,
86-
tagsProvider.getIfAvailable(() -> new JerseyTagsProviderAdapter(micrometerTagsProvider.getObject())),
87-
metricName, true, new AnnotationUtilsAnnotationFinder()));
66+
return (config) -> config.register(new ObservationApplicationEventListener(observationRegistry, metricName,
67+
jerseyObservationConvention.getIfAvailable()));
8868
}
8969

9070
@Bean
@@ -97,38 +77,4 @@ public MeterFilter jerseyMetricsUriTagFilter(MetricsProperties metricsProperties
9777
metricsProperties.getWeb().getServer().getMaxUriTags(), filter);
9878
}
9979

100-
/**
101-
* An {@link AnnotationFinder} that uses {@link AnnotationUtils}.
102-
*/
103-
private static final class AnnotationUtilsAnnotationFinder implements AnnotationFinder {
104-
105-
@Override
106-
public <A extends Annotation> A findAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType) {
107-
return AnnotationUtils.findAnnotation(annotatedElement, annotationType);
108-
}
109-
110-
}
111-
112-
@SuppressWarnings("deprecation")
113-
static final class JerseyTagsProviderAdapter implements JerseyTagsProvider {
114-
115-
private final io.micrometer.core.instrument.binder.jersey.server.JerseyTagsProvider delegate;
116-
117-
private JerseyTagsProviderAdapter(
118-
io.micrometer.core.instrument.binder.jersey.server.JerseyTagsProvider delegate) {
119-
this.delegate = delegate;
120-
}
121-
122-
@Override
123-
public Iterable<Tag> httpRequestTags(RequestEvent event) {
124-
return this.delegate.httpRequestTags(event);
125-
}
126-
127-
@Override
128-
public Iterable<Tag> httpLongRequestTags(RequestEvent event) {
129-
return this.delegate.httpLongRequestTags(event);
130-
}
131-
132-
}
133-
13480
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/jersey/JerseyServerMetricsAutoConfigurationTests.java

+5-85
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,18 @@
1717
package org.springframework.boot.actuate.autoconfigure.metrics.jersey;
1818

1919
import java.net.URI;
20-
import java.util.Set;
2120

2221
import io.micrometer.core.instrument.MeterRegistry;
23-
import io.micrometer.core.instrument.Tag;
2422
import io.micrometer.core.instrument.Timer;
2523
import jakarta.ws.rs.GET;
2624
import jakarta.ws.rs.Path;
2725
import jakarta.ws.rs.PathParam;
28-
import org.assertj.core.api.InstanceOfAssertFactories;
29-
import org.glassfish.jersey.micrometer.server.DefaultJerseyTagsProvider;
30-
import org.glassfish.jersey.micrometer.server.JerseyTagsProvider;
31-
import org.glassfish.jersey.micrometer.server.MetricsApplicationEventListener;
26+
import org.glassfish.jersey.micrometer.server.ObservationApplicationEventListener;
3227
import org.glassfish.jersey.server.ResourceConfig;
33-
import org.glassfish.jersey.server.monitoring.RequestEvent;
3428
import org.junit.jupiter.api.Test;
3529

3630
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
3731
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
38-
import org.springframework.boot.actuate.autoconfigure.metrics.jersey.JerseyServerMetricsAutoConfiguration.JerseyTagsProviderAdapter;
3932
import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun;
4033
import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration;
4134
import org.springframework.boot.autoconfigure.AutoConfigurations;
@@ -58,6 +51,7 @@
5851
*
5952
* @author Michael Weirauch
6053
* @author Michael Simons
54+
* @author Moritz Halbritter
6155
*/
6256
class JerseyServerMetricsAutoConfigurationTests {
6357

@@ -80,32 +74,10 @@ void shouldOnlyBeActiveInWebApplicationContext() {
8074

8175
@Test
8276
void shouldProvideAllNecessaryBeans() {
83-
this.webContextRunner.run((context) -> assertThat(context).hasSingleBean(DefaultJerseyTagsProvider.class)
77+
this.webContextRunner.run((context) -> assertThat(context).hasBean("jerseyMetricsUriTagFilter")
8478
.hasSingleBean(ResourceConfigCustomizer.class));
8579
}
8680

87-
@Test
88-
void shouldHonorExistingTagProvider() {
89-
this.webContextRunner.withUserConfiguration(CustomJerseyTagsProviderConfiguration.class)
90-
.run((context) -> assertThat(context).hasSingleBean(CustomJerseyTagsProvider.class));
91-
}
92-
93-
@Test
94-
@Deprecated(since = "3.3.0", forRemoval = true)
95-
void shouldHonorExistingMicrometerTagProvider() {
96-
this.webContextRunner.withUserConfiguration(CustomMicrometerJerseyTagsProviderConfiguration.class)
97-
.run((context) -> {
98-
assertThat(context).hasSingleBean(CustomMicrometerJerseyTagsProvider.class);
99-
ResourceConfig config = new ResourceConfig();
100-
context.getBean(ResourceConfigCustomizer.class).customize(config);
101-
Set<Object> instances = config.getInstances();
102-
assertThat(instances).hasSize(1)
103-
.first(InstanceOfAssertFactories.type(MetricsApplicationEventListener.class))
104-
.satisfies((listener) -> assertThat(listener).extracting("tagsProvider")
105-
.isInstanceOf(JerseyTagsProviderAdapter.class));
106-
});
107-
}
108-
10981
@Test
11082
void httpRequestsAreTimed() {
11183
this.webContextRunner.run((context) -> {
@@ -118,10 +90,9 @@ void httpRequestsAreTimed() {
11890

11991
@Test
12092
void noHttpRequestsTimedWhenJerseyInstrumentationMissingFromClasspath() {
121-
this.webContextRunner.withClassLoader(new FilteredClassLoader(MetricsApplicationEventListener.class))
93+
this.webContextRunner.withClassLoader(new FilteredClassLoader(ObservationApplicationEventListener.class))
12294
.run((context) -> {
12395
doRequest(context);
124-
12596
MeterRegistry registry = context.getBean(MeterRegistry.class);
12697
assertThat(registry.find("http.server.requests").timer()).isNull();
12798
});
@@ -144,7 +115,7 @@ ResourceConfig resourceConfig() {
144115
}
145116

146117
@Path("/users")
147-
public class TestResource {
118+
public static class TestResource {
148119

149120
@GET
150121
@Path("/{id}")
@@ -156,55 +127,4 @@ public String getUser(@PathParam("id") String id) {
156127

157128
}
158129

159-
@Configuration(proxyBeanMethods = false)
160-
static class CustomJerseyTagsProviderConfiguration {
161-
162-
@Bean
163-
JerseyTagsProvider customJerseyTagsProvider() {
164-
return new CustomJerseyTagsProvider();
165-
}
166-
167-
}
168-
169-
static class CustomJerseyTagsProvider implements JerseyTagsProvider {
170-
171-
@Override
172-
public Iterable<Tag> httpRequestTags(RequestEvent event) {
173-
return null;
174-
}
175-
176-
@Override
177-
public Iterable<Tag> httpLongRequestTags(RequestEvent event) {
178-
return null;
179-
}
180-
181-
}
182-
183-
@SuppressWarnings("deprecation")
184-
@Configuration(proxyBeanMethods = false)
185-
static class CustomMicrometerJerseyTagsProviderConfiguration {
186-
187-
@Bean
188-
io.micrometer.core.instrument.binder.jersey.server.JerseyTagsProvider customJerseyTagsProvider() {
189-
return new CustomMicrometerJerseyTagsProvider();
190-
}
191-
192-
}
193-
194-
@SuppressWarnings("deprecation")
195-
static class CustomMicrometerJerseyTagsProvider
196-
implements io.micrometer.core.instrument.binder.jersey.server.JerseyTagsProvider {
197-
198-
@Override
199-
public Iterable<Tag> httpRequestTags(RequestEvent event) {
200-
return null;
201-
}
202-
203-
@Override
204-
public Iterable<Tag> httpLongRequestTags(RequestEvent event) {
205-
return null;
206-
}
207-
208-
}
209-
210130
}

spring-boot-project/spring-boot-docs/src/docs/asciidoc/actuator/metrics.adoc

+1-1
Original file line numberDiff line numberDiff line change
@@ -815,7 +815,7 @@ By default, Jersey server metrics are tagged with the following information:
815815
| The request's URI template prior to variable substitution, if possible (for example, `/api/person/\{id}`)
816816
|===
817817

818-
To customize the tags, provide a `@Bean` that implements `JerseyTagsProvider`.
818+
To customize the tags, provide a `@Bean` that implements `JerseyObservationConvention`.
819819

820820

821821

0 commit comments

Comments
 (0)