Skip to content

Stream device logs (follow mode)

GET
/api/v1/devices/{id}/logs/stream
curl --request GET \
--url 'http://localhost:3000/api/v1/devices/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/logs/stream?severity=DEBUG&source=my-container&q=connection%20refused' \
--header 'X-API-Key: <X-API-Key>' \
--header 'last-event-id: example'

Server-Sent Events stream of new log lines for a device as they arrive, honoring the same severity/source/q filters as the paged /logs endpoint (FM-773, composed through the same buildDeviceLogQuery() builder). Implemented as short-interval polling of Loki’s query_range, re-emitted as SSE — see LogStreamService for why. Named events on the stream: log (a LogEntryDto, id set to a resumable <timestampMs>:<seq> cursor — reconnect with the Last-Event-ID header to resume exactly after it, which browsers do automatically on a dropped connection), heartbeat (keepalive, ~15s, survives idle proxies), skip ({ skipped: number }, emitted when the server had to drop the oldest lines of a poll tick under backpressure rather than buffer unboundedly), error (a transient upstream query failure; the stream keeps polling), and permission-revoked (the stream ends immediately after — the caller’s TELEMETRY_READ permission is re-checked periodically, not only at connect). Subject to per-organization and per-user concurrent-connection caps — 429 Too Many Requests when exceeded, returned as an ordinary JSON response before any SSE headers are sent.

id
required
string format: uuid

Device UUID

severity
string
Allowed values: DEBUG INFO WARN ERROR

Filter by severity level

source
string
Example
my-container

Filter by log source (container name, service, or “system”)

q
string
Example
connection refused

Full-text search against the log message body, same semantics as the paged endpoint.

last-event-id
required
string

Text/event-stream of device log events

Forbidden — caller lacks required permission

Device not found

Too many concurrent log stream connections for this organization or user