Real-time Logs
The Core captures output from backend processes and broadcasts it via Server-Sent Events (SSE). Logs are ephemeral (in-memory broadcast channel, not persisted to disk).
How it works
Each worker process gets a broadcast channel (capacity: 256 entries). Log entries are pushed to the channel from three sources:
- Worker IPC messages:
console.log(),console.warn(),console.error()in your backend code are intercepted by the prelude and sent as structured IPC messages with a level. - Raw stderr: anything written directly to stderr is captured line-by-line with level
"stderr". - Core lifecycle events: worker start, stop, crash, and backoff events with level
"system".
Subscribers receive entries via SSE as they are produced.
Log levels
| Level | Source |
|---|---|
info |
console.log() or log.info() in your backend |
warn |
console.warn() or log.warn() in your backend |
error |
console.error() or log.error() in your backend |
stderr |
Raw stderr output from the process (not via IPC) |
system |
Core lifecycle events (worker started, stopped, crashed, backoff) |
event |
Custom events emitted via emit(name, data) |
Logging from your backend
The prelude intercepts standard console methods and routes them through IPC:
// These all go through IPC as structured log messages:
console.log("Processing:", method); // level: "info"
console.warn("Rate limit approaching"); // level: "warn"
console.error("Connection failed"); // level: "error"
// Or use the explicit log object:
log.info("Processing started");
log.warn("Approaching limit");
log.error("Connection failed");
console.debug is aliased to console.log (level: "info").
Log messages are truncated at 8192 characters.
SSE endpoint
GET /api/v1/apps/{appId}/logs
Authorization: Bearer <token>
Requires authentication. Returns text/event-stream.
Each event contains a JSON payload:
data: {"level":"info","message":"Processing order #123"}
data: {"level":"stderr","message":"Warning: deprecated API usage"}
data: {"level":"system","message":"worker started"}
Keep-alive
The SSE stream sends a keep-alive comment every 15 seconds to prevent client timeout.
Lagged subscribers
If a subscriber falls behind (more than 256 entries in the buffer), it receives a system message indicating how many entries were dropped:
data: {"level":"system","message":"... 42 messages dropped ..."}
The stream continues from the current position after the lag notification.
Stream termination
The stream ends when:
- The worker is stopped or uninstalled (channel closed).
- The client disconnects.
Custom events
Your backend can emit named events:
emit("order_processed", { orderId: "abc123", total: 4999 });
These appear in the log stream with level "event" and the format "{name}: {data}".
Technical details
| Property | Value |
|---|---|
| Transport | Server-Sent Events (SSE) |
| Persistence | None (in-memory broadcast only) |
| Channel capacity | 256 entries per worker |
| Keep-alive interval | 15 seconds |
| Message truncation | 8192 characters (IPC log messages) |
| Lag handling | Notifies subscriber of dropped count, continues streaming |
| Entry format | {"level": "...", "message": "..."} |
API endpoints summary
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api/v1/apps/{appId}/logs |
Yes | Subscribe to live log stream (SSE) |