Bastion.Telemetry
lib/telemetry.march — Bastion.Telemetry: structured event hooks.
A lightweight telemetry bus that lets the framework emit named events and user code attach handlers to them. The pattern mirrors :telemetry in the Erlang/Elixir ecosystem, adapted to March's type system.
Events are hierarchical string lists such as: ["bastion", "request", "start"] ["bastion", "request", "stop"] ["bastion", "depot", "query", "stop"] ["bastion", "channel", "message", "stop"]
── Usage ──────────────────────────────────────────────────────────────────────
-- Attach a handler at application startup:
Bastion.Telemetry.attach(
"my_logger",
[["bastion", "request", "stop"]],
fn event measurements metadata ->
Logger.info("request completed", [
("path", Conn.path(metadata.conn)),
("status", String.from_int(measurements.status)),
("duration", String.from_int(measurements.duration_ms) ++ "ms")
])
end
)
-- Emit an event from framework or application code:
Bastion.Telemetry.execute(
["bastion", "request", "stop"],
{ status: 200, duration_ms: 42 },
{ conn: conn }
)
-- Detach when no longer needed:
Bastion.Telemetry.detach("my_logger")Functions
Attach a handler function to one or more event names.
handler_id — unique string identifier for this handler (used to detach)
event_names — list of event name lists to subscribe to
handler_fn — fn(event_name, measurements, metadata) called on each event
If handler_id is already attached, the old handler is replaced.
Bastion.Telemetry.attach("my_metrics", [["bastion", "request", "stop"]], fn ev m d ->
update_counter(m.status)
end)Return the list of all attached handler IDs.
Detach a previously attached handler.
Bastion.Telemetry.detach("my_metrics")Emit a telemetry event.
Iterates all attached handlers. Handlers whose subscription list includes
this event name (or a prefix of it) are called inline. Handler errors
are isolated: one failing handler does not prevent others from running.
event_name — list of string segments, e.g. ["bastion", "request", "stop"]
measurements — record with numeric measurements (any shape)
metadata — record with contextual data (any shape)
Bastion.Telemetry.execute(["bastion", "request", "stop"],
{ status: 200, duration_ms: 42 },
{ conn: conn })Emit the standard request start event. Call at the beginning of your pipeline.
Bastion.Telemetry.request_start(conn)Emit the standard request stop event. Call after the handler returns.
duration_ms — wall clock time from request_start to nowExecute a function while emitting start and stop telemetry events.
Emits `event_prefix ++ ["start"]` before calling fn, and
`event_prefix ++ ["stop"]` after. The stop event includes a
`duration_ms` measurement.
Bastion.Telemetry.span(["bastion", "depot", "query"], metadata, fn () ->
Depot.exec(query)
end)