You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by re...@apache.org on 2020/11/01 15:44:15 UTC
[cxf] 01/02: CXF-8252: Add Micrometer metric support for JAX-RS
(Spring Boot) (#716)
This is an automated email from the ASF dual-hosted git repository.
reta pushed a commit to branch 3.3.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git
commit e225ae38db06bc5778d22f2de063780073f67875
Author: Andriy Redko <dr...@gmail.com>
AuthorDate: Sun Nov 1 09:12:31 2020 -0500
CXF-8252: Add Micrometer metric support for JAX-RS (Spring Boot) (#716)
(cherry picked from commit 595cc425ed3fbd729635d59d8e7fccf18334542d)
---
.../main/release/samples/jax_rs/spring_boot/README | 8 +-
.../release/samples/jax_rs/spring_boot/pom.xml | 13 ++
.../sample/rs/service/SampleRestApplication.java | 11 +-
.../src/main/resources/application.properties | 3 +
integration/spring-boot/autoconfigure/pom.xml | 6 +
.../spring/boot/autoconfigure/CxfProperties.java | 15 +-
.../MicrometerMetricsAutoConfiguration.java | 85 ++++++----
.../SpringBasedTimedAnnotationProvider.java | 38 ++++-
.../MicrometerMetricsAutoConfigurationTest.java | 91 +++++++++++
.../micrometer/MicrometerMetricsProperties.java | 10 +-
.../micrometer/MicrometerMetricsProvider.java | 19 ++-
.../provider/DefaultTimedAnnotationProvider.java | 32 ++--
.../metrics/micrometer/provider/StandardTags.java | 2 +-
.../jaxrs/JaxrsOperationTagsCustomizer.java | 43 +++++
.../micrometer/provider/jaxrs/JaxrsTags.java | 44 +++++
.../micrometer/MicrometerMetricsProviderTest.java | 30 +++-
.../DefaultExceptionClassProviderTest.java | 6 +-
.../DefaultTimedAnnotationProviderTest.java | 9 +-
.../provider/StandardTagsProviderTest.java | 4 +-
.../micrometer/provider/StandardTagsTest.java | 7 +-
.../jaxrs/JaxrsOperationTagsCustomizerTest.java | 73 +++++++++
.../micrometer/provider/jaxrs/JaxrsTagsTest.java | 65 ++++++++
.../cxf/systest/jaxrs/resources/Library.java | 6 +
.../systest/jaxrs/spring/boot/SpringJaxrsTest.java | 181 +++++++++++++++++++++
.../src/test/resources/application-jaxrs.yml | 7 +
.../src/test/resources/application-jaxws.yml | 5 +-
26 files changed, 734 insertions(+), 79 deletions(-)
diff --git a/distribution/src/main/release/samples/jax_rs/spring_boot/README b/distribution/src/main/release/samples/jax_rs/spring_boot/README
index 164955b..b9f3d73 100644
--- a/distribution/src/main/release/samples/jax_rs/spring_boot/README
+++ b/distribution/src/main/release/samples/jax_rs/spring_boot/README
@@ -1,7 +1,8 @@
== Spring Boot - Samples - CXF Rest Web Services
This sample project demonstrates how to use CXF JAX-RS services
-with Spring Boot. This demo has two JAX-RS class resources being deployed in a single JAX-RS endpoint.
+with Spring Boot and Spring Actuator. This demo has two JAX-RS class resources being deployed
+in a single JAX-RS endpoint.
= Starting the server =
@@ -60,6 +61,11 @@ or access it from the CXF Services page:
http://localhost:8080/services/helloservice/services
and follow a Swagger link.
+To view the exposed metrics:
+ http://localhost:8080/actuator/metrics
+
+The Apache CXF specific metrics are available under:
+ http://localhost:8080/actuator/metrics/cxf.server.requests
---- From the command line ----
diff --git a/distribution/src/main/release/samples/jax_rs/spring_boot/pom.xml b/distribution/src/main/release/samples/jax_rs/spring_boot/pom.xml
index 5895749..03fa264 100644
--- a/distribution/src/main/release/samples/jax_rs/spring_boot/pom.xml
+++ b/distribution/src/main/release/samples/jax_rs/spring_boot/pom.xml
@@ -46,6 +46,19 @@
<version>${project.version}</version>
</dependency>
<dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-features-metrics</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.micrometer</groupId>
+ <artifactId>micrometer-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-actuator</artifactId>
+ </dependency>
+ <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
diff --git a/distribution/src/main/release/samples/jax_rs/spring_boot/src/main/java/sample/rs/service/SampleRestApplication.java b/distribution/src/main/release/samples/jax_rs/spring_boot/src/main/java/sample/rs/service/SampleRestApplication.java
index 6f1cef3..7ae97b0 100644
--- a/distribution/src/main/release/samples/jax_rs/spring_boot/src/main/java/sample/rs/service/SampleRestApplication.java
+++ b/distribution/src/main/release/samples/jax_rs/spring_boot/src/main/java/sample/rs/service/SampleRestApplication.java
@@ -25,6 +25,8 @@ import org.apache.cxf.ext.logging.LoggingFeature;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.apache.cxf.jaxrs.openapi.OpenApiFeature;
import org.apache.cxf.jaxrs.swagger.ui.SwaggerUiConfig;
+import org.apache.cxf.metrics.MetricsFeature;
+import org.apache.cxf.metrics.MetricsProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -37,6 +39,8 @@ import sample.rs.service.hello2.HelloServiceImpl2;
public class SampleRestApplication {
@Autowired
private Bus bus;
+ @Autowired
+ private MetricsProvider metricsProvider;
public static void main(String[] args) {
SpringApplication.run(SampleRestApplication.class, args);
@@ -48,7 +52,7 @@ public class SampleRestApplication {
endpoint.setBus(bus);
endpoint.setServiceBeans(Arrays.<Object>asList(new HelloServiceImpl1(), new HelloServiceImpl2()));
endpoint.setAddress("/");
- endpoint.setFeatures(Arrays.asList(createOpenApiFeature(), new LoggingFeature()));
+ endpoint.setFeatures(Arrays.asList(createOpenApiFeature(), metricsFeature(), new LoggingFeature()));
return endpoint.create();
}
@@ -67,4 +71,9 @@ public class SampleRestApplication {
.url("/services/helloservice/openapi.json"));
return openApiFeature;
}
+
+ @Bean
+ public MetricsFeature metricsFeature() {
+ return new MetricsFeature(metricsProvider);
+ }
}
diff --git a/distribution/src/main/release/samples/jax_rs/spring_boot/src/main/resources/application.properties b/distribution/src/main/release/samples/jax_rs/spring_boot/src/main/resources/application.properties
index d9993d1..ff5a5a2 100644
--- a/distribution/src/main/release/samples/jax_rs/spring_boot/src/main/resources/application.properties
+++ b/distribution/src/main/release/samples/jax_rs/spring_boot/src/main/resources/application.properties
@@ -2,3 +2,6 @@ cxf.path=/services/helloservice
cxf.jaxrs.client.address=http://localhost:8080/services/helloservice
cxf.jaxrs.client.headers.accept=text/plain
cxf.jaxrs.client.classes-scan-packages=sample.rs.service.api
+
+management.endpoint.metrics.enabled=true
+management.endpoints.web.exposure.include=*
diff --git a/integration/spring-boot/autoconfigure/pom.xml b/integration/spring-boot/autoconfigure/pom.xml
index 4d6d9d6..2b45f0c 100644
--- a/integration/spring-boot/autoconfigure/pom.xml
+++ b/integration/spring-boot/autoconfigure/pom.xml
@@ -170,5 +170,11 @@
<version>${cxf.hibernate.validator.version}</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.assertj</groupId>
+ <artifactId>assertj-core</artifactId>
+ <version>3.18.0</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
diff --git a/integration/spring-boot/autoconfigure/src/main/java/org/apache/cxf/spring/boot/autoconfigure/CxfProperties.java b/integration/spring-boot/autoconfigure/src/main/java/org/apache/cxf/spring/boot/autoconfigure/CxfProperties.java
index 0f53bd8..016851d 100644
--- a/integration/spring-boot/autoconfigure/src/main/java/org/apache/cxf/spring/boot/autoconfigure/CxfProperties.java
+++ b/integration/spring-boot/autoconfigure/src/main/java/org/apache/cxf/spring/boot/autoconfigure/CxfProperties.java
@@ -94,8 +94,12 @@ public class CxfProperties {
}
public static class Metrics {
-
private final Server server = new Server();
+
+ /**
+ * Enables or disables metrics instrumentation
+ */
+ private boolean enabled = true;
public Server getServer() {
return this.server;
@@ -145,6 +149,15 @@ public class CxfProperties {
this.maxUriTags = maxUriTags;
}
}
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
}
}
diff --git a/integration/spring-boot/autoconfigure/src/main/java/org/apache/cxf/spring/boot/autoconfigure/micrometer/MicrometerMetricsAutoConfiguration.java b/integration/spring-boot/autoconfigure/src/main/java/org/apache/cxf/spring/boot/autoconfigure/micrometer/MicrometerMetricsAutoConfiguration.java
index 86788a3..89aee36 100644
--- a/integration/spring-boot/autoconfigure/src/main/java/org/apache/cxf/spring/boot/autoconfigure/micrometer/MicrometerMetricsAutoConfiguration.java
+++ b/integration/spring-boot/autoconfigure/src/main/java/org/apache/cxf/spring/boot/autoconfigure/micrometer/MicrometerMetricsAutoConfiguration.java
@@ -21,6 +21,7 @@ package org.apache.cxf.spring.boot.autoconfigure.micrometer;
import java.util.List;
+import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
import org.apache.cxf.metrics.MetricsProvider;
import org.apache.cxf.metrics.micrometer.MicrometerMetricsProperties;
@@ -32,6 +33,8 @@ import org.apache.cxf.metrics.micrometer.provider.StandardTagsProvider;
import org.apache.cxf.metrics.micrometer.provider.TagsCustomizer;
import org.apache.cxf.metrics.micrometer.provider.TagsProvider;
import org.apache.cxf.metrics.micrometer.provider.TimedAnnotationProvider;
+import org.apache.cxf.metrics.micrometer.provider.jaxrs.JaxrsOperationTagsCustomizer;
+import org.apache.cxf.metrics.micrometer.provider.jaxrs.JaxrsTags;
import org.apache.cxf.metrics.micrometer.provider.jaxws.JaxwsFaultCodeProvider;
import org.apache.cxf.metrics.micrometer.provider.jaxws.JaxwsFaultCodeTagsCustomizer;
import org.apache.cxf.metrics.micrometer.provider.jaxws.JaxwsOperationTagsCustomizer;
@@ -46,8 +49,8 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter;
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.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
@@ -58,11 +61,10 @@ import io.micrometer.core.instrument.config.MeterFilter;
@Configuration
@AutoConfigureAfter({MetricsAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class})
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
-@ConditionalOnClass({JaxWsServerFactoryBean.class, MetricsProvider.class})
-@ConditionalOnBean({MeterRegistry.class})
-@EnableConfigurationProperties(CxfProperties.class)
+@ConditionalOnClass(MetricsProvider.class)
+@ConditionalOnProperty(name = "cxf.metrics.enabled", matchIfMissing = true)
+@ConditionalOnBean(MeterRegistry.class)
public class MicrometerMetricsAutoConfiguration {
-
private final CxfProperties properties;
public MicrometerMetricsAutoConfiguration(CxfProperties properties) {
@@ -75,36 +77,12 @@ public class MicrometerMetricsAutoConfiguration {
}
@Bean
- public JaxwsTags jaxwsTags() {
- return new JaxwsTags();
- }
-
- @Bean
@ConditionalOnMissingBean(ExceptionClassProvider.class)
public ExceptionClassProvider exceptionClassProvider() {
return new DefaultExceptionClassProvider();
}
@Bean
- @ConditionalOnMissingBean(JaxwsFaultCodeProvider.class)
- public JaxwsFaultCodeProvider jaxwsFaultCodeProvider() {
- return new JaxwsFaultCodeProvider();
- }
-
- @Bean
- @ConditionalOnMissingBean(JaxwsFaultCodeTagsCustomizer.class)
- public JaxwsFaultCodeTagsCustomizer jaxwsFaultCodeTagsCustomizer(JaxwsTags jaxwsTags,
- JaxwsFaultCodeProvider jaxwsFaultCodeProvider) {
- return new JaxwsFaultCodeTagsCustomizer(jaxwsTags, jaxwsFaultCodeProvider);
- }
-
- @Bean
- @ConditionalOnMissingBean(JaxwsOperationTagsCustomizer.class)
- public JaxwsOperationTagsCustomizer jaxwsOperationTagsCustomizer(JaxwsTags jaxwsTags) {
- return new JaxwsOperationTagsCustomizer(jaxwsTags);
- }
-
- @Bean
@ConditionalOnMissingBean(StandardTags.class)
public StandardTags standardTags() {
return new StandardTags();
@@ -126,7 +104,7 @@ public class MicrometerMetricsAutoConfiguration {
Server server = this.properties.getMetrics().getServer();
micrometerMetricsProperties.setAutoTimeRequests(server.isAutoTimeRequests());
- micrometerMetricsProperties.setRequestsMetricName(server.getRequestsMetricName());
+ micrometerMetricsProperties.setServerRequestsMetricName(server.getRequestsMetricName());
return new MicrometerMetricsProvider(registry, tagsProvider, tagsCustomizers, timedAnnotationProvider,
micrometerMetricsProperties);
@@ -141,4 +119,51 @@ public class MicrometerMetricsAutoConfiguration {
return MeterFilter.maximumAllowableTags(
metricName, "uri", this.properties.getMetrics().getServer().getMaxUriTags(), filter);
}
+
+ @Configuration
+ @ConditionalOnClass(JaxWsServerFactoryBean.class)
+ @ConditionalOnProperty(name = "cxf.metrics.jaxws.enabled", matchIfMissing = true)
+ protected static class JaxWsMetricsConfiguration {
+ @Bean
+ @ConditionalOnMissingBean(JaxwsFaultCodeProvider.class)
+ public JaxwsFaultCodeProvider jaxwsFaultCodeProvider() {
+ return new JaxwsFaultCodeProvider();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean(JaxwsFaultCodeTagsCustomizer.class)
+ public JaxwsFaultCodeTagsCustomizer jaxwsFaultCodeTagsCustomizer(JaxwsTags jaxwsTags,
+ JaxwsFaultCodeProvider jaxwsFaultCodeProvider) {
+ return new JaxwsFaultCodeTagsCustomizer(jaxwsTags, jaxwsFaultCodeProvider);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean(JaxwsOperationTagsCustomizer.class)
+ public JaxwsOperationTagsCustomizer jaxwsOperationTagsCustomizer(JaxwsTags jaxwsTags) {
+ return new JaxwsOperationTagsCustomizer(jaxwsTags);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean(JaxwsTags.class)
+ public JaxwsTags jaxwsTags() {
+ return new JaxwsTags();
+ }
+ }
+
+ @Configuration
+ @ConditionalOnClass(JAXRSServerFactoryBean.class)
+ @ConditionalOnProperty(name = "cxf.metrics.jaxrs.enabled", matchIfMissing = true)
+ protected static class JaxRsMetricsConfiguration {
+ @Bean
+ @ConditionalOnMissingBean(JaxrsTags.class)
+ public JaxrsTags jaxrsTags() {
+ return new JaxrsTags();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean(JaxrsOperationTagsCustomizer.class)
+ public JaxrsOperationTagsCustomizer jaxrsOperationTagsCustomizer(JaxrsTags jaxrsTags) {
+ return new JaxrsOperationTagsCustomizer(jaxrsTags);
+ }
+ }
}
diff --git a/integration/spring-boot/autoconfigure/src/main/java/org/apache/cxf/spring/boot/autoconfigure/micrometer/provider/SpringBasedTimedAnnotationProvider.java b/integration/spring-boot/autoconfigure/src/main/java/org/apache/cxf/spring/boot/autoconfigure/micrometer/provider/SpringBasedTimedAnnotationProvider.java
index eada8d8..557a78c 100644
--- a/integration/spring-boot/autoconfigure/src/main/java/org/apache/cxf/spring/boot/autoconfigure/micrometer/provider/SpringBasedTimedAnnotationProvider.java
+++ b/integration/spring-boot/autoconfigure/src/main/java/org/apache/cxf/spring/boot/autoconfigure/micrometer/provider/SpringBasedTimedAnnotationProvider.java
@@ -25,6 +25,7 @@ import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import org.apache.cxf.jaxrs.model.OperationResourceInfo;
import org.apache.cxf.message.Exchange;
import org.apache.cxf.metrics.micrometer.provider.TimedAnnotationProvider;
import org.apache.cxf.service.Service;
@@ -42,7 +43,10 @@ public class SpringBasedTimedAnnotationProvider implements TimedAnnotationProvid
@Override
public Set<Timed> getTimedAnnotations(Exchange ex) {
- HandlerMethod handlerMethod = new HandlerMethod(ex);
+ HandlerMethod handlerMethod = HandlerMethod.create(ex);
+ if (handlerMethod == null) {
+ return emptySet();
+ }
final Set<Timed> exists = timedAnnotationCache.get(handlerMethod);
if (exists != null) {
@@ -66,19 +70,35 @@ public class SpringBasedTimedAnnotationProvider implements TimedAnnotationProvid
}
private static final class HandlerMethod {
- private final Class beanType;
+ private final Class<?> beanType;
private final Method method;
- private HandlerMethod(Exchange exchange) {
- Service service = exchange.getService();
- BindingOperationInfo bop = exchange.getBindingOperationInfo();
- MethodDispatcher md = (MethodDispatcher) service.get(MethodDispatcher.class.getName());
+ private HandlerMethod(Class<?> beanType, Method method) {
+ this.beanType = beanType;
+ this.method = method;
+ }
- this.method = md.getMethod(bop);
- this.beanType = method.getDeclaringClass();
+ private static HandlerMethod create(Exchange exchange) {
+ final Service service = exchange.getService();
+ if (service != null) {
+ final BindingOperationInfo bop = exchange.getBindingOperationInfo();
+ if (bop != null) { /* JAX-WS call */
+ final MethodDispatcher md = (MethodDispatcher) service.get(MethodDispatcher.class.getName());
+ final Method method = md.getMethod(bop);
+ return new HandlerMethod(method.getDeclaringClass(), method);
+ } else { /* JAX-RS call */
+ final OperationResourceInfo ori = exchange.get(OperationResourceInfo.class);
+ if (ori != null) {
+ return new HandlerMethod(ori.getClassResourceInfo().getResourceClass(),
+ ori.getAnnotatedMethod());
+ }
+ }
+ }
+
+ return null;
}
- private Class getBeanType() {
+ private Class<?> getBeanType() {
return beanType;
}
diff --git a/integration/spring-boot/autoconfigure/src/test/java/org/apache/cxf/spring/boot/autoconfigure/micrometer/MicrometerMetricsAutoConfigurationTest.java b/integration/spring-boot/autoconfigure/src/test/java/org/apache/cxf/spring/boot/autoconfigure/micrometer/MicrometerMetricsAutoConfigurationTest.java
new file mode 100644
index 0000000..f43ff9d
--- /dev/null
+++ b/integration/spring-boot/autoconfigure/src/test/java/org/apache/cxf/spring/boot/autoconfigure/micrometer/MicrometerMetricsAutoConfigurationTest.java
@@ -0,0 +1,91 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.spring.boot.autoconfigure.micrometer;
+
+import org.apache.cxf.metrics.MetricsProvider;
+import org.apache.cxf.metrics.micrometer.MicrometerMetricsProvider;
+import org.apache.cxf.metrics.micrometer.provider.jaxrs.JaxrsTags;
+import org.apache.cxf.metrics.micrometer.provider.jaxws.JaxwsTags;
+import org.apache.cxf.spring.boot.autoconfigure.CxfProperties;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
+import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
+import org.springframework.boot.autoconfigure.AutoConfigurations;
+import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
+
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertThrows;
+
+public class MicrometerMetricsAutoConfigurationTest {
+ private final WebApplicationContextRunner runner = new WebApplicationContextRunner()
+ .withBean(CxfProperties.class)
+ .withConfiguration(AutoConfigurations.of(
+ MetricsAutoConfiguration.class,
+ SimpleMetricsExportAutoConfiguration.class,
+ MicrometerMetricsAutoConfiguration.class
+ ));
+
+ @Test
+ public void metricsProviderShouldBeAvailable() {
+ runner
+ .run(ctx -> {
+ assertThat(ctx.getBean(MetricsProvider.class), instanceOf(MicrometerMetricsProvider.class));
+ assertThat(ctx.getBean(JaxrsTags.class), not(nullValue()));
+ assertThat(ctx.getBean(JaxwsTags.class), not(nullValue()));
+ });
+ }
+
+ @Test
+ public void metricsProviderShouldNotBeAvailable() {
+ runner
+ .withPropertyValues("cxf.metrics.enabled=false")
+ .run(ctx -> {
+ assertThrows(NoSuchBeanDefinitionException.class, () -> ctx.getBean(MetricsProvider.class));
+ assertThrows(NoSuchBeanDefinitionException.class, () -> ctx.getBean(JaxrsTags.class));
+ assertThrows(NoSuchBeanDefinitionException.class, () -> ctx.getBean(JaxwsTags.class));
+ });
+ }
+
+ @Test
+ public void jaxrsMetricsShouldNotBeAvailable() {
+ runner
+ .withPropertyValues("cxf.metrics.jaxrs.enabled=false")
+ .run(ctx -> {
+ assertThat(ctx.getBean(MetricsProvider.class), instanceOf(MicrometerMetricsProvider.class));
+ assertThrows(NoSuchBeanDefinitionException.class, () -> ctx.getBean(JaxrsTags.class));
+ assertThat(ctx.getBean(JaxwsTags.class), not(nullValue()));
+ });
+ }
+
+ @Test
+ public void jaxwsMetricsShouldNotBeAvailable() {
+ runner
+ .withPropertyValues("cxf.metrics.jaxws.enabled=false")
+ .run(ctx -> {
+ assertThat(ctx.getBean(MetricsProvider.class), instanceOf(MicrometerMetricsProvider.class));
+ assertThat(ctx.getBean(JaxrsTags.class), not(nullValue()));
+ assertThrows(NoSuchBeanDefinitionException.class, () -> ctx.getBean(JaxwsTags.class));
+ });
+ }
+}
diff --git a/rt/features/metrics/src/main/java/org/apache/cxf/metrics/micrometer/MicrometerMetricsProperties.java b/rt/features/metrics/src/main/java/org/apache/cxf/metrics/micrometer/MicrometerMetricsProperties.java
index 8144067..6573392 100644
--- a/rt/features/metrics/src/main/java/org/apache/cxf/metrics/micrometer/MicrometerMetricsProperties.java
+++ b/rt/features/metrics/src/main/java/org/apache/cxf/metrics/micrometer/MicrometerMetricsProperties.java
@@ -31,7 +31,7 @@ public class MicrometerMetricsProperties {
/**
* Name of the metric for received requests.
*/
- private String requestsMetricName = "cxf.server.requests";
+ private String serverRequestsMetricName = "cxf.server.requests";
public boolean isAutoTimeRequests() {
return autoTimeRequests;
@@ -41,11 +41,11 @@ public class MicrometerMetricsProperties {
this.autoTimeRequests = autoTimeRequests;
}
- public String getRequestsMetricName() {
- return requestsMetricName;
+ public String getServerRequestsMetricName() {
+ return serverRequestsMetricName;
}
- public void setRequestsMetricName(String requestsMetricName) {
- this.requestsMetricName = requestsMetricName;
+ public void setServerRequestsMetricName(String requestsMetricName) {
+ this.serverRequestsMetricName = requestsMetricName;
}
}
diff --git a/rt/features/metrics/src/main/java/org/apache/cxf/metrics/micrometer/MicrometerMetricsProvider.java b/rt/features/metrics/src/main/java/org/apache/cxf/metrics/micrometer/MicrometerMetricsProvider.java
index 3cd4dd4..d4c0601 100644
--- a/rt/features/metrics/src/main/java/org/apache/cxf/metrics/micrometer/MicrometerMetricsProvider.java
+++ b/rt/features/metrics/src/main/java/org/apache/cxf/metrics/micrometer/MicrometerMetricsProvider.java
@@ -60,7 +60,7 @@ public class MicrometerMetricsProvider implements MetricsProvider {
* {@inheritDoc}
*/
@Override
- public MetricsContext createEndpointContext(Endpoint endpoint, boolean isClient, String clientId) {
+ public MetricsContext createEndpointContext(Endpoint endpoint, boolean asClient, String clientId) {
return null;
}
@@ -70,8 +70,14 @@ public class MicrometerMetricsProvider implements MetricsProvider {
@Override
public MetricsContext createOperationContext(Endpoint endpoint, BindingOperationInfo boi, boolean asClient,
String clientId) {
+ // Client metrics are not yet supported
+ if (asClient) {
+ return null;
+ }
+
return new MicrometerMetricsContext(registry, tagsProvider, timedAnnotationProvider, tagsCustomizers,
- micrometerMetricsProperties.getRequestsMetricName(), micrometerMetricsProperties.isAutoTimeRequests());
+ micrometerMetricsProperties.getServerRequestsMetricName(),
+ micrometerMetricsProperties.isAutoTimeRequests());
}
@@ -81,6 +87,13 @@ public class MicrometerMetricsProvider implements MetricsProvider {
@Override
public MetricsContext createResourceContext(Endpoint endpoint, String resourceName, boolean asClient,
String clientId) {
- return null;
+ // Client metrics are not yet supported
+ if (asClient) {
+ return null;
+ }
+
+ return new MicrometerMetricsContext(registry, tagsProvider, timedAnnotationProvider, tagsCustomizers,
+ micrometerMetricsProperties.getServerRequestsMetricName(),
+ micrometerMetricsProperties.isAutoTimeRequests());
}
}
diff --git a/rt/features/metrics/src/main/java/org/apache/cxf/metrics/micrometer/provider/DefaultTimedAnnotationProvider.java b/rt/features/metrics/src/main/java/org/apache/cxf/metrics/micrometer/provider/DefaultTimedAnnotationProvider.java
index d9be969..5b018d0 100644
--- a/rt/features/metrics/src/main/java/org/apache/cxf/metrics/micrometer/provider/DefaultTimedAnnotationProvider.java
+++ b/rt/features/metrics/src/main/java/org/apache/cxf/metrics/micrometer/provider/DefaultTimedAnnotationProvider.java
@@ -31,9 +31,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.cxf.message.Exchange;
-import org.apache.cxf.service.Service;
-import org.apache.cxf.service.invoker.MethodDispatcher;
-import org.apache.cxf.service.model.BindingOperationInfo;
+import org.apache.cxf.message.MessageUtils;
import io.micrometer.core.annotation.Timed;
import io.micrometer.core.annotation.TimedSet;
@@ -46,8 +44,11 @@ public class DefaultTimedAnnotationProvider implements TimedAnnotationProvider {
@Override
public Set<Timed> getTimedAnnotations(Exchange ex) {
- HandlerMethod handlerMethod = new HandlerMethod(ex);
-
+ final HandlerMethod handlerMethod = HandlerMethod.create(ex);
+ if (handlerMethod == null) {
+ return emptySet();
+ }
+
final Set<Timed> exists = timedAnnotationCache.get(handlerMethod);
if (exists != null) {
return exists;
@@ -94,19 +95,22 @@ public class DefaultTimedAnnotationProvider implements TimedAnnotationProvider {
}
private static final class HandlerMethod {
- private final Class beanType;
+ private final Class<?> beanType;
private final Method method;
- private HandlerMethod(Exchange exchange) {
- Service service = exchange.getService();
- BindingOperationInfo bop = exchange.getBindingOperationInfo();
- MethodDispatcher md = (MethodDispatcher) service.get(MethodDispatcher.class.getName());
-
- this.method = md.getMethod(bop);
- this.beanType = method.getDeclaringClass();
+ private HandlerMethod(Class<?> beanType, Method method) {
+ this.method = method;
+ this.beanType = beanType;
+ }
+
+ private static HandlerMethod create(Exchange exchange) {
+ return MessageUtils
+ .getTargetMethod(exchange.getInMessage())
+ .map(method -> new HandlerMethod(method.getDeclaringClass(), method))
+ .orElse(null);
}
- private Class getBeanType() {
+ private Class<?> getBeanType() {
return beanType;
}
diff --git a/rt/features/metrics/src/main/java/org/apache/cxf/metrics/micrometer/provider/StandardTags.java b/rt/features/metrics/src/main/java/org/apache/cxf/metrics/micrometer/provider/StandardTags.java
index 86897f0..9b63ecf 100644
--- a/rt/features/metrics/src/main/java/org/apache/cxf/metrics/micrometer/provider/StandardTags.java
+++ b/rt/features/metrics/src/main/java/org/apache/cxf/metrics/micrometer/provider/StandardTags.java
@@ -75,7 +75,7 @@ public class StandardTags {
public Tag uri(Message request) {
return ofNullable(request)
- .map(e -> e.get(Message.BASE_PATH))
+ .map(e -> e.get(Message.REQUEST_URI))
.filter(e -> e instanceof String)
.map(e -> (String) e)
.map(e -> Tag.of("uri", e))
diff --git a/rt/features/metrics/src/main/java/org/apache/cxf/metrics/micrometer/provider/jaxrs/JaxrsOperationTagsCustomizer.java b/rt/features/metrics/src/main/java/org/apache/cxf/metrics/micrometer/provider/jaxrs/JaxrsOperationTagsCustomizer.java
new file mode 100644
index 0000000..0a90b8a
--- /dev/null
+++ b/rt/features/metrics/src/main/java/org/apache/cxf/metrics/micrometer/provider/jaxrs/JaxrsOperationTagsCustomizer.java
@@ -0,0 +1,43 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.metrics.micrometer.provider.jaxrs;
+
+import org.apache.cxf.message.Exchange;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.metrics.micrometer.provider.TagsCustomizer;
+
+import io.micrometer.core.instrument.Tag;
+import io.micrometer.core.instrument.Tags;
+
+import static java.util.Optional.ofNullable;
+
+public class JaxrsOperationTagsCustomizer implements TagsCustomizer {
+ private final JaxrsTags jaxrsTags;
+
+ public JaxrsOperationTagsCustomizer(JaxrsTags jaxrsTags) {
+ this.jaxrsTags = jaxrsTags;
+ }
+
+ @Override
+ public Iterable<Tag> getAdditionalTags(Exchange ex) {
+ Message request = ofNullable(ex.getInMessage()).orElseGet(ex::getInFaultMessage);
+ return Tags.of(jaxrsTags.operation(request));
+ }
+}
diff --git a/rt/features/metrics/src/main/java/org/apache/cxf/metrics/micrometer/provider/jaxrs/JaxrsTags.java b/rt/features/metrics/src/main/java/org/apache/cxf/metrics/micrometer/provider/jaxrs/JaxrsTags.java
new file mode 100644
index 0000000..d966445
--- /dev/null
+++ b/rt/features/metrics/src/main/java/org/apache/cxf/metrics/micrometer/provider/jaxrs/JaxrsTags.java
@@ -0,0 +1,44 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.metrics.micrometer.provider.jaxrs;
+
+import java.lang.reflect.Method;
+
+import org.apache.cxf.message.Message;
+import org.apache.cxf.message.MessageUtils;
+
+import io.micrometer.core.instrument.Tag;
+
+import static java.util.Optional.ofNullable;
+
+public class JaxrsTags {
+
+ private static final String UNKNOWN = "UNKNOWN";
+
+ private static final Tag OPERATION_UNKNOWN = Tag.of("operation", UNKNOWN);
+
+ public Tag operation(Message request) {
+ return ofNullable(request)
+ .flatMap(MessageUtils::getTargetMethod)
+ .map(Method::getName)
+ .map(operation -> Tag.of("operation", operation))
+ .orElse(OPERATION_UNKNOWN);
+ }
+}
diff --git a/rt/features/metrics/src/test/java/org/apache/cxf/metrics/micrometer/MicrometerMetricsProviderTest.java b/rt/features/metrics/src/test/java/org/apache/cxf/metrics/micrometer/MicrometerMetricsProviderTest.java
index 7d2c41a..a79232a 100644
--- a/rt/features/metrics/src/test/java/org/apache/cxf/metrics/micrometer/MicrometerMetricsProviderTest.java
+++ b/rt/features/metrics/src/test/java/org/apache/cxf/metrics/micrometer/MicrometerMetricsProviderTest.java
@@ -65,7 +65,7 @@ public class MicrometerMetricsProviderTest {
initMocks(this);
micrometerMetricsProperties = new MicrometerMetricsProperties();
- micrometerMetricsProperties.setRequestsMetricName("http.server.requests");
+ micrometerMetricsProperties.setServerRequestsMetricName("http.server.requests");
micrometerMetricsProperties.setAutoTimeRequests(true);
underTest =
@@ -86,11 +86,35 @@ public class MicrometerMetricsProviderTest {
}
@Test
- public void testCreateOperationContext() throws NoSuchFieldException, IllegalAccessException {
+ public void testCreateServerOperationContext() throws NoSuchFieldException, IllegalAccessException {
+ // when
+ MetricsContext actual = underTest.createOperationContext(endpoint, boi, false, "clientId");
+
+ // then
+ assertThat(actual, instanceOf(MicrometerMetricsContext.class));
+ assertThat(getFieldValue(actual, "registry"), is(registry));
+ assertThat(getFieldValue(actual, "tagsProvider"), is(tagsProvider));
+ assertThat(getFieldValue(actual, "timedAnnotationProvider"), is(timedAnnotationProvider));
+ assertThat(getFieldValue(actual, "metricName"), is("http.server.requests"));
+ assertThat(getFieldValue(actual, "autoTimeRequests"), is(true));
+ assertThat(getFieldValue(actual, "tagsCustomizers"), is(Collections.singletonList(tagsCustomizer)));
+ }
+
+ @Test
+ public void testCreateClientOperationContext() throws NoSuchFieldException, IllegalAccessException {
// when
MetricsContext actual = underTest.createOperationContext(endpoint, boi, true, "clientId");
// then
+ assertThat(actual, is(nullValue()));
+ }
+
+ @Test
+ public void testCreateServerResourceContext() throws NoSuchFieldException, IllegalAccessException {
+ // when
+ MetricsContext actual = underTest.createResourceContext(endpoint, "resourceName", false, "clientId");
+
+ // then
assertThat(actual, instanceOf(MicrometerMetricsContext.class));
assertThat(getFieldValue(actual, "registry"), is(registry));
assertThat(getFieldValue(actual, "tagsProvider"), is(tagsProvider));
@@ -101,7 +125,7 @@ public class MicrometerMetricsProviderTest {
}
@Test
- public void testCreateResourceContext() {
+ public void testCreateClientResourceContext() {
// when
MetricsContext actual = underTest.createResourceContext(endpoint, "resourceName", true, "clientId");
diff --git a/rt/features/metrics/src/test/java/org/apache/cxf/metrics/micrometer/provider/DefaultExceptionClassProviderTest.java b/rt/features/metrics/src/test/java/org/apache/cxf/metrics/micrometer/provider/DefaultExceptionClassProviderTest.java
index f8feb7d..54b7543 100644
--- a/rt/features/metrics/src/test/java/org/apache/cxf/metrics/micrometer/provider/DefaultExceptionClassProviderTest.java
+++ b/rt/features/metrics/src/test/java/org/apache/cxf/metrics/micrometer/provider/DefaultExceptionClassProviderTest.java
@@ -32,7 +32,7 @@ import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.MockitoAnnotations.initMocks;
+import static org.mockito.MockitoAnnotations.openMocks;
public class DefaultExceptionClassProviderTest {
@@ -50,7 +50,7 @@ public class DefaultExceptionClassProviderTest {
@Before
public void setUp() {
- initMocks(this);
+ openMocks(this);
underTest = new DefaultExceptionClassProvider();
}
@@ -58,7 +58,7 @@ public class DefaultExceptionClassProviderTest {
@Test
public void testGetExceptionClassReturnCauseExceptionFromExchange() {
// given
- Class expected = CauseException.class;
+ Class<?> expected = CauseException.class;
doReturn(FAULT_EXCEPTION).when(exchange).get(Exception.class);
diff --git a/rt/features/metrics/src/test/java/org/apache/cxf/metrics/micrometer/provider/DefaultTimedAnnotationProviderTest.java b/rt/features/metrics/src/test/java/org/apache/cxf/metrics/micrometer/provider/DefaultTimedAnnotationProviderTest.java
index b29e281..0229112 100644
--- a/rt/features/metrics/src/test/java/org/apache/cxf/metrics/micrometer/provider/DefaultTimedAnnotationProviderTest.java
+++ b/rt/features/metrics/src/test/java/org/apache/cxf/metrics/micrometer/provider/DefaultTimedAnnotationProviderTest.java
@@ -24,6 +24,7 @@ import java.util.Set;
import java.util.stream.Collectors;
import org.apache.cxf.message.Exchange;
+import org.apache.cxf.message.Message;
import org.apache.cxf.service.Service;
import org.apache.cxf.service.invoker.MethodDispatcher;
import org.apache.cxf.service.model.BindingOperationInfo;
@@ -39,7 +40,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.empty;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.MockitoAnnotations.initMocks;
+import static org.mockito.MockitoAnnotations.openMocks;
@SuppressWarnings({"unused"})
public class DefaultTimedAnnotationProviderTest {
@@ -54,15 +55,19 @@ public class DefaultTimedAnnotationProviderTest {
private BindingOperationInfo bindingOperationInfo;
@Mock
private MethodDispatcher methodDispatcher;
+ @Mock
+ private Message message;
@Before
public void setUp() {
- initMocks(this);
+ openMocks(this);
underTest = new DefaultTimedAnnotationProvider();
doReturn(service).when(exchange).getService();
doReturn(bindingOperationInfo).when(exchange).getBindingOperationInfo();
doReturn(methodDispatcher).when(service).get(MethodDispatcher.class.getName());
+ doReturn(message).when(exchange).getInMessage();
+ doReturn(exchange).when(message).getExchange();
}
@Test
diff --git a/rt/features/metrics/src/test/java/org/apache/cxf/metrics/micrometer/provider/StandardTagsProviderTest.java b/rt/features/metrics/src/test/java/org/apache/cxf/metrics/micrometer/provider/StandardTagsProviderTest.java
index 2ed8dce..a6e5529 100644
--- a/rt/features/metrics/src/test/java/org/apache/cxf/metrics/micrometer/provider/StandardTagsProviderTest.java
+++ b/rt/features/metrics/src/test/java/org/apache/cxf/metrics/micrometer/provider/StandardTagsProviderTest.java
@@ -33,7 +33,7 @@ import org.mockito.Mock;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.MockitoAnnotations.initMocks;
+import static org.mockito.MockitoAnnotations.openMocks;
public class StandardTagsProviderTest {
@@ -53,7 +53,7 @@ public class StandardTagsProviderTest {
@Before
public void setUp() {
- initMocks(this);
+ openMocks(this);
underTest = new StandardTagsProvider(exceptionClassProvider, standardTags);
diff --git a/rt/features/metrics/src/test/java/org/apache/cxf/metrics/micrometer/provider/StandardTagsTest.java b/rt/features/metrics/src/test/java/org/apache/cxf/metrics/micrometer/provider/StandardTagsTest.java
index ae8a4c2..92a13b3 100644
--- a/rt/features/metrics/src/test/java/org/apache/cxf/metrics/micrometer/provider/StandardTagsTest.java
+++ b/rt/features/metrics/src/test/java/org/apache/cxf/metrics/micrometer/provider/StandardTagsTest.java
@@ -34,7 +34,7 @@ import org.mockito.Mock;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.MockitoAnnotations.initMocks;
+import static org.mockito.MockitoAnnotations.openMocks;
public class StandardTagsTest {
@@ -65,7 +65,7 @@ public class StandardTagsTest {
@Before
public void setUp() {
- initMocks(this);
+ openMocks(this);
doReturn(exchange).when(request).getExchange();
doReturn(bindingOperationInfo).when(exchange).getBindingOperationInfo();
@@ -263,7 +263,7 @@ public class StandardTagsTest {
@Test
public void testUriReturnWithCorrectValue() {
// given
- doReturn(DUMMY_URI).when(request).get(Message.BASE_PATH);
+ doReturn(DUMMY_URI).when(request).get(Message.REQUEST_URI);
// when
Tag actual = underTest.uri(request);
@@ -298,6 +298,7 @@ public class StandardTagsTest {
public void testExceptionReturnWithNameWhenExceptionIsAnonymous() {
// given
Exception exception = new Exception() {
+ private static final long serialVersionUID = 1L;
};
// when
diff --git a/rt/features/metrics/src/test/java/org/apache/cxf/metrics/micrometer/provider/jaxrs/JaxrsOperationTagsCustomizerTest.java b/rt/features/metrics/src/test/java/org/apache/cxf/metrics/micrometer/provider/jaxrs/JaxrsOperationTagsCustomizerTest.java
new file mode 100644
index 0000000..ff4fcef
--- /dev/null
+++ b/rt/features/metrics/src/test/java/org/apache/cxf/metrics/micrometer/provider/jaxrs/JaxrsOperationTagsCustomizerTest.java
@@ -0,0 +1,73 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.metrics.micrometer.provider.jaxrs;
+
+import org.apache.cxf.message.Exchange;
+import org.apache.cxf.message.ExchangeImpl;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.message.MessageImpl;
+import org.apache.cxf.metrics.micrometer.provider.TagsCustomizer;
+
+import io.micrometer.core.instrument.Tag;
+import io.micrometer.core.instrument.Tags;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+public class JaxrsOperationTagsCustomizerTest {
+ private static final String OPERATION_METRIC_NAME = "operation";
+ private static final String DUMMY_OPERATOR = "getOperator";
+
+ private Message message;
+ private TagsCustomizer tagsCustomizer;
+ private Exchange exchange;
+
+ @Before
+ public void setUp() {
+ exchange = new ExchangeImpl();
+
+ message = new MessageImpl();
+ message.setExchange(exchange);
+
+ exchange.setInMessage(message);
+ tagsCustomizer = new JaxrsOperationTagsCustomizer(new JaxrsTags());
+ }
+
+ @Test
+ public void testOperationReturnWithUnknownWhenRequestIsNull() {
+ final Iterable<Tag> actual = tagsCustomizer.getAdditionalTags(exchange);
+ assertThat(actual, equalTo(Tags.of(Tag.of(OPERATION_METRIC_NAME, "UNKNOWN"))));
+ }
+
+ @Test
+ public void testOperationReturnWithCorrectValue() throws NoSuchMethodException, SecurityException {
+ message.put("org.apache.cxf.resource.method", getClass().getDeclaredMethod("getOperator"));
+ final Iterable<Tag> actual = tagsCustomizer.getAdditionalTags(exchange);
+ assertThat(actual, equalTo(Tags.of(Tag.of(OPERATION_METRIC_NAME, DUMMY_OPERATOR))));
+ }
+
+ @SuppressWarnings("unused")
+ private void getOperator() {
+ /* operation method */
+ }
+}
\ No newline at end of file
diff --git a/rt/features/metrics/src/test/java/org/apache/cxf/metrics/micrometer/provider/jaxrs/JaxrsTagsTest.java b/rt/features/metrics/src/test/java/org/apache/cxf/metrics/micrometer/provider/jaxrs/JaxrsTagsTest.java
new file mode 100644
index 0000000..4706966
--- /dev/null
+++ b/rt/features/metrics/src/test/java/org/apache/cxf/metrics/micrometer/provider/jaxrs/JaxrsTagsTest.java
@@ -0,0 +1,65 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.metrics.micrometer.provider.jaxrs;
+
+import org.apache.cxf.message.ExchangeImpl;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.message.MessageImpl;
+
+import io.micrometer.core.instrument.Tag;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+public class JaxrsTagsTest {
+ private static final String OPERATION_METRIC_NAME = "operation";
+ private static final String DUMMY_OPERATOR = "getOperator";
+
+ private JaxrsTags tags;
+ private Message message;
+
+ @Before
+ public void setUp() throws NoSuchMethodException, SecurityException {
+ message = new MessageImpl();
+ message.setExchange(new ExchangeImpl());
+ message.put("org.apache.cxf.resource.method", getClass().getDeclaredMethod("getOperator"));
+ tags = new JaxrsTags();
+ }
+
+ @Test
+ public void testOperationReturnWithUnknownWhenRequestIsNull() {
+ final Tag actual = tags.operation(null);
+ assertThat(actual, is(Tag.of(OPERATION_METRIC_NAME, "UNKNOWN")));
+ }
+
+ @Test
+ public void testOperationReturnWithCorrectValue() {
+ final Tag actual = tags.operation(message);
+ assertThat(actual, is(Tag.of(OPERATION_METRIC_NAME, DUMMY_OPERATOR)));
+ }
+
+ @SuppressWarnings("unused")
+ private void getOperator() {
+ /* operation method */
+ }
+}
diff --git a/systests/spring-boot/src/test/java/org/apache/cxf/systest/jaxrs/resources/Library.java b/systests/spring-boot/src/test/java/org/apache/cxf/systest/jaxrs/resources/Library.java
index 43fa6da..c540eb3 100644
--- a/systests/spring-boot/src/test/java/org/apache/cxf/systest/jaxrs/resources/Library.java
+++ b/systests/spring-boot/src/test/java/org/apache/cxf/systest/jaxrs/resources/Library.java
@@ -23,6 +23,7 @@ import java.util.Collections;
import java.util.Map;
import java.util.TreeMap;
+import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
@@ -62,4 +63,9 @@ public class Library {
? Response.ok().entity(books.get(id)).build()
: Response.status(Status.NOT_FOUND).build();
}
+
+ @DELETE
+ public void deleteBooks() {
+ throw new UnsupportedOperationException("Operation is not supported by the server");
+ }
}
diff --git a/systests/spring-boot/src/test/java/org/apache/cxf/systest/jaxrs/spring/boot/SpringJaxrsTest.java b/systests/spring-boot/src/test/java/org/apache/cxf/systest/jaxrs/spring/boot/SpringJaxrsTest.java
new file mode 100644
index 0000000..7771653
--- /dev/null
+++ b/systests/spring-boot/src/test/java/org/apache/cxf/systest/jaxrs/spring/boot/SpringJaxrsTest.java
@@ -0,0 +1,181 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.systest.jaxrs.spring.boot;
+
+import java.util.Map;
+
+import javax.ws.rs.InternalServerErrorException;
+import javax.ws.rs.NotFoundException;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Response;
+
+import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
+
+import org.apache.cxf.bus.spring.SpringBus;
+import org.apache.cxf.feature.Feature;
+import org.apache.cxf.metrics.MetricsFeature;
+import org.apache.cxf.metrics.MetricsProvider;
+import org.apache.cxf.systest.jaxrs.resources.Book;
+import org.apache.cxf.systest.jaxrs.resources.Library;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.boot.test.system.OutputCaptureRule;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.core.instrument.Tag;
+import io.micrometer.core.instrument.search.RequiredSearch;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static java.util.stream.Collectors.toMap;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.assertj.core.api.Assertions.entry;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = SpringJaxrsTest.TestConfig.class)
+@ActiveProfiles("jaxrs")
+public class SpringJaxrsTest {
+ @Rule
+ public OutputCaptureRule output = new OutputCaptureRule();
+
+ @Autowired
+ private MeterRegistry registry;
+
+ @LocalServerPort
+ private int port;
+
+ @Configuration
+ @EnableAutoConfiguration
+ @ComponentScan(basePackageClasses = Library.class)
+ static class TestConfig {
+ @Bean
+ public SpringBus cxf() {
+ final SpringBus bus = new SpringBus();
+ // Bye default, the exception are propagated and out fault interceptors are not called
+ bus.setProperty("org.apache.cxf.propagate.exception", Boolean.FALSE);
+ return bus;
+ }
+
+ @Bean
+ public Feature metricsFeature(MetricsProvider metricsProvider) {
+ return new MetricsFeature(metricsProvider);
+ }
+
+ @Bean
+ public JacksonJsonProvider jacksonJsonProvider() {
+ return new JacksonJsonProvider();
+ }
+ }
+
+ @Before
+ public void setUp() {
+ this.registry.getMeters().forEach(meter -> registry.remove(meter));
+ }
+
+ @Test
+ public void testJaxrsSuccessMetric() {
+ final WebTarget target = createWebTarget();
+
+ try (Response r = target.request().get()) {
+ assertThat(r.getStatus()).isEqualTo(200);
+ }
+
+ RequiredSearch requestMetrics = registry.get("cxf.server.requests");
+
+ Map<Object, Object> tags = requestMetrics.timer().getId().getTags().stream()
+ .collect(toMap(Tag::getKey, Tag::getValue));
+
+ assertThat(tags)
+ .containsOnly(
+ entry("exception", "None"),
+ entry("method", "GET"),
+ entry("operation", "getBooks"),
+ entry("uri", "/api/library"),
+ entry("outcome", "SUCCESS"),
+ entry("status", "200"));
+ }
+
+ @Test
+ public void testJaxrsFailedMetric() {
+ final WebTarget target = createWebTarget();
+
+ assertThatThrownBy(() -> target.path("100").request().get(Book.class))
+ .isInstanceOf(NotFoundException.class)
+ .hasMessageContaining("Not Found");
+
+ RequiredSearch requestMetrics = registry.get("cxf.server.requests");
+
+ Map<Object, Object> tags = requestMetrics.timer().getId().getTags().stream()
+ .collect(toMap(Tag::getKey, Tag::getValue));
+
+ assertThat(tags)
+ .containsOnly(
+ entry("exception", "None"),
+ entry("method", "GET"),
+ entry("operation", "getBook"),
+ entry("uri", "/api/library/100"),
+ entry("outcome", "CLIENT_ERROR"),
+ entry("status", "404"));
+ }
+
+ @Test
+ public void testJaxrsExceptionMetric() {
+ final WebTarget target = createWebTarget();
+
+ assertThatThrownBy(() -> target.request().delete(String.class))
+ .isInstanceOf(InternalServerErrorException.class)
+ .hasMessageContaining("Internal Server Error");
+
+ RequiredSearch requestMetrics = registry.get("cxf.server.requests");
+
+ Map<Object, Object> tags = requestMetrics.timer().getId().getTags().stream()
+ .collect(toMap(Tag::getKey, Tag::getValue));
+
+ assertThat(tags)
+ .containsOnly(
+ entry("exception", "UnsupportedOperationException"),
+ entry("method", "DELETE"),
+ entry("operation", "deleteBooks"),
+ entry("uri", "/api/library"),
+ entry("outcome", "SERVER_ERROR"),
+ entry("status", "500"));
+ }
+
+ private WebTarget createWebTarget() {
+ return ClientBuilder
+ .newClient()
+ .register(JacksonJsonProvider.class)
+ .target("http://localhost:" + port + "/api/library");
+ }
+
+}
diff --git a/systests/spring-boot/src/test/resources/application-jaxrs.yml b/systests/spring-boot/src/test/resources/application-jaxrs.yml
new file mode 100644
index 0000000..4049aaf
--- /dev/null
+++ b/systests/spring-boot/src/test/resources/application-jaxrs.yml
@@ -0,0 +1,7 @@
+cxf:
+ path: /api
+ jaxrs:
+ component-scan: true
+ metrics:
+ jaxws:
+ enabled: false
\ No newline at end of file
diff --git a/systests/spring-boot/src/test/resources/application-jaxws.yml b/systests/spring-boot/src/test/resources/application-jaxws.yml
index 4fec840..49c747e 100644
--- a/systests/spring-boot/src/test/resources/application-jaxws.yml
+++ b/systests/spring-boot/src/test/resources/application-jaxws.yml
@@ -1,2 +1,5 @@
cxf:
- path: /Service
\ No newline at end of file
+ path: /Service
+ metrics:
+ jaxrs:
+ enabled: false
\ No newline at end of file