Log History
LogDeck stores container logs locally, so history outlives the containers that produced it.
By default, LogDeck tails every container on every configured host and writes those lines to a SQLite database on its own disk. That store is what powers History mode in the log viewer: logs you can still read after a container restarts, after it is rebuilt with a new image, and even after it is removed entirely.
This is a local convenience store, not a log aggregation platform. It is bounded by retention caps, it lives on the machine running LogDeck, and it is not replicated anywhere.
LogDeck writes logs.db into the same directory as its config file — /data/logs.db with the default CONFIG_PATH. If /data is not a mounted volume, the database is stored inside the container's filesystem and is destroyed the next time you recreate LogDeck.
The same volume also holds config.json (hosts, API tokens, alert rules) and alerts-history.json.
services:
logdeck:
image: amoabakelvin/logdeck:latest
container_name: logdeck
ports:
- "8123:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /proc:/host/proc:ro
# Config file, stored logs, and alert history live here
- logdeck-data:/data
restart: unless-stopped
volumes:
logdeck-data:What survives what
A container's stored history is keyed by its host and its name, not by its engine ID. Every engine container ID is recorded as a separate generation of that name, and queries stitch the generations back together in timestamp order. That is what makes history survive operations that give a container a brand-new ID:
- Restart (
docker restart, a crash loop, a restart policy) — one continuous timeline. - Rebuild or recreate (
docker compose up -d --build, an image bump, an environment-variable edit in LogDeck) — the new container appends to the same timeline under the same name. - Removal — the lines already stored stay readable (see below), even though the container is gone from the engine.
- Restarting LogDeck itself — on startup, LogDeck re-reads each container's engine logs from where it left off, so lines emitted while it was down are backfilled rather than lost.
• Backfill reads the logs the engine still holds. If a container is removed while LogDeck is down, the engine discards its logs with it, and whatever LogDeck had not already stored is unrecoverable.
• Containers whose logging driver has no read API (awslogs, syslog, none, …) cannot be read by LogDeck at all. They are excluded from the store, and the reason is written to the server log.
• Renaming a container starts a new timeline, because the name is the identity.
Using History mode
On a container's log page, the toolbar shows a Live | History toggle whenever the store is enabled. Live streams from the engine as always; History queries the database.
In History mode:
- Search, level filter, and time range are applied server-side across everything stored for that container — not just the lines currently loaded in the browser. Search accepts plain text or a regex.
- Results page backwards from the newest line. A Load older button fetches the previous page (500 lines) until you reach the beginning of stored history.
- Timestamps, wrapping, line selection, pinning, copying, and downloading (JSON or TXT) all work exactly as they do in Live mode.
- Streaming controls (Stream, Pause, tail size, auto-scroll) are hidden — there is nothing to stream.
History is available for single containers on the container log page. Aggregated Compose stack logs are live-only: the stack view merges live streams and has no History toggle. The quick-look log sheet on the dashboard is live-only too — open the container's full log page for history.
Removed containers
When LogDeck holds stored logs for a container that no longer exists on any host, the dashboard's state summary grows a Removed chip. Removed containers are hidden under "All states" — click the chip (or pick Removed in the state filter) to list them.
A removed container shows how much log data is stored for it instead of CPU and memory, and offers a single action: View stored logs. Its log page opens locked to History; there is no live stream, no terminal, and no environment or resources tab, because there is no container left to inspect.
Retention and disk use
Two caps bound the store, and a sweep runs every minute to enforce them by evicting the oldest lines first:
- Per container (default
50MB) — applied to a logical container, meaning all generations of the same name together. A rebuilt container does not get a fresh budget. - Total (default
1024MB) — applied to the whole store, across every host and container.
The database file is never vacuumed: SQLite reuses freed pages, so after eviction the file plateaus at its high-water mark rather than shrinking. Size /data for roughly the total cap plus headroom.
Configuration
Persistence is enabled by default. It is configured in the config file under logStore, and every field can be overridden by an environment variable, which wins over the file. There is no Settings page for it.
{
"logStore": {
"enabled": true,
"perContainerMB": 50,
"totalMB": 1024
}
}LOG_STORE_ENABLEDfalse turns persistence off entirely: no database file is created, History mode disappears from the UI, and the history endpoints report the store as disabled. Existing data is left on disk untouched. Default: true.
LOG_STORE_PER_CONTAINER_MBPer-container retention cap in MB. Must be a positive integer; anything else is ignored with a warning. Default: 50.
LOG_STORE_TOTAL_MBTotal retention cap in MB across the whole store. Must be a positive integer. Default: 1024.
If the database cannot be opened — a read-only volume, a missing mount — LogDeck logs a warning and keeps running without stored logs. Persistence never blocks startup. Check the server log for Log persistence is ENABLED (with the path and the caps) to confirm it came up.
API
The store is queryable over the HTTP API. These are read endpoints, so a read-scoped API token can call them.
GET /api/v1/history/status— whether persistence is available ({"enabled": true}).GET /api/v1/history/containers— every logical container the store knows about, including removed ones, with their stored size.GET /api/v1/history/logs— one page of stored logs. Returns503when persistence is disabled.
/history/logs takes container (required), host, search, regex (boolean), levels (comma-separated, including UNKNOWN), since and until (RFC3339), limit (default 500, max 1000), and cursor. Pages walk backwards through history: follow the returned nextCursor for older lines.
curl -H "Authorization: Bearer ldk_..." \
"http://localhost:8123/api/v1/history/logs?container=api&host=local&levels=ERROR,FATAL&limit=200"