diff --git a/metrics/opentelemetry-metrics/src/main/scala/sttp/tapir/server/metrics/opentelemetry/OpenTelemetryMetrics.scala b/metrics/opentelemetry-metrics/src/main/scala/sttp/tapir/server/metrics/opentelemetry/OpenTelemetryMetrics.scala index 9389c4c121..dfec33b98a 100644 --- a/metrics/opentelemetry-metrics/src/main/scala/sttp/tapir/server/metrics/opentelemetry/OpenTelemetryMetrics.scala +++ b/metrics/opentelemetry-metrics/src/main/scala/sttp/tapir/server/metrics/opentelemetry/OpenTelemetryMetrics.scala @@ -80,15 +80,28 @@ object OpenTelemetryMetrics { def requestActive[F[_]](meter: Meter, labels: MetricLabels): Metric[F, LongUpDownCounter] = Metric[F, LongUpDownCounter]( meter - .upDownCounterBuilder("request_active") + .upDownCounterBuilder("http.server.active_requests") .setDescription("Active HTTP requests") .setUnit("1") .build(), onRequest = (req, counter, m) => { m.unit { EndpointMetric() - .onEndpointRequest { ep => m.eval(counter.add(1, asOpenTelemetryAttributes(labels, ep, req))) } - .onResponseBody { (ep, _) => m.eval(counter.add(-1, asOpenTelemetryAttributes(labels, ep, req))) } + .onEndpointRequest { ep => + m.eval { + val attrs = asOpenTelemetryAttributes(labels, ep, req) + println(s"[DEBUG] Incrementing active requests with attributes: $attrs") + + counter.add(1, attrs) + } + } + .onResponseBody { (ep, _) => + m.eval { + val attrs = asOpenTelemetryAttributes(labels, ep, req) + println(s"[DEBUG] Decrementing active requests with attributes: $attrs") + counter.add(-1, attrs) + } + } .onException { (ep, _) => m.eval(counter.add(-1, asOpenTelemetryAttributes(labels, ep, req))) } } } @@ -97,7 +110,7 @@ object OpenTelemetryMetrics { def requestTotal[F[_]](meter: Meter, labels: MetricLabels): Metric[F, LongCounter] = Metric[F, LongCounter]( meter - .counterBuilder("request_total") + .counterBuilder("http.server.request.total") .setDescription("Total HTTP requests") .setUnit("1") .build(), @@ -106,8 +119,11 @@ object OpenTelemetryMetrics { EndpointMetric() .onResponseBody { (ep, res) => m.eval { - val otLabels = + val otLabels: Attributes = merge(asOpenTelemetryAttributes(labels, ep, req), asOpenTelemetryAttributes(labels, Right(res), None)) + + println(s"[DEBUG] Incrementing total requests with labels: $otLabels") + counter.add(1, otLabels) } } @@ -125,14 +141,14 @@ object OpenTelemetryMetrics { def requestDuration[F[_]](meter: Meter, labels: MetricLabels): Metric[F, DoubleHistogram] = Metric[F, DoubleHistogram]( meter - .histogramBuilder("request_duration") + .histogramBuilder("http.server.request.duration") .setDescription("Duration of HTTP requests") - .setUnit("ms") + .setUnit("s") .build(), onRequest = (req, recorder, m) => m.eval { val requestStart = Instant.now() - def duration = Duration.between(requestStart, Instant.now()).toMillis.toDouble + def duration = Duration.between(requestStart, Instant.now()).toMillis.toDouble / 1000.0 EndpointMetric() .onResponseHeaders { (ep, res) => m.eval { diff --git a/metrics/opentelemetry-metrics/src/test/scala/sttp/tapir/server/metrics/opentelemetry/OpenTelemetryMetricsTest.scala b/metrics/opentelemetry-metrics/src/test/scala/sttp/tapir/server/metrics/opentelemetry/OpenTelemetryMetricsTest.scala index fcc096a963..4581b09594 100644 --- a/metrics/opentelemetry-metrics/src/test/scala/sttp/tapir/server/metrics/opentelemetry/OpenTelemetryMetricsTest.scala +++ b/metrics/opentelemetry-metrics/src/test/scala/sttp/tapir/server/metrics/opentelemetry/OpenTelemetryMetricsTest.scala @@ -25,7 +25,7 @@ import scala.concurrent.Future class OpenTelemetryMetricsTest extends AnyFlatSpec with Matchers { - "default metrics" should "collect requests active" in { + "default metrics" should "collect http.server.active_requests" in { // given val reader = InMemoryMetricReader.create() val provider = SdkMeterProvider.builder().registerMetricReader(reader).build() @@ -51,17 +51,27 @@ class OpenTelemetryMetricsTest extends AnyFlatSpec with Matchers { // then val point = longSumData(reader).head - point.getAttributes shouldBe Attributes.of(AttributeKey.stringKey("method"), "GET", AttributeKey.stringKey("path"), "/person") + point.getAttributes shouldBe Attributes.of( + AttributeKey.stringKey("http.request.method"), + "GET", + AttributeKey.stringKey("path"), + "/person" + ) point.getValue shouldBe 1 ScalaFutures.whenReady(response, Timeout(Span(3, Seconds))) { _ => val point = longSumData(reader).head - point.getAttributes shouldBe Attributes.of(AttributeKey.stringKey("method"), "GET", AttributeKey.stringKey("path"), "/person") + point.getAttributes shouldBe Attributes.of( + AttributeKey.stringKey("http.request.method"), + "GET", + AttributeKey.stringKey("path"), + "/person" + ) point.getValue shouldBe 0 } } - "default metrics" should "collect requests total" in { + "default metrics" should "collect http.server.request.total" in { // given val reader = InMemoryMetricReader.create() val provider = SdkMeterProvider.builder().registerMetricReader(reader).build() @@ -87,29 +97,29 @@ class OpenTelemetryMetricsTest extends AnyFlatSpec with Matchers { .count { case dp if dp.getAttributes == Attributes.of( - AttributeKey.stringKey("method"), + AttributeKey.stringKey("http.request.method"), "GET", AttributeKey.stringKey("path"), "/person", - AttributeKey.stringKey("status"), - "2xx" + AttributeKey.longKey("http.response.status_code").asInstanceOf[AttributeKey[Long]], // Explicitly cast to Long + 200L ) && dp.getValue == 2 => true case dp if dp.getAttributes == Attributes.of( - AttributeKey.stringKey("method"), + AttributeKey.stringKey("http.request.method"), "GET", AttributeKey.stringKey("path"), "/person", - AttributeKey.stringKey("status"), - "4xx" + AttributeKey.longKey("http.response.status_code").asInstanceOf[AttributeKey[Long]], // Explicitly cast to Long + 400L ) && dp.getValue == 2 => true case _ => false } shouldBe 2 } - "default metrics" should "collect requests duration" in { + "default metrics" should "collect http.server.request.duration" in { // given val reader = InMemoryMetricReader.create() val provider = SdkMeterProvider.builder().registerMetricReader(reader).build() @@ -140,14 +150,12 @@ class OpenTelemetryMetricsTest extends AnyFlatSpec with Matchers { val point = reader.collectAllMetrics().asScala.head.getHistogramData.getPoints.asScala point.map(_.getAttributes) should contain( Attributes.of( - AttributeKey.stringKey("method"), + AttributeKey.stringKey("http.request.method"), "GET", AttributeKey.stringKey("path"), "/person", - AttributeKey.stringKey("status"), - "2xx", - AttributeKey.stringKey("phase"), - "body" + AttributeKey.longKey("http.response.status_code").asInstanceOf[AttributeKey[Long]], // Explicitly cast to Long + 200L ) ) } @@ -197,12 +205,12 @@ class OpenTelemetryMetricsTest extends AnyFlatSpec with Matchers { // then val point = longSumData(reader).head point.getAttributes shouldBe Attributes.of( - AttributeKey.stringKey("method"), + AttributeKey.stringKey("http.request.method"), "GET", AttributeKey.stringKey("path"), "/person", - AttributeKey.stringKey("status"), - "5xx" + AttributeKey.longKey("http.response.status_code").asInstanceOf[AttributeKey[Long]], // Explicitly cast to Long + 500L ) point.getValue shouldBe 1 }