---
title: Logs
---

# Logs

systemg writes internal operational logs and can optionally capture service stdout/stderr.

## What's logged

- Service lifecycle (start, stop, restart, crash)
- Cron job execution
- Configuration changes
- Supervisor events

## Location

`~/.local/share/systemg/logs/supervisor.log` (user mode)
`/var/log/systemg/supervisor.log` (system mode)

Service output uses the same directory:

- `{service}.log`

By default, systemg pipes each managed service's stdout and stderr into reader
threads, then writes both streams through one per-service writer into
`{service}.log`. `sysg logs` reads that stored file; it does not attach to the
original process streams.

> **Info:** The default service log is stacked in capture order. Each line gets
> a systemg UTC capture timestamp plus a stream label, such as `stdout` or
> `stderr`, so `sysg logs --kind stderr` can filter recent lines without needing
> a second stderr file.

## Service output configuration

Use the top-level `logs` block to set defaults for all services:

```yaml
version: "1"
logs:
  sink: file
  max_bytes: 10485760
  max_files: 5
services:
  api:
    command: "python app.py"
```

Use a service-level `logs` block to override the global defaults:

```yaml
services:
  noisy_worker:
    command: "worker --verbose"
    logs:
      sink: none
```

Supported sinks:

- `file` - Capture stdout/stderr and write systemg-managed log files.
- `none` - Discard stdout/stderr without creating log-writer threads or files.

`max_bytes` controls active file rotation for the `file` sink. `max_files` controls how many numbered rotated files are retained. Set `sink: none` for high-output services when another logging pipeline is already responsible for collection.

## View logs

```bash
# Last 50 lines
$ sysg logs --kind supervisor

# Follow in real-time
$ tail -f ~/.local/share/systemg/logs/supervisor.log

# Search for events
$ grep "Starting service" ~/.local/share/systemg/logs/supervisor.log
```

## Log levels

Set verbosity when starting:

```bash
$ sysg start --log-level debug
```

Levels: `trace` (5), `debug` (4), `info` (3), `warn` (2), `error` (1), `off` (0)

## Log format

```
2025-12-02T10:30:15.123456Z  INFO systemg::daemon: Starting service: api
```

Format: `[TIMESTAMP] [LEVEL] [MODULE]: [MESSAGE]`

## Common messages

### Service events
```
Starting service: api
Service api exited with status 0
Restarting service: api (attempt 1/5)
Service api crashed: exit code 1
```

### Cron events
```
Running cron job 'backup'
Cron job 'backup' completed successfully
Cron job 'backup' exited with non-zero status
```

### Supervisor events
```
systemg supervisor listening on "/path/to/socket"
Supervisor shutting down
Reloading configuration from "/path/to/config"
```

## Supervisor log rotation

### Using logrotate

Create `/etc/logrotate.d/systemg`:

```
~/.local/share/systemg/logs/supervisor.log {
    daily
    rotate 7
    compress
    missingok
}
```

### Manual rotation

```bash
$ mv ~/.local/share/systemg/logs/supervisor.log ~/.local/share/systemg/logs/supervisor.log.old
# systemg creates new file automatically
```

## Troubleshooting

**Log file missing**
- Check systemg has started
- Verify directory exists

**Empty logs**
- Try `--log-level debug`
- Check services are running

**Large log files**
- Configure service log rotation with `logs.max_bytes` and `logs.max_files`
- Use logrotate for `supervisor.log`
- Reduce log level

## See also

- [`logs`](/how-it-works/commands/logs) - View service output
- [`status`](/how-it-works/commands/status) - Check service health
