Meter behaviour and dispatch facade (OTel metrics/api.md
§Meter, Status: Stable, L157-L176).
A Meter creates instruments. Per spec L161-L162 "Meter
SHOULD NOT be responsible for the configuration. This
should be the responsibility of the MeterProvider
instead" — we honour this by keeping configuration
(resource, views, etc.) in Otel.API.Metrics.MeterProvider
and exposing no config-related functions on the Meter
itself. Spec L166-L174 enumerates seven instruments the
Meter MUST provide creation functions for; all seven are
covered (create_counter/3, create_histogram/3,
create_gauge/3, create_updown_counter/3, plus the
three create_observable_* pairs).
BEAM representation
A Meter is represented as a {dispatcher_module, state}
tuple — the same shape Tracer and Logger use for
facade dispatch. Callers obtain a Meter via
Otel.API.Metrics.MeterProvider.get_meter/1 rather than
constructing the tuple directly; the dispatcher_module
MUST implement this behaviour.
All functions are safe for concurrent use (spec L1351-L1352, §Concurrency §Instrument).
Divergences from opentelemetry-erlang
opentelemetry-erlang's otel_meter.erl diverges in
seven places. All are spec-aligned or intentional
API-surface trims:
- Creation API shape — erlang has generic
create_instrument/4,6(Kind)callbacks taking the kind as a parameter; we expose one callback per instrument kind (10 callbacks total across/3and/5arities). Matches the facade-per-kind pattern exposed byCounter,Histogram,ObservableGauge, and siblings. register_callback/5signature — erlang hasregister_callback/4(noopts, returnsok). We acceptoptsand return aregistration()handle consumable byunregister_callback/1.unregister_callback/1added — erlang has no such function. Specapi.mdL419-L420 MUST "user MUST be able to undo registration of the specific callback"; we implement it.enabled?/2added — erlang has no such function. Specapi.mdL475-L495 SHOULD provides the instrument-enabled API; we implement it.record/3without context — erlang threadsCtxthroughrecord/5. Our synchronous metric recording does not associate with context at the API boundary; the SDK attaches context viaOtel.API.Ctxif relevant.scope/1not exposed — erlang returns the instrumentation scope from a Meter. We do not expose this; MeterProvider holds the scope, and the{module, state}tuple carries whatever the SDK needs. Not a spec MUST; API surface trim.lookup_instrument/2not exposed — erlang supports looking up an existing instrument by name. Not a spec operation; callers hold the struct handle returned bycreate_*. API surface trim.
Public API
| Function | Role |
|---|---|
create_counter/3 | Application (OTel API MUST) — Counter creation (api.md L510-L542) |
create_histogram/3 | Application (OTel API MUST) — Histogram creation (api.md L746-L777) |
create_gauge/3 | Application (OTel API MUST) — Gauge creation (api.md L852-L872) |
create_updown_counter/3 | Application (OTel API MUST) — UpDownCounter creation (api.md L1084-L1115) |
create_observable_counter/3,5 | Application (OTel API MUST) — Async Counter creation (api.md L613-L703) |
create_observable_gauge/3,5 | Application (OTel API MUST) — Async Gauge creation (api.md L934-L1031) |
create_observable_updown_counter/3,5 | Application (OTel API MUST) — Async UpDownCounter creation (api.md L1176-L1277) |
record/3 | Application (OTel API MUST) — Counter Add / Histogram Record / Gauge Record / UpDownCounter Add dispatch |
register_callback/5 | Application (OTel API MUST) — callback creation (api.md L408-L410) |
unregister_callback/1 | Application (OTel API MUST) — undo registration (api.md L419-L420) |
enabled?/2 | Application (OTel API SHOULD) — Enabled (api.md L475-L495) |
@callback declarations of the above | SDK (OTel API MUST/SHOULD) — SDK dispatch contract |
References
- OTel Metrics API §Meter:
opentelemetry-specification/specification/metrics/api.mdL157-L176 - OTel Metrics API §Synchronous Instrument API:
opentelemetry-specification/specification/metrics/api.mdL302-L348 - OTel Metrics API §Asynchronous Instrument API:
opentelemetry-specification/specification/metrics/api.mdL350-L472 - OTel Metrics API §General operations / Enabled:
opentelemetry-specification/specification/metrics/api.mdL473-L495 - OTel Metrics API §Concurrency §Instrument:
opentelemetry-specification/specification/metrics/api.mdL1351-L1352 - Reference impl:
opentelemetry-erlang/apps/opentelemetry_api_experimental/src/otel_meter.erl
Summary
Types
Handle returned by register_callback/5. Pass to
unregister_callback/1 to undo the registration.
A {dispatcher_module, state} pair.
Callbacks
SDK (OTel API MUST) — Dispatch callback for
create_counter/3 (api.md §Counter creation L510-L542).
SDK (OTel API MUST) — Dispatch callback for
create_gauge/3 (api.md §Gauge creation L852-L872).
SDK (OTel API MUST) — Dispatch callback for
create_histogram/3 (api.md §Histogram creation
L746-L777).
SDK (OTel API MUST) — Dispatch callback for
create_observable_counter/3 without inline callback
(api.md §Asynchronous Counter creation L613-L703).
SDK (OTel API MUST) — Dispatch callback for
create_observable_counter/5 with inline callback
(api.md L613-L703 + L446-L447 MUST — callbacks
registered at creation time).
SDK (OTel API MUST) — Dispatch callback for
create_observable_gauge/3 without inline callback
(api.md §Asynchronous Gauge creation L934-L1031).
SDK (OTel API MUST) — Dispatch callback for
create_observable_gauge/5 with inline callback
(api.md L934-L1031 + L446-L447 MUST).
SDK (OTel API MUST) — Dispatch callback for
create_observable_updown_counter/3 without inline
callback (api.md §Asynchronous UpDownCounter creation
L1176-L1277).
SDK (OTel API MUST) — Dispatch callback for
create_observable_updown_counter/5 with inline callback
(api.md L1176-L1277 + L446-L447 MUST).
SDK (OTel API MUST) — Dispatch callback for
create_updown_counter/3 (api.md §UpDownCounter
creation L1084-L1115).
SDK (OTel API SHOULD) — Dispatch callback for
enabled?/2 (api.md §General operations — Enabled,
L475-L495).
SDK (OTel API MUST) — Dispatch callback for record/3
(api.md §Counter Add L545-L598 / §Histogram Record
L781-L826 / §Gauge Record L876-L915 / §UpDownCounter Add
L1118-L1156).
SDK (OTel API MUST) — Dispatch callback for
register_callback/5 (api.md L408-L410 — callback
creation for async instruments).
SDK (OTel API MUST) — Dispatch callback for
unregister_callback/1 (api.md L419-L420 — undo
callback registration).
Functions
Application (OTel API MUST) — "Counter creation"
(api.md L510-L542). Dispatches to
dispatcher_module.create_counter/3.
Application (OTel API MUST) — "Gauge creation"
(api.md L852-L872). Dispatches to
dispatcher_module.create_gauge/3.
Application (OTel API MUST) — "Histogram creation"
(api.md L746-L777). Dispatches to
dispatcher_module.create_histogram/3.
Application (OTel API MUST) — "Async Counter creation"
without inline callback (api.md L613-L703). Dispatches to
dispatcher_module.create_observable_counter/3.
Application (OTel API MUST) — "Async Counter creation"
with inline callback (api.md L613-L703). callback is a
1-arity function receiving callback_args and returning
[Measurement.t()] per spec L441-L442 list-return form.
Dispatches to
dispatcher_module.create_observable_counter/5.
Application (OTel API MUST) — "Async Gauge creation"
without inline callback (api.md L934-L1031). Dispatches
to dispatcher_module.create_observable_gauge/3.
Application (OTel API MUST) — "Async Gauge creation"
with inline callback (api.md L934-L1031). Same callback
contract as create_observable_counter/5.
Application (OTel API MUST) — "Async UpDownCounter
creation" without inline callback (api.md L1176-L1277).
Dispatches to
dispatcher_module.create_observable_updown_counter/3.
Application (OTel API MUST) — "Async UpDownCounter
creation" with inline callback (api.md L1176-L1277).
Same callback contract as create_observable_counter/5.
Application (OTel API MUST) — "UpDownCounter creation"
(api.md L1084-L1115). Dispatches to
dispatcher_module.create_updown_counter/3.
Application (OTel API SHOULD) — "Enabled" (api.md
§General operations — Enabled, L475-L495).
Application (OTel API MUST) — Records a measurement for the given instrument.
Application (OTel API MUST) — Registers a callback for
one or more asynchronous instruments (api.md L408-L410
MUST support callback creation).
Application (OTel API MUST) — Undoes a prior
register_callback/5 registration (api.md L419-L420
"user MUST be able to undo registration of the specific
callback").
Types
@type primitive_any() :: primitive() | [primitive_any()] | %{required(String.t()) => primitive_any()}
Handle returned by register_callback/5. Pass to
unregister_callback/1 to undo the registration.
Structurally a {dispatcher_module, state} pair — the
same shape as t/0 — but distinct in role: registration
identifies a callback registration rather than a Meter.
The API layer treats state as opaque; callers should
consume the handle exclusively through
unregister_callback/1 rather than destructuring it.
Not declared @opaque because dispatcher implementations
(e.g. Otel.API.Metrics.Meter.Noop, the SDK Meter) must
construct the tuple directly — an @opaque type cannot
be constructed from outside its defining module, which
would require an extra factory function per the
{module, state} dispatch idiom the project already uses
unopaqued on Tracer.t/0, Logger.t/0, and Meter.t/0.
A {dispatcher_module, state} pair.
The API layer treats state as opaque; only
dispatcher_module knows how to interpret it.
dispatcher_module MUST implement the
Otel.API.Metrics.Meter behaviour.
Obtain a Meter via
Otel.API.Metrics.MeterProvider.get_meter/1 rather than
constructing the tuple directly.
Callbacks
@callback create_counter( meter :: t(), name :: String.t(), opts :: Otel.API.Metrics.Instrument.create_opts() ) :: Otel.API.Metrics.Instrument.t()
SDK (OTel API MUST) — Dispatch callback for
create_counter/3 (api.md §Counter creation L510-L542).
@callback create_gauge( meter :: t(), name :: String.t(), opts :: Otel.API.Metrics.Instrument.create_opts() ) :: Otel.API.Metrics.Instrument.t()
SDK (OTel API MUST) — Dispatch callback for
create_gauge/3 (api.md §Gauge creation L852-L872).
@callback create_histogram( meter :: t(), name :: String.t(), opts :: Otel.API.Metrics.Instrument.create_opts() ) :: Otel.API.Metrics.Instrument.t()
SDK (OTel API MUST) — Dispatch callback for
create_histogram/3 (api.md §Histogram creation
L746-L777).
@callback create_observable_counter( meter :: t(), name :: String.t(), opts :: Otel.API.Metrics.Instrument.create_opts() ) :: Otel.API.Metrics.Instrument.t()
SDK (OTel API MUST) — Dispatch callback for
create_observable_counter/3 without inline callback
(api.md §Asynchronous Counter creation L613-L703).
@callback create_observable_counter( meter :: t(), name :: String.t(), callback :: (term() -> [Otel.API.Metrics.Measurement.t()]), callback_args :: term(), opts :: Otel.API.Metrics.Instrument.create_opts() ) :: Otel.API.Metrics.Instrument.t()
SDK (OTel API MUST) — Dispatch callback for
create_observable_counter/5 with inline callback
(api.md L613-L703 + L446-L447 MUST — callbacks
registered at creation time).
@callback create_observable_gauge( meter :: t(), name :: String.t(), opts :: Otel.API.Metrics.Instrument.create_opts() ) :: Otel.API.Metrics.Instrument.t()
SDK (OTel API MUST) — Dispatch callback for
create_observable_gauge/3 without inline callback
(api.md §Asynchronous Gauge creation L934-L1031).
@callback create_observable_gauge( meter :: t(), name :: String.t(), callback :: (term() -> [Otel.API.Metrics.Measurement.t()]), callback_args :: term(), opts :: Otel.API.Metrics.Instrument.create_opts() ) :: Otel.API.Metrics.Instrument.t()
SDK (OTel API MUST) — Dispatch callback for
create_observable_gauge/5 with inline callback
(api.md L934-L1031 + L446-L447 MUST).
@callback create_observable_updown_counter( meter :: t(), name :: String.t(), opts :: Otel.API.Metrics.Instrument.create_opts() ) :: Otel.API.Metrics.Instrument.t()
SDK (OTel API MUST) — Dispatch callback for
create_observable_updown_counter/3 without inline
callback (api.md §Asynchronous UpDownCounter creation
L1176-L1277).
@callback create_observable_updown_counter( meter :: t(), name :: String.t(), callback :: (term() -> [Otel.API.Metrics.Measurement.t()]), callback_args :: term(), opts :: Otel.API.Metrics.Instrument.create_opts() ) :: Otel.API.Metrics.Instrument.t()
SDK (OTel API MUST) — Dispatch callback for
create_observable_updown_counter/5 with inline callback
(api.md L1176-L1277 + L446-L447 MUST).
@callback create_updown_counter( meter :: t(), name :: String.t(), opts :: Otel.API.Metrics.Instrument.create_opts() ) :: Otel.API.Metrics.Instrument.t()
SDK (OTel API MUST) — Dispatch callback for
create_updown_counter/3 (api.md §UpDownCounter
creation L1084-L1115).
@callback enabled?( instrument :: Otel.API.Metrics.Instrument.t(), opts :: Otel.API.Metrics.Instrument.enabled_opts() ) :: boolean()
SDK (OTel API SHOULD) — Dispatch callback for
enabled?/2 (api.md §General operations — Enabled,
L475-L495).
@callback record( instrument :: Otel.API.Metrics.Instrument.t(), value :: number(), attributes :: %{required(String.t()) => primitive_any()} ) :: :ok
SDK (OTel API MUST) — Dispatch callback for record/3
(api.md §Counter Add L545-L598 / §Histogram Record
L781-L826 / §Gauge Record L876-L915 / §UpDownCounter Add
L1118-L1156).
@callback register_callback( meter :: t(), instruments :: [Otel.API.Metrics.Instrument.t()], callback :: (term() -> [ {Otel.API.Metrics.Instrument.t(), Otel.API.Metrics.Measurement.t()} ]), callback_args :: term(), opts :: Otel.API.Metrics.Instrument.register_callback_opts() ) :: registration()
SDK (OTel API MUST) — Dispatch callback for
register_callback/5 (api.md L408-L410 — callback
creation for async instruments).
@callback unregister_callback(state :: term()) :: :ok
SDK (OTel API MUST) — Dispatch callback for
unregister_callback/1 (api.md L419-L420 — undo
callback registration).
Functions
@spec create_counter( meter :: t(), name :: String.t(), opts :: Otel.API.Metrics.Instrument.create_opts() ) :: Otel.API.Metrics.Instrument.t()
Application (OTel API MUST) — "Counter creation"
(api.md L510-L542). Dispatches to
dispatcher_module.create_counter/3.
@spec create_gauge( meter :: t(), name :: String.t(), opts :: Otel.API.Metrics.Instrument.create_opts() ) :: Otel.API.Metrics.Instrument.t()
Application (OTel API MUST) — "Gauge creation"
(api.md L852-L872). Dispatches to
dispatcher_module.create_gauge/3.
@spec create_histogram( meter :: t(), name :: String.t(), opts :: Otel.API.Metrics.Instrument.create_opts() ) :: Otel.API.Metrics.Instrument.t()
Application (OTel API MUST) — "Histogram creation"
(api.md L746-L777). Dispatches to
dispatcher_module.create_histogram/3.
@spec create_observable_counter( meter :: t(), name :: String.t(), opts :: Otel.API.Metrics.Instrument.create_opts() ) :: Otel.API.Metrics.Instrument.t()
Application (OTel API MUST) — "Async Counter creation"
without inline callback (api.md L613-L703). Dispatches to
dispatcher_module.create_observable_counter/3.
@spec create_observable_counter( meter :: t(), name :: String.t(), callback :: (term() -> [Otel.API.Metrics.Measurement.t()]), callback_args :: term(), opts :: Otel.API.Metrics.Instrument.create_opts() ) :: Otel.API.Metrics.Instrument.t()
Application (OTel API MUST) — "Async Counter creation"
with inline callback (api.md L613-L703). callback is a
1-arity function receiving callback_args and returning
[Measurement.t()] per spec L441-L442 list-return form.
Dispatches to
dispatcher_module.create_observable_counter/5.
@spec create_observable_gauge( meter :: t(), name :: String.t(), opts :: Otel.API.Metrics.Instrument.create_opts() ) :: Otel.API.Metrics.Instrument.t()
Application (OTel API MUST) — "Async Gauge creation"
without inline callback (api.md L934-L1031). Dispatches
to dispatcher_module.create_observable_gauge/3.
@spec create_observable_gauge( meter :: t(), name :: String.t(), callback :: (term() -> [Otel.API.Metrics.Measurement.t()]), callback_args :: term(), opts :: Otel.API.Metrics.Instrument.create_opts() ) :: Otel.API.Metrics.Instrument.t()
Application (OTel API MUST) — "Async Gauge creation"
with inline callback (api.md L934-L1031). Same callback
contract as create_observable_counter/5.
@spec create_observable_updown_counter( meter :: t(), name :: String.t(), opts :: Otel.API.Metrics.Instrument.create_opts() ) :: Otel.API.Metrics.Instrument.t()
Application (OTel API MUST) — "Async UpDownCounter
creation" without inline callback (api.md L1176-L1277).
Dispatches to
dispatcher_module.create_observable_updown_counter/3.
@spec create_observable_updown_counter( meter :: t(), name :: String.t(), callback :: (term() -> [Otel.API.Metrics.Measurement.t()]), callback_args :: term(), opts :: Otel.API.Metrics.Instrument.create_opts() ) :: Otel.API.Metrics.Instrument.t()
Application (OTel API MUST) — "Async UpDownCounter
creation" with inline callback (api.md L1176-L1277).
Same callback contract as create_observable_counter/5.
@spec create_updown_counter( meter :: t(), name :: String.t(), opts :: Otel.API.Metrics.Instrument.create_opts() ) :: Otel.API.Metrics.Instrument.t()
Application (OTel API MUST) — "UpDownCounter creation"
(api.md L1084-L1115). Dispatches to
dispatcher_module.create_updown_counter/3.
@spec enabled?( instrument :: Otel.API.Metrics.Instrument.t(), opts :: Otel.API.Metrics.Instrument.enabled_opts() ) :: boolean()
Application (OTel API SHOULD) — "Enabled" (api.md
§General operations — Enabled, L475-L495).
Returns whether the instrument is enabled. Per spec L493-L495 the returned value is not static — it can change over time as configuration or sampling state evolves. Instrumentation authors SHOULD call this each time before recording to have the most up-to-date response.
@spec record( instrument :: Otel.API.Metrics.Instrument.t(), value :: number(), attributes :: %{required(String.t()) => primitive_any()} ) :: :ok
Application (OTel API MUST) — Records a measurement for the given instrument.
All synchronous recording paths route through here:
Otel.API.Metrics.Counter.add/3→ Counter Add (api.mdL545-L598)Otel.API.Metrics.UpDownCounter.add/3→ UpDownCounter Add (api.mdL1118-L1156)Otel.API.Metrics.Histogram.record/3→ Histogram Record (api.mdL781-L826)Otel.API.Metrics.Gauge.record/3→ Gauge Record (api.mdL876-L915)
The instrument carries its dispatcher module in its
meter field; record/3 pattern-matches on that and
dispatches to module.record/3.
@spec register_callback( meter :: t(), instruments :: [Otel.API.Metrics.Instrument.t()], callback :: (term() -> [ {Otel.API.Metrics.Instrument.t(), Otel.API.Metrics.Measurement.t()} ]), callback_args :: term(), opts :: Otel.API.Metrics.Instrument.register_callback_opts() ) :: registration()
Application (OTel API MUST) — Registers a callback for
one or more asynchronous instruments (api.md L408-L410
MUST support callback creation).
All instruments MUST belong to the same Meter (spec
L455-L457). The callback is 1-arity and receives
callback_args; its return is a list of
{Instrument, Measurement} pairs per spec L1302-L1303
and the L452-L453 MUST that "multiple-instrument
Callbacks MUST distinguish the instrument associated with
each observed Measurement value".
Returns a registration() handle — pass it to
unregister_callback/1 to undo the registration.
@spec unregister_callback(registration :: registration()) :: :ok
Application (OTel API MUST) — Undoes a prior
register_callback/5 registration (api.md L419-L420
"user MUST be able to undo registration of the specific
callback").
registration is the opaque handle returned by
register_callback/5. After this call the callback is no
longer evaluated during collection.