4.7 KiB
title, description, weight, type
| title | description | weight | type |
|---|---|---|---|
| Logging | Configurable channel-based logging with sinks | 25 | docs |
Logging in ƿit is channel-based. Any log.X(value) call writes to channel "X". Channels are routed to sinks — named destinations that format and deliver log output to the console or to files.
Channels
Three channels are conventional:
| Channel | Usage |
|---|---|
log.console(msg) |
General output |
log.error(msg) |
Errors and warnings |
log.system(msg) |
Internal system messages |
Any name works. log.debug(msg) creates channel "debug", log.perf(msg) creates "perf", and so on.
log.console("server started on port 8080")
log.error("connection refused")
log.debug({query: "SELECT *", rows: 42})
Non-text values are JSON-encoded automatically.
Default Behavior
With no configuration, a default sink routes console, error, and system to the terminal in pretty format:
[a3f12] [console] main.ce:5 server started on port 8080
[a3f12] [error] main.ce:12 connection refused
The format is [actor_id] [channel] file:line message.
Configuration
Logging is configured in .cell/log.toml. Each [sink.NAME] section defines a sink.
[sink.terminal]
type = "console"
format = "bare"
channels = ["console"]
[sink.errors]
type = "file"
path = ".cell/logs/errors.jsonl"
channels = ["error"]
[sink.everything]
type = "file"
path = ".cell/logs/all.jsonl"
channels = ["*"]
exclude = ["console"]
Sink fields
| Field | Values | Description |
|---|---|---|
type |
"console", "file" |
Where output goes |
format |
"pretty", "bare", "json" |
How output is formatted |
channels |
array of names, or ["*"] |
Which channels this sink receives. Quote '*' on the CLI to prevent shell glob expansion. |
exclude |
array of names | Channels to skip (useful with "*") |
path |
file path | Output file (file sinks only) |
Formats
pretty — human-readable, one line per message. Includes actor ID, channel, source location, and message.
[a3f12] [console] main.ce:5 server started
bare — minimal. Actor ID and message only.
[a3f12] server started
json — structured JSONL (one JSON object per line). Used for file sinks and machine consumption.
{"actor_id":"a3f12...","timestamp":1702656000.5,"channel":"console","event":"server started","source":{"file":"main.ce","line":5,"column":3,"function":"init"}}
Log Records
Every log call produces a record:
{
actor_id: "a3f12...", // full actor GUID
timestamp: 1702656000.5, // seconds since epoch
channel: "console", // channel name
event: "the message", // value passed to log
source: {
file: "main.ce",
line: 5,
column: 3,
function: "init"
}
}
File sinks write one JSON-encoded record per line. Console sinks format the record according to their format setting.
CLI
The pit log command manages sinks and reads log files. See CLI — pit log for the full reference.
pit log list # show sinks
pit log add terminal console --format=bare --channels=console
pit log add dump file .cell/logs/dump.jsonl '--channels=*' --exclude=console
pit log remove terminal
pit log read dump --lines=20 --channel=error
pit log tail dump
Examples
Development setup
Route console output to the terminal with minimal formatting. Send everything else to a structured log file for debugging.
[sink.terminal]
type = "console"
format = "bare"
channels = ["console"]
[sink.debug]
type = "file"
path = ".cell/logs/debug.jsonl"
channels = ["*"]
exclude = ["console"]
log.console("listening on :8080") // -> terminal: [a3f12] listening on :8080
log.error("bad request") // -> debug.jsonl only
log.debug({latency: 0.042}) // -> debug.jsonl only
Separate error log
Keep a dedicated error log alongside a full dump.
[sink.terminal]
type = "console"
format = "pretty"
channels = ["console", "error", "system"]
[sink.errors]
type = "file"
path = ".cell/logs/errors.jsonl"
channels = ["error"]
[sink.all]
type = "file"
path = ".cell/logs/all.jsonl"
channels = ["*"]
JSON console
Output structured JSON to the console for piping into other tools.
[sink.json_out]
type = "console"
format = "json"
channels = ["console", "error"]
pit run myapp.ce | jq '.event'
Reading logs
# Last 50 error entries
pit log read errors --lines=50
# Errors since a timestamp
pit log read errors --since=1702656000
# Filter a wildcard sink to one channel
pit log read all --channel=debug --lines=10
# Follow a log file in real time
pit log tail all