All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jvmMain.aws.smithy.kotlin.runtime.telemetry.otel.OtelMeterProvider.kt Maven / Gradle / Ivy

There is a newer version: 1.3.25
Show newest version
/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0
 */

package aws.smithy.kotlin.runtime.telemetry.otel

import aws.smithy.kotlin.runtime.collections.Attributes
import aws.smithy.kotlin.runtime.telemetry.context.Context
import aws.smithy.kotlin.runtime.telemetry.metrics.*
import io.opentelemetry.api.OpenTelemetry
import io.opentelemetry.api.metrics.ObservableDoubleMeasurement
import io.opentelemetry.api.metrics.ObservableLongMeasurement
import io.opentelemetry.api.metrics.DoubleHistogram as OtelDoubleHistogram
import io.opentelemetry.api.metrics.LongCounter as OtelLongCounter
import io.opentelemetry.api.metrics.LongHistogram as OtelLongHistogram
import io.opentelemetry.api.metrics.LongUpDownCounter as OtelLongUpDownCounter
import io.opentelemetry.api.metrics.Meter as OpenTelemetryMeter

internal class OtelMeterProvider(private val otel: OpenTelemetry) : MeterProvider {
    override fun getOrCreateMeter(scope: String): Meter {
        val meter = otel.getMeter(scope)
        return OtelMeter(meter)
    }
}

private class OtelMeter(
    private val otelMeter: OpenTelemetryMeter,
) : Meter {
    override fun createUpDownCounter(name: String, units: String?, description: String?): UpDownCounter {
        val counter = otelMeter.upDownCounterBuilder(name)
            .apply {
                description?.let { setDescription(it) }
                units?.let { setUnit(units) }
            }
            .build()
        return OtelUpDownCounterImpl(counter)
    }

    override fun createAsyncUpDownCounter(
        name: String,
        callback: LongUpDownCounterCallback,
        units: String?,
        description: String?,
    ): AsyncMeasurementHandle {
        val observer = otelMeter.upDownCounterBuilder(name)
            .apply {
                description?.let { setDescription(it) }
                units?.let { setUnit(units) }
            }
            .buildWithCallback {
                callback(OtelLongAsyncMeasurementImpl(it))
            }

        return OtelAsyncMeasurementHandleImpl(observer)
    }

    override fun createMonotonicCounter(name: String, units: String?, description: String?): MonotonicCounter {
        val counter = otelMeter.counterBuilder(name)
            .apply {
                description?.let { setDescription(it) }
                units?.let { setUnit(units) }
            }
            .build()
        return OtelMonotonicCounterImpl(counter)
    }

    override fun createLongHistogram(name: String, units: String?, description: String?): LongHistogram {
        val hist = otelMeter.histogramBuilder(name)
            .apply {
                description?.let { setDescription(it) }
                units?.let { setUnit(units) }
            }
            .ofLongs()
            .build()
        return OtelLongHistogramImpl(hist)
    }

    override fun createDoubleHistogram(name: String, units: String?, description: String?): DoubleHistogram {
        val hist = otelMeter.histogramBuilder(name)
            .apply {
                description?.let { setDescription(it) }
                units?.let { setUnit(units) }
            }
            .build()
        return OtelDoubleHistogramImpl(hist)
    }

    override fun createLongGauge(
        name: String,
        callback: LongGaugeCallback,
        units: String?,
        description: String?,
    ): AsyncMeasurementHandle {
        val observer = otelMeter.gaugeBuilder(name)
            .apply {
                description?.let { setDescription(it) }
                units?.let { setUnit(units) }
            }
            .ofLongs()
            .buildWithCallback {
                callback(OtelLongAsyncMeasurementImpl(it))
            }
        return OtelAsyncMeasurementHandleImpl(observer)
    }

    override fun createDoubleGauge(
        name: String,
        callback: DoubleGaugeCallback,
        units: String?,
        description: String?,
    ): AsyncMeasurementHandle {
        val observer = otelMeter.gaugeBuilder(name)
            .apply {
                description?.let { setDescription(it) }
                units?.let { setUnit(units) }
            }
            .buildWithCallback {
                callback(OtelDoubleAsyncMeasurementImpl(it))
            }
        return OtelAsyncMeasurementHandleImpl(observer)
    }
}

private class OtelUpDownCounterImpl(
    private val instrument: OtelLongUpDownCounter,
) : UpDownCounter {
    override fun add(value: Long, attributes: Attributes, context: Context?) {
        val otelCtx = (context as? OtelContext)?.context
        if (otelCtx != null) {
            instrument.add(value, attributes.toOtelAttributes(), otelCtx)
        } else {
            instrument.add(value, attributes.toOtelAttributes())
        }
    }
}

private class OtelMonotonicCounterImpl(
    private val instrument: OtelLongCounter,
) : MonotonicCounter {
    override fun add(value: Long, attributes: Attributes, context: Context?) {
        val otelCtx = (context as? OtelContext)?.context
        if (otelCtx != null) {
            instrument.add(value, attributes.toOtelAttributes(), otelCtx)
        } else {
            instrument.add(value, attributes.toOtelAttributes())
        }
    }
}

private class OtelLongHistogramImpl(
    private val instrument: OtelLongHistogram,
) : LongHistogram {
    override fun record(value: Long, attributes: Attributes, context: Context?) {
        val otelCtx = (context as? OtelContext)?.context
        if (otelCtx != null) {
            instrument.record(value, attributes.toOtelAttributes(), otelCtx)
        } else {
            instrument.record(value, attributes.toOtelAttributes())
        }
    }
}

private class OtelDoubleHistogramImpl(
    private val instrument: OtelDoubleHistogram,
) : DoubleHistogram {
    override fun record(value: Double, attributes: Attributes, context: Context?) {
        val otelCtx = (context as? OtelContext)?.context
        if (otelCtx != null) {
            instrument.record(value, attributes.toOtelAttributes(), otelCtx)
        } else {
            instrument.record(value, attributes.toOtelAttributes())
        }
    }
}

private class OtelLongAsyncMeasurementImpl(private val measurement: ObservableLongMeasurement) : LongAsyncMeasurement {
    override fun record(value: Long, attributes: Attributes, context: Context?) {
        if (attributes.isEmpty) {
            measurement.record(value)
        } else {
            measurement.record(value, attributes.toOtelAttributes())
        }
    }
}

private class OtelDoubleAsyncMeasurementImpl(private val measurement: ObservableDoubleMeasurement) : DoubleAsyncMeasurement {
    override fun record(value: Double, attributes: Attributes, context: Context?) {
        if (attributes.isEmpty) {
            measurement.record(value)
        } else {
            measurement.record(value, attributes.toOtelAttributes())
        }
    }
}

private class OtelAsyncMeasurementHandleImpl(private val otelHandle: AutoCloseable) : AsyncMeasurementHandle {
    override fun stop() {
        otelHandle.close()
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy