1
Admin – Logging and Audit
Dmitrii Iurco edited this page 2026-06-11 15:39:28 -04:00

Status: Active | Owner: @roof | Applies to: main (2026-06) | Updated: 2026-06-11

Admin – Logging and Audit


Log levels

PIC has two separate log-level axes:

  1. Python service log levels — control verbosity for the Flask API's manager modules (for example, network, wireguard, email). Changes apply hot to the running process.
  2. Container log levels — control verbosity inside specific containers (Caddy, CoreDNS, WireGuard, mailserver). Some changes apply hot; others require a container restart.

Python log levels

Each manager module has its own logger. You can set them individually or set a root level that applies to everything not otherwise specified.

Available levels: DEBUG, INFO, WARNING, ERROR, CRITICAL.

Retrieve current levels:

GET /api/logs/verbosity

Update levels:

PUT /api/logs/verbosity
Content-Type: application/json

{
  "python": {
    "root": "INFO",
    "services": {
      "network": "DEBUG",
      "wireguard": "DEBUG",
      "email": "INFO"
    }
  }
}

Valid service names for the services map: network, wireguard, email, calendar, files, routing, vault.

Container log levels

Pass a "containers" key in the same request:

PUT /api/logs/verbosity
Content-Type: application/json

{
  "containers": {
    "caddy": "DEBUG",
    "coredns": "INFO"
  }
}

The response includes an "applied" map showing "hot" or "pending_restart" per container. caddy and coredns apply hot (Caddy is reloaded; CoreDNS is reloaded via SIGUSR1). wireguard and mailserver require a container restart for the level change to take effect.


Log files

Logs are written to data/logs/ inside the API container (/app/logs/ inside the container). Each service has its own log file with rotation at 5 MB and 5 backups.

Retrieve the last N lines for a service:

GET /api/logs?service=wireguard&lines=100

Search logs:

GET /api/logs/search?q=<query>&service=<service>

From the command line:

# Run on: the cell server host, from /opt/pic
make logs           # follow all container logs via docker compose
make logs-api       # follow the api container log
make logs-wireguard # follow the wireguard container log
make logs-caddy     # follow the caddy container log

Activity audit log

PIC maintains an append-only, hash-chained audit trail of administrative actions. Every mutating API request (POST, PUT, DELETE, PATCH) is recorded with:

  • Who — username, role, and source IP
  • What — action type and target (for example, peer_add, peer:laptop)
  • When — UTC timestamp
  • Resultsuccess or failure
  • Summary — a human-readable description; key names only, never values (secrets are never written)

The chain uses a per-entry SHA-256 hash linking each entry to the previous one. Tampering with the log file is detectable by verifying the chain.

The audit log is admin-only. Peer sessions cannot read it.

Querying the audit log

GET /api/audit
GET /api/audit?actor=admin&action=peer_add&limit=50
GET /api/audit?since=2026-01-01T00:00:00Z&until=2026-06-01T00:00:00Z

Filter parameters: actor, action, target_type, target_id, result, since, until. Pagination via limit (default 100) and offset.

Exporting the audit log

GET /api/audit/export?format=csv

Returns a CSV file attachment.

Verifying the chain

GET /api/audit/verify

Returns whether the hash chain is intact.

Storage

The audit log lives at data/api/audit/audit.log (a JSONL file). It rotates at 10 MB with 10 backup files kept. The audit log is included in both make backup and API-driven backups.

What is not audited

Read-only requests (GET) and diagnostic POST endpoints (for example, connectivity test) are not recorded. The audit log tracks state changes only.

Internals: see Dev – API Reference