All Downloads are FREE. Search and download functionalities are using the official Maven repository.

natchez-mock_2.13.0.3.7.source-code.MockSpan.scala Maven / Gradle / Ivy

// Copyright (c) 2019-2020 by Rob Norris and Contributors
// This software is licensed under the MIT License (MIT).
// For more information see LICENSE or https://opensource.org/licenses/MIT

package natchez
package mock

import scala.jdk.CollectionConverters._

import cats.effect.{Resource, Sync}
import cats.syntax.all._
import io.opentracing.log.Fields
import io.{opentracing => ot}
import io.opentracing.propagation.{Format, TextMapAdapter}
import io.opentracing.tag.Tags
import natchez.TraceValue.{BooleanValue, NumberValue, StringValue}
import java.net.URI

final case class MockSpan[F[_]: Sync](tracer: ot.mock.MockTracer, span: ot.mock.MockSpan)
    extends Span.Default[F] {

  def kernel: F[Kernel] =
    Sync[F].delay {
      val m = new java.util.HashMap[String, String]
      tracer.inject(
        span.context,
        Format.Builtin.HTTP_HEADERS,
        new TextMapAdapter(m)
      )
      Kernel.fromJava(m)
    }

  def put(fields: (String, TraceValue)*): F[Unit] =
    fields.toList.traverse_ {
      case (k, StringValue(v))  => Sync[F].delay(span.setTag(k, v))
      case (k, NumberValue(v))  => Sync[F].delay(span.setTag(k, v))
      case (k, BooleanValue(v)) => Sync[F].delay(span.setTag(k, v))
    }

  def attachError(err: Throwable, fields: (String, TraceValue)*): F[Unit] =
    put(
      Tags.ERROR.getKey -> true
    ) >>
      Sync[F].delay {
        span.log {
          val otherFields = fields.toList.nested.map(_.value).value.toMap
          val errorFields = Map(
            Fields.EVENT -> "error",
            Fields.ERROR_OBJECT -> err,
            Fields.ERROR_KIND -> err.getClass.getSimpleName,
            Fields.MESSAGE -> err.getMessage,
            Fields.STACK -> err.getStackTrace.mkString
          )
          (otherFields ++ errorFields).asJava
        }
      }.void

  override def log(fields: (String, TraceValue)*): F[Unit] = {
    val map = fields.map { case (k, v) => k -> v.value }.toMap.asJava
    Sync[F].delay(span.log(map)).void
  }

  override def log(event: String): F[Unit] =
    Sync[F].delay(span.log(event)).void

  override protected val spanCreationPolicyOverride: Span.Options.SpanCreationPolicy =
    Span.Options.SpanCreationPolicy.Default

  override def makeSpan(name: String, options: Span.Options): Resource[F, Span[F]] =
    Span.putErrorFields {
      Resource
        .make {
          val p = options.parentKernel.map(k =>
            tracer.extract(
              Format.Builtin.HTTP_HEADERS,
              new TextMapAdapter(k.toJava)
            )
          )
          Sync[F].delay(tracer.buildSpan(name).asChildOf(p.orNull).asChildOf(span).start)
        } { s =>
          Sync[F].delay(s.finish())
        }
        .map(MockSpan(tracer, _))
    }

  def traceId: F[Option[String]] =
    span.context.toTraceId.some.pure[F]

  def spanId: F[Option[String]] =
    span.context.toSpanId.some.pure[F]

  def traceUri: F[Option[URI]] =
    none.pure[F]

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy