View Source OpentelemetryProcessPropagator (Opentelemetry Process Propagator v0.2.2)
OpentelemetryProcessPropagator
provides helpers for dealing
with context propagation across process boundaries.
context-propagation
Context Propagation
Erlang and Elixir do not have a mechanism for transparently passing context between processes. This requires the user to explicitly pass data between processes. In order to continue a trace across processes, the user must start a new span and pass it to the spawned process.
span_ctx = OpenTelemetry.Tracer.start_span("child")
ctx = OpenTelemetry.Ctx.get_current()
task =
Task.async(fn ->
OpenTelemetry.Ctx.attach(ctx)
OpenTelemetry.Tracer.set_current_span(span_ctx)
# do work here
OpenTelemetry.Tracer.end_span(span_ctx)
end)
_result = Task.await(task)
reverse-propagation
Reverse Propagation
It's not always possible to have full control over traces, such as
when using telemetry
events emitted from a library you don't control
to create a span. In such cases, a mechanism to fetch a context from a
calling process is necessary. This is effectively context propagation
in reverse.
As an example, Ecto uses the Task
module to execute preloads which are
each a separate query. Since a task is a spawned process, creating an otel
span results in orphan spans. To correctly connect these spans we must
find the otel context which spawned the process.
usage
Usage
Example of using fetch_parent_ctx/1
to find a parent context.
OpenTelemetry.with_span :span_started_in_your_app do
# some span being created in a process spawned by a library
# you don't control, e.g. Ecto preloads
Task.async(fn ->
parent_ctx = OpentelemetryProcessPropagator.fetch_parent_ctx(:"$callers")
OpenTelemetry.Ctx.attach(parent_ctx)
attrs = %{some_attr: :from_telemetry_event}
span =
OpenTelemetry.Tracer.start_span(:span_created_in_lib, %{attributes: attrs})
OpenTelemetry.Span.end_span(span)
end)
end
?with_span(span_started_in_your_app, , fun() ->
%% some span being created in a process spawned by a library
%% you don't control
proc_lib:spawn_link(fun() ->
Tracer = opentelemetry:get_tracer(test_tracer),
ParentCtx = opentelemetry_process_propagator:fetch_parent_ctx(),
otel_ctx:attach(ParentCtx),
Span = otel_tracer:start_span(Tracer, span_created_in_lib, ),
otel_tracer:end_span(Span).
).
end
Link to this section Summary
Functions
Attempt to fetch an otel context from a give pid.
Attempt to find an otel context in the spawning process.
Attempt to find an otel context in a spawning process within n
number of parent
processes
Attempt to find an otel context under a given process dictionary key
within n
number of parent processes. The first context found will be
returned.
Link to this section Functions
@spec fetch_ctx(pid()) :: OpenTelemetry.Ctx.t() | :undefined
Attempt to fetch an otel context from a give pid.
@spec fetch_parent_ctx() :: OpenTelemetry.Ctx.t() | :undefined
Attempt to find an otel context in the spawning process.
This is equivalent to calling fetch_parent_ctx(1, :"$ancestors")
@spec fetch_parent_ctx(non_neg_integer()) :: OpenTelemetry.Ctx.t() | :undefined
Attempt to find an otel context in a spawning process within n
number of parent
processes
@spec fetch_parent_ctx(non_neg_integer(), atom()) :: OpenTelemetry.Ctx.t() | :undefined
Attempt to find an otel context under a given process dictionary key
within n
number of parent processes. The first context found will be
returned.
Processes spawned by proc_lib
are stored under :"$ancestors
. The
Elixir Task
module uses the :"$callers
key.