Skip to content

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

PropertyValue
Plugin IDlogs
TierSDK (pluginsdk.BackendPlugin)
Version2.0.0
HTTP routesYes — query + SSE tail
Prometheus metricsNone
Bus subscriptionsevt.logs.v1.*
DB schemaYes — 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

MethodPathPermissionDescription
GET/api/v1/plugins/logs/lines/{device_id}logs/stream:readQuery historical log lines
GET/api/v1/plugins/logs/tail/{device_id}logs/stream:readStream 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:

ParameterTypeDefaultDescription
sourcestringFilter by log source (e.g. syslog, app)
levelstringFilter by severity: debug, info, warn, error
limitint200Maximum number of lines to return
sinceRFC 3339Return lines at or after this timestamp
untilRFC 3339Return lines before or at this timestamp

Example request:

http
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):

json
[
  {
    "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:

http
GET /api/v1/plugins/logs/tail/550e8400-e29b-41d4-a716-446655440000
Authorization: Bearer <token>
X-Tenant-ID: <tenant-id>
Accept: text/event-stream

Response headers:

http
HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive

SSE event types:

Event typeWhen sentData format
connectedOn successful connection{"device_id": "..."}
logFor each new log lineJSON 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

PermissionDefault rolesDescription
logs/stream:readviewer, operator, tenant_adminQuery log lines and open live tail streams
typescript
can(perms, 'logs/stream', 'read')   // show device logs panel

Message 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:

  1. Persisted to the configured storage backend.
  2. Written into the in-memory tail store for live SSE clients.

Storage Backends

The logs plugin supports two configurable storage backends:

BackendConfig valueDescription
PostgreSQLpostgres (default)Logs stored in the platform database; subject to standard tenant RLS
ElasticsearchelasticsearchLogs stored in an external Elasticsearch cluster for high-volume scenarios

Set the backend via plugin configuration:

json
{
  "backend": "postgres"
}

Plugin Configuration

KeyTypeDefaultDescription
sourcesstringfile:/var/log/syslogLog sources the agent collects from (space-separated URIs)
max_lines_per_secint100Rate limit per device to prevent log flooding
backendstringpostgresStorage backend: postgres or elasticsearch
elasticsearch_urlstringRequired when backend=elasticsearch

Example config:

json
{
  "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):

json
{
  "log_retention_days": 30
}

Agent-Side Plugin

The device agent runs a corresponding logs agent plugin that:

  1. Reads the sources configuration (default: file:/var/log/syslog).
  2. Tails the configured log files, parsing each line for severity and timestamp.
  3. Rate-limits outgoing lines to max_lines_per_sec.
  4. Publishes batches as evt.logs.v1.lines on the agent bus, bridged to the server via NATS.
  5. Hot-reloads configuration when cfg.plugins.v1.set is received.

See Also

Umoo — IoT Device Management Platform