com.dwolla.tracing

Members list

Packages

Type members

Classlikes

Attributes

Companion
object
Source
ToTraceValue.scala
Supertypes
class Object
trait Matchable
class Any
Known subtypes

Attributes

Source
ToTraceValue.scala
Supertypes
class Object
trait Matchable
class Any
Known subtypes

Attributes

Companion
class
Source
RootSpanProvidingFunctionK.scala
Supertypes
class Object
trait Matchable
class Any
Self type
class RootSpanProvidingFunctionK[F[_]](entryPoint: EntryPoint[F])(implicit evidence$1: MonadCancelThrow[F]) extends FunctionK[[_] =>> Instrumentation[[_] =>> Kleisli[F, Span[F], _$5], _$6], F]

Use this FunctionK when you have an algebra in Instrumentation[Kleisli[F, Span[F], *], *] and you want each method call on the algebra to create a new root span using the given EntryPoint[F].

Use this FunctionK when you have an algebra in Instrumentation[Kleisli[F, Span[F], *], *] and you want each method call on the algebra to create a new root span using the given EntryPoint[F].

Note that if you have an algebra Alg[F] for which an Instrument[Alg] exists, you can convert it to Alg[Instrumentation[Kleisli[F, Span[F], *], *]] in two steps, using Kleisli.liftK and Instrument[Alg].instrument:

import cats.data._, cats.effect._, cats.tagless.aop._, cats.tagless.syntax.all._, cats._

trait Foo[F[_]] {
  def foo: F[Unit]
}

object Foo {
  implicit val fooInstrument: Instrument[Foo] = { // Derive.instrument
    // TODO reintroduce derived instance when cats-tagless-macros supports Scala 3
    new Instrument[Foo] {
      override def instrument[F[_]](af: Foo[F]): Foo[Instrumentation[F, *]] =
        new Foo[Instrumentation[F, *]] {
          override def foo: Instrumentation[F, Unit] =
            Instrumentation(af.foo, "Foo", "foo")
        }

      override def mapK[F[_], G[_]](af: Foo[F])(fk: F ~> G): Foo[G] =
        new Foo[G] {
          override def foo: G[Unit] = fk(af.foo)
        }
    }
  }
}

def myFoo: Foo[IO] = new Foo[IO] {
  def foo = IO.println("foo!")
}

val instrumentedFoo: Foo[Instrumentation[Kleisli[IO, natchez.Span[IO], *], *]] =
  myFoo.mapK(Kleisli.liftK[IO, natchez.Span[IO]]).instrument

Value parameters

entryPoint

the Natchez EntryPoint[F] that will construct the new root spans

Attributes

Companion
object
Source
RootSpanProvidingFunctionK.scala
Supertypes
trait FunctionK[[_] =>> Instrumentation[[_] =>> Kleisli[F, Span[F], _$5], _$6], F]
trait Serializable
class Object
trait Matchable
class Any

Attributes

Companion
class
Source
TraceInstrumentation.scala
Supertypes
class Object
trait Matchable
class Any
Self type
class TraceInstrumentation[F[_]] extends FunctionK[[_] =>> Instrumentation[F, _$4], F]

Use this FunctionK when you have an algebra in Instrumentation[F, *] and you want each method call on the algebra to introduce a new child span, using the ambient Trace[F].

Use this FunctionK when you have an algebra in Instrumentation[F, *] and you want each method call on the algebra to introduce a new child span, using the ambient Trace[F]. Each child span will be named using the algebra name and method name as captured in the Instrumentation[F, A].

Note if you have an algebra Alg[F] for which an Instrument[Alg] exists, it can be converted to Alg[Instrumentation[F, *]] using Instrument[Alg].instrument:

import cats.effect._, cats.tagless.aop._, cats.tagless.syntax.all._, cats._

trait Foo[F[_]] {
  def foo: F[Unit]
}

object Foo {
  implicit val fooInstrument: Instrument[Foo] = { // Derive.instrument
    // TODO reintroduce derived instance when cats-tagless-macros supports Scala 3
    new Instrument[Foo] {
      override def instrument[F[_]](af: Foo[F]): Foo[Instrumentation[F, *]] =
        new Foo[Instrumentation[F, *]] {
          override def foo: Instrumentation[F, Unit] =
            Instrumentation(af.foo, "Foo", "foo")
        }

      override def mapK[F[_], G[_]](af: Foo[F])(fk: F ~> G): Foo[G] =
        new Foo[G] {
          override def foo: G[Unit] = fk(af.foo)
        }
    }
  }
}

def myFoo: Foo[IO] = new Foo[IO] {
  def foo = IO.println("foo!")
}

val instrumentedFoo: Foo[Instrumentation[IO, *]] =
  myFoo.instrument

