Logs Plugin
The logs plugin collects structured log lines from devices, stores them server-side, and streams them in real time via Server-Sent Events (SSE). Logs are queryable by time range, source, and severity level, with configurable per-tenant retention.
Overview
| Property | Value |
|---|---|
| Plugin ID | logs |
| Tier | SDK (pluginsdk.BackendPlugin) |
| Version | 2.0.0 |
| HTTP routes | Yes — query + SSE tail |
| Prometheus metrics | None |
| Bus subscriptions | evt.logs.v1.* |
| DB schema | Yes — log lines table per backend |
HTTP Routes
All routes are mounted under /api/v1/plugins/logs/ and go through the standard middleware stack:
Rate limit → JWT auth → Tenant auth → per-route RBAC check
| Method | Path | Permission | Description |
|---|---|---|---|
GET | /api/v1/plugins/logs/lines/{device_id} | logs/stream:read | Query historical log lines |
GET | /api/v1/plugins/logs/tail/{device_id} | logs/stream:read | Stream new log lines via SSE |
Query Log Lines (GET /lines/{device_id})
Returns a paginated list of historical log lines for a specific device.
Query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
source | string | — | Filter by log source (e.g. syslog, app) |
level | string | — | Filter by severity: debug, info, warn, error |
limit | int | 200 | Maximum number of lines to return |
since | RFC 3339 | — | Return lines at or after this timestamp |
until | RFC 3339 | — | Return lines before or at this timestamp |
Example request:
GET /api/v1/plugins/logs/lines/550e8400-e29b-41d4-a716-446655440000
?level=error&since=2025-03-25T00:00:00Z&limit=50
Authorization: Bearer <token>
X-Tenant-ID: <tenant-id>Response (JSON array):
[
{
"tenant_id": "660f9511-...",
"device_id": "550e8400-...",
"source": "syslog",
"level": "error",
"message": "Out of disk space on /dev/sda1",
"logged_at": "2025-03-25T10:42:00Z"
}
]Tail Log Stream (GET /tail/{device_id})
Opens a long-lived Server-Sent Events stream that delivers new log lines as they arrive. Suitable for a live "tail -f" UI.
Request:
GET /api/v1/plugins/logs/tail/550e8400-e29b-41d4-a716-446655440000
Authorization: Bearer <token>
X-Tenant-ID: <tenant-id>
Accept: text/event-streamResponse headers:
HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-aliveSSE event types:
| Event type | When sent | Data format |
|---|---|---|
connected | On successful connection | {"device_id": "..."} |
log | For each new log line | JSON log line object (same schema as query response) |
Example SSE stream:
event: connected
data: {"device_id":"550e8400-e29b-41d4-a716-446655440000"}
event: log
data: {"tenant_id":"660f9511-...","device_id":"550e8400-...","source":"app","level":"info","message":"Service started","logged_at":"2025-03-25T10:43:01Z"}
event: log
data: {"tenant_id":"660f9511-...","device_id":"550e8400-...","source":"syslog","level":"warn","message":"CPU temperature high","logged_at":"2025-03-25T10:43:05Z"}The server uses an in-memory tail store to buffer the most recent lines per device and fan them out to connected SSE clients.
RBAC Permissions
| Permission | Default roles | Description |
|---|---|---|
logs/stream:read | viewer, operator, tenant_admin | Query log lines and open live tail streams |
can(perms, 'logs/stream', 'read') // show device logs panelMessage Bus
The logs plugin subscribes to evt.logs.v1.* to receive log events forwarded from device agents via the NATS bridge.
Each incoming event is:
- Persisted to the configured storage backend.
- Written into the in-memory tail store for live SSE clients.
Storage Backends
The logs plugin supports two configurable storage backends:
| Backend | Config value | Description |
|---|---|---|
| PostgreSQL | postgres (default) | Logs stored in the platform database; subject to standard tenant RLS |
| Elasticsearch | elasticsearch | Logs stored in an external Elasticsearch cluster for high-volume scenarios |
Set the backend via plugin configuration:
{
"backend": "postgres"
}Plugin Configuration
| Key | Type | Default | Description |
|---|---|---|---|
sources | string | file:/var/log/syslog | Log sources the agent collects from (space-separated URIs) |
max_lines_per_sec | int | 100 | Rate limit per device to prevent log flooding |
backend | string | postgres | Storage backend: postgres or elasticsearch |
elasticsearch_url | string | — | Required when backend=elasticsearch |
Example config:
{
"sources": "file:/var/log/syslog file:/var/log/app.log",
"max_lines_per_sec": 200,
"backend": "postgres"
}Log Retention
The plugin runs a daily retention sweep that deletes log lines older than the tenant's configured LogRetentionDays. The default retention period is configured in the platform settings and applies per-tenant.
To change retention for a specific tenant, update the tenant settings via UpdateTenant (requires tenant_admin):
{
"log_retention_days": 30
}Agent-Side Plugin
The device agent runs a corresponding logs agent plugin that:
- Reads the
sourcesconfiguration (default:file:/var/log/syslog). - Tails the configured log files, parsing each line for severity and timestamp.
- Rate-limits outgoing lines to
max_lines_per_sec. - Publishes batches as
evt.logs.v1.lineson the agent bus, bridged to the server via NATS. - Hot-reloads configuration when
cfg.plugins.v1.setis received.
See Also
- Monitoring Guide — telemetry and dashboards
- Auth & RBAC — full permission model
- Terminal Plugin — interactive device shell