March Docs

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

fnattachattach(handler_id : String, event_names : List(List(String)), handler_fn)#

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)
fnattached_handlersattached_handlers() : List(String)#

Return the list of all attached handler IDs.

fndetachdetach(handler_id : String)#

Detach a previously attached handler.

    Bastion.Telemetry.detach("my_metrics")
fnexecuteexecute(event_name : List(String), measurements, metadata)#

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 })
fnrequest_startrequest_start(conn)#

Emit the standard request start event. Call at the beginning of your pipeline.

    Bastion.Telemetry.request_start(conn)
fnrequest_stoprequest_stop(conn, duration_ms : Int)#

Emit the standard request stop event. Call after the handler returns.

duration_ms — wall clock time from request_start to now
fnspanspan(event_prefix : List(String), metadata, fn_)#

Execute 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)