am I the only person in the world that wants to ad...
# ktor
a
am I the only person in the world that wants to add custom opentelemetry spans to a Ktor app? 😂 I can’t seem to find any solid info about this on Google, and my attempt at creating spans seems to not properly attach them to the active trace.
p
I'm about to do it as well, but my current Jaeger installation is broken, so I need to fix it first 🙂 will report back once I succeed or lose hope
a
haha, thanks! Hope you figure it out 😄
it’s probably pretty basic to get going, but it seems like there’s a bit of a dissonance between thread locals and the JVM, and Kotlin with coroutines etc
d
I am not sure what exactly is missing for you, but for us this works:
Copy code
import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.api.common.Attributes
import io.opentelemetry.api.trace.Span
import io.opentelemetry.api.trace.SpanBuilder
import io.opentelemetry.api.trace.StatusCode
import io.opentelemetry.api.trace.Tracer
import io.opentelemetry.extension.kotlin.asContextElement
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.withContext
import kotlin.coroutines.cancellation.CancellationException
import kotlin.coroutines.coroutineContext

/**
 * Executes [block] in a tracing span with optional SpanBuilder [parameters].
 *
 * [parameters] example: `parameters = { setParent(parentContext); addLink(span1.spanContext) }`
 *
 * The span will be
 * - a child of a parent context, if set via [parameters], or
 * - a child of the current span (from the current coroutine context), or
 * - a top-level span.
 *
 * Guidelines:
 * - [Trace Semantic Conventions](<<https://opentelemetry.io/docs/reference/specification/trace/semantic_conventions/>>)
 * - [Attribute Naming](<<https://opentelemetry.io/docs/reference/specification/common/attribute-naming/>>)
 */
suspend fun <Result> withSpan(
    tracer: Tracer,
    name: String,
    parameters: (SpanBuilder.() -> Unit)? = null,
    exceptionIsError: (Throwable) -> Boolean = { it !is CancellationException },
    block: suspend (span: Span?) -> Result,
): Result {
    val span: Span = tracer.spanBuilder(name).run {
        if (parameters != null) {
            parameters()
        }
        coroutineContext[CoroutineName]?.let {
            setAttribute("coroutine.name", it.name)
        }
        startSpan()
    }

    return withContext(span.asContextElement()) {
        try {
            block(span).also {
                span.setStatus(StatusCode.OK)
            }
        } catch (throwable: Throwable) {
            if (exceptionIsError(throwable)) {
                span.setStatus(StatusCode.ERROR)
                span.recordException(throwable)
            } else {
                span.addEvent(
                    "Completed with exception",
                    Attributes.of(
                        AttributeKey.stringKey("exception.type"),
                        throwable.javaClass.name,
                        AttributeKey.stringKey("exception.message"),
                        (throwable.message ?: "(none)"),
                    ),
                )
                span.setStatus(StatusCode.OK)
            }
            throw throwable
        } finally {
            span.end()
        }
    }
}
And the usage:
Copy code
val tracer = GlobalOpenTelemetry.get().getTracer("somename", "1.0.0")
val someData = withSpan(tracer, "fetching data", { setAttribute("someId", id) }) {
            myService.findById(id)
                ?: throw InvalidArgumentException(message = "No data found for the provided id.")
        }
In Sentry (which we use) this looks like this:
a
Sweet, thanks! Is this in a library somewhere?
related, seems like the Ktor tracer by default does not read traceparent (i.e. the header that’s conventionally used for distributed traces)
d
This is everything, we don't use any specific library. We do use the Sentry JavaAgent, though. This one also takes care of the corresponding headers (we use it on client side as well), so I am not sure how "plain" Ktor handles these headers.
a
ah I see, good to know