Live tail streaming model
The live tail is a real-time stream of your tenant’s API request log, delivered over Server-Sent Events (SSE) fromGET /api/v1/logs/tail. Every authenticated request to the Orbit API completes, and its row — method, path, status, latency, request id — reaches every connected tail within sub-second. It is the data source behind the Live tail toggle on the dashboard’s request-logs page, and you can open it directly from your own tooling.
This page explains the stream’s semantics and guarantees. Endpoint schemas, per-parameter auth, and SDK consumption snippets live in the Tail API reference; the console walkthrough is in the Request Logs console guide. What the tail deliberately is not — a durable log store — and how it differs from the persisted query surface is covered here and in the Request Logs model.
1. What the tail is — and is not
The tail is a tenant-scoped, live-only debugging surface:- Scoped to one tenant per connection. Every row that crosses the stream was authenticated against your organization; the connection itself sees exactly that one tenant’s traffic. Two tenants’ tails never share rows, a connection cap, or a Redis channel.
- Sub-second from response to frame. A request’s row is published from the response-completed hook and lands on open connections while the next request is still in flight — the bar this surface ships against is sub-second, not the tens of seconds a provider console log typically lags.
- A live view, not a system of record. The stream carries only recent rows plus whatever sends while you are connected. The durable, queryable record of your API traffic is the Request Logs surface — a persisted log corpus with cursor pagination over roughly a year of retained history. Reaching the tail without a reconnect cursor gives you a snapshot for watching now, not an archive.
- All authenticated
/api/v1/*requests — REST and SDK calls made by your users and API keys. - Unauthenticated requests are never published. A row exists only if the request resolved to your tenant, so probing, forged, and expired-credential traffic never reaches you.
- Excluded by design: health, readiness, and metrics probes, the tail endpoint itself, and inbound provider webhook ingress (
/api/v1/webhooks/…,/api/v1/integrations/webhooks/…). Those receiver-side requests are operator/provider noise on this surface — provider signature failures and replay would read as “customer traffic errors” and dilute the signals the inbound webhook surfaces own. Webhook live-debugging lives in the inbound webhook debug log.
2. Stream shape: connect → optional replay → live
The transport is plain SSE overGET /api/v1/logs/tail — one long-lived HTTP response in text/event-stream. After connecting, the server sends, in order:
- A
connectedhandshake frame carrying your organization id and the backfill size the stream is about to paint. - A backfill of the most recent ~100 request rows in chronological order, so a fresh console session has immediate context.
- Live rows — one named
logframe per completed request, oldest-to-newest, for the rest of the connection.
: heartbeat comment frame every 30 seconds, plus TCP keepalive at the same cadence, so an idle connection stays open across proxies and a vanished browser tab is reclaimed from your connection cap promptly.
Reconnecting and replay. Every log frame carries an SSE id that is a durable stream cursor. If the connection drops, send that cursor back — Last-Event-ID (browser EventSource does this automatically), or the lastEventId query parameter from a client that cannot set headers — and the server replays the rows newer than your cursor before resuming live. Two boundaries to internalize:
- The replay buffer is bounded. It holds only recent stream history, capped at roughly the same ~100-row window the connect backfill paints. A cursor that has fallen out of the buffer behaves like a fresh connect: you get the backfill and the live stream, and anything older is gone from this surface.
- Missed history is not lost — it just isn’t here. The durable answer to “what happened while I was disconnected” is the Request Logs surface, whose persisted corpus the tail deliberately does not try to replicate.
3. Entry payload model
Onelog frame’s data: line is one JSON object — a compact, per-request row:
What is redacted by construction. Only the fields above exist on the stream — request bodies, response bodies, query strings, and headers never cross it, and path normalization removes embedded ids before the row is even published. The surface carries enough to debug routing, status, and latency without shipping payload content into a live broadcast; inspecting actual payload bytes belongs to the bounded, per-row payload view in the Request Logs console.
Adding fields is backwards-compatible — ignore keys you do not recognize.
Dashboard Live tail toggle vs the raw endpoint. The Live tail toggle on the dashboard request-logs page is a client of the same endpoint: it opens an EventSource against
GET /api/v1/logs/tail with your session token and paints rows into the table as they arrive. The raw endpoint is for your own tooling — server-side log forwarders feeding a SIEM, an on-call bot, or a CLI watch while you integrate. Same stream, same role gate (owner/admin/developer on the tenant), same drops and caps; the toggle is a browser convenience, not a second surface.
4. Delivery semantics: buffering, drops, isolation, and limits
The stream is a best-effort live view on top of a bounded in-memory transport. That produces four explicit guarantees rather than one vague one:- Per-tenant isolation. Each tenant’s traffic publishes to its own channel; a single tail connection subscribes to exactly one channel after authenticating to that tenant. No cross-tenant row is ever emitted, and no other tenant’s bursts, drops, or reconnects affect your stream.
- Connection cap. A tenant may hold at most 10 concurrent tail connections, counted cluster-wide. An 11th attempt gets
429withTOO_MANY_CONNECTIONS; closed tabs and dead peers release their slot promptly (heartbeat cadence), and even a slot leaked wholesale self-heals within an hour. Keep your own consumers to one or two long-lived connections. - Slow-consumer drop policy. Each connection’s outbound buffer carries a soft cap (1 MB) and a hard cap (5 MB). Over the soft cap, the server drops the frame, writes a
: slow_consumeradvisory comment frame, and continues — your client stays connected but missed a row, and the cursor you resume from still finds the row in the replay buffer if it is recent. Over the hard cap, the connection is force-closed (the server logs it; you reconnect with your last cursor). Sustained slow consumption therefore degrades you to an incomplete-but-connected stream before it ever risks the API process. - Failure posture of the pipeline. Row publishing is fire-and-forget from the response hook — a transient outage of the real-time backing store never slows your API responses down. If the backing store is unavailable when you connect, the connection attempt answers
503rather than hanging; once connected, a replay or backfill failure degrades to live-rows-only, not an error on the stream. Treat503and429from a server consumer as back-off-and-retry conditions.
5. Which observability surface answers which question
The operator observability map frames the full surface set; this table is the request-level slice of it:
A decision rule the table compresses: the moment you need history, you are done with the tail.
6. Worked example: a session with reconnect
Open the stream against the tenant whose traffic you own, then keep your last cursor:id: you receive. On a drop, reconnect with it and the server fills the gap from the replay buffer before going live:
EventSource cannot set headers), pass the token as the token query parameter and the cursor as lastEventId — the dashboard’s Live tail toggle does exactly this. Server-side consumers never put the credential in the URL (it lands in proxy and access logs): use the X-API-Key header and set headers through your SSE/http client, per the Tail API reference.
Related reading
- Tail API reference — endpoint contract, frame schema, SDK and curl consumption, limits and errors.
- Request Logs model — the persisted request-log surface the tail complements.
- Request Logs console guide — the dashboard page, including the Live tail toggle.
- Inbound webhook debug log — the inbound-side surface the tail deliberately excludes.
- Observability stats surface and operator observability map — where aggregates and the wider surface set fit.