One trace's worth of spans (a request's own call tree), kept in the calling process's own
process dictionary: the same isolation boundary ForgeOpsTracker.set_user/1 and
ForgeOpsTracker.add_breadcrumb/4 already use, and for the same reason (Phoenix and Oban both
run one unit of work in one process). Not something app code normally calls directly; see
ForgeOpsTracker.span/4 and ForgeOpsTracker.record_span/5.
Nesting comes from a stack of open span ids: a span opened while another is open becomes its
child, and anything else parents under the root. A trace is sent only when its root span took at
least Configuration.trace_capture_threshold milliseconds, or the request errored, decided here
once the root finishes, so a fast, successful request costs nothing on the wire.
Alongside the spans, the process dictionary holds the request's own context (trace id, the
remote parent span id from an incoming traceparent, transaction name, endpoint, and whether it
errored), kept whether or not track_tracing is on: the trace id is also what an error event
carries so ForgeOps can link it to errors other services reported for the same trace.
Summary
Functions
True when the calling process has an open trace.
The calling process's current trace id, or nil outside a trace.
The top-level fields an error event carries for the request it happened in:
"trace_id", "transaction_name", "endpoint", each left out when unknown. Falls back to
what snapshot_escaped/1 remembered for reason once the request itself is over, and to %{}
outside a request.
Ends the calling process's trace, always clearing it along with the request context, and queues
it for delivery when the root took at least trace_capture_threshold milliseconds or the request
errored. started_at is a DateTime.
Makes one outgoing HTTP call inside the calling process's trace: records it as an "http" span
named "<METHOD> <host>" (never the path or query, which could carry an id or a token) and calls
fun with a list of {name, value} headers to add to the request, currently a W3C
traceparent whose parent id is that span's own id. The headers are [] outside a trace, when
propagate_traces is off, or when the host isn't in trace_propagation_targets; outside a trace
no span is recorded either, and with track_tracing off the header is still handed over but no
span is kept.
Marks the current request errored, so its trace is sent however fast it was.
Records a span you timed yourself under the current one; a no-op outside a trace.
Names the current request (a no-op outside one): transaction_name is the same name its
performance sample and root span use, endpoint the HTTP method plus the route pattern.
Remembers the current request's context for reason, an error escaping the request, and marks
it errored, so an error reported only after finish_trace/4 has cleared the request (as a
Phoenix request's crash is, by the :logger handler, once the router has already emitted
:exception) still carries it. The calling process's user and breadcrumbs are untouched by
finish_trace/4, so only the request context needs remembering. Cleared by the next
start_trace/1 on the same process.
Times fun as a child span of whatever span is open (or of the root), returning its result.
Outside a trace it just runs fun. Recorded even if fun raises, throws or exits, which then
propagates unchanged.
Starts a fresh trace on the calling process, discarding any earlier one. traceparent is the
incoming request's own header value: a usable W3C value continues the caller's trace (same trace
id, and the root span's parent is the caller's span), anything else (nil, blank, malformed)
starts a new one. The request context is set whenever the client is enabled; spans are only
recorded when track_tracing is on too. A no-op when the client isn't enabled.
Types
Functions
@spec active?() :: boolean()
True when the calling process has an open trace.
@spec current_trace_id() :: String.t() | nil
The calling process's current trace id, or nil outside a trace.
The top-level fields an error event carries for the request it happened in:
"trace_id", "transaction_name", "endpoint", each left out when unknown. Falls back to
what snapshot_escaped/1 remembered for reason once the request itself is over, and to %{}
outside a request.
@spec finish_trace(String.t(), String.t(), DateTime.t(), number()) :: :ok
Ends the calling process's trace, always clearing it along with the request context, and queues
it for delivery when the root took at least trace_capture_threshold milliseconds or the request
errored. started_at is a DateTime.
@spec http_span(String.t() | atom(), String.t() | URI.t(), map(), (headers() -> result)) :: result when result: var
Makes one outgoing HTTP call inside the calling process's trace: records it as an "http" span
named "<METHOD> <host>" (never the path or query, which could carry an id or a token) and calls
fun with a list of {name, value} headers to add to the request, currently a W3C
traceparent whose parent id is that span's own id. The headers are [] outside a trace, when
propagate_traces is off, or when the host isn't in trace_propagation_targets; outside a trace
no span is recorded either, and with track_tracing off the header is still handed over but no
span is kept.
@spec mark_errored() :: :ok
Marks the current request errored, so its trace is sent however fast it was.
@spec record_span(String.t(), String.t(), DateTime.t(), number(), map()) :: :ok
Records a span you timed yourself under the current one; a no-op outside a trace.
Names the current request (a no-op outside one): transaction_name is the same name its
performance sample and root span use, endpoint the HTTP method plus the route pattern.
@spec snapshot_escaped(term()) :: :ok
Remembers the current request's context for reason, an error escaping the request, and marks
it errored, so an error reported only after finish_trace/4 has cleared the request (as a
Phoenix request's crash is, by the :logger handler, once the router has already emitted
:exception) still carries it. The calling process's user and breadcrumbs are untouched by
finish_trace/4, so only the request context needs remembering. Cleared by the next
start_trace/1 on the same process.
Times fun as a child span of whatever span is open (or of the root), returning its result.
Outside a trace it just runs fun. Recorded even if fun raises, throws or exits, which then
propagates unchanged.
@spec start_trace(String.t() | nil) :: :ok
Starts a fresh trace on the calling process, discarding any earlier one. traceparent is the
incoming request's own header value: a usable W3C value continues the caller's trace (same trace
id, and the root span's parent is the caller's span), anything else (nil, blank, malformed)
starts a new one. The request context is set whenever the client is enabled; spans are only
recorded when track_tracing is on too. A no-op when the client isn't enabled.