Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ResponseMeteredLevel parameter to ResponseMetered annotation jersey31 #3116

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -126,19 +133,48 @@ public ExceptionMeterMetric(final MetricRegistry registry,
* different response codes
*/
private static class ResponseMeterMetric {
public final List<Meter> meters;
private static final Set<ResponseMeteredLevel> COARSE_METER_LEVELS = EnumSet.of(COARSE, ALL);
private static final Set<ResponseMeteredLevel> DETAILED_METER_LEVELS = EnumSet.of(DETAILED, ALL);
private final List<Meter> meters;
private final Map<Integer, Meter> 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))));
}
}

Expand Down Expand Up @@ -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());
}
}
}
Expand Down
Expand Up @@ -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
Expand Down
Expand Up @@ -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();
}
}
Expand Up @@ -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 {
Expand Down Expand Up @@ -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")
Expand Down
Expand Up @@ -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
Expand Down