Tracing Reference

View Source

Complete API reference for the distributed tracing system.

Overview

The instrument_tracer module provides an OpenTelemetry-compatible tracing API with:

  • Span creation and lifecycle management
  • Attributes, events, and status
  • Context propagation
  • Multiple export options

TracerProvider API

instrument_tracer:get_tracer/1, instrument_tracer:get_tracer/2

Gets or creates a tracer.

-spec get_tracer(Name) -> tracer() when
    Name :: binary() | atom().

-spec get_tracer(Name, Opts) -> tracer() when
    Name :: binary() | atom(),
    Opts :: #{
        version => binary(),
        schema_url => binary(),
        resource => map()
    }.

Example:

Tracer = instrument_tracer:get_tracer(<<"my_service">>).
Tracer = instrument_tracer:get_tracer(my_service, #{version => <<"1.0.0">>}).

Span Lifecycle

instrument_tracer:with_span/2, instrument_tracer:with_span/3

Executes a function within a span. Recommended for most use cases.

-spec with_span(Name, Fun) -> Result when
    Name :: binary() | atom(),
    Fun :: fun(() -> Result),
    Result :: term().

-spec with_span(Name, Opts, Fun) -> Result when
    Name :: binary() | atom(),
    Opts :: span_opts(),
    Fun :: fun(() -> Result),
    Result :: term().

Span Options:

-type span_opts() :: #{
    kind => client | server | producer | consumer | internal,
    attributes => map(),
    links => [#span_link{}],
    start_time => integer(),
    parent => #span_ctx{} | undefined,
    span_id => binary()     %% Custom 8-byte binary or 16-char hex string
}.

Examples:

%% Basic span
Result = instrument_tracer:with_span(<<"operation">>, fun() ->
    do_work()
end).

%% Span with options
Result = instrument_tracer:with_span(<<"http_request">>, #{
    kind => server,
    attributes => #{<<"http.method">> => <<"GET">>}
}, fun() ->
    handle_request()
end).

Behavior:

  • Automatically starts the span
  • Captures exceptions and records them
  • Sets error status on exceptions
  • Re-raises exceptions after recording
  • Ends the span in all cases (success, error, exception)

instrument_tracer:start_span/1, instrument_tracer:start_span/2

Manually starts a span. Use when you need more control.

-spec start_span(Name) -> span().
-spec start_span(Name, Opts) -> span().

Example:

Span = instrument_tracer:start_span(<<"manual_operation">>),
try
    do_work()
after
    instrument_tracer:end_span(Span)
end.

instrument_tracer:end_span/0, instrument_tracer:end_span/1

Ends a span.

-spec end_span() -> ok.
-spec end_span(Span) -> ok when Span :: span().

instrument_tracer:current_span/0

Returns the current span or undefined.

-spec current_span() -> span() | undefined.

Span Modification

instrument_tracer:set_attributes/1

Sets multiple attributes on the current span.

-spec set_attributes(Attrs) -> ok when
    Attrs :: map().

Example:

instrument_tracer:set_attributes(#{
    <<"http.method">> => <<"GET">>,
    <<"http.url">> => <<"https://example.com/api">>,
    <<"http.status_code">> => 200
}).

instrument_tracer:set_attribute/2

Sets a single attribute.

-spec set_attribute(Key, Value) -> ok when
    Key :: term(),
    Value :: term().

instrument_tracer:add_event/1, instrument_tracer:add_event/2

Adds a timestamped event to the span.

-spec add_event(Name) -> ok when
    Name :: binary().

-spec add_event(Name, Attrs) -> ok when
    Name :: binary(),
    Attrs :: map().

Example:

instrument_tracer:add_event(<<"cache_hit">>).
instrument_tracer:add_event(<<"query_executed">>, #{
    <<"db.rows_affected">> => 5
}).

instrument_tracer:set_status/1, instrument_tracer:set_status/2

Sets the span status.

-spec set_status(Status) -> ok when
    Status :: ok | error.

-spec set_status(error, Description) -> ok when
    Description :: binary().

Example:

instrument_tracer:set_status(ok).
instrument_tracer:set_status(error, <<"Payment declined">>).

instrument_tracer:record_exception/1, instrument_tracer:record_exception/2

Records an exception as a span event.

-spec record_exception(Exception) -> ok when
    Exception :: term().

-spec record_exception(Exception, Opts) -> ok when
    Exception :: term(),
    Opts :: #{stacktrace => list()}.

Example:

try
    risky_operation()
catch
    error:Reason:Stacktrace ->
        instrument_tracer:record_exception(Reason, #{
            stacktrace => Stacktrace
        }),
        handle_error(Reason)
end.

Adds a link to another span.

-spec add_link(SpanCtx | Opts) -> ok when
    SpanCtx :: #span_ctx{},
    Opts :: #{
        span_ctx := #span_ctx{},
        attributes => map()
    }.

instrument_tracer:update_name/1

Updates the span name.

-spec update_name(Name) -> ok when
    Name :: binary().

SpanContext

instrument_tracer:span_ctx/0, instrument_tracer:span_ctx/1

Gets the span context.

-spec span_ctx() -> #span_ctx{} | undefined.
-spec span_ctx(Span) -> #span_ctx{}.

instrument_tracer:trace_id/0, instrument_tracer:trace_id/1

Gets the trace ID as a hex string.

-spec trace_id() -> binary() | undefined.
-spec trace_id(Span) -> binary().

instrument_tracer:span_id/0, instrument_tracer:span_id/1

Gets the span ID as a hex string.

-spec span_id() -> binary() | undefined.
-spec span_id(Span) -> binary().

instrument_tracer:is_recording/0

Checks if the current span is recording.

-spec is_recording() -> boolean().

instrument_tracer:is_sampled/0