Attributes

Companion
object
Source
TraceInstrumentation.scala
Supertypes
trait FunctionK[[_] =>> Instrumentation[F, _$4], F]
trait Serializable
class Object
trait Matchable
class Any

Attributes

Source
TraceResourceAcquisition.scala
Supertypes
class Object
trait Matchable
class Any
Self type

Attributes

Companion
class
Source
TraceWeaveCapturingInputs.scala
Supertypes
class Object
trait Matchable
class Any
Self type
class TraceWeaveCapturingInputs[F[_], Cod[_]] extends FunctionK[[_] =>> Weave[F, TraceableValue, Cod, _$6], F]

Use this FunctionK when you have an algebra in Weave[F, TraceableValue, Cod, *] and you want each method call on the algebra to introduce a new child span, using the ambient Trace[F].

Use this FunctionK when you have an algebra in Weave[F, TraceableValue, Cod, *] and you want each method call on the algebra to introduce a new child span, using the ambient Trace[F]. Each child span will be named using the algebra name and method name as captured in the Instrumentation[F, A], and the parameters given to the method call will be attached to the span as attributes.

The format of the attributes is controlled via the implementation of the TraceableValue typeclass. There are provided implementations for String, Int, Boolean, and Unit, as well as Option[A] where TraceableValue[A] exists. Other types that have Show or Circe Encoder instances will also be converted.

If a parameter is sensitive, one way to ensure the sensitive value is not included in the trace is to use a newtype for the parameter type, and then manually write a redacted TraceableValue[Newtype] instance. For example, using io.monix::newtypes-core:

import monix.newtypes._, natchez._

type Password = Password.Type

object Password extends NewtypeWrapped[String] {
  implicit val PasswordTraceableValue: TraceableValue[Password] = new TraceableValue[Password] {
    override def toTraceValue(a: Password): TraceValue = "redacted password value"
  }
}

With that implementation of TraceableValue[Password], the span will record "redacted password value" as an attribute, but the actual value will not be recorded. Similar functionality can be achieved using the newtype library of your choice.

TraceWeaveCapturingInputs ignores the codomain (i.e. output) type, so your algebra could have an Aspect.Domain[Alg, TraceableValue] (equivalent to Aspect[Alg, TraceableValue, Trivial]), Aspect[Alg, TraceableValue, TraceableValue], or really any other typeclass in the Cod[_] position, and still work with this transformation.

Note if you have an algebra Alg[F] for which an Aspect.Domain[Alg, TraceableValue] exists, it can be converted to Alg[Weave.Domain[F, TraceableValue, *]] using Aspect.Domain[Alg, TraceableValue].weave:

import cats.effect._, cats.tagless._, cats.tagless.aop._, cats.tagless.syntax.all._, cats._

trait Foo[F[_]] {
  def foo(i: Int): F[Unit]
}

object Foo {
  implicit val fooTracingAspect: Aspect.Domain[Foo, TraceableValue] = { // Derive.instrument
    // TODO reintroduce derived instance when cats-tagless-macros supports Scala 3
    new Aspect.Domain[Foo, TraceableValue] {
      override def weave[F[_]](af: Foo[F]): Foo[Aspect.Weave[F, TraceableValue, Trivial, *]] =
        new Foo[Aspect.Weave[F, TraceableValue, Trivial, *]] {
          override def foo(i: Int): Aspect.Weave[F, TraceableValue, Trivial, Unit] =
            Aspect.Weave[F, TraceableValue, Trivial, Unit](
              "Foo",
              List(List(Aspect.Advice.byValue[TraceableValue, Int]("i", i))),
              Aspect.Advice[F, Trivial, Unit]("foo", af.foo(i))
            )
        }

      override def mapK[F[_], G[_]](af: Foo[F])(fk: F ~> G): Foo[G] =
        new Foo[G] {
          override def foo(i: Int): G[Unit] = fk(af.foo(i))
        }
    }
  }
}

def myFoo: Foo[IO] = new Foo[IO] {
  def foo(i: Int) = IO.println(s"foo!").replicateA_(i)
}

val wovenFoo: Foo[Aspect.Weave.Domain[IO, TraceableValue, *]] =
  myFoo.weave

Ensure that TraceableValue instances exist for all the method parameter types in the algebra, or you'll see compile-time errors similar to this:

 exception during macro expansion:
 scala.reflect.macros.TypecheckException: could not find implicit value for evidence parameter of type TraceableValue[X]
     implicit val fooTracingAspect: Aspect.Domain[Foo, TraceableValue] = Derive.aspect
                                                                              ^
 one error found

