How Telescope works
Batches and entries, trace propagation, sampling, redaction, analysis, delivery and remote settings.
Batches and entries
A batch is one unit of work. Its root entry is the request, job, command or scheduled task itself; every other entry is something it did, with an offset from the start, a duration and an optional parent (so spans nest).
Entry types: request command job schedule (roots) · query model
event middleware exception log http cache redis mail
notification gate view dump batch span.
Traces across services and queues
Every batch belongs to a trace. The SDKs read an incoming W3C traceparent
header and add one to outgoing HTTP calls and to queued jobs, so:
Sampling
The sample rate (console, or per service in code) decides which journeys are kept. The decision is made at the end of the unit of work (tail sampling), so a journey that failed, was slow, or carries a monitored tag is kept regardless. A sampled-out journey costs nothing on the wire.
Redaction
Header and payload keys matching the redaction list are replaced before anything
leaves your process — authorization, cookie, set-cookie, x-api-key,
CSRF tokens, passwords, secrets and tokens by default — and the backend applies
the same list again on ingest. Add keys in Telescope → Settings.
Analysis
When a batch arrives (and again whenever you open it), Nexus normalises every
SQL statement into a shape — literals and bindings replaced with ? — and
computes:
| Finding | Rule |
|---|---|
| N+1 | The same shape run ≥ threshold times (default 5) in one batch |
| Duplicate | The same shape and bindings run more than once (skipped when the driver doesn't expose bindings) |
| Slow query | Duration ≥ slow-query threshold (default 100 ms) |
| Slow request | Root duration ≥ slow-request threshold (default 1000 ms) |
Shapes also power Families in the console: every endpoint, query shape, job and command, with counts and p50 / p95 durations.
Delivery
- PHP delivers in
terminate(), after the response has been sent (PHP-FPM, Octane) — no added latency. - Node, Python, .NET buffer finished journeys and ship them every ~2 seconds
on a background loop, and on shutdown.
flush()forces it. - A delivery that is retried is de-duplicated by batch id, so a journey is never stored twice.
- Each journey is capped at
max_entries(2000 by default); the rest are counted but not stored.
Remote settings
Every ingest response carries the environment's Telescope settings — enabled,
sample rate, thresholds, ignored paths and types, redaction keys, monitored tags.
The SDKs apply them to the next journeys, so changes in the console take effect
within seconds, without a deploy. Values you set in code win over the console's
(e.g. a per-service sample_rate).
Storage & retention
Journeys are kept for the environment's Telescope retention — 48 hours by default, up to 14 days — then deleted.
Billing
Telescope meters entries stored (telescope.entries, 1,000,000 free per
month). Exceptions and log lines inside journeys are billed once, by Errors and
Logs, not again by Telescope. Usage limits apply: over the cap nothing more is
stored, and the SDKs keep receiving their settings.
