# `Monitorex.Storage`

Pure read/query layer over the Collector's ETS tables.

All functions read directly from named ETS tables — no GenServer calls,
no casts, no side effects. Designed for read-only access to telemetry data
collected by `Monitorex.Collector`.

# `count_recent_inbound`

```elixir
@spec count_recent_inbound(keyword()) :: non_neg_integer()
```

Returns count of recent inbound events matching optional filters.

Same filtering as `list_recent_inbound/1` but returns count instead of events.

# `count_recent_outbound`

```elixir
@spec count_recent_outbound(keyword()) :: non_neg_integer()
```

Returns count of recent outbound events matching optional filters.

Same filtering as `list_recent_outbound/1` but returns count instead of events.

# `get_event`

```elixir
@spec get_event(integer()) :: Monitorex.Event.t() | nil
```

Fetches a specific event from the recent tables by timestamp key.

Searches both outbound and inbound recent tables and returns the first
match, or `nil` if no event is found.

# `list_consumers`

```elixir
@spec list_consumers() :: [map()]
```

Returns consumer aggregates from `:monitorex_inbound_consumers`,
sorted by requests descending.

# `list_consumers_for_route`

```elixir
@spec list_consumers_for_route(String.t()) :: [map()]
```

Returns consumer breakdown for a given route key (`"Method:path"`).

Queries `:monitorex_inbound_recent`, groups events by consumer, and
computes aggregate stats (requests, errors, total_duration, avg_latency,
last_seen) for each consumer on that route.

# `list_endpoints_for_host`

```elixir
@spec list_endpoints_for_host(String.t()) :: [map()]
```

Returns list of endpoint aggregates for a given host.

Queries `:monitorex_outbound_endpoints` for entries whose key matches
the given host (key is `{host, path}`).

# `list_hosts`

```elixir
@spec list_hosts() :: [map()]
```

Returns list of host aggregates from `:monitorex_outbound_hosts`,
sorted by requests descending.

Each entry includes computed p50, p95, p99 from duration samples
and the error rate.

# `list_recent_inbound`

```elixir
@spec list_recent_inbound(keyword()) :: [Monitorex.Event.t()]
```

Returns most recent inbound Events with optional filtering.

## Options

  * `:limit` — maximum number of events to return (default: 50, must be positive)
  * `:offset` — number of events to skip (default: 0)
  * `:status_class` — filter by status class atom (e.g. `:error`, `:success`).
    `nil` or omission means no filter.
  * `:consumer` — filter by exact consumer match.
  * `:route` — filter by route key (`"Method:path"`).

# `list_recent_outbound`

```elixir
@spec list_recent_outbound(keyword()) :: [Monitorex.Event.t()]
```

Returns most recent outbound Events with optional filtering.

## Options

  * `:limit` — maximum number of events to return (default: 50, must be positive)
  * `:offset` — number of events to skip (default: 0)
  * `:status_class` — filter by status class atom (e.g. `:error`, `:success`).
    `nil` or omission means no filter.
  * `:host` — filter by exact host match. `nil` or omission means no filter.

# `list_routes`

```elixir
@spec list_routes() :: [map()]
```

Returns route aggregates from `:monitorex_inbound_routes`, sorted by requests
descending.

Parses the "Method:path" key into separate `:method` and `:path` fields.
Each entry includes computed p50, p95, p99 from duration samples and error rate.

---

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