# `DDD.Telemetry`
[🔗](https://github.com/blackuprise/vicander/blob/v0.1.1/lib/ddd/operations/telemetry.ex#L1)

The `:telemetry` events the framework emits, in one place.

Attach with `:telemetry.attach_many/4`, or feed them to `Telemetry.Metrics` / OpenTelemetry.
Durations are in `:native` time units (`System.convert_time_unit/3`).

## Spans (`:start`, `:stop`, `:exception`)

| event prefix | metadata |
|---|---|
| `[:ddd, :command]` | `:command`, and on stop `:result` (`:ok`/`:error`), `:error_codes`, `:error_kind` |
| `[:ddd, :query]` | `:query`, and on stop `:result`, `:error_codes`, `:error_kind` |
| `[:ddd, :handler, :deliver]` | `:handler`, `:event`, and on stop `:outcome` (`:delivered`, `:skipped`, `:rejected`, `:error`) |
| `[:ddd, :projection, :rebuild]` | `:projection`, and on stop `:events` (how many were replayed) |

## Counters

| event | measurements | metadata |
|---|---|---|
| `[:ddd, :command, :retry]` | `%{attempt: n}` | `:command` |
| `[:ddd, :repository, :conflict]` | `%{count: 1}` | `:aggregate`, `:id`, `:expected_version`, `:actual_version` |
| `[:ddd, :outbox, :poll]` | `%{claimed: n}` | |
| `[:ddd, :outbox, :published]` | `%{count: 1, delay_ms: ms}` (event age) | `:event_type` |
| `[:ddd, :outbox, :retry]` | `%{attempts: n, delay_ms: ms}` | `:event_type`, `:error` |
| `[:ddd, :outbox, :dead_letter]` | `%{attempts: n}` | `:id`, `:event_type`, `:aggregate_type`, `:aggregate_id`, `:error` |

## Gauges (call `report/1`, or let `DDD.Health` do it)

| event | measurements | metadata |
|---|---|---|
| `[:ddd, :outbox, :stats]` | `%{pending, in_flight, dead_letters, oldest_pending_age_ms}` | |
| `[:ddd, :projection, :lag]` | `%{pending, oldest_pending_age_ms}` | `:projection` |

`report/1` reads the database and emits the gauges, so run it on a timer (for example with
`:telemetry_poller`) and chart them; an outbox that stops draining shows as a growing
`oldest_pending_age_ms`.

# `events`

```elixir
@spec events() :: [[atom()]]
```

Every event name the framework emits (spans expand to start/stop/exception).

# `outbox_stats`

```elixir
@spec outbox_stats(module()) :: %{
  pending: non_neg_integer(),
  in_flight: non_neg_integer(),
  dead_letters: non_neg_integer(),
  oldest_pending_age_ms: non_neg_integer()
}
```

The state of the outbox, straight from the table:

  * `:pending` - waiting for delivery or a retry (not dead-lettered)
  * `:in_flight` - currently claimed by a poller
  * `:dead_letters` - given up on and not yet resolved
  * `:oldest_pending_age_ms` - how long the oldest pending event has been waiting (0 if none)

# `report`

```elixir
@spec report(module(), [module()]) :: map()
```

Emit the gauges (`[:ddd, :outbox, :stats]`, and `[:ddd, :projection, :lag]` for each given
projection) read from `repo`. Returns the outbox stats.

---

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