ZTracer
ZTracer is the abstraction provided by this library which allows you to seamlessly create traces & spans. For example:
import zio.*
import io.kaizensolutions.trace4cats.zio.extras.ZTracer
val nestedTraceExample: URIO[ZTracer, Unit] =
ZTracer.span("parent") {
ZTracer
.span("child1")(ZTracer.span("grandchild")(ZIO.unit))
.zipParLeft(ZTracer.span("child2")(ZIO.unit))
}
This generates the following structure:
Notice that using the ZTracer abstraction cannot fail; meaning if you mis-configure the tracing configuration, your application will continue to function but traces will not be reported.
ZStream integration
ZTracer can also be used to trace ZStreams in tandem with the Spanned datatype where each element of the ZStream
has an associated span (i.e. Kafka messages). For example:
import zio.*
import zio.stream.*
import io.kaizensolutions.trace4cats.zio.extras.*
import trace4cats.*
// create a stream where each element is associated with a trace header
val stream: ZStream[ZTracer, Nothing, (Int, TraceHeaders)] =
ZStream.range(1, 100)
.mapZIO(i =>
ZTracer.withSpan(s"name-$i")(span =>
ZIO.succeed((i, span.extractHeaders(ToHeaders.standard)))
)
)
// create spans for elements in the stream
val tracedOperationStream: ZStream[ZTracer, Throwable, Spanned[Int]] =
stream.traceEachElement(element => /* we name each span based on the element*/ s"in-begin-$element") {
case (_, headers) => headers // we extract the headers from the element
}
.mapThrough(_._1) // we only care about the element, not the headers - traceEachElement will automatically add the headers back
.mapZIOTraced("Plus 1")(e =>
ZTracer.span(s"plus 1 for $e")(Console.printLine(s"Adding ${e} + 1 = ${e + 1}") *> ZIO.succeed(e + 1))
)
.mapZIOParTraced("Plus 2")(8)(e =>
ZTracer.span(s"plus 2 for $e")(
Console.printLine(s"Adding ${e} + 2 = ${e + 2}").delay(500.millis) *>
ZIO.succeed(e + 2)
)
)
.mapZIOParTraced("Plus 4")(3)(e =>
ZTracer.span(s"plus 4 for $e")(
ZTracer.spanSource()(Console.printLine(s"Adding ${e} + 4 = ${e + 4}").delay(1.second)) *>
ZIO.succeed(e + 2)
)
)
Running the stream above, we'd expect to see something along the lines of:
Have a look at the example if you want to learn more.