Using ZIO and open telemetry IMHO I have to provide an Interceptor propagates OpenTelemetry’s `io.opentelemetry.context.Context` (ThreadLocal) into zio-opentelemetry’s `ContextStorage` (FiberRef) for each Tapir request, so that `zio.telemetry.opentelemetry.tracing.Tracing` spans (e.g. `tracing.span`) are children of the HTTP sttp.tapir.server.tracing.opentelemetry.OpenTelemetryTracing `SERVER` span.
object ZioOtelContextBridge {
def tapirRequestInterceptor(storage: ContextStorage): RequestInterceptor[Task] =
RequestInterceptor.transformResultEffect[Task](
new RequestInterceptor.RequestResultEffectTransform[Task] {
def apply[B](
request: ServerRequest,
result: Task[RequestResult[B]]
): Task[RequestResult[B]] = {
// Captured while `OpenTelemetryTracing` still has the server `Span` in `Context` (synchronous transform hook).
val ctx: Context = Context.current()
storage.locally(ctx)(result)
}
}
)
}
WDYT, is seem to works like a charm, I this is useful would you be interested by a contrib ?
Attachmenent bellow, without the Interceptor the inner span are not child of the entry point span.
Yes, that’s exactly the kind of integration that is needed to make otel work with libs like ZIO. Though, where does the context originally come from? That is - what is setting the context that’s being read by Context.current()?
Yes, but the context needs to be populated - typically by parsing incoming tracing headers. And this has to be done by ZIO, as that’s the only component that knows about the headers :). Unless you’re setting an empty context, but then the interceptor could do just that, set an empty one?
You mean in case of distributed tracing (baggage & carrier) ?
My need right now was just to link tapir span and ZIO ones, distributed tracing is my next objective.
Ah yes, well in the end for a full ZIO integration I think you’ll need a custom zio-tracing interceptor (instead of tapir/tracing/opentelemetry-tracing/src at master · softwaremill/tapir · GitHub which I suspect you’re using now?) so that it reads the context from ContextStorage. Plus another one for parsing the dist tracing headers.
But it make me realize that ZIO OpenTelemetry pulls all observability dependencies (log, tracing and metrics), hence instead of tracing/zio-tracing module is not the best name
Also, what is the best/prefered tactic to support scala 2/3 ? Stick to Scala 2 or rely on Scala2 and Scala3 sources ?