diff --git a/micrometer-core/src/main/java/io/micrometer/core/instrument/binder/jersey/server/JerseyKeyValues.java b/micrometer-core/src/main/java/io/micrometer/core/instrument/binder/jersey/server/JerseyKeyValues.java index e6e44488da..d2a0cd3ed3 100644 --- a/micrometer-core/src/main/java/io/micrometer/core/instrument/binder/jersey/server/JerseyKeyValues.java +++ b/micrometer-core/src/main/java/io/micrometer/core/instrument/binder/jersey/server/JerseyKeyValues.java @@ -39,6 +39,9 @@ class JerseyKeyValues { private static final KeyValue URI_ROOT = JerseyObservationDocumentation.JerseyLegacyLowCardinalityTags.URI .withValue("root"); + private static final KeyValue URI_UNKNOWN = JerseyObservationDocumentation.JerseyLegacyLowCardinalityTags.URI + .withValue("UNKNOWN"); + private static final KeyValue EXCEPTION_NONE = JerseyObservationDocumentation.JerseyLegacyLowCardinalityTags.EXCEPTION .withValue("None"); @@ -94,6 +97,9 @@ static KeyValue uri(RequestEvent event) { } } String matchingPattern = JerseyTags.getMatchingPattern(event); + if (matchingPattern == null) { + return URI_UNKNOWN; + } if (matchingPattern.equals("/")) { return URI_ROOT; } diff --git a/micrometer-core/src/main/java/io/micrometer/core/instrument/binder/jersey/server/JerseyTags.java b/micrometer-core/src/main/java/io/micrometer/core/instrument/binder/jersey/server/JerseyTags.java index a7b175fccb..2b29b4dc7a 100644 --- a/micrometer-core/src/main/java/io/micrometer/core/instrument/binder/jersey/server/JerseyTags.java +++ b/micrometer-core/src/main/java/io/micrometer/core/instrument/binder/jersey/server/JerseyTags.java @@ -15,6 +15,7 @@ */ package io.micrometer.core.instrument.binder.jersey.server; +import io.micrometer.common.lang.Nullable; import io.micrometer.common.util.StringUtils; import io.micrometer.core.instrument.Tag; import io.micrometer.core.instrument.binder.http.Outcome; @@ -45,6 +46,8 @@ public final class JerseyTags { private static final Tag URI_ROOT = Tag.of("uri", "root"); + private static final Tag URI_UNKNOWN = Tag.of("uri", "UNKNOWN"); + private static final Tag EXCEPTION_NONE = Tag.of("exception", "None"); private static final Tag STATUS_SERVER_ERROR = Tag.of("status", "500"); @@ -97,7 +100,10 @@ public static Tag uri(RequestEvent event) { } } String matchingPattern = getMatchingPattern(event); - if (matchingPattern.equals("/")) { + if (matchingPattern == null) { + return URI_UNKNOWN; + } + else if (matchingPattern.equals("/")) { return URI_ROOT; } return Tag.of("uri", matchingPattern); @@ -107,10 +113,19 @@ static boolean isRedirection(int status) { return 300 <= status && status < 400; } + /** + * Gets the pattern for which the request was matched and normalizes it for tagging + * purposes. + * @param event request from which to extract the pattern + * @return normalized matched pattern or {@code null} if nothing matched + */ + @Nullable static String getMatchingPattern(RequestEvent event) { ExtendedUriInfo uriInfo = event.getUriInfo(); List templates = uriInfo.getMatchedTemplates(); - + if (templates.isEmpty()) { + return null; + } StringBuilder sb = new StringBuilder(); sb.append(uriInfo.getBaseUri().getPath()); for (int i = templates.size() - 1; i >= 0; i--) { diff --git a/micrometer-core/src/main/java/io/micrometer/core/instrument/binder/jersey/server/MetricsRequestEventListener.java b/micrometer-core/src/main/java/io/micrometer/core/instrument/binder/jersey/server/MetricsRequestEventListener.java index 876fe2cf09..bd0f954916 100644 --- a/micrometer-core/src/main/java/io/micrometer/core/instrument/binder/jersey/server/MetricsRequestEventListener.java +++ b/micrometer-core/src/main/java/io/micrometer/core/instrument/binder/jersey/server/MetricsRequestEventListener.java @@ -75,7 +75,7 @@ public void onEvent(RequestEvent event) { switch (event.getType()) { case ON_EXCEPTION: - if (!isNotFoundException(event)) { + if (!isClientError(event)) { break; } case REQUEST_MATCHED: @@ -111,13 +111,14 @@ public void onEvent(RequestEvent event) { } } - private boolean isNotFoundException(RequestEvent event) { + private boolean isClientError(RequestEvent event) { Throwable t = event.getException(); if (t == null) { return false; } - String className = t.getClass().getCanonicalName(); - return className.equals("jakarta.ws.rs.NotFoundException") || className.equals("javax.ws.rs.NotFoundException"); + String className = t.getClass().getSuperclass().getCanonicalName(); + return className.equals("jakarta.ws.rs.ClientErrorException") + || className.equals("javax.ws.rs.ClientErrorException"); } private Set shortTimers(Set timed, RequestEvent event) { diff --git a/micrometer-core/src/test/java/io/micrometer/core/instrument/binder/jersey/server/DefaultJerseyTagsProviderTest.java b/micrometer-core/src/test/java/io/micrometer/core/instrument/binder/jersey/server/DefaultJerseyTagsProviderTest.java index 084997cf57..fb3dcb6ab9 100644 --- a/micrometer-core/src/test/java/io/micrometer/core/instrument/binder/jersey/server/DefaultJerseyTagsProviderTest.java +++ b/micrometer-core/src/test/java/io/micrometer/core/instrument/binder/jersey/server/DefaultJerseyTagsProviderTest.java @@ -51,7 +51,7 @@ class DefaultJerseyTagsProviderTest { @Test void testRootPath() { - assertThat(tagsProvider.httpRequestTags(event(200, null, "/", (String[]) null))) + assertThat(tagsProvider.httpRequestTags(event(200, null, "/", "/"))) .containsExactlyInAnyOrder(tagsFrom("root", 200, null, "SUCCESS")); } @@ -86,21 +86,21 @@ void redirectsAreShunted() { @Test @SuppressWarnings("serial") void exceptionsAreMappedCorrectly() { - assertThat(tagsProvider.httpRequestTags(event(500, new IllegalArgumentException(), "/app", (String[]) null))) + assertThat(tagsProvider.httpRequestTags(event(500, new IllegalArgumentException(), "/app", "/"))) .containsExactlyInAnyOrder(tagsFrom("/app", 500, "IllegalArgumentException", "SERVER_ERROR")); - assertThat(tagsProvider.httpRequestTags( - event(500, new IllegalArgumentException(new NullPointerException()), "/app", (String[]) null))) + assertThat(tagsProvider + .httpRequestTags(event(500, new IllegalArgumentException(new NullPointerException()), "/app", "/"))) .containsExactlyInAnyOrder(tagsFrom("/app", 500, "NullPointerException", "SERVER_ERROR")); - assertThat(tagsProvider.httpRequestTags(event(406, new NotAcceptableException(), "/app", (String[]) null))) + assertThat(tagsProvider.httpRequestTags(event(406, new NotAcceptableException(), "/app", "/"))) .containsExactlyInAnyOrder(tagsFrom("/app", 406, "NotAcceptableException", "CLIENT_ERROR")); assertThat(tagsProvider.httpRequestTags(event(500, new Exception("anonymous") { - }, "/app", (String[]) null))).containsExactlyInAnyOrder(tagsFrom("/app", 500, + }, "/app", "/"))).containsExactlyInAnyOrder(tagsFrom("/app", 500, "io.micrometer.core.instrument.binder.jersey.server.DefaultJerseyTagsProviderTest$1", "SERVER_ERROR")); } @Test void longRequestTags() { - assertThat(tagsProvider.httpLongRequestTags(event(0, null, "/app", (String[]) null))) + assertThat(tagsProvider.httpLongRequestTags(event(0, null, "/app", "/"))) .containsExactlyInAnyOrder(Tag.of("method", "GET"), Tag.of("uri", "/app")); } diff --git a/micrometer-core/src/test/java/io/micrometer/core/instrument/binder/jersey/server/MetricsRequestEventListenerTest.java b/micrometer-core/src/test/java/io/micrometer/core/instrument/binder/jersey/server/MetricsRequestEventListenerTest.java index 70166534b2..23b1224e95 100644 --- a/micrometer-core/src/test/java/io/micrometer/core/instrument/binder/jersey/server/MetricsRequestEventListenerTest.java +++ b/micrometer-core/src/test/java/io/micrometer/core/instrument/binder/jersey/server/MetricsRequestEventListenerTest.java @@ -27,6 +27,7 @@ import javax.ws.rs.NotFoundException; import javax.ws.rs.core.Application; +import javax.ws.rs.core.MediaType; import java.util.logging.Level; import java.util.logging.Logger; @@ -149,6 +150,11 @@ void exceptionsAreMappedCorrectly() { } catch (Exception ignored) { } + try { + target("produces-text-plain").request(MediaType.APPLICATION_JSON).get(); + } + catch (Exception ignored) { + } assertThat(registry.get(METRIC_NAME) .tags(tagsFrom("/throws-exception", "500", "SERVER_ERROR", "IllegalArgumentException")) @@ -164,6 +170,11 @@ void exceptionsAreMappedCorrectly() { .tags(tagsFrom("/throws-mappable-exception", "410", "CLIENT_ERROR", "ResourceGoneException")) .timer() .count()).isEqualTo(1); + + assertThat(registry.get(METRIC_NAME) + .tags(tagsFrom("UNKNOWN", "406", "CLIENT_ERROR", "NotAcceptableException")) + .timer() + .count()).isEqualTo(1); } private static Iterable tagsFrom(String uri, String status, String outcome, String exception) { diff --git a/micrometer-core/src/test/java/io/micrometer/core/instrument/binder/jersey/server/resources/TestResource.java b/micrometer-core/src/test/java/io/micrometer/core/instrument/binder/jersey/server/resources/TestResource.java index bb6e299a73..19ef41a156 100644 --- a/micrometer-core/src/test/java/io/micrometer/core/instrument/binder/jersey/server/resources/TestResource.java +++ b/micrometer-core/src/test/java/io/micrometer/core/instrument/binder/jersey/server/resources/TestResource.java @@ -82,6 +82,13 @@ public String throwsMappableException() { throw new ResourceGoneException("Resource has been permanently removed."); } + @GET + @Path("produces-text-plain") + @Produces(MediaType.TEXT_PLAIN) + public String producesTextPlain() { + return "hello"; + } + @GET @Path("redirect/{status}") public Response redirect(@PathParam("status") int status) {