Natchez provides interfaces that abstract over many distributed tracing back-ends.
Trace are the most important of these interfaces.
The central interface in Natchez is the
Span, which is a managed resource that records timing information and other details about its own lifetime. We perform computations within the lifetime of a span and thus gather timing information about these computations.
Span can create child spans, whose lifetimes are bounded (usually!) by the lifetime of the parent. We can thus gather timing information for various phases of computation within a larger computation. Concurrent computations may have many active child spans.
Spans thus form a tree.
Span (in addition to a parent, name, intrinisic timing information, and other back-end-specific data) contains a string-keyed map of
TraceValues (strings, booleans, and numbers) for arbitrary user-defined information.
Span can provide a hunk of data called a
Kernel, which can be sent to a remote computer, typically via HTTP headers. The remote computer can then create child spans that will be linked with the originating span by the tracing back-end. Tracing is thus distributed.
See the reference for more information on spans.
Before we can add fields to a
Span or create child spans, we must have a span! The chicken-and-egg problem is resolved by the
EntryPoint, which provides us with an initial span.
An initial span can be a root span (with no parent) or a continued span (with a parent on another computer). To construct a continued span we must provide the
Kernel from a parent span, typically received via HTTP headers.
See the reference for more information on entry points.
We must be aware of the current
Span if we wish to add fields or create child spans, which means we must pass the current span around.
It is perfectly fine to pass the current span around explicitly, and if you are working in a concrete effect type like
IO from Cats-Effect 2 this may be the best choice. However for
IO in Cats-Effect 3, as well as the increasingly common case of applications constructed in tagless style (where computations are peformed in some abstract effect) we have a
Trace constraint that ensures an ambient span is always available.
Given an effect
F[_]: Trace we can add fields to the ambient span, gets its kernel, or run a computation in a child of the ambient span, without referencing the underlying
See the reference for more information on the