Request-metrics thin thresholds: windows, gates, and aggregate predicates
The Developer API analytics and request-logs reads look like simple query endpoints, but four bounded filters run between your request and the aggregate it returns. This page names each one so you can predict the numbers: the window filter chain that decides the time range, the feature-flag gate on the advanced block, the rejection exclusion the latency aggregates apply, and the pipeline bounds that thin which rows ever get recorded. It complements the request-metrics pipeline concept, which owns the write path — this page is about the thresholds that decide what lands and what the reader drops.1. The window filter chain: start, end, trailing bound
Every time-bounded read resolves its window through the same precedence order. The/stats/request-logs viewer (the Developer → Request Logs
surface) applies it verbatim; the advanced message-analytics block under
/stats/analytics accepts the same three inputs:
start_date+end_date(custom range) — aYYYY-MM-DDpair. The start is inclusive day-start, the end inclusive day-end, and the pair takes precedence over every trailing form below.days(trailing bound) — the dashboard’s preset ranges resolve to this; capped at 365 days.- Bucket preset — request-logs also accepts a fixed set
(
1h,6h,24h,7d,30d,90d). - Default — with no window input at all, request-logs reads the trailing 24 hours and the analytics block reads 30 days.
2. Origin-protection gate: the advanced-analytics feature flag
The/stats/analytics block (summary, channels, volume, delivery funnel)
sits behind a per-tenant feature flag. When the flag is off for your
workspace, the block returns 403 FEATURE_DISABLED — a deliberate
origin-protection response that keeps the heavy aggregate reads out of
reach of tenants that have not opted in. When the flag is on, the same
window chain above runs and returns the full payload with a 200.
This gate is the only feature-flagged read on the stats surface. The
always-on widgets (summary, channel-health, usage, activity, request-logs,
dashboard) are available to every reader with the analytics:read scope
regardless of the flag; your client fields either the full payload or the
403, and it should treat the 403 as “not enabled”, never as an error to
retry.
3. Predicate thresholds on the latency aggregates
Thresholds inside the API-analytics aggregates shape what the p50/p95 and mean latency actually measure rather than just which rows exist. The head aggregate excludes rate-limit rejections (429) from the latency
percentiles and the mean: a rejected request is answered at the
rate-limit guard in a few milliseconds before the handler runs, and
folding those rejections into the percentiles would pull the rendered p50
far below your real handler latency. Excluding them keeps the quality
numbers meaningful while the volume counters still count every metered
row — 429s included.
The same predicate discipline runs on the write side: the pipeline names
its self-observation and keepalive paths on an explicit skip list (the
health probes, the API-analytics console’s own reads, presence
heartbeats, and realtime transports) rather than drawing a blanket
“everything authenticated counts” line. A row that matches the skip list
never enters the aggregate, so the percentiles measure genuine API
traffic instead of the tab that rendered the dashboard.
4. When an excluded class dominates, the band coarsens
Exclusion thresholds guard the quality metrics, but they also mean the rendered percentile drifts when the excluded family dominates the window. Two concrete shapes to recognise:- A 429 spike lowers the aggregate numerator, not the latency mean. A tenant being rate-limited sees its error-rate card climb while the latency percentile stays pinned to the served subset — a healthy shape, not a contradiction.
- A skipped transport row no longer counts. The keepalive and self-observation skips mean the “API Requests (24h)” counter reads operator-intent API calls only; a quiet dashboard tab with a pinned SSE connection contributes no API-call rows at all, so a one-day idle tab stops inflating the count the way it used to.
5. Idempotency spot-check: one row per request, one namespace per tenant
Two invariants keep the pipeline safe to re-consume:- Request id is the row key. Every completed request writes exactly one telemetry row, attributed to your tenant, so a reader that pages or re-queries the same window sees the same set — the row already exists or it does not, and no read ever mutates it.
- Tenant id is the only namespace. A row with no resolvable tenant context is dropped rather than keyed under a wrong or empty organ, so the aggregate never mixes another workspace’s traffic into yours — and your own traffic never lands in theirs.
6. Wiring it into the console
Read the head aggregate (/developers/api-analytics/overview) for the
threshold-cleaned p50/p95, the per-endpoint breakdown for the per-route
predicate result, and /stats/request-logs for the per-request drill into
a filtered window — the same window chain you set with start_date /
end_date / days. When you write a client of these reads, follow the
chain order in section 1 so a re-invoked preset (for example days=30)
takes precedence exactly the way the dashboard’s own picker passes it, and
handle the section-2 403 as a feature-flag state rather than an exception.
See also
- Request-metrics pipeline concept — the write-side hook, the Redis buffer, and the read surface this page thresholds.
- Request Logs model — the sibling Cloud Logging read this page’s window chain drives.
- The stats surface map — which route family answers which question.