Skip to main content
Container logs are stored node-local (see observability) with a bounded retention window. Log archive ships them to a storage destination as gzip-compressed NDJSON, on a schedule you set per app or once for every app, so logs outlive the node-local store and you need no third-party log shipper. A storage destination must exist first; see object storage for connecting one.

What gets archived

Every line a container writes to stdout or stderr, exactly as the node-local log store received it. Objects are written to:
for example log-archive/service/web/2026/09/24/13/1790255400000000000.ndjson.gz. The prefix can be changed with APP_LOG_ARCHIVE_PREFIX. Each line is a JSON object:
fields is only present when message parsed as a JSON object (structured: true); plain-text lines carry message only.

How it behaves

  • The archiver pulls, it does not push. A scheduler wakes once a minute (APP_LOG_ARCHIVE_TICK), checks which policies are due, and reads new lines from the node-local store.
  • Each policy keeps a watermark. Objects are named by their chunk start, so a retry after a failure overwrites the same key instead of duplicating lines. A failed window keeps the watermark in place and is retried on the next run.
  • Runs are bounded: one at a time, at most 24 hour-windows per scheduled run, and at most 200,000 lines per object (APP_LOG_ARCHIVE_MAX_LINES_PER_OBJECT). Lines are spooled to a temp file first so the log database is never held open during an upload. A new policy archives forward from the moment it is created; use a dump for history.
  • Each scheduled tick or manual dump is recorded as a run with a status (running, succeeded, failed), the time range it covered, and object/line/byte counts, visible via levelrail-cli logs archive status or GET /api/v1/log-archive/runs.

Retention

Set “Keep for (days)” on a policy (0 means forever) to have the archiver delete objects older than that after each successful scheduled run, up to 500 deletions per run. The global policy (no app set) leaves apps that have their own policy alone, so a per-app retention setting always wins over the global one. If you would rather let the provider manage deletion, add a bucket lifecycle rule on the log-archive/ prefix and leave retention at 0.

Manage policies

Use an app’s Logs, Archive tab for a per-app policy, or Settings, Storage destinations for the global policy that covers every app.
Intervals run from 5 minutes to 24 hours and default to 1 hour (PUT /api/v1/log-archive/policy).

Dump now

Archive a past range immediately, without waiting for the schedule:
--from and --to take an RFC3339 timestamp or a duration back from now. The range is capped at 31 days. The dashboard has the same control on the Archive tab. Under the hood this is POST /api/v1/log-archive/dump, which answers 202 Accepted with a run to poll (GET /api/v1/log-archive/runs) rather than blocking until the dump finishes.

Retrieving archived logs

Equivalently, GET /api/v1/log-archive/objects?target_id=<id>&app=web lists keys page by page (100 per page, follow next), and GET /api/v1/log-archive/objects/download?target_id=<id>&key=<key> streams the object back with Content-Type: application/gzip. Download is limited to keys under the archive prefix; a key outside it is rejected. Read an object with zcat file.ndjson.gz | jq .. Archived objects have no search index; use your bucket provider’s tooling (Athena, DuckDB, zgrep) to search them.

Alerting

Create a log_archive_stale alert rule (dashboard: Alerts, or levelrail-cli apps alerts create <app> --kind log_archive_stale) to be notified when a policy’s last run failed, or when it has gone longer than the rule’s for_duration without a success (default: three intervals, at least two hours).

API and MCP

REST routes live under /api/v1/log-archive (see the API reference). Reads need the read ability, policy changes and dumps need write. The MCP server exposes list_log_archive_policies, set_log_archive_policy, start_log_archive_dump, list_log_archive_runs, and list_archived_logs.

Next steps

Object storage

Connect the bucket that archived logs are written to.

Observability

Live logs, metrics, and alert rules.
Last modified on October 12, 2026