Otel.API.Trace.TracerProvider behaviour (otel v0.2.0)

Copy Markdown View Source

Global TracerProvider registration and Tracer retrieval (OTel trace/api.md §TracerProvider, L88-L157).

Holds the process-wide pointer to the installed TracerProvider implementation. When no SDK is installed, all operations resolve to the no-op tracer (Otel.API.Trace.Tracer.Noop, matching the {otel_tracer_noop, []} fallback in opentelemetry-erlang).

No API-level Tracer cache

get_tracer/1 does not cache the Tracer it returns. Every call delegates to the registered provider's get_tracer/2 callback (or returns Noop if none). This avoids a bootstrap race: if an early get_tracer/1 is made before the SDK registers, a cached Noop would survive provider installation and silently drop every subsequent span.

The spec's "identical for identical parameters" requirement (trace/api.md L136-L140) is still satisfied because SDK implementations return structurally-equal Tracer tuples for equal scopes, and the Noop case is trivially {Noop, []} on every call.

This is an intentional divergence from opentelemetry-erlang — its opentelemetry.erl caches tracers in persistent_term keyed by scope components. Our implementation trades that micro-optimisation for bootstrap-safety correctness. SDK implementations that care about Tracer-instance reuse should cache internally on their own get_tracer/2 path.

Storage

The global provider pointer lives in :persistent_term. This diverges from erlang — its otel_tracer_provider.erl uses a registered gen_server reached via gen_server:call/2, while we read a persistent_term slot directly to avoid the round-trip on the hot path.

All functions are safe for concurrent use (spec L842).

Public API

FunctionRole
get_tracer/1Application (OTel API MUST) — Get a Tracer (L107-L157)
@callback get_tracer/2SDK (OTel API MUST) — Dispatch callback (L107-L157)
get_provider/0SDK (installation hook) — access global provider (L95-L97)
set_provider/1SDK (installation hook) — register global provider (L95-L97)

References

  • OTel Trace API §TracerProvider: opentelemetry-specification/specification/trace/api.md L88-L157, L842
  • Reference impl (tracer cache): opentelemetry-erlang/apps/opentelemetry_api/src/opentelemetry.erl
  • Reference impl (global provider): opentelemetry-erlang/apps/opentelemetry_api/src/otel_tracer_provider.erl

Summary

Types

t()

A {dispatcher_module, state} pair.

Callbacks

SDK (OTel API MUST) — Dispatch callback invoked by get_tracer/1.

Functions

SDK (installation hook) — access the global TracerProvider (trace/api.md L95-L97).

Application (OTel API MUST) — "Get a Tracer" (trace/api.md L107-L157).

SDK (installation hook) — register the global TracerProvider (trace/api.md L95-L97).

Types

t()

@type t() :: {module(), term()}

A {dispatcher_module, state} pair.

The API layer treats the state as opaque; only dispatcher_module knows how to use it. This mirrors Otel.API.Trace.Tracer.t/0 and keeps the API decoupled from SDK internals (GenServer, Registry, etc.).

dispatcher_module MUST implement the Otel.API.Trace.TracerProvider behaviour.

Callbacks

get_tracer(state, instrumentation_scope)

@callback get_tracer(
  state :: term(),
  instrumentation_scope :: Otel.API.InstrumentationScope.t()
) :: Otel.API.Trace.Tracer.t()

SDK (OTel API MUST) — Dispatch callback invoked by get_tracer/1.

Implementations receive the opaque state they registered via set_provider/1 along with the requested instrumentation scope, and return a Tracer. The get_tracer/2 shape is the API↔SDK dispatch contract for §"Get a Tracer" (trace/api.md L107-L157).

Functions

get_provider()

@spec get_provider() :: t() | nil

SDK (installation hook) — access the global TracerProvider (trace/api.md L95-L97).

"the API SHOULD provide a way to set/register and access a global default TracerProvider."

Returns the currently registered provider, or nil if none is registered.

get_tracer(instrumentation_scope)

@spec get_tracer(instrumentation_scope :: Otel.API.InstrumentationScope.t()) ::
  Otel.API.Trace.Tracer.t()

Application (OTel API MUST) — "Get a Tracer" (trace/api.md L107-L157).

Returns a Tracer for the given instrumentation scope. Each call delegates to the registered provider's get_tracer/2 callback, or returns the noop tracer when no provider is installed (spec L120-121: invalid or unresolved scope MUST still yield a working Tracer rather than crash) — no API-level cache, see the module's "No API-level Tracer cache" section.

set_provider(provider)

@spec set_provider(provider :: t()) :: :ok

SDK (installation hook) — register the global TracerProvider (trace/api.md L95-L97).

"the API SHOULD provide a way to set/register and access a global default TracerProvider."

Registers the given {module, state} as the global TracerProvider. The SDK TracerProvider calls this from its init/1 with {__MODULE__, server_ref}; module must implement the Otel.API.Trace.TracerProvider behaviour.