Otel.Metrics.MetricExporter (otel v0.4.1)

Copy Markdown View Source

Metrics export pipeline — timer-driven snapshot of the per-table XxxStorage GenServers + OTLP encode + HTTP POST. Single GenServer collapsing what was previously a separate Otel.Metrics.MetricReader.PeriodicExporting GenServer (timer + collect) plus a passive HTTP-only MetricExporter module.

Unlike Otel.Trace.SpanExporter and Otel.Logs.LogRecordExporter (which drain a queue), Metrics exports a snapshot of live state — the Otel.Metrics.{InstrumentsStorage, MetricsStorage, ExemplarsStorage} GenServers hold accumulating aggregation / exemplar state. collect/0 walks the instruments ETS table and returns one metric() per registered instrument; the next collect tick reads the same state with fresh aggregation values.

Lifecycle

TriggerAction
:loop self-message every @scheduled_delay_mscollect/1 + encode + POST
force_flush/1force collect + encode + POST synchronously
terminate/2force collect + encode + POST before exit

OTLP HTTP transport

POSTs OTLP/protobuf via Req. User config is read from Application.get_env(:otel, :req_options, []) on every export and forwarded to Req.post/1 — anything Req accepts (TLS, auth, timeouts, retry overrides, mock plugs) works.

The SDK only forces :body (the encoded protobuf). Defaults via Keyword.put_new:

  • :base_urlhttp://localhost:4318 if absent
  • :url/v1/metrics if absent
  • :retry → predicate matching the OTLP-spec retryable response codes (opentelemetry-proto/docs/specification.md L564-575: 429 / 502 / 503 / 504 SHOULD be retried, all other 4xx / 5xx MUST NOT) plus network-level exceptions. Backoff strategy (exponential + jitter) and Retry-After honoring come from Req's default :retry_delay, which satisfies the spec MUST in opentelemetry-specification/specification/protocol/exporter.md L182-202.
  • content-type: application/x-protobuf and user-agent headers merged into the user's :headers

:max_retries is left to Req's default (3 retries = 4 attempts) — the OTLP spec mandates the strategy but not a specific attempt count.

Concurrency

Spec metrics/sdk.md L1880-L1881 (Status: Stable) — "Collect, ForceFlush (for periodic exporting MetricReader) and Shutdown MUST be safe to be called concurrently." The single GenServer mailbox serialises force_flush/1 against the timer-driven :loop message, satisfying the MUST. collect/1 is a pure pull from ETS / :persistent_term state and is safe to call from any process.

References

  • OTel Metrics SDK §MetricReader: opentelemetry-specification/specification/metrics/sdk.md L1280-L1442
  • OTel Metrics SDK §Periodic exporting MetricReader: opentelemetry-specification/specification/metrics/sdk.md L1443-L1500
  • OTel Metrics SDK §MetricExporter: opentelemetry-specification/specification/metrics/sdk.md L1530-L1660
  • OTLP retryable response codes: opentelemetry-proto/docs/specification.md L565-L573

Summary

Functions

Returns a specification to start this module under a supervisor.

SDK — Walks Otel.Metrics.InstrumentsStorage and returns one metric() per registered instrument.

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

collect()

@spec collect() :: [Otel.Metrics.Metric.t()]

SDK — Walks Otel.Metrics.InstrumentsStorage and returns one metric() per registered instrument.

Pure pull from ETS state — safe to invoke from any process.

force_flush(timeout \\ 30000)

@spec force_flush(timeout :: timeout()) :: :ok

start_link(opts \\ [])

@spec start_link(opts :: keyword()) :: GenServer.on_start()