From b0b8579199594fae502ae77dd4acba4cbdbc951b Mon Sep 17 00:00:00 2001 From: Denny Abraham Cheriyan Date: Fri, 13 Jan 2023 00:37:32 -0800 Subject: [PATCH] Add ResponseMeteredLevel parameter to ResponseMetered annotation jersey31 --- ...ntedResourceMethodApplicationListener.java | 65 ++++++++++++----- .../jersey31/SingletonMetricsJerseyTest.java | 71 ++++++++++++++----- ...ricsResponseMeteredPerClassJerseyTest.java | 15 ++-- .../resources/InstrumentedResource.java | 28 ++++---- ...tedSubResourceResponseMeteredPerClass.java | 4 +- 5 files changed, 131 insertions(+), 52 deletions(-) diff --git a/metrics-jersey31/src/main/java/io/dropwizard/metrics/jersey31/InstrumentedResourceMethodApplicationListener.java b/metrics-jersey31/src/main/java/io/dropwizard/metrics/jersey31/InstrumentedResourceMethodApplicationListener.java index 4f14f116f6..71a935b969 100644 --- a/metrics-jersey31/src/main/java/io/dropwizard/metrics/jersey31/InstrumentedResourceMethodApplicationListener.java +++ b/metrics-jersey31/src/main/java/io/dropwizard/metrics/jersey31/InstrumentedResourceMethodApplicationListener.java @@ -9,6 +9,7 @@ import com.codahale.metrics.annotation.ExceptionMetered; import com.codahale.metrics.annotation.Metered; import com.codahale.metrics.annotation.ResponseMetered; +import com.codahale.metrics.annotation.ResponseMeteredLevel; import com.codahale.metrics.annotation.Timed; import jakarta.ws.rs.core.Configuration; import jakarta.ws.rs.ext.Provider; @@ -26,13 +27,19 @@ import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collections; +import java.util.EnumSet; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; import static com.codahale.metrics.MetricRegistry.name; +import static com.codahale.metrics.annotation.ResponseMeteredLevel.ALL; +import static com.codahale.metrics.annotation.ResponseMeteredLevel.COARSE; +import static com.codahale.metrics.annotation.ResponseMeteredLevel.DETAILED; /** * An application event listener that listens for Jersey application initialization to @@ -126,19 +133,48 @@ public ExceptionMeterMetric(final MetricRegistry registry, * different response codes */ private static class ResponseMeterMetric { - public final List meters; + private static final Set COARSE_METER_LEVELS = EnumSet.of(COARSE, ALL); + private static final Set DETAILED_METER_LEVELS = EnumSet.of(DETAILED, ALL); + private final List meters; + private final Map responseCodeMeters; + private final MetricRegistry metricRegistry; + private final String metricName; + private final ResponseMeteredLevel level; public ResponseMeterMetric(final MetricRegistry registry, final ResourceMethod method, final ResponseMetered responseMetered) { - final String metricName = chooseName(responseMetered.name(), responseMetered.absolute(), method); - this.meters = Collections.unmodifiableList(Arrays.asList( - registry.meter(name(metricName, "1xx-responses")), // 1xx - registry.meter(name(metricName, "2xx-responses")), // 2xx - registry.meter(name(metricName, "3xx-responses")), // 3xx - registry.meter(name(metricName, "4xx-responses")), // 4xx - registry.meter(name(metricName, "5xx-responses")) // 5xx - )); + this.metricName = chooseName(responseMetered.name(), responseMetered.absolute(), method); + this.level = responseMetered.level(); + this.meters = COARSE_METER_LEVELS.contains(level) ? + Collections.unmodifiableList(Arrays.asList( + registry.meter(name(metricName, "1xx-responses")), // 1xx + registry.meter(name(metricName, "2xx-responses")), // 2xx + registry.meter(name(metricName, "3xx-responses")), // 3xx + registry.meter(name(metricName, "4xx-responses")), // 4xx + registry.meter(name(metricName, "5xx-responses")) // 5xx + )) : Collections.emptyList(); + this.responseCodeMeters = DETAILED_METER_LEVELS.contains(level) ? new ConcurrentHashMap<>() : Collections.emptyMap(); + this.metricRegistry = registry; + } + + public void mark(int statusCode) { + if (DETAILED_METER_LEVELS.contains(level)) { + getResponseCodeMeter(statusCode).mark(); + } + + if (COARSE_METER_LEVELS.contains(level)) { + final int responseStatus = statusCode / 100; + if (responseStatus >= 1 && responseStatus <= 5) { + meters.get(responseStatus - 1).mark(); + } + } + } + + private Meter getResponseCodeMeter(int statusCode) { + return responseCodeMeters + .computeIfAbsent(statusCode, sc -> metricRegistry + .meter(name(metricName, String.format("%d-responses", sc)))); } } @@ -270,15 +306,10 @@ public void onEvent(RequestEvent event) { if (metric != null) { ContainerResponse containerResponse = event.getContainerResponse(); - if (containerResponse == null) { - if (event.getException() != null) { - metric.meters.get(4).mark(); - } + if (containerResponse == null && event.getException() != null) { + metric.mark(500); } else { - final int responseStatus = containerResponse.getStatus() / 100; - if (responseStatus >= 1 && responseStatus <= 5) { - metric.meters.get(responseStatus - 1).mark(); - } + metric.mark(containerResponse.getStatus()); } } } diff --git a/metrics-jersey31/src/test/java/io/dropwizard/metrics/jersey31/SingletonMetricsJerseyTest.java b/metrics-jersey31/src/test/java/io/dropwizard/metrics/jersey31/SingletonMetricsJerseyTest.java index 11c0d4ce9a..e96fd56375 100644 --- a/metrics-jersey31/src/test/java/io/dropwizard/metrics/jersey31/SingletonMetricsJerseyTest.java +++ b/metrics-jersey31/src/test/java/io/dropwizard/metrics/jersey31/SingletonMetricsJerseyTest.java @@ -95,38 +95,73 @@ public void exceptionMeteredMethodsAreExceptionMetered() { } @Test - public void responseMeteredMethodsAreMetered() { + public void responseMeteredMethodsAreMeteredWithCoarseLevel() { final Meter meter2xx = registry.meter(name(InstrumentedResource.class, - "response2xxMetered", + "responseMeteredCoarse", "2xx-responses")); - final Meter meter4xx = registry.meter(name(InstrumentedResource.class, - "response4xxMetered", - "4xx-responses")); - final Meter meter5xx = registry.meter(name(InstrumentedResource.class, - "response5xxMetered", - "5xx-responses")); + final Meter meter200 = registry.meter(name(InstrumentedResource.class, + "responseMeteredCoarse", + "200-responses")); assertThat(meter2xx.getCount()).isZero(); - assertThat(target("response-2xx-metered") + assertThat(meter200.getCount()).isZero(); + assertThat(target("response-metered-coarse") .request() .get().getStatus()) .isEqualTo(200); - assertThat(meter4xx.getCount()).isZero(); - assertThat(target("response-4xx-metered") + assertThat(meter2xx.getCount()).isOne(); + assertThat(meter200.getCount()).isZero(); + } + + @Test + public void responseMeteredMethodsAreMeteredWithDetailedLevel() { + final Meter meter2xx = registry.meter(name(InstrumentedResource.class, + "responseMeteredDetailed", + "2xx-responses")); + final Meter meter200 = registry.meter(name(InstrumentedResource.class, + "responseMeteredDetailed", + "200-responses")); + final Meter meter201 = registry.meter(name(InstrumentedResource.class, + "responseMeteredDetailed", + "201-responses")); + + assertThat(meter2xx.getCount()).isZero(); + assertThat(meter200.getCount()).isZero(); + assertThat(meter201.getCount()).isZero(); + assertThat(target("response-metered-detailed") + .request() + .get().getStatus()) + .isEqualTo(200); + assertThat(target("response-metered-detailed") + .queryParam("status_code", 201) .request() .get().getStatus()) - .isEqualTo(400); + .isEqualTo(201); - assertThat(meter5xx.getCount()).isZero(); - assertThat(target("response-5xx-metered") + assertThat(meter2xx.getCount()).isZero(); + assertThat(meter200.getCount()).isOne(); + assertThat(meter201.getCount()).isOne(); + } + + @Test + public void responseMeteredMethodsAreMeteredWithAllLevel() { + final Meter meter2xx = registry.meter(name(InstrumentedResource.class, + "responseMeteredAll", + "2xx-responses")); + final Meter meter200 = registry.meter(name(InstrumentedResource.class, + "responseMeteredAll", + "200-responses")); + + assertThat(meter2xx.getCount()).isZero(); + assertThat(meter200.getCount()).isZero(); + assertThat(target("response-metered-all") .request() .get().getStatus()) - .isEqualTo(500); + .isEqualTo(200); - assertThat(meter2xx.getCount()).isEqualTo(1); - assertThat(meter4xx.getCount()).isEqualTo(1); - assertThat(meter5xx.getCount()).isEqualTo(1); + assertThat(meter2xx.getCount()).isOne(); + assertThat(meter200.getCount()).isOne(); } @Test diff --git a/metrics-jersey31/src/test/java/io/dropwizard/metrics/jersey31/SingletonMetricsResponseMeteredPerClassJerseyTest.java b/metrics-jersey31/src/test/java/io/dropwizard/metrics/jersey31/SingletonMetricsResponseMeteredPerClassJerseyTest.java index 7836bb9ffd..4aa38774b9 100644 --- a/metrics-jersey31/src/test/java/io/dropwizard/metrics/jersey31/SingletonMetricsResponseMeteredPerClassJerseyTest.java +++ b/metrics-jersey31/src/test/java/io/dropwizard/metrics/jersey31/SingletonMetricsResponseMeteredPerClassJerseyTest.java @@ -126,14 +126,21 @@ public void responseMeteredUnmappedExceptionPerClassMethodsAreMetered() { @Test public void subresourcesFromLocatorsRegisterMetrics() { + final Meter meter2xx = registry.meter(name(InstrumentedSubResourceResponseMeteredPerClass.class, + "responseMeteredPerClass", + "2xx-responses")); + final Meter meter200 = registry.meter(name(InstrumentedSubResourceResponseMeteredPerClass.class, + "responseMeteredPerClass", + "200-responses")); + + assertThat(meter2xx.getCount()).isZero(); + assertThat(meter200.getCount()).isZero(); assertThat(target("subresource/responseMeteredPerClass") .request() .get().getStatus()) .isEqualTo(200); - final Meter meter = registry.meter(name(InstrumentedSubResourceResponseMeteredPerClass.class, - "responseMeteredPerClass", - "2xx-responses")); - assertThat(meter.getCount()).isEqualTo(1); + assertThat(meter2xx.getCount()).isOne(); + assertThat(meter200.getCount()).isOne(); } } diff --git a/metrics-jersey31/src/test/java/io/dropwizard/metrics/jersey31/resources/InstrumentedResource.java b/metrics-jersey31/src/test/java/io/dropwizard/metrics/jersey31/resources/InstrumentedResource.java index 7d346777d1..60e3efb2c2 100644 --- a/metrics-jersey31/src/test/java/io/dropwizard/metrics/jersey31/resources/InstrumentedResource.java +++ b/metrics-jersey31/src/test/java/io/dropwizard/metrics/jersey31/resources/InstrumentedResource.java @@ -14,6 +14,10 @@ import java.io.IOException; +import static com.codahale.metrics.annotation.ResponseMeteredLevel.ALL; +import static com.codahale.metrics.annotation.ResponseMeteredLevel.COARSE; +import static com.codahale.metrics.annotation.ResponseMeteredLevel.DETAILED; + @Path("/") @Produces(MediaType.TEXT_PLAIN) public class InstrumentedResource { @@ -42,24 +46,24 @@ public String exceptionMetered(@QueryParam("splode") @DefaultValue("false") bool } @GET - @ResponseMetered - @Path("/response-2xx-metered") - public Response response2xxMetered() { - return Response.ok().build(); + @ResponseMetered(level = DETAILED) + @Path("/response-metered-detailed") + public Response responseMeteredDetailed(@QueryParam("status_code") @DefaultValue("200") int statusCode) { + return Response.status(Response.Status.fromStatusCode(statusCode)).build(); } @GET - @ResponseMetered - @Path("/response-4xx-metered") - public Response response4xxMetered() { - return Response.status(Response.Status.BAD_REQUEST).build(); + @ResponseMetered(level = COARSE) + @Path("/response-metered-coarse") + public Response responseMeteredCoarse(@QueryParam("status_code") @DefaultValue("200") int statusCode) { + return Response.status(Response.Status.fromStatusCode(statusCode)).build(); } @GET - @ResponseMetered - @Path("/response-5xx-metered") - public Response response5xxMetered() { - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); + @ResponseMetered(level = ALL) + @Path("/response-metered-all") + public Response responseMeteredAll(@QueryParam("status_code") @DefaultValue("200") int statusCode) { + return Response.status(Response.Status.fromStatusCode(statusCode)).build(); } @Path("/subresource") diff --git a/metrics-jersey31/src/test/java/io/dropwizard/metrics/jersey31/resources/InstrumentedSubResourceResponseMeteredPerClass.java b/metrics-jersey31/src/test/java/io/dropwizard/metrics/jersey31/resources/InstrumentedSubResourceResponseMeteredPerClass.java index 31bbf6a85d..cf429599bc 100644 --- a/metrics-jersey31/src/test/java/io/dropwizard/metrics/jersey31/resources/InstrumentedSubResourceResponseMeteredPerClass.java +++ b/metrics-jersey31/src/test/java/io/dropwizard/metrics/jersey31/resources/InstrumentedSubResourceResponseMeteredPerClass.java @@ -7,7 +7,9 @@ import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; -@ResponseMetered +import static com.codahale.metrics.annotation.ResponseMeteredLevel.ALL; + +@ResponseMetered(level = ALL) @Produces(MediaType.TEXT_PLAIN) public class InstrumentedSubResourceResponseMeteredPerClass { @GET