Ensure there is a TraceableValue for the missing type (in the example above, it would be X) in the implicit scope where the Aspect is being derived, and then try again. You may have to iterate several times before all the necessary types are defined.

Attributes

Companion
object
Source
TraceWeaveCapturingInputs.scala
Supertypes
trait FunctionK[[_] =>> Weave[F, TraceableValue, Cod, _$6], F]
trait Serializable
class Object
trait Matchable
class Any

Attributes

Companion
class
Source
TraceWeaveCapturingInputsAndOutputs.scala
Supertypes
class Object
trait Matchable
class Any
Self type

Use this FunctionK when you have an algebra in Weave[F, TraceableValue, TraceableValue, *] and you want each method call on the algebra to introduce a new child span, using the ambient Trace[F].

Use this FunctionK when you have an algebra in Weave[F, TraceableValue, TraceableValue, *] and you want each method call on the algebra to introduce a new child span, using the ambient Trace[F]. Each child span will be named using the algebra name and method name as captured in the Instrumentation[F, A], and the parameters given to the method call and its return value will be attached to the span as attributes.

The format of the attributes is controlled via the implementation of the TraceableValue typeclass. There are implementations provided for String, Int, Boolean, and Unit, as well as Option[A] where TraceableValue[A] exists. Other types that have Show or Circe Encoder instances will also be converted.

If a parameter or return value is sensitive, one way to ensure the sensitive value is not included in the trace is to use a newtype for the parameter type, and then manually write a redacted TraceableValue[Newtype] instance. For example, using io.monix::newtypes-core:

import monix.newtypes._, natchez._

type Password = Password.Type

object Password extends NewtypeWrapped[String] {
  implicit val PasswordTraceableValue: TraceableValue[Password] = new TraceableValue[Password] {
    override def toTraceValue(a: Password): TraceValue = "redacted password value"
  }
}

With that implementation of TraceableValue[Password], the span will record "redacted password value" as an attribute, but the actual value will not be recorded. Similar functionality can be achieved using the newtype library of your choice.

Note if you have an algebra Alg[F] for which an Aspect[Alg, TraceableValue, TraceableValue] exists, it can be converted to Alg[Weave[F, TraceableValue, TraceableValue, *]] using Aspect[Alg, TraceableValue, TraceableValue].weave:

import cats.effect._, cats.tagless.aop._, cats.tagless.syntax.all._, cats._

trait Foo[F[_]] {
  def foo(i: Int): F[Unit]
}

object Foo {
  import LowPriorityTraceableValueInstances._
  implicit val fooTracingAspect: Aspect[Foo, TraceableValue, TraceableValue] = { // Derive.aspect
    // TODO reintroduce derived instance when cats-tagless-macros supports Scala 3
    new Aspect[Foo, TraceableValue, TraceableValue] {
      override def weave[F[_]](af: Foo[F]): Foo[Aspect.Weave[F, TraceableValue, TraceableValue, *]] =
        new Foo[Aspect.Weave[F, TraceableValue, TraceableValue, *]] {
          override def foo(i: Int): Aspect.Weave[F, TraceableValue, TraceableValue, Unit] =
            Aspect.Weave[F, TraceableValue, TraceableValue, Unit](
              "Foo",
              List(List(Aspect.Advice.byValue[TraceableValue, Int]("i", i))),
              Aspect.Advice[F, TraceableValue, Unit]("foo", af.foo(i))
            )
        }

      override def mapK[F[_], G[_]](af: Foo[F])(fk: F ~> G): Foo[G] =
        new Foo[G] {
          override def foo(i: Int): G[Unit] = fk(af.foo(i))
        }
    }
  }
}

def myFoo: Foo[IO] = new Foo[IO] {
  def foo(i: Int) = IO.println(s"foo!").replicateA_(i)
}

val wovenFoo: Foo[Aspect.Weave[IO, TraceableValue, TraceableValue, *]] =
  myFoo.weave

Ensure that TraceableValue instances exist for all the method parameter and return types in the algebra, or you'll see compile-time errors similar to this:

 exception during macro expansion:
 scala.reflect.macros.TypecheckException: could not find implicit value for evidence parameter of type TraceableValue[X]
     implicit val fooTracingAspect: Aspect.Domain[Foo, TraceableValue] = Derive.aspect
                                                                              ^
 one error found

Ensure there is a TraceableValue for the missing type (in the example above, it would be X) in the implicit scope where the Aspect is being derived, and then try again. You may have to iterate several times before all the necessary types are defined.

Attributes

Companion
object
Source
TraceWeaveCapturingInputsAndOutputs.scala
Supertypes
trait FunctionK[[_] =>> Weave[F, TraceableValue, TraceableValue, _$4], F]
trait Serializable
class Object
trait Matchable
class Any