AuroraMeter.OpenTelemetry.Bridge (Aurora Meter v1.0.0)

View Source

Internal. Not part of the supported API (see API inventory). It may change in any release, including a patch. Hosts call AuroraMeter.OpenTelemetry.attach/1.

Everything the OpenTelemetry bridge does, with the tracer as a parameter.

AuroraMeter.OpenTelemetry is compiled only when opentelemetry_api is installed, and it is four lines of delegation into this module plus the implementation of AuroraMeter.OpenTelemetry.Tracer that calls the real API. All of the behaviour lives here so that it is compiled, and tested, in a build with no OpenTelemetry at all.

What gets a span, and what deliberately does not

Slow work: the durable write, the flush, a replay batch, a hold reconciliation, an outbox delivery, a provider round trip. Every one of them is database-bound or network-bound and is worth a trace.

The hot path gets nothing. [:aurora_meter, :track], [:aurora_meter, :reserve], [:aurora_meter, :broadcast], [:aurora_meter, :cluster, :apply] and every gauge are not instrumented, and there is no friendly switch to turn them on. track/4 runs at the rate a metering library is built for; one span per increment would dominate the hot path and the host's trace budget alike. A caller who really wants one passes the event name in :events and owns the consequence.

Attributes carry no identifier

Every attribute goes through AuroraMeter.Telemetry.redact/2, so a tenant key, a reference, an object id, a provider reference and an exception's message are all dropped before anything reaches a tracer. An error is reported as error_class (the exception module or the outcome tag), never as its message, which is where a query, a key or a customer's data ends up.

tenant: :digest puts a stable pseudonym on the span instead, and tenant: :raw puts the key itself there. Both are spelled out at the call site so that carrying an identifier into a tracing pipeline is a decision somebody wrote down.

Idempotency

attach/2 detaches its own handler ids before attaching, so calling it five times leaves exactly the same handler set as calling it once. Two different :name values are independent by construction, because the name is part of every handler id.

Summary

Types

One instrumented event: its base name and whether it is a span triple.

Functions

Attaches one :telemetry handler per instrumented event name.

The events instrumented by default, as {base_event, :span | :flat}.

Removes every handler attached under name, and nothing else.

The handler id this bridge uses for name and event.

Event names this bridge never instruments unless the caller lists them.

Types

instrumented()

@type instrumented() :: {[atom()], :span | :flat}

One instrumented event: its base name and whether it is a span triple.

Functions

attach(opts)

@spec attach(keyword()) :: :ok

Attaches one :telemetry handler per instrumented event name.

Options are AuroraMeter.OpenTelemetry.attach/1's, plus :tracer, the module implementing AuroraMeter.OpenTelemetry.Tracer.

default_events(opts \\ [])

@spec default_events(keyword()) :: [instrumented()]

The events instrumented by default, as {base_event, :span | :flat}.

:include selects halves of the catalogue: [:core, :pro] by default.

Examples

iex> AuroraMeter.OpenTelemetry.Bridge.default_events(include: [:core])
...> |> Enum.map(&elem(&1, 0))
...> |> Enum.member?([:aurora_meter, :flush])
true

iex> AuroraMeter.OpenTelemetry.Bridge.default_events(include: [:core])
...> |> Enum.map(&elem(&1, 0))
...> |> Enum.member?([:aurora_meter, :track])
false

detach(name)

@spec detach(atom()) :: :ok

Removes every handler attached under name, and nothing else.

handler_id(name, event)

@spec handler_id(atom(), [atom()]) :: {module(), atom(), [atom()]}

The handler id this bridge uses for name and event.

never_by_default()

@spec never_by_default() :: [[atom()]]

Event names this bridge never instruments unless the caller lists them.

Examples

iex> [:aurora_meter, :track] in AuroraMeter.OpenTelemetry.Bridge.never_by_default()
true