# `Accrue.Telemetry`
[🔗](https://github.com/szTheory/accrue/blob/accrue-v0.3.0/lib/accrue/telemetry.ex#L1)

Telemetry conventions and helpers for Accrue (D-17, D-18, OBS-01).

## Event naming

All Accrue telemetry events follow a **4-level name** plus a phase suffix:

    [:accrue, :domain, :resource, :action, :start | :stop | :exception]

The domain layer is one of `:billing`, `:events`, `:webhooks`, `:mail`,
`:pdf`, `:processor`. Concrete examples:

    [:accrue, :billing, :subscription, :create, :start]
    [:accrue, :mail, :deliver, :payment_succeeded, :stop]
    [:accrue, :pdf, :render, :invoice, :exception]

This mirrors Ecto's `[:ecto, :repo, :query]` and Phoenix's
`[:phoenix, :endpoint, :start]` depth conventions.

## span/3

`span/3` is a thin wrapper over `:telemetry.span/3` that accepts a
zero-arity callable and emits `:start`, `:stop`, and `:exception`
events. The fun's return value is passed through to the caller
unchanged — the helper does the metadata plumbing.

> ⚠️ `span/3` does NOT auto-include raw arguments in metadata — only
> the explicit metadata map you pass. Plan 04's Stripe processor MUST
> NOT shove raw `lattice_stripe` responses into span metadata. Mitigates
> T-OBS-01.

## OpenTelemetry bridge

`current_trace_id/0` returns the active OTel trace id as a hex string
when `:opentelemetry` is loaded, and `nil` otherwise. The conditional
compile pattern (CLAUDE.md §Conditional Compilation) keeps the
`without_opentelemetry` CI matrix warning-free.

# `event_name`

```elixir
@type event_name() :: [atom()]
```

# `current_trace_id`

```elixir
@spec current_trace_id() :: String.t() | nil
```

Returns the current OpenTelemetry trace id as a hex string, or `nil`
when `:opentelemetry` is not loaded.

# `span`

```elixir
@spec span(event_name(), map(), (-&gt; result)) :: result when result: var
```

Wraps `fun` in a `:telemetry.span/3` call.

`fun` is a zero-arity callable that returns the result value. This
wrapper handles the `{result, metadata}` contract expected by
`:telemetry.span/3` internally so call sites stay clean.

The initial `metadata` map is merged with the current actor
(`Accrue.Actor.current/0`) when present under the `:actor` key.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
