diff --git a/modules/core/shared/src/main/scala/Span.scala b/modules/core/shared/src/main/scala/Span.scala index 18e0196f..814dc460 100644 --- a/modules/core/shared/src/main/scala/Span.scala +++ b/modules/core/shared/src/main/scala/Span.scala @@ -51,6 +51,15 @@ trait Span[F[_]] { */ def traceUri: F[Option[URI]] + /** Run impure code with the span of underlying tracing backend activated on the current thread + * for the duration of the call. + * + * This is useful when calling into Java or other non-cats-effect code that is instrumented by the tracing backend. + * + * This should always be wrapped in `Sync.suspend` or equivalent. + */ + def unsafeRunWithActivatedSpan[T](run: => T): T = run + /** Converts this `Span[F]` to a `Span[G]` using a `F ~> G`. */ def mapK[G[_]](f: F ~> G)(implicit F: MonadCancel[F, _], diff --git a/modules/datadog/src/main/scala/DDSpan.scala b/modules/datadog/src/main/scala/DDSpan.scala index 73e42e91..2d4bd98d 100644 --- a/modules/datadog/src/main/scala/DDSpan.scala +++ b/modules/datadog/src/main/scala/DDSpan.scala @@ -112,4 +112,10 @@ final case class DDSpan[F[_]: Sync]( ) ++ fields.toList.nested.map(_.value).value.toMap).asJava ) }.void + + override def unsafeRunWithActivatedSpan[T](run: => T): T = { + val scope = tracer.activateSpan(span) + try run + finally scope.close() + } } diff --git a/modules/jaeger/src/main/scala/JaegerSpan.scala b/modules/jaeger/src/main/scala/JaegerSpan.scala index 83e0578f..1cd1a1b6 100644 --- a/modules/jaeger/src/main/scala/JaegerSpan.scala +++ b/modules/jaeger/src/main/scala/JaegerSpan.scala @@ -100,6 +100,12 @@ private[jaeger] final case class JaegerSpan[F[_]: Sync]( (Nested(prefix.pure[F]), Nested(traceId)).mapN { (uri, id) => uri.resolve(s"/trace/$id") }.value + + override def unsafeRunWithActivatedSpan[T](run: => T): T = { + val scope = tracer.activateSpan(span) + try run + finally scope.close() + } } private[jaeger] object JaegerSpan { diff --git a/modules/lightstep/src/main/scala/LightstepSpan.scala b/modules/lightstep/src/main/scala/LightstepSpan.scala index 9a8beed1..9a76b842 100644 --- a/modules/lightstep/src/main/scala/LightstepSpan.scala +++ b/modules/lightstep/src/main/scala/LightstepSpan.scala @@ -96,4 +96,10 @@ private[lightstep] final case class LightstepSpan[F[_]: Sync]( // TODO def traceUri: F[Option[URI]] = none.pure[F] + + override def unsafeRunWithActivatedSpan[T](run: => T): T = { + val scope = tracer.activateSpan(span) + try run + finally scope.close() + } } diff --git a/modules/opencensus/src/main/scala/OpenCensusSpan.scala b/modules/opencensus/src/main/scala/OpenCensusSpan.scala index dd991233..b1423e6b 100644 --- a/modules/opencensus/src/main/scala/OpenCensusSpan.scala +++ b/modules/opencensus/src/main/scala/OpenCensusSpan.scala @@ -95,6 +95,12 @@ private[opencensus] final case class OpenCensusSpan[F[_]: Sync]( ("error.class" -> TraceValue.StringValue(err.getClass.getSimpleName)) :: fields.toList: _* ) + + override def unsafeRunWithActivatedSpan[T](run: => T): T = { + val scope = tracer.withSpan(span) + try run + finally scope.close() + } } private[opencensus] object OpenCensusSpan { diff --git a/modules/opentelemetry/src/main/scala/natchez/opentelemetry/OpenTelemetrySpan.scala b/modules/opentelemetry/src/main/scala/natchez/opentelemetry/OpenTelemetrySpan.scala index d2c350ee..69345e65 100644 --- a/modules/opentelemetry/src/main/scala/natchez/opentelemetry/OpenTelemetrySpan.scala +++ b/modules/opentelemetry/src/main/scala/natchez/opentelemetry/OpenTelemetrySpan.scala @@ -131,6 +131,12 @@ private[opentelemetry] final case class OpenTelemetrySpan[F[_]: Sync]( (Nested(prefix.pure[F]), Nested(traceId)).mapN { (uri, id) => uri.resolve(s"/trace/$id") }.value + + override def unsafeRunWithActivatedSpan[T](run: => T): T = { + val scope = span.makeCurrent() + try run + finally scope.close() + } } private[opentelemetry] object OpenTelemetrySpan {