- Endpoint
- Unified Event Schema
- Time & Timestamp Handling
- Severity, Labels, and Coloring
- Cursor & Resume Behavior
- Reconnect Semantics
- Status Badge (Consumer UI)
- Query Parameters
- Heartbeats
- Internal Events
- Typical Consumer Flow
- Debugging
- Notes & Limitations
- Usage
This endpoint exposes systemd-journald logs over Server‑Sent Events (SSE). It is designed as a data‑only transport layer: the PHP service emits normalized JSON events, and the consumer application is responsible for rendering, persistence, and UX decisions.
GET /log_stream.phpResponse is an SSE stream (text/event-stream).
Every SSE data: message contains exactly one JSON object with the following
fields. All events — journal entries, internal messages, and heartbeats —
use the same schema.
{
"type": "journal" | "internal",
"playback": true | false,
"__CURSOR": "s=...;i=...;b=...;m=...;t=...;x=..." | null,
"__REALTIME_TIMESTAMP": "1738198123456789",
"PRIORITY": "0",
"SYSLOG_IDENTIFIER": "wsprrypi",
"MESSAGE": "Started WsprryPi.",
"_SYSTEMD_UNIT": "wsprrypi.service"
}| Field | Description |
|---|---|
type |
journal for real journald entries, internal for adapter-generated events |
playback |
true when emitted during replay/backlog |
__CURSOR |
Journald cursor; null for internal events |
__REALTIME_TIMESTAMP |
Microseconds since Unix epoch, emitted as a decimal string so 32-bit PHP cannot overflow current timestamps |
PRIORITY |
Syslog priority (0 = emerg … 7 = debug) |
MESSAGE |
Human-readable log message |
- Transport uses
__REALTIME_TIMESTAMP(µs since Unix epoch) as a decimal string. - Consumers render timestamps as ISO‑8601 strings.
- Microsecond precision is preserved internally.
- Formatting and timezone presentation are consumer responsibilities.
Example rendered timestamp:
2026-01-31T00:09:25.035Z
PRIORITYfollows syslog semantics (0..7).- Consumers map priority to labels:
| Priority | Label |
|---|---|
| 0 | EMERG |
| 1 | ALERT |
| 2 | CRIT |
| 3 | ERROR |
| 4 | WARN |
| 5 | NOTICE |
| 6 | INFO |
| 7 | DEBUG |
- Coloring is consumer-side only.
- Coloring must be idempotent and replay-safe.
- Internal events may be styled separately or hidden.
- Journal events include an SSE
id:equal to the URL‑encoded__CURSOR. - Browsers resend this value as
Last-Event-IDon reconnect. - Server resumes using
journalctl --after-cursor.
Persist only cursors from events where
type === "journal"and__CURSOR !== null.
- Browsers auto-reconnect on transient network errors.
- If
EventSource.readyState === CLOSED, auto-reconnect has stopped. - Consumers must initiate a manual reconnect with backoff.
- Jittered exponential backoff is recommended to avoid reconnect storms.
Consumers may present a connection-status badge for visibility:
| State | Meaning |
|---|---|
| Connected | SSE stream active |
| Reconnecting | Manual reconnect scheduled |
| Disconnected | Stream closed and retry pending |
The badge is informational only and does not affect protocol behavior.
| Parameter | Default | Description |
|---|---|---|
playback |
1 |
Enable replay/backlog |
backlog |
200 |
Number of entries to replay |
Replay occurs even on resume when enabled, scoped by cursor if present.
priority_min,priority_maxmap tojournalctl -punitfilters systemd units (*disables filtering)
- Internal heartbeat events are emitted during idle periods.
MESSAGEis[HEARTBEAT]- Priority is
7(DEBUG).
Internal events report adapter state such as:
- Connection start
- Replay start/end
- Follow restarts
- Heartbeats
They share the same schema and never advance cursors.
- Open
EventSource - Render events
- Persist last journal cursor
- Handle reconnect and resume
- Style or suppress internal events
- Open your browser DevTools Console on the logs page and run any of these:
viewLogs.toggle()→ switches Journal ⇄ InternalviewLogs.showJournal()→ show journald viewviewLogs.showInternal()→ show internal viewviewLogs.showBoth()→ show both panesviewLogs.get()→ returns current viewviewLogs.help()→ prints the available commands
- Also supported:
- URL override:
?view=journal,?view=internal, or?view=both - The selection is persisted in localStorage (so reloads keep your last view).
- URL override:
- Each client spawns a
journalctlprocess. - Intended for admin dashboards, not public fan-out.
- Requires read access to systemd journal.
Transport-only API.
Rendering, persistence, and UI conventions are consumer-defined.