Unseal SpanProcessor and other traits
Hey, I'm currently implementing async-profiler profiling data to be linked with the traces.
This is one case in which custom SpanProcessor may actually be useful to be provided.
Obviously we can work around this by writing a wrapper around TracerProvider to call required methods by ourselves. See:
https://github.com/grafana/otel-profiling-java/blob/6ddc19fe2e37ad1b60ec26baf613a049c2be30e5/src/main/java/io/otel/pyroscope/PyroscopeOtelSpanProcessor.java#L8
class ProfilingSpanProcessor(localSpan: LocalSpan) extends SpanProcessor[IO] {
override def name: String = "ProfilingSpanProcessor"
override def onStart: OnStart[IO] = new OnStart[IO] {
override def apply(parentContext: Option[SpanContext], span: SpanRef[IO]): IO[Unit] = {
val spanIdStr = span.context.spanIdHex
val spanId = java.lang.Long.parseUnsignedLong(spanIdStr, 16)
for {
_ <- span.addAttributes(Seq(Attribute("pyroscope.profile.id", spanIdStr)))
_ <- IO(localSpan.set(Some(TraceSpan(spanId))))
} yield ()
}
}
override def onEnd: OnEnd[IO] = new OnEnd[IO] {
override def apply(span: SpanData): IO[Unit] = IO(localSpan.set(None))
}
override def forceFlush: IO[Unit] = IO.unit
}
I've also created a discussion that shows the concrete use case.
Which backend do you plan to use?
otel4s-oteljava(backed by https://github.com/open-telemetry/opentelemetry-java)otel4s-sdk(our own implementation of OpenTelemetry)?
If you plan to use otel4s-oteljava, you can use https://github.com/grafana/otel-profiling-java almost directly.
However, if you plan to use otel4s-sdk, then we should unseal the interface.
I think in cats-effect runtime we can't use otel-profiling-java because the spanId assignment to async-profiler tracing context won't guarantee us that all of those computations will be run on the same Thread, thus the context won't stay correct.
E.g
Tracer[IO].span("do-something") {
// at this place onStart from otel-profiling-java will trigger setting the context
IO(doSomething) >> IO.blocking(blockingOp) >> IO(doSomething)
}
I'm quite new to cats, but according to my understanding of runtime, there are no guarantees that each of those IO's will be run on the same Thread (it is preferred but not guaranteed). That means if IO(doSomething) is run on different thread it won't have the tracing context of span set correctly.