Telemetry integration for mailglass.
Event Naming Convention
All mailglass events follow the 4-level path plus a phase suffix:
[:mailglass, :domain, :resource, :action, :start | :stop | :exception]Named span helpers wrap :telemetry.span/3 for each domain. Domain helpers
land in their owning phase (render in , send/batch in ,
persist/events in , webhook_verify/webhook_ingest in ,
preview_render in ).
Events
Render pipeline
[:mailglass, :render, :message, :start | :stop | :exception]— Measurements on:start:%{system_time: integer}— Measurements on:stop:%{duration: native_time}— Metadata:%{tenant_id: string, mailable: atom}
Metadata Policy ()
Whitelisted keys: :tenant_id, :mailable, :provider, :status, :message_id, :delivery_id, :event_id, :latency_ms, :recipient_count, :bytes, :retry_count.
Forbidden (PII): :to, :from, :body, :html_body, :subject, :headers, :recipient, :email.
Telemetry metadata must never include recipient or message-content PII.
Enforcement is lint-time ( custom Credo check NoPiiInTelemetryMeta)
plus a runtime StreamData property test that asserts every emitted stop
event's metadata keys are a subset of the whitelist across 1000 varied
inputs.
Handler Isolation
:telemetry.span/3 wraps each attached handler in a try/catch. A handler
that raises is detached automatically and [:telemetry, :handler, :failure]
is emitted — the caller's pipeline is unaffected. Mailglass does not
add a parallel try/rescue wrapper (would duplicate or — worse — swallow
the meta-event operators rely on).
Default Logger
Call attach_default_logger/1 at boot (or configure
[telemetry: [default_logger: true]] in the Application env) to log every
Mailglass event:
Mailglass.Telemetry.attach_default_logger()
Mailglass.Telemetry.attach_default_logger(level: :warning)
Summary
Functions
Attaches the default logger handler for the event set.
Named span helper wrapping the adapter.deliver/2 call (, ).
Named span helper for the events-append write path. surface.
One-shot wrapper around :telemetry.execute/3 for non-span counter events.
Named span helper wrapping each Multi commit in the send pipeline (, ).
Named span helper for persist-layer write paths (projector, reconciler). surface.
Named span helper for the render pipeline. surface.
Named span helper for the Outbound hot path (, ).
Wraps a zero-arity function in :telemetry.span/3, emitting :start,
:stop, and (on exception) :exception events under event_prefix.
Functions
@spec attach_default_logger(keyword()) :: :ok | {:error, :already_exists}
Attaches the default logger handler for the event set.
Returns :ok on first attach and {:error, :already_exists} if a handler
with the same ID is already attached (useful for idempotent boot paths).
Options
:level— log level passed toLogger.log/2. Default::info.
Named span helper wrapping the adapter.deliver/2 call (, ).
Emits [:mailglass, :outbound, :dispatch, :start | :stop | :exception].
Provider latency is the fat tail — this span captures it.
Named span helper for the events-append write path. surface.
Equivalent to span([:mailglass, :events, :append], metadata, fun).
:stop metadata SHOULD include inserted?: boolean and
idempotency_key_present?: boolean per .
One-shot wrapper around :telemetry.execute/3 for non-span counter events.
Callers are expected to prepend :mailglass to the event path.
Named span helper wrapping each Multi commit in the send pipeline (, ).
| Emits `[:mailglass, :persist, :outbound, :multi, :start | :stop | :exception]`. |
Metadata carries :step_name (`:persist_queued | :persist_dispatched | :persist_failed`). |
Named span helper for persist-layer write paths (projector, reconciler). surface.
Event path: [:mailglass, :persist | suffix]. Examples:
Mailglass.Telemetry.persist_span([:delivery, :update_projections], meta, fn -> ... end)
Mailglass.Telemetry.persist_span([:reconcile, :link], meta, fn -> ... end)
Named span helper for the render pipeline. surface.
Equivalent to span([:mailglass, :render, :message], metadata, fun).
Named span helper for the Outbound hot path (, ).
Emits [:mailglass, :outbound, :send, :start | :stop | :exception].
Metadata whitelist per : :tenant_id, :mailable, :stream, :delivery_id, :status, :latency_ms.
Wraps a zero-arity function in :telemetry.span/3, emitting :start,
:stop, and (on exception) :exception events under event_prefix.
The same metadata map is emitted on every phase. The function's return value is returned unchanged.
Examples
Mailglass.Telemetry.span([:mailglass, :render, :message],
%{tenant_id: "acme", mailable: MyMailer},
fn -> render(message) end)