Entry Points
An EntryPoint
provides a way to create a root Span
, or continue a Span
that began on another computer. In practice this means that an entry point is a live connection to some tracing back-end. This is where you start: typically IOApp.run
will construct an entry point that you use for the life of your program.
You can obtain an EntryPoint
through a vendor-specific factory. See the list of back ends and select the one you’d like to use.
Creating an Initial Span
EntryPoint[F]
provides three methods for constructing an initial span resource.
root
creates a new top-level span resource with no parent. This kind of initial span is typically used for endpoints on the public surface of a system.continue
creates a span resource with a parent specified by a providedKernel
(typically received in http headers). If the kernel is invalid (this is determined in a vendor-specific manner) an error is raised inF
. This kind of initial span is typically used for endpoints of internal services that are always invoked by higher-level services, in which failure to find an incoming kernel is an error.continueOrElseRoot
attempts tocontinue
and on failure (if the kernel is invalid) it creates a newroot
. This is a good default.
Http4s Server Example
The examples in this section use the following imports:
import cats.effect.IO
import natchez.{ EntryPoint, Kernel }
import org.http4s.HttpRoutes
import org.http4s.dsl.io._
Given an EntryPoint
we can trace an Http4s request by constructing a new root span in the routing handler.
def routes(ep: EntryPoint[IO]): HttpRoutes[IO] =
HttpRoutes.of[IO] {
case GET -> Root / "hello" / name =>
ep.root("hello").use { span =>
span.put("the-name" -> name) *> Ok(s"Hello, $name.")
}
}
We can also attempt to continue a trace started on another computer by constructing a Kernel
from our header values
def continuedRoutes(ep: EntryPoint[IO]): HttpRoutes[IO] =
HttpRoutes.of[IO] {
case req@(GET -> Root / "hello" / name) =>
val k: Kernel =
Kernel(req.headers.headers.map { h => h.name.toString -> h.value }.toMap)
ep.continueOrElseRoot("hello", k).use { span =>
span.put("the-name" -> name) *>
Ok(s"Hello, $name.")
}
}
The natchez-http4s
project provides server and client middlewares to receive and propagate kernels, as well as lifting machinery for Trace
constraints. Please use it instead of writing it yourself!