Skip to content

Commit

Permalink
Pass ZIO Metrics histogram boundaries to OTEL (#864)
Browse files Browse the repository at this point in the history
* Pass ZIO Metrics histogram boundaries to OTEL

* Pass ZIO Metrics histogram boundaries to OTEL
  • Loading branch information
andrzejressel authored Jul 30, 2024
1 parent 0fb6733 commit 398aa7b
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import zio._
import zio.telemetry.opentelemetry.context.ContextStorage
import zio.telemetry.opentelemetry.metrics.{Counter, Histogram, ObservableMeasurement, UpDownCounter}

import scala.jdk.CollectionConverters._

trait Instrument[-A] {

def record0(
Expand All @@ -28,7 +30,12 @@ object Instrument {
description: Option[String] = None
): UpDownCounter[Long]

def histogram(name: String, unit: Option[String] = None, description: Option[String] = None): Histogram[Double]
def histogram(
name: String,
unit: Option[String] = None,
description: Option[String] = None,
boundaries: Option[Chunk[Double]] = None
): Histogram[Double]

def observableCounter(
name: String,
Expand Down Expand Up @@ -88,12 +95,14 @@ object Instrument {
override def histogram(
name: String,
unit: Option[String] = None,
description: Option[String] = None
description: Option[String] = None,
boundaries: Option[Chunk[Double]] = None
): Histogram[Double] = {
val builder = meter.histogramBuilder(name)

unit.foreach(builder.setUnit)
description.foreach(builder.setDescription)
boundaries.foreach(seq => builder.setExplicitBucketBoundariesAdvice(seq.map(Double.box).asJava))

Histogram.double(builder.build(), ctxStorage, logAnnotated)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ trait InstrumentRegistry {

def getCounter(key: MetricKey.Counter): Counter[Long]

def getHistorgram(key: MetricKey.Histogram): Histogram[Double]
def getHistogram(key: MetricKey.Histogram): Histogram[Double]

def getGauge(key: MetricKey.Gauge): AtomicDouble

Expand All @@ -33,8 +33,10 @@ private[opentelemetry] object InstrumentRegistry {
def getCounter(key: MetricKey.Counter): Counter[Long] =
getOrCreateInstrument[Counter, Long](key)(builder.counter(key.name, description = key.description))

def getHistorgram(key: MetricKey.Histogram): Histogram[Double] =
getOrCreateInstrument[Histogram, Double](key)(builder.histogram(key.name, description = key.description))
def getHistogram(key: MetricKey.Histogram): Histogram[Double] =
getOrCreateInstrument[Histogram, Double](key)(
builder.histogram(key.name, description = key.description, boundaries = Some(key.keyType.boundaries.values))
)

def getGauge(key: MetricKey.Gauge): AtomicDouble =
gauges.computeIfAbsent(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ private[opentelemetry] object OtelMetricListener {
override def updateHistogram(key: MetricKey[MetricKeyType.Histogram], value: Double)(implicit
unsafe: Unsafe
): Unit =
registry.getHistorgram(key).record0(value, attributes(key.tags))
registry.getHistogram(key).record0(value, attributes(key.tags))

override def updateCounter(key: MetricKey[MetricKeyType.Counter], value: Double)(implicit
unsafe: Unsafe
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package zio.telemetry.opentelemetry.metrics
import io.opentelemetry.sdk.metrics.SdkMeterProvider
import io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader
import zio._
import zio.metrics.Metric
import zio.metrics.MetricKeyType.Histogram.Boundaries
import zio.telemetry.opentelemetry.OpenTelemetry
import zio.telemetry.opentelemetry.common.{Attribute, Attributes}
import zio.telemetry.opentelemetry.context.ContextStorage
import zio.telemetry.opentelemetry.metrics.internal.Instrument
Expand All @@ -16,7 +19,9 @@ object MeterTest extends ZIOSpecDefault {
val inMemoryMetricReaderLayer: ZLayer[Any, Nothing, InMemoryMetricReader] =
ZLayer(ZIO.succeed(InMemoryMetricReader.create()))

def meterLayer(logAnnotated: Boolean = false): ZLayer[InMemoryMetricReader with ContextStorage, Nothing, Meter] = {
def meterLayer(
logAnnotated: Boolean = false
): ZLayer[InMemoryMetricReader with ContextStorage, Nothing, Meter with Instrument.Builder] = {
val jmeter = ZLayer {
for {
metricReader <- ZIO.service[InMemoryMetricReader]
Expand All @@ -26,7 +31,7 @@ object MeterTest extends ZIOSpecDefault {
}
val builder = jmeter >>> Instrument.Builder.live(logAnnotated)

builder >>> Meter.live
builder >+> Meter.live
}

val observableRefLayer: ULayer[Ref[Long]] =
Expand All @@ -45,7 +50,8 @@ object MeterTest extends ZIOSpecDefault {
suite("Meter")(
normalSpec,
contextualSpec,
logAnnotatedSpec
logAnnotatedSpec,
zioMetricsSpec
)
)

Expand Down Expand Up @@ -216,4 +222,19 @@ object MeterTest extends ZIOSpecDefault {
}
).provide(inMemoryMetricReaderLayer, meterLayer(logAnnotated = true), ContextStorage.fiberRef)

private val zioMetricsSpec =
suite("ZIO metrics integration")(
test("histogram boundaries should be passed to OTEL") {
val histogram = Metric.histogram("test_histogram", Boundaries(Chunk(1, 2, 3)))

for {
reader <- ZIO.service[InMemoryMetricReader]
_ <- histogram.update(2.0)
metric = reader.collectAllMetrics().asScala.find(_.getName == "test_histogram").get
metricPoint = metric.getHistogramData().getPoints().asScala.toList.head
boundaries = metricPoint.getBoundaries.asScala.map(_.toDouble).toSeq
} yield assertTrue(boundaries == Seq(1.0, 2.0, 3.0))
}
).provide(inMemoryMetricReaderLayer, meterLayer(), ContextStorage.fiberRef, OpenTelemetry.zioMetrics)

}

0 comments on commit 398aa7b

Please sign in to comment.