Project
Telelogs
A self-hosted log aggregator: tail Docker and Kubernetes, read it all in a native desktop app, keep every line in a bucket you own.
I didn’t want another place my logs live. I wanted a nicer way to read the place they already live.
What it is
Telelogs is an open-source log aggregator. A small server tails your Docker containers and Kubernetes pods, a native desktop app (built with GPUI) shows them as one live stream, and every line gets archived to S3, R2, MinIO, GCS or a local folder.
It’s at v0.2.0. Docker and Kubernetes work, VMs are next, and the app is macOS only for now.
docker run -d --name telelog-server \
-v /var/run/docker.sock:/var/run/docker.sock \
-p 127.0.0.1:7070:7070 \
ghcr.io/tolaniverse/telelog-server --allow-unauthenticated
Architecture at a glance
Docker socket ─┐
├─► telelog-sources ─► telelog-server ─┬─► gRPC ─► telelog-app (GPUI)
Kubernetes API ┘ │ memory buffer │
▼ │
s3 / r2 / gcs / file ◄───┘ Query reads past the buffer
| Crate | Role |
|---|---|
telelog-core | The shared log model: LogRecord, Target, Filter |
telelog-proto | The gRPC API and conversions |
telelog-sources | Docker (bollard) and Kubernetes (kube-rs) |
telelog-server | Collects, buffers, archives and serves logs |
telelog-app | The desktop client |
The parts I care about
- One model for a log line. Docker, Kubernetes and later VMs all become the same
LogRecord, so the server and app never care where a line came from. - The bucket is just files. Lines are zstd-compressed JSON under
<prefix>/v1/<YYYY-MM-DD>/<HH>/, each file named after the time range it covers. Finding a time range means listing a folder, no index or database. - No gaps after a restart. A
_checkpoint.jsonrecords the newest archived line, and a restarted server picks up from there with no gap and no duplicates. - Live and archived don’t double up. A query tells the server, per source, which lines the app already holds live, so merging the two never shows a line twice. That’s also how logs from removed containers come back.
- Safe by default. Open on localhost, and it refuses to listen anywhere else without a token.
Tested against a real AKS cluster (4 nodes, 99 containers): ready in about 3 seconds, around 40 MB of memory while streaming.
Known limits
- A bucket query returns at most the newest 20,000 matching lines.
- The macOS app isn’t notarized yet, so the first launch needs Open Anyway in System Settings.
I wrote the full walkthrough, with an animated diagram, in How Telelogs works.