Otel.API.Logs.LoggerProvider behaviour (otel v0.2.0)

Copy Markdown View Source

Global LoggerProvider registration and Logger retrieval (OTel logs/api.md §LoggerProvider, L54-L97).

Holds the process-wide pointer to the installed LoggerProvider implementation. When no SDK is installed, all operations resolve to the no-op logger (Otel.API.Logs.Logger.Noop).

No API-level Logger cache

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

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

Performance: the API dispatches directly to the provider's get_logger/2 on every call (or returns Noop when no provider is registered). SDK implementations that care about Logger-instance reuse should cache internally on their own get_logger/2 path.

Storage

The global provider pointer lives in :persistent_term. The dispatch pattern ({dispatcher_module, state} tuple + get_logger/2 callback) is shared across Trace, Metrics, and Logs.

Unlike Otel.API.Trace.TracerProvider, opentelemetry-erlang has no otel_logger_provider.erl equivalent — erlang routes Logs through OTP's built-in :logger module rather than exposing a dedicated API. This module fills that gap so the API surface stays uniform across the three signals.

All functions are safe for concurrent use (spec L172-L173).

Public API

FunctionRole
get_logger/0,1Application (OTel API MUST) — Get a Logger (L66-L97)
@callback get_logger/2SDK (OTel API MUST) — Dispatch callback (L66-L97)
get_provider/0SDK (installation hook) — access global provider (L58-L60)
set_provider/1SDK (installation hook) — register global provider (L58-L60)

References

  • OTel Logs API §LoggerProvider: opentelemetry-specification/specification/logs/api.md L54-L97
  • OTel Logs API §Concurrency: opentelemetry-specification/specification/logs/api.md L172-L173

Summary

Types

t()

A {dispatcher_module, state} pair.

Callbacks

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

Functions

Application (OTel API MUST) — "Get a Logger" (logs/api.md L66-L97).

SDK (installation hook) — access the global LoggerProvider (logs/api.md L58-L60).

SDK (installation hook) — register the global LoggerProvider (logs/api.md L58-L60).

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.Logs.Logger.t/0 and keeps the API decoupled from SDK internals (GenServer, Registry, etc.).

dispatcher_module MUST implement the Otel.API.Logs.LoggerProvider behaviour.

Callbacks

get_logger(state, instrumentation_scope)

@callback get_logger(
  state :: term(),
  instrumentation_scope :: Otel.API.InstrumentationScope.t()
) :: Otel.API.Logs.Logger.t()

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

Implementations receive the opaque state they registered via set_provider/1 along with the requested instrumentation scope, and return a Logger. The get_logger/2 shape is the API↔SDK dispatch contract for §"Get a Logger" (logs/api.md L66-L97).

Functions

get_logger(instrumentation_scope \\ %Otel.API.InstrumentationScope{})

@spec get_logger(instrumentation_scope :: Otel.API.InstrumentationScope.t()) ::
  Otel.API.Logs.Logger.t()

Application (OTel API MUST) — "Get a Logger" (logs/api.md L66-L97).

Returns a Logger for the given instrumentation scope. Each call delegates to the registered provider's get_logger/2 callback, or returns the noop logger when no provider is installed — no API-level cache, see the module's "No API-level Logger cache" section.

The full InstrumentationScope struct (name, version, schema_url, attributes — spec L73-L93) is passed to the provider. Spec's "identical for identical parameters" (L95-L97) is satisfied by SDK-side structural equality.

Without arguments, uses a default empty scope.

get_provider()

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

SDK (installation hook) — access the global LoggerProvider (logs/api.md L58-L60).

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

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

set_provider(provider)

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

SDK (installation hook) — register the global LoggerProvider (logs/api.md L58-L60).

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

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

To clear the registration (e.g. in tests), use :persistent_term.erase/1 directly.