From 58a7207254625890f9040c625fd40cbb947a72d9 Mon Sep 17 00:00:00 2001 From: Brian Holt Date: Thu, 12 Jan 2023 01:34:42 -0600 Subject: [PATCH] add links and span kind to LogOdin --- modules/log-odin/src/main/scala/Log.scala | 24 ++++++---- modules/log-odin/src/main/scala/LogSpan.scala | 44 ++++++++++++------- 2 files changed, 45 insertions(+), 23 deletions(-) diff --git a/modules/log-odin/src/main/scala/Log.scala b/modules/log-odin/src/main/scala/Log.scala index b2d5f0af..d5c45918 100644 --- a/modules/log-odin/src/main/scala/Log.scala +++ b/modules/log-odin/src/main/scala/Log.scala @@ -19,14 +19,22 @@ object Log { def make(span: F[LogSpan[F]]): Resource[F, Span[F]] = Resource.makeCase(span)(LogSpan.finish).widen - def continue(name: String, kernel: Kernel): Resource[F, Span[F]] = - make(LogSpan.fromKernel(service, name, kernel)) - - def continueOrElseRoot(name: String, kernel: Kernel): Resource[F, Span[F]] = - make(LogSpan.fromKernelOrElseRoot(service, name, kernel)) - - def root(name: String): Resource[F, Span[F]] = - make(LogSpan.root(service, name)) + override def continue( + name: String, + kernel: Kernel, + options: Span.Options + ): Resource[F, Span[F]] = + make(LogSpan.fromKernel(service, name, kernel, options)) + + override def continueOrElseRoot( + name: String, + kernel: Kernel, + options: Span.Options + ): Resource[F, Span[F]] = + make(LogSpan.fromKernelOrElseRoot(service, name, kernel, options)) + + override def root(name: String, options: Span.Options): Resource[F, Span[F]] = + make(LogSpan.root(service, name, options)) } diff --git a/modules/log-odin/src/main/scala/LogSpan.scala b/modules/log-odin/src/main/scala/LogSpan.scala index 20f6e5f9..1d92695d 100644 --- a/modules/log-odin/src/main/scala/LogSpan.scala +++ b/modules/log-odin/src/main/scala/LogSpan.scala @@ -9,15 +9,16 @@ import cats.effect._ import cats.effect.Resource.ExitCase import cats.effect.Resource.ExitCase._ import cats.implicits._ + import java.time.Instant import java.util.UUID import natchez._ import natchez.TraceValue._ -import io.circe.Json -import io.circe.Encoder +import io.circe.{Encoder, Json, JsonObject, KeyEncoder} import io.circe.syntax._ -import io.circe.JsonObject import io.odin.Logger +import natchez.Span.Options + import java.net.URI import org.typelevel.ci._ @@ -30,10 +31,12 @@ private[logodin] final case class LogSpan[F[_]: Sync: Logger]( timestamp: Instant, fields: Ref[F, Map[String, Json]], children: Ref[F, List[JsonObject]], - spanCreationPolicy: Span.Options.SpanCreationPolicy + options: Span.Options ) extends Span.Default[F] { import LogSpan._ + override protected val spanCreationPolicy: Options.SpanCreationPolicy = options.spanCreationPolicy + def spanId: F[Option[String]] = sid.toString.some.pure[F] @@ -72,7 +75,7 @@ private[logodin] final case class LogSpan[F[_]: Sync: Logger]( def makeSpan(label: String, options: Span.Options): Resource[F, Span[F]] = Resource - .makeCase(LogSpan.child(this, label, options.spanCreationPolicy))(LogSpan.finish[F]) + .makeCase(LogSpan.child(this, label, options))(LogSpan.finish[F]) .widen def json(finish: Instant, exitCase: ExitCase): F[JsonObject] = @@ -96,7 +99,9 @@ private[logodin] final case class LogSpan[F[_]: Sync: Logger]( "duration_ms" -> (finish.toEpochMilli - timestamp.toEpochMilli).asJson, "trace.span_id" -> sid.asJson, "trace.parent_id" -> parentId.asJson, - "trace.trace_id" -> tid.asJson + "trace.trace_id" -> tid.asJson, + "span.kind" -> options.spanKind.asJson, + "span.links" -> options.links.asJson ) ++ { exitCase match { case Succeeded => List("exit.case" -> "completed".asJson) @@ -130,6 +135,12 @@ private[logodin] object LogSpan { case NumberValue(n) => n.doubleValue.asJson } + implicit val KeyEncodeCIString: KeyEncoder[CIString] = KeyEncoder[String].contramap(_.toString) + + implicit val EncodeSpanKind: Encoder[Span.SpanKind] = Encoder[String].contramap(_.toString) + + implicit val EncodeKernel: Encoder[Kernel] = Encoder[Map[CIString, String]].contramap(_.toHeaders) + object Headers { val TraceId = ci"X-Natchez-Trace-Id" val SpanId = ci"X-Natchez-Parent-Span-Id" @@ -155,7 +166,7 @@ private[logodin] object LogSpan { def child[F[_]: Sync: Logger]( parent: LogSpan[F], name: String, - spanCreationPolicy: Span.Options.SpanCreationPolicy + options: Span.Options ): F[LogSpan[F]] = for { spanId <- uuid[F] @@ -171,12 +182,13 @@ private[logodin] object LogSpan { timestamp = timestamp, fields = fields, children = children, - spanCreationPolicy = spanCreationPolicy + options = options ) def root[F[_]: Sync: Logger]( service: String, - name: String + name: String, + options: Span.Options ): F[LogSpan[F]] = for { spanId <- uuid[F] @@ -193,13 +205,14 @@ private[logodin] object LogSpan { timestamp = timestamp, fields = fields, children = children, - spanCreationPolicy = Span.Options.SpanCreationPolicy.Default + options = options ) def fromKernel[F[_]: Sync: Logger]( service: String, name: String, - kernel: Kernel + kernel: Kernel, + options: Span.Options ): F[LogSpan[F]] = for { traceId <- Sync[F].catchNonFatal(UUID.fromString(kernel.toHeaders(Headers.TraceId))) @@ -217,15 +230,16 @@ private[logodin] object LogSpan { timestamp = timestamp, fields = fields, children = children, - spanCreationPolicy = Span.Options.SpanCreationPolicy.Default + options = options ) def fromKernelOrElseRoot[F[_]: Sync: Logger]( service: String, name: String, - kernel: Kernel + kernel: Kernel, + options: Span.Options ): F[LogSpan[F]] = - fromKernel(service, name, kernel).recoverWith { case _: NoSuchElementException => - root(service, name) + fromKernel(service, name, kernel, options).recoverWith { case _: NoSuchElementException => + root(service, name, options) } }