Checks if the current span is sampled.

-spec is_sampled() -> boolean().

Export

instrument_tracer:register_exporter/1

Registers a span exporter function.

-spec register_exporter(Exporter) -> ok when
    Exporter :: fun((span()) -> ok).

Example:

%% Console exporter
instrument_tracer:register_exporter(
    fun(Span) -> instrument_exporter_console:export(Span) end
).

%% Custom exporter
instrument_tracer:register_exporter(fun(Span) ->
    io:format("Span: ~s (~.3f ms)~n", [
        Span#span.name,
        (Span#span.end_time - Span#span.start_time) / 1000000
    ])
end).

instrument_tracer:unregister_exporter/1

Unregisters an exporter.

-spec unregister_exporter(Exporter) -> ok.

Context Module

The instrument_context module manages context propagation.

instrument_context:new/0

Creates an empty context.

-spec new() -> context().

instrument_context:current/0

Returns the current context.

-spec current() -> context().

instrument_context:attach/1

Attaches a context, returning a token for detachment.

-spec attach(Context) -> token().

instrument_context:detach/1

Detaches and restores the previous context.

-spec detach(Token) -> ok.

instrument_context:set_current/1

Sets the current context without history (for spawned processes).

-spec set_current(Context) -> ok.

instrument_context:with_context/2

Executes a function with a context attached.

-spec with_context(Context, Fun) -> Result.

Context Values

%% Get a value
Value = instrument_context:get_value(Ctx, Key).
Value = instrument_context:get_value(Ctx, Key, Default).

%% Set a value (returns new context)
NewCtx = instrument_context:set_value(Ctx, Key, Value).

%% Remove a value
NewCtx = instrument_context:remove_value(Ctx, Key).

Process Spawning

%% Spawn with context
Pid = instrument_context:spawn_with_context(Fun).
Pid = instrument_context:spawn_with_context(Module, Function).

%% Spawn linked with context
Pid = instrument_context:spawn_link_with_context(Fun).
Pid = instrument_context:spawn_link_with_context(Module, Function).

Propagation Module

The instrument_propagation module handles cross-boundary propagation.

Process Spawning

Pid = instrument_propagation:spawn(Fun).
Pid = instrument_propagation:spawn(Fun, Args).
Pid = instrument_propagation:spawn_link(Fun).
Pid = instrument_propagation:spawn_link(Fun, Args).
{Pid, Ref} = instrument_propagation:spawn_monitor(Fun).
Pid = instrument_propagation:spawn_opt(Fun, Opts).

Gen Server Integration

%% Call with context
Result = instrument_propagation:call_with_context(Server, Request).
Result = instrument_propagation:call_with_context(Server, Request, Timeout).

%% Cast with context
ok = instrument_propagation:cast_with_context(Server, Msg).

HTTP Headers

%% Inject into headers
Headers = instrument_propagation:inject_headers(Context).
%% Returns: [{<<"traceparent">>, <<"00-...">>}, ...]

%% Extract from headers
Context = instrument_propagation:extract_headers(Headers).

Generic Carrier

%% Inject into map
Carrier = instrument_propagation:inject(#{}).
Carrier = instrument_propagation:inject(Context, #{}).

%% Extract from map
Context = instrument_propagation:extract(Carrier).
Context = instrument_propagation:extract(Carrier, BaseContext).

Types

-type tracer() :: #tracer{
    name :: binary(),
    version :: binary() | undefined,
    schema_url :: binary() | undefined,
    resource :: map() | undefined
}.

-type span() :: #span{
    name :: binary(),
    ctx :: #span_ctx{},
    parent_ctx :: #span_ctx{} | undefined,
    kind :: span_kind(),
    start_time :: integer(),
    end_time :: integer() | undefined,
    attributes :: map(),
    events :: [#span_event{}],
    links :: [#span_link{}],
    status :: ok | error | {error, binary()} | unset,
    is_recording :: boolean()
}.

-type span_ctx() :: #span_ctx{
    trace_id :: binary(),
    span_id :: binary(),
    trace_flags :: integer(),
    trace_state :: list(),
    is_remote :: boolean()
}.

-type span_kind() :: client | server | producer | consumer | internal.

-type context() :: #{term() => term()}.
-type token() :: reference().

Span Kinds

KindDescriptionUse Case
internalDefault. Internal operationFunction calls, computations
serverHandles incoming requestHTTP server, gRPC server
clientMakes outgoing requestHTTP client, DB client
producerSends messageQueue producer, pub/sub
consumerReceives messageQueue consumer, subscriber

Custom Span IDs

You can provide a custom span ID when creating spans. This is useful for:

  • Correlating spans with external systems that generate their own IDs
  • Replaying or importing traces from external sources
  • Testing with predictable IDs

Usage

%% Using 8-byte binary
SpanId = crypto:strong_rand_bytes(8),
instrument_tracer:with_span(<<"operation">>, #{span_id => SpanId}, fun() ->
    do_work()
end).

%% Using 16-character hex string
instrument_tracer:with_span(<<"operation">>, #{span_id => <<"abcd1234abcd1234">>}, fun() ->
    do_work()
end).

ID Format

  • Binary format: 8 bytes (64 bits)
  • Hex string format: 16 lowercase hex characters

The span ID must be non-zero per W3C TraceContext spec.

Best Practices

Span Naming

  • Use descriptive, low-cardinality names
  • Include operation type: db_query, http_request
  • Avoid dynamic values in names (use attributes)

Attributes

  • Follow semantic conventions
  • Include relevant context for debugging
  • Avoid sensitive data

Context Management

  • Always detach attached contexts
  • Use with_span when possible
  • Propagate context across process boundaries

Performance

  • Don't create spans for trivial operations
  • Check is_recording() before expensive attribute computation
  • Use batch processor in production