RequestMetricSupport { public static void setup(RequestContext ctx, AttributeKey<Boolean> requestMetricsSetKey, MeterIdPrefixFunction meterIdPrefixFunction, boolean server) { final Boolean isRequestMetricsSet = ctx.attr(requestMetricsSetKey); if (Boolean.TRUE.equals(isRequestMetricsSet)) { return; } ctx.setAttr(requestMetricsSetKey, true); ctx.log() .whenAvailable(RequestLogProperty.REQUEST_START_TIME, RequestLogProperty.REQUEST_HEADERS, RequestLogProperty.NAME, RequestLogProperty.SESSION) .thenAccept(log -> onRequest(log, meterIdPrefixFunction, server)); } private  RequestMetricSupport(); static void setup(RequestContext ctx, AttributeKey<Boolean> requestMetricsSetKey,
                             MeterIdPrefixFunction meterIdPrefixFunction, boolean server);  }
@Test void requestTimedOutInServerSide() { final MeterRegistry registry = PrometheusMeterRegistries.newRegistry(); final ServiceRequestContext ctx = ServiceRequestContext.builder(HttpRequest.of(HttpMethod.POST, "/foo")) .meterRegistry(registry) .build(); final String serviceTag = "service=" + ctx.config().service().getClass().getName(); final MeterIdPrefixFunction meterIdPrefixFunction = MeterIdPrefixFunction.ofDefault("foo"); RequestMetricSupport.setup(ctx, REQUEST_METRICS_SET, meterIdPrefixFunction, true); ctx.logBuilder().requestFirstBytesTransferred(); ctx.logBuilder().responseHeaders(ResponseHeaders.of(503)); ctx.logBuilder().responseFirstBytesTransferred(); ctx.logBuilder().responseLength(456); ctx.logBuilder().endRequest(); ctx.logBuilder().endResponse(RequestTimeoutException.get()); final Map<String, Double> measurements = measureAll(registry); assertThat(measurements) .containsEntry("foo.active.requests#value{hostname.pattern=*,method=POST," + serviceTag + '}', 0.0) .containsEntry("foo.requests#count{hostname.pattern=*,http.status=503,method=POST," + "result=success," + serviceTag + '}', 0.0) .containsEntry("foo.requests#count{hostname.pattern=*,http.status=503,method=POST," + "result=failure," + serviceTag + '}', 1.0) .containsEntry("foo.timeouts#count{cause=RequestTimeoutException,hostname.pattern=*," + "http.status=503,method=POST," + serviceTag + '}', 1.0) .containsEntry("foo.response.duration#count{hostname.pattern=*,http.status=503,method=POST," + serviceTag + '}', 1.0) .containsEntry("foo.response.length#count{hostname.pattern=*,http.status=503,method=POST," + serviceTag + '}', 1.0) .containsEntry("foo.total.duration#count{hostname.pattern=*,http.status=503,method=POST," + serviceTag + '}', 1.0); }
@Test void rpc() { final MeterRegistry registry = PrometheusMeterRegistries.newRegistry(); final ClientRequestContext ctx = ClientRequestContext.builder(HttpRequest.of(HttpMethod.POST, "/bar")) .meterRegistry(registry) .endpoint(Endpoint.of("example.com", 8080)) .build(); final MeterIdPrefixFunction meterIdPrefixFunction = MeterIdPrefixFunction.ofDefault("bar"); RequestMetricSupport.setup(ctx, REQUEST_METRICS_SET, meterIdPrefixFunction, false); ctx.logBuilder().name("BarService", "baz"); assertThat(measureAll(registry)) .containsEntry("bar.active.requests#value{method=baz,service=BarService}", 1.0); }
@Test void serviceAndClientContext() { final MeterRegistry registry = PrometheusMeterRegistries.newRegistry(); final ServiceRequestContext sctx = ServiceRequestContext.builder(HttpRequest.of(HttpMethod.POST, "/foo")) .meterRegistry(registry) .build(); final String serviceTag = "service=" + sctx.config().service().getClass().getName(); RequestMetricSupport.setup(sctx, REQUEST_METRICS_SET, MeterIdPrefixFunction.ofDefault("foo"), true); sctx.logBuilder().endRequest(); try (SafeCloseable ignored = sctx.push()) { final ClientRequestContext cctx = ClientRequestContext.builder(HttpRequest.of(HttpMethod.POST, "/foo")) .meterRegistry(registry) .endpoint(Endpoint.of("example.com", 8080)) .build(); RequestMetricSupport.setup(cctx, AttributeKey.valueOf("differentKey"), MeterIdPrefixFunction.ofDefault("bar"), false); cctx.logBuilder().endRequest(); cctx.logBuilder().responseHeaders(ResponseHeaders.of(200)); cctx.logBuilder().endResponse(); } sctx.logBuilder().responseHeaders(ResponseHeaders.of(200)); sctx.logBuilder().endResponse(); final Map<String, Double> measurements = measureAll(registry); assertThat(measurements) .containsEntry("bar.active.requests#value{method=POST,service=none}", 0.0) .containsEntry("bar.requests#count{http.status=200,method=POST,result=success,service=none}", 1.0) .containsEntry("bar.requests#count{http.status=200,method=POST,result=failure,service=none}", 0.0) .containsEntry("bar.response.duration#count{http.status=200,method=POST,service=none}", 1.0) .containsEntry("bar.response.length#count{http.status=200,method=POST,service=none}", 1.0) .containsEntry("bar.total.duration#count{http.status=200,method=POST,service=none}", 1.0) .containsEntry("foo.active.requests#value{hostname.pattern=*,method=POST," + serviceTag + '}', 0.0) .containsEntry("foo.requests#count{hostname.pattern=*,http.status=200,method=POST," + "result=success," + serviceTag + '}', 1.0) .containsEntry("foo.requests#count{hostname.pattern=*,http.status=200,method=POST," + "result=failure," + serviceTag + '}', 0.0) .containsEntry("foo.response.duration#count{hostname.pattern=*,http.status=200,method=POST," + serviceTag + '}', 1.0) .containsEntry("foo.response.length#count{hostname.pattern=*,http.status=200,method=POST," + serviceTag + '}', 1.0) .containsEntry("foo.total.duration#count{hostname.pattern=*,http.status=200,method=POST," + serviceTag + '}', 1.0); }