Skip to main content

logs

View stored output from managed services.
Info: From the interactive sysg status table, select a UNIT with Tab/arrow navigation and press L to jump straight into that unit’s logs. The status shortcut runs sysg logs -s <UNIT> -l 100 --stream 2, which shows the latest 100 lines and refreshes the snapshot every 2 seconds.

Options

Scoping

Logs are always scoped — a bare sysg logs is refused (SG0019) so you never get the wrong project’s output. Each project’s logs live in their own place ({project}/{service}), so two projects can share a service name without their logs colliding.
A bare -s <service> reads only the loose bundle. If the service is in a project, pass -p; naming a non-loose service without -p is refused with SG0021. Combining --supervisor with a selector is SG0020.

Modes

logs is really five modes: show (the default), follow (--follow), print-path (--path), purge (--purge), and prune (--prune). The mode flags are mutually exclusive, and none combines with --follow — an illegal combination is refused with SG0204 rather than guessed at.
--purge clears logs through the running supervisor when one is up, so both the on-disk files and the supervisor’s in-memory buffer that sysg logs replays from are dropped together. Clearing files alone would leave sysg logs still showing the “purged” lines.
--prune needs a bound to prune against. Running it with neither --max-size nor --max-age is refused with SG0017.

Examples

View one project’s service logs

View logs from specific service

To disambiguate a service in a multi-project supervisor, provide the stable project id:
Info: By default, sysg logs shows a stacked stdout+stderr stream in capture order. systemg adds its own UTC capture timestamp and stream label to service output as it is written, then reads the combined service log for the default view. Use --kind stdout or --kind stderr when you need a single stream only.

Follow mode and non-interactive callers

Whether sysg logs follows the stream (stays attached and prints new lines as they arrive) or prints a one-shot snapshot and exits depends on how it is invoked:
  • --follow / -f always follows, until you interrupt it. In a terminal, press Esc or Ctrl-C to stop following and return to the shell; the stream reconnects on its own if the supervisor connection drops, so it never freezes silently while a service is still logging.
  • --no-follow always prints a one-shot snapshot and exits.
  • With neither flag, systemg follows only when stdout is an interactive terminal and SYSTEMG_AGENT is unset. When stdout is a pipe, a file, an SSH command, or SYSTEMG_AGENT is set, it prints a one-shot snapshot and exits.
This keeps automation from wedging: a plain sysg logs -s api over ssh host 'sysg logs -s api', sysg logs -s api | grep error, or any agent returns immediately instead of blocking on a follow that can never be interrupted.
--lines 0 --follow is the standard live-streaming form: it skips existing log history, stays attached, and prints only newly emitted lines.

Purge logs for a specific service

This truncates api’s current stdout and stderr log files in place and does not print logs.

Purge logs for all services

This truncates all service log files, plus supervisor.log, in place and does not print logs.

View stderr logs

View supervisor logs

Show more history

Filter by pattern

--grep takes a regular expression and keeps only matching lines. It composes with --kind, the time bounds, and --all.

Filter by time window

Time bounds are matched against systemg’s capture timestamp (the UTC prefix on each stored line). --since / --until accept an RFC3339 timestamp, a bare UTC date (taken as midnight), or a relative age in the past (30m, 2h, 7d). Because following cannot honor an upper bound, any --since / --until / --all read is a one-shot snapshot.

Read the full rotated history

By default sysg logs reads the latest 100 lines from the active {service}.log; pass --lines N to choose another tail size. --all concatenates the rotated backups ({service}.log.2, {service}.log.1) followed by the active file, oldest to newest, so you can query the entire retained history without joining files by hand. --all ignores --lines.

Machine-readable output

--format json emits one JSON object per captured line — {"ts","stream","service","line"} — dropping banners and section headers so the stream is a clean JSON-lines document. ANSI escapes are stripped automatically.

Project-wide filtering and aggregation

Every content flag — --grep, --since / --until, and --all — applies to project-wide reads (--project, or the no-service default) exactly as it does to a single --service. Each JSON record carries the resolved service name of the unit that produced the line, so you can aggregate by service without querying each one separately.

Raw application output

--raw prints only the application’s original log line, without systemg’s capture timestamp and stream label — the closest equivalent to reading the service’s own stdout. Banners are dropped and ANSI is stripped by default.

ANSI handling

systemg records service output verbatim, so lines a service colored for its own terminal are stored with their ANSI escapes.
Info: When output is a pipe, a file, or --format json / --raw, sysg logs strips those escapes so downstream tools (grep, jq, awk) see clean text. Pass --no-strip-ansi to keep the color, or --strip-ansi to force stripping even on an interactive terminal.

Stream snapshots

In stream mode, each refresh replaces the current frame with a new snapshot of the latest --lines entries. Without --lines, each frame contains the latest 100 lines.

Prune rotated backups

Deletes rotated backup files ({name}.log.1, {name}.log.2, …) older than --max-age and then trims the remaining backups oldest-first until their total size is under --max-size. Active .log files are never touched. At least one of --max-size or --max-age is required.

Log files

Logs are stored in ~/.local/share/systemg/logs/:
  • {service}.log - Canonical stdout+stderr stream in capture order
  • {service}_stdout.log / {service}_stderr.log - Legacy split-stream files from older systemg versions, still read as a fallback when no canonical log exists
  • supervisor.log - systemg’s own log output

Locate log files

Use --path to print where logs live instead of reading them — handy when you need to point another tool at the files directly:

Rotation and retention

Every active log file (service logs and supervisor.log) is size-capped. When an active file would exceed logs.max_bytes (default 10 MiB) it is rotated to {name}.log.1, older backups shift up, and at most logs.max_files (default 5) numbered backups are retained. A single log event larger than 16 KiB is truncated with a …[truncated N bytes] marker before it is written, so one oversized payload cannot blow past the size cap. Tune the caps with the logs.max_bytes / logs.max_files config keys, globally or per service. systemg’s own verbosity is info by default and honors per-crate RUST_LOG directives (for example RUST_LOG=mycrate=debug,noisycrate=warn), so enabling debug for one target does not pull in dependency-wide debug noise. Each captured service line is stored with a systemg capture timestamp and stream label:
Info: The leading timestamp is systemg’s own capture time; a service that prints its own timestamp will show both. Use --raw to drop systemg’s prefix and keep only the application’s line, or --format json to get the timestamp, stream, and message as separate fields.

Performance model

For the default file logging sink, systemg captures each service’s stdout and stderr through pipes and writes complete, immediately flushed lines through one per-service writer into {project}/{service}.log. A single-service follow (--follow, or the interactive default) tails that canonical file. A project-wide follow atomically takes a recent complete-line backlog and subscribes to future lines from the supervisor so several services can share one stream. The one-shot view (--no-follow, or the default when stdout is not an interactive terminal) reads the persisted active file once and exits. --kind stdout and --kind stderr filter captured lines by the stored stream label. The command itself is lightweight; the continuous cost comes from the capture threads, one writer thread, and one append-only file write path per service. For high-output production workloads, configure logs.sink: none globally or per service to discard service output and avoid systemg log-writer threads, pipe backpressure from log capture, and file growth.

See also