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

commonMain.aws.smithy.kotlin.runtime.http.operation.OperationTelemetry.kt Maven / Gradle / Ivy

The newest version!
/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0
 */

package aws.smithy.kotlin.runtime.http.operation

import aws.smithy.kotlin.runtime.ExperimentalApi
import aws.smithy.kotlin.runtime.InternalApi
import aws.smithy.kotlin.runtime.client.*
import aws.smithy.kotlin.runtime.collections.*
import aws.smithy.kotlin.runtime.http.interceptors.OperationTelemetryInterceptor
import aws.smithy.kotlin.runtime.telemetry.TelemetryProvider
import aws.smithy.kotlin.runtime.telemetry.TelemetryProviderContext
import aws.smithy.kotlin.runtime.telemetry.logging.LoggingContextElement
import aws.smithy.kotlin.runtime.telemetry.trace.SpanKind
import aws.smithy.kotlin.runtime.telemetry.trace.TraceSpan
import kotlin.coroutines.CoroutineContext

/**
 * Telemetry parameters used to instrument an operation
 *
 * @property provider the telemetry provider to use to instrument the operation with
 * @property spanName the overall operation span name to use (defaults to )
 * @property spanKind the kind of span to create for the operation (defaults to [SpanKind.CLIENT])
 * @property attributes initial attributes to add to the operation span
 * @property metrics the metrics container to report operation metrics to when this operation is invoked (defaults to no-op)
 * @property scope the telemetry scope to instrument with (will default to service name if not configured)
 */
@InternalApi
public class SdkOperationTelemetry {
    public var provider: TelemetryProvider = TelemetryProvider.None
    public var spanName: String? = null
    public var spanKind: SpanKind = SpanKind.CLIENT
    public var attributes: Attributes = emptyAttributes()
    public var metrics: OperationMetrics = OperationMetrics.None
    public var scope: String? = null
}

/**
 * Configure operation telemetry parameters
 */
@InternalApi
public inline fun  SdkHttpOperationBuilder.telemetry(block: SdkOperationTelemetry.() -> Unit) {
    telemetry.apply(block)
}

/**
 * Instrument an operation with telemetry. This should be invoked right when the operation is actually executed
 * as the returned span is in the active state (i.e. current).
 * @return the span for the operation and the additional coroutine context to execute the operation with containing
 * telemetry elements.
 */
@OptIn(ExperimentalApi::class)
internal fun  SdkHttpOperation.instrument(): Pair {
    val serviceName = checkNotNull(context.serviceName)
    val opName = checkNotNull(context.operationName)

    val scope = telemetry.scope ?: serviceName

    val tracer = telemetry.provider.tracerProvider.getOrCreateTracer(scope)
    val parentCtx = telemetry.provider.contextManager.current()

    val opAttributes = attributesOf {
        "rpc.service" to serviceName
        "rpc.method" to opName
    }

    val initialAttributes = telemetry.attributes.toMutableAttributes().apply {
        merge(opAttributes)
    }

    val rpcName = "$serviceName.$opName"
    val spanName = telemetry.spanName ?: rpcName

    val span = tracer.createSpan(
        spanName,
        initialAttributes,
        telemetry.spanKind,
        parentCtx,
    )

    val telemetryCtx = TelemetryProviderContext(telemetry.provider) +
        LoggingContextElement(
            "rpc" to rpcName,
            "sdkInvocationId" to context.sdkInvocationId,
        )

    context[HttpOperationContext.OperationMetrics] = telemetry.metrics
    context[HttpOperationContext.OperationAttributes] = opAttributes

    // wire up operation level telemetry (other metrics e.g. from http are instrumented elsewhere)
    interceptors.add(OperationTelemetryInterceptor(telemetry.metrics, serviceName, opName))

    return span to telemetryCtx
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy