From 7077a4dce180713c6925b71ff064e2cd8bc7d411 Mon Sep 17 00:00:00 2001 From: Nicu Reut Date: Tue, 1 Nov 2022 16:28:53 +0100 Subject: [PATCH] Add global labels to the OpenTelemetry metrics implementation [PLEN-5] (#15407) --- ledger/metrics/BUILD.bazel | 1 + .../com/daml/metrics/api/MetricsContext.scala | 2 + .../opentelemetry/OpenTelemetryFactory.scala | 18 ++++--- .../daml/metrics/api/MetricsContextSpec.scala | 47 +++++++++++++++++++ 4 files changed, 62 insertions(+), 6 deletions(-) create mode 100644 ledger/metrics/src/test/suite/scala/com/daml/metrics/api/MetricsContextSpec.scala diff --git a/ledger/metrics/BUILD.bazel b/ledger/metrics/BUILD.bazel index e8c5f552e5..9cabfedd1f 100644 --- a/ledger/metrics/BUILD.bazel +++ b/ledger/metrics/BUILD.bazel @@ -24,6 +24,7 @@ da_scala_library( runtime_deps = [], deps = [ "//ledger/ledger-resources", + "//libs-scala/build-info", "//libs-scala/concurrent", "//libs-scala/resources", "//libs-scala/resources-akka", diff --git a/ledger/metrics/src/main/scala/com/daml/metrics/api/MetricsContext.scala b/ledger/metrics/src/main/scala/com/daml/metrics/api/MetricsContext.scala index a0ebcf7271..5a3419d152 100644 --- a/ledger/metrics/src/main/scala/com/daml/metrics/api/MetricsContext.scala +++ b/ledger/metrics/src/main/scala/com/daml/metrics/api/MetricsContext.scala @@ -15,6 +15,8 @@ case class MetricsContext(labels: Map[String, String]) { .build() } + def merge(context: MetricsContext): MetricsContext = this.copy(labels = labels ++ context.labels) + } object MetricsContext { diff --git a/ledger/metrics/src/main/scala/com/daml/metrics/api/opentelemetry/OpenTelemetryFactory.scala b/ledger/metrics/src/main/scala/com/daml/metrics/api/opentelemetry/OpenTelemetryFactory.scala index a3de5540ce..e06e54829a 100644 --- a/ledger/metrics/src/main/scala/com/daml/metrics/api/opentelemetry/OpenTelemetryFactory.scala +++ b/ledger/metrics/src/main/scala/com/daml/metrics/api/opentelemetry/OpenTelemetryFactory.scala @@ -6,6 +6,7 @@ package com.daml.metrics.api.opentelemetry import java.time.Duration import java.util.concurrent.TimeUnit +import com.daml.buildinfo.BuildInfo import com.daml.metrics.api.Gauges.VarGauge import com.daml.metrics.api.MetricHandle.Timer.TimerHandle import com.daml.metrics.api.MetricHandle.{Counter, Factory, Gauge, Histogram, Meter, Timer} @@ -20,7 +21,12 @@ import io.opentelemetry.api.metrics.{ trait OpenTelemetryFactory extends Factory { + val globalMetricsContext: MetricsContext = MetricsContext( + Map("daml_version" -> BuildInfo.Version) + ) + def otelMeter: OtelMeter + override def timer( name: MetricName )(implicit @@ -29,12 +35,12 @@ trait OpenTelemetryFactory extends Factory { OpentelemetryTimer( name, otelMeter.histogramBuilder(name).ofLongs().setUnit("ms").build(), - context, + globalMetricsContext.merge(context), ) override def gauge[T](name: MetricName, initial: T)(implicit context: MetricsContext = MetricsContext.Empty ): MetricHandle.Gauge[T] = { - val attributes = context.asAttributes + val attributes = globalMetricsContext.merge(context).asAttributes initial match { case longInitial: Int => val varGauge = new VarGauge[Int](longInitial) @@ -67,7 +73,7 @@ trait OpenTelemetryFactory extends Factory { context: MetricsContext = MetricsContext.Empty ): Unit = { val value = valueSupplier() - val attributes = context.asAttributes + val attributes = globalMetricsContext.merge(context).asAttributes value match { case _: Int => otelMeter @@ -104,21 +110,21 @@ trait OpenTelemetryFactory extends Factory { ): Meter = OpentelemetryMeter( name, otelMeter.counterBuilder(name).build(), - context, + globalMetricsContext.merge(context), ) override def counter(name: MetricName)(implicit context: MetricsContext = MetricsContext.Empty ): MetricHandle.Counter = OpentelemetryCounter( name, otelMeter.upDownCounterBuilder(name).build(), - context, + globalMetricsContext.merge(context), ) override def histogram(name: MetricName)(implicit context: MetricsContext = MetricsContext.Empty ): MetricHandle.Histogram = OpentelemetryHistogram( name, otelMeter.histogramBuilder(name).ofLongs().build(), - context, + globalMetricsContext.merge(context), ) } diff --git a/ledger/metrics/src/test/suite/scala/com/daml/metrics/api/MetricsContextSpec.scala b/ledger/metrics/src/test/suite/scala/com/daml/metrics/api/MetricsContextSpec.scala new file mode 100644 index 0000000000..c053e2e207 --- /dev/null +++ b/ledger/metrics/src/test/suite/scala/com/daml/metrics/api/MetricsContextSpec.scala @@ -0,0 +1,47 @@ +// Copyright (c) 2022 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.daml.metrics.api + +import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpec + +class MetricsContextSpec extends AnyWordSpec with Matchers { + + "merging metrics contexts" should { + + "merge all labels" in { + MetricsContext( + Map("key" -> "value") + ).merge( + MetricsContext( + Map("key2" -> "value") + ) + ) should equal( + MetricsContext( + Map( + "key" -> "value", + "key2" -> "value", + ) + ) + ) + } + + "handle duplicate labels" in { + MetricsContext( + Map("key" -> "value1") + ).merge( + MetricsContext( + Map("key" -> "value2") + ) + ) should equal( + MetricsContext( + Map( + "key" -> "value2" + ) + ) + ) + } + } + +}