Skip to content

Commit 7875732

Browse files
committed
Auto-configure Jersey2 server instrumentation
Relates to gh-12447 and micrometer-metrics/micrometer#486
1 parent 3ae4a54 commit 7875732

File tree

8 files changed

+291
-1
lines changed

8 files changed

+291
-1
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@
9292
<artifactId>micrometer-core</artifactId>
9393
<optional>true</optional>
9494
</dependency>
95+
<dependency>
96+
<groupId>io.micrometer</groupId>
97+
<artifactId>micrometer-jersey2</artifactId>
98+
<optional>true</optional>
99+
</dependency>
95100
<dependency>
96101
<groupId>io.micrometer</groupId>
97102
<artifactId>micrometer-registry-atlas</artifactId>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.metrics.jersey2.server;
18+
19+
import java.lang.annotation.Annotation;
20+
import java.lang.reflect.AnnotatedElement;
21+
22+
import io.micrometer.core.instrument.MeterRegistry;
23+
import io.micrometer.jersey2.server.AnnotationFinder;
24+
import io.micrometer.jersey2.server.DefaultJerseyTagsProvider;
25+
import io.micrometer.jersey2.server.JerseyTagsProvider;
26+
import io.micrometer.jersey2.server.MetricsApplicationEventListener;
27+
import org.glassfish.jersey.server.ResourceConfig;
28+
29+
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
30+
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
31+
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
32+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
33+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
34+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
35+
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
36+
import org.springframework.boot.autoconfigure.jersey.ResourceConfigCustomizer;
37+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
38+
import org.springframework.context.annotation.Bean;
39+
import org.springframework.context.annotation.Configuration;
40+
import org.springframework.core.annotation.AnnotationUtils;
41+
42+
/**
43+
* Auto-configuration for Jersey server instrumentation.
44+
*
45+
* @author Michael Weirauch
46+
* @since 2.0.1
47+
*/
48+
@Configuration
49+
@AutoConfigureAfter({ MetricsAutoConfiguration.class,
50+
SimpleMetricsExportAutoConfiguration.class })
51+
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
52+
@ConditionalOnClass({ ResourceConfig.class, MetricsApplicationEventListener.class })
53+
@ConditionalOnBean(MeterRegistry.class)
54+
@EnableConfigurationProperties(JerseyServerMetricsProperties.class)
55+
public class JerseyServerMetricsAutoConfiguration {
56+
57+
@Bean
58+
@ConditionalOnMissingBean(JerseyTagsProvider.class)
59+
public DefaultJerseyTagsProvider jerseyTagsProvider() {
60+
return new DefaultJerseyTagsProvider();
61+
}
62+
63+
@Bean
64+
public ResourceConfigCustomizer jerseyResourceConfigCustomizer(
65+
MeterRegistry meterRegistry, JerseyServerMetricsProperties properties,
66+
JerseyTagsProvider tagsProvider) {
67+
return (config) -> config.register(new MetricsApplicationEventListener(
68+
meterRegistry, tagsProvider, properties.getRequestsMetricName(),
69+
properties.isAutoTimeRequests(), new AnnotationFinder() {
70+
@Override
71+
public <A extends Annotation> A findAnnotation(
72+
AnnotatedElement annotatedElement, Class<A> annotationType) {
73+
return AnnotationUtils.findAnnotation(annotatedElement,
74+
annotationType);
75+
}
76+
}));
77+
}
78+
79+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.metrics.jersey2.server;
18+
19+
import org.springframework.boot.context.properties.ConfigurationProperties;
20+
21+
/**
22+
* Configuration for Jersey server instrumentation.
23+
*
24+
* @author Michael Weirauch
25+
* @since 2.0.1
26+
*/
27+
@ConfigurationProperties(prefix = "management.metrics.jersey2.server")
28+
public class JerseyServerMetricsProperties {
29+
30+
private String requestsMetricName = "http.server.requests";
31+
32+
private boolean autoTimeRequests = true;
33+
34+
public String getRequestsMetricName() {
35+
return this.requestsMetricName;
36+
}
37+
38+
public void setRequestsMetricName(String requestsMetricName) {
39+
this.requestsMetricName = requestsMetricName;
40+
}
41+
42+
public boolean isAutoTimeRequests() {
43+
return this.autoTimeRequests;
44+
}
45+
46+
public void setAutoTimeRequests(boolean autoTimeRequests) {
47+
this.autoTimeRequests = autoTimeRequests;
48+
}
49+
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
/**
18+
* Auto-configuration for Jersey server actuator metrics.
19+
*/
20+
package org.springframework.boot.actuate.autoconfigure.metrics.jersey2.server;

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ org.springframework.boot.actuate.autoconfigure.metrics.export.signalfx.SignalFxM
4949
org.springframework.boot.actuate.autoconfigure.metrics.export.statsd.StatsdMetricsExportAutoConfiguration,\
5050
org.springframework.boot.actuate.autoconfigure.metrics.export.wavefront.WavefrontMetricsExportAutoConfiguration,\
5151
org.springframework.boot.actuate.autoconfigure.metrics.jdbc.DataSourcePoolMetricsAutoConfiguration,\
52+
org.springframework.boot.actuate.autoconfigure.metrics.jersey2.server.JerseyServerMetricsAutoConfiguration,\
5253
org.springframework.boot.actuate.autoconfigure.metrics.web.client.RestTemplateMetricsAutoConfiguration,\
5354
org.springframework.boot.actuate.autoconfigure.metrics.web.reactive.WebFluxMetricsAutoConfiguration,\
5455
org.springframework.boot.actuate.autoconfigure.metrics.web.servlet.WebMvcMetricsAutoConfiguration,\
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.metrics.jersey2.server;
18+
19+
import java.net.URI;
20+
21+
import javax.ws.rs.ApplicationPath;
22+
import javax.ws.rs.GET;
23+
import javax.ws.rs.Path;
24+
import javax.ws.rs.PathParam;
25+
26+
import io.micrometer.core.instrument.MeterRegistry;
27+
import io.micrometer.core.instrument.Timer;
28+
import io.micrometer.jersey2.server.MetricsApplicationEventListener;
29+
import org.glassfish.jersey.server.ResourceConfig;
30+
import org.junit.Test;
31+
32+
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
33+
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
34+
import org.springframework.boot.autoconfigure.AutoConfigurations;
35+
import org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration;
36+
import org.springframework.boot.autoconfigure.jersey.ResourceConfigCustomizer;
37+
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
38+
import org.springframework.boot.test.context.FilteredClassLoader;
39+
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
40+
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
41+
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
42+
import org.springframework.context.annotation.Bean;
43+
import org.springframework.context.annotation.Configuration;
44+
import org.springframework.web.client.RestTemplate;
45+
46+
import static org.assertj.core.api.Assertions.assertThat;
47+
48+
/**
49+
* Tests for {@link JerseyServerMetricsAutoConfiguration}.
50+
*
51+
* @author Michael Weirauch
52+
*/
53+
public class JerseyServerMetricsAutoConfigurationTests {
54+
55+
private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner(
56+
AnnotationConfigServletWebServerApplicationContext::new)
57+
.withConfiguration(
58+
AutoConfigurations.of(JerseyAutoConfiguration.class,
59+
JerseyServerMetricsAutoConfiguration.class,
60+
ServletWebServerFactoryAutoConfiguration.class,
61+
SimpleMetricsExportAutoConfiguration.class,
62+
MetricsAutoConfiguration.class))
63+
.withUserConfiguration(ResourceConfiguration.class)
64+
.withPropertyValues("server.port:0");
65+
66+
@Test
67+
public void httpRequestsAreTimed() {
68+
this.contextRunner.run((context) -> {
69+
doRequest(context);
70+
71+
MeterRegistry registry = context.getBean(MeterRegistry.class);
72+
Timer timer = registry.get("http.server.requests").tag("uri", "/users/{id}")
73+
.timer();
74+
assertThat(timer.count()).isEqualTo(1);
75+
});
76+
}
77+
78+
@Test
79+
public void noHttpRequestsTimedWhenJerseyInstrumentationMissingFromClasspath() {
80+
this.contextRunner
81+
.withClassLoader(
82+
new FilteredClassLoader(MetricsApplicationEventListener.class))
83+
.run((context) -> {
84+
doRequest(context);
85+
86+
MeterRegistry registry = context.getBean(MeterRegistry.class);
87+
assertThat(registry.find("http.server.requests").timer()).isNull();
88+
});
89+
}
90+
91+
private static void doRequest(AssertableWebApplicationContext context) {
92+
int port = context
93+
.getSourceApplicationContext(
94+
AnnotationConfigServletWebServerApplicationContext.class)
95+
.getWebServer().getPort();
96+
RestTemplate restTemplate = new RestTemplate();
97+
restTemplate.getForEntity(URI.create("http://localhost:" + port + "/users/3"),
98+
String.class);
99+
}
100+
101+
@Configuration
102+
@ApplicationPath("/")
103+
static class ResourceConfiguration {
104+
105+
@Bean
106+
ResourceConfig resourceConfig() {
107+
return new ResourceConfig();
108+
}
109+
110+
@Bean
111+
ResourceConfigCustomizer resourceConfigCustomizer() {
112+
return (config) -> config.register(new TestResource());
113+
}
114+
115+
@Path("/users")
116+
public class TestResource {
117+
118+
@GET
119+
@Path("/{id}")
120+
public String getUser(@PathParam("id") String id) {
121+
return id;
122+
}
123+
124+
}
125+
126+
}
127+
128+
}

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
3838
import org.springframework.boot.actuate.autoconfigure.metrics.export.statsd.StatsdMetricsExportAutoConfiguration;
3939
import org.springframework.boot.actuate.autoconfigure.metrics.jdbc.DataSourcePoolMetricsAutoConfiguration;
40+
import org.springframework.boot.actuate.autoconfigure.metrics.jersey2.server.JerseyServerMetricsAutoConfiguration;
4041
import org.springframework.boot.actuate.autoconfigure.metrics.web.client.RestTemplateMetricsAutoConfiguration;
4142
import org.springframework.boot.actuate.autoconfigure.metrics.web.reactive.WebFluxMetricsAutoConfiguration;
4243
import org.springframework.boot.actuate.autoconfigure.metrics.web.servlet.WebMvcMetricsAutoConfiguration;
@@ -76,7 +77,8 @@ public final class MetricsRun {
7677
RabbitMetricsAutoConfiguration.class, CacheMetricsAutoConfiguration.class,
7778
DataSourcePoolMetricsAutoConfiguration.class,
7879
RestTemplateMetricsAutoConfiguration.class,
79-
WebFluxMetricsAutoConfiguration.class, WebMvcMetricsAutoConfiguration.class);
80+
WebFluxMetricsAutoConfiguration.class, WebMvcMetricsAutoConfiguration.class,
81+
JerseyServerMetricsAutoConfiguration.class);
8082

8183
private MetricsRun() {
8284
}

spring-boot-project/spring-boot-dependencies/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -860,6 +860,11 @@
860860
<artifactId>micrometer-core</artifactId>
861861
<version>${micrometer.version}</version>
862862
</dependency>
863+
<dependency>
864+
<groupId>io.micrometer</groupId>
865+
<artifactId>micrometer-jersey2</artifactId>
866+
<version>${micrometer.version}</version>
867+
</dependency>
863868
<dependency>
864869
<groupId>io.micrometer</groupId>
865870
<artifactId>micrometer-registry-atlas</artifactId>

0 commit comments

Comments
 (0)