# `AgentDb.Observability`
[🔗](https://github.com/manhvu/agent_db/blob/v0.1.0/lib/agent_db/observability.ex#L1)

Stateless runtime diagnostics: low-cardinality telemetry, distributed traces,
and redacted structured logs.

No process, no endpoint, no exporter. `:telemetry` events are always emitted
locally; OpenTelemetry spans are no-ops unless the host configures an SDK.
Failures here never replace an operation result.

# `emit_job`

```elixir
@spec emit_job(
  atom() | term(),
  :ok | :error | atom(),
  non_neg_integer(),
  non_neg_integer(),
  term()
) ::
  :ok
```

Emits a job queue/execution measurement with queue-wait vs execution split.

# `emit_model`

```elixir
@spec emit_model(atom() | term(), atom(), non_neg_integer(), term()) :: :ok
```

Emits a model load/inference measurement.

# `error_code`

```elixir
@spec error_code(term()) :: String.t()
```

Machine-readable code for a store error: the classified tag as a string,
shared by every transport error response and by telemetry/logging.

The code set is the `classify_reason/1` taxonomy: caller errors
(`invalid_mode`, `invalid_uri`, `invalid_query`, `invalid_limit`,
`not_a_memory_uri`, `missing_argument`, `unknown_event`, `unknown_tool`,
`unsafe_path`, …), missing (`not_found`, `no_memory`), retryable
(`model_loading`, `background_jobs_pending`), and server failures
(`inference_failed`, `inference_timeout`, `model_load_failed`,
`download_failed`, `background_jobs_failed`, `hybrid_leg_timeout`,
`hybrid_leg_failed`, …), with anything unrecognised as `"error"`.
A new failure mode reuses an existing code or extends the taxonomy;
transports never emit free-form text as the only signal.

# `error_message`

```elixir
@spec error_message(term()) :: String.t()
```

JSON-safe, detail-free message for a store error, for transport responses.

Renders the classified tag only, never the detail: details routinely carry
URIs, queries, and paths, which must not leak into client-facing payloads.
Always encodable (a plain string), so no error term can break an encoder.

# `extract_context`

```elixir
@spec extract_context(map() | keyword() | list()) :: map() | nil
```

Extracts trace context from HTTP headers or WS event metadata (never rejects).

# `from_conn`

```elixir
@spec from_conn(Plug.Conn.t()) :: map() | nil
```

Extracts W3C trace context from a Plug connection (never rejects).

# `http_status`

```elixir
@spec http_status(term()) :: 400 | 401 | 404 | 413 | 422 | 429 | 500 | 503
```

HTTP status for a store error: 404 for missing, 503 for retryable
unavailability, 422/413/429 for caller errors, 401 for authorization, and
500 for server-side failures and anything unrecognised.

# `log`

```elixir
@spec log(atom(), keyword()) :: :ok
```

Structured operational log without content, prompts, or credentials.

# `operation_stats`

```elixir
@spec operation_stats() :: map()
```

Counts of operations, jobs, and model calls by outcome, as
`%{{family, dimensions, outcome} => count}`.

Dimensions are only the bounded labels the events already carry -- operation,
kind, role -- so the number of counters follows the store's code rather than
the traffic through it.

# `parse_traceparent`

```elixir
@spec parse_traceparent(String.t() | nil) :: {:ok, map()} | :error
```

Parses a W3C `traceparent` value. Returns `{:ok, %{trace_id, span_id}}` or
`:error` for missing/malformed input (caller starts a new trace).

# `recent_errors`

```elixir
@spec recent_errors(pos_integer()) :: [map()]
```

Recent failures, newest first, each with the operation it happened in and its
classified reason.

Read from `Observability.Sink`, which records the failures among the events
above. Entries carry a classification and a timestamp only -- never a URI,
document content, a prompt, a user, or a credential -- and the list is bounded
and in memory, so it starts empty again on a restart rather than becoming a
history the store accumulates forever.

A store whose sink is not running answers an empty list rather than an error:
diagnostics are never a reason an operation fails.

# `redact_url`

```elixir
@spec redact_url(String.t()) :: String.t()
```

Redacts credentials and secret query params from a URL for logging.

# `stage`

```elixir
@spec stage(atom(), atom() | nil, (-&gt; result)) :: result when result: var
```

Runs a retrieval stage with a bounded OTel span and telemetry measurement.

Only `stage`, `mode`, and `outcome` are recorded -- never URIs, content,
prompts, users, or credentials. A missing or malformed parent context
starts a new trace without changing the result.

# `timed`

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

Runs `fun`, emitting a low-cardinality operation measurement.

Metadata carries only `operation` and `outcome` (plus `kind`/`role` where
relevant) — never URIs, content, prompts, users, credentials, or tokens.

# `with_correlation`

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

Runs `fun` with `correlation` added to this process's log correlation.

Correlation is process-scoped and additive: a nested context adds to what is
already there, and the previous value is restored when `fun` returns, raises,
or exits. Long-lived processes — workers, channels — rely on that restore so a
correlation never attaches to an unrelated later operation. Only the bounded
correlation fields are kept, and a nil entry never clears one already set.

# `with_span`

```elixir
@spec with_span(String.t(), map(), (-&gt; result)) :: result when result: var
```

Runs `fun` inside an OTel span when available, otherwise runs directly.

---

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