ZenoLog is a lean, in-memory, OTel-native log buffer. Instant visibility into all your services' logs — via OTLP SDKs, Kubernetes container log discovery, or Azure Container Apps. No databases, no persistent storage. Just a 17 MB binary.
You just want to see your logs. But the industry says you need a cluster for that.
ELK needs 3+ pods, 2 GB RAM minimum, and 50 GB disk before you see a single log line.
Cloud logging charges per GB ingested. A medium cluster can cost more than the compute it monitors.
Loki needs object storage. Elasticsearch needs tuning. Fluentd needs configuration. All before day one.
ZenoLog: 1 pod, 15 MB RAM, 0 disk, 0 configuration.
ZenoLog replaces your entire log-viewing stack with a single binary. Native OpenTelemetry ingestion, Kubernetes container log discovery, in-memory ring buffers, full-text search, live tail, trace correlation — and both a Web UI and Terminal UI baked right in.
A full-featured Web UI and a keyboard-driven Terminal UI — both shipped inside the same 17 MB binary.
Two log paths into one buffer. OTLP SDKs and K8s container stdout — side by side.
Your apps send structured OTel log records with trace IDs, severity, and attributes via gRPC or HTTP. Full fidelity.
ZenoLog discovers pods automatically, resolves owner chains (Deployment, StatefulSet, DaemonSet, CronJob), and streams container stdout/stderr via the K8s API.
Shared informers watch all namespaces. Pods appear in the catalog as they're created — no configuration needed.
You choose which sources to stream. Activate with specific containers via the Web UI, TUI, or API. No surprise bandwidth.
Automatically parses [INFO], [ERROR], level=warn, and other common patterns from plain-text container logs.
Pods are grouped by their owner chain: Pod → ReplicaSet → Deployment. Source key: namespace~owner.
Auto-discover your ACA apps and stream container logs — no code changes, no agents to install.
Azure Container Apps abstracts away Kubernetes, which means you lose kubectl logs. ZenoLog brings that visibility back by discovering your apps via the Azure Resource Manager API and streaming container logs in real time.
Deploy ZenoLog as a Container App in the same environment, assign a Managed Identity, and every app in your environment appears automatically.
Every feature designed around how engineers actually debug.
Dual-protocol OpenTelemetry receivers. Point your existing OTel SDKs and they just work.
Automatic per-service isolation with dual-limit eviction. No noisy neighbor problems.
Per-source severity thresholds with probabilistic sampling. Control what you keep.
Instant search across all buffered logs with rich filtering. Find the needle in real time.
Real-time log streaming as events arrive. Watch your services in real time.
Click any trace ID to see every log from that transaction, across all services.
Full-featured SvelteKit dashboard compiled into the binary. No separate frontend to deploy.
Bubble Tea TUI for terminal-native workflows. SSH into a box and inspect logs instantly.
Auto-discover pods via shared informers. Activate container log streaming with one click.
Discover ACA apps via ARM API. Stream container logs with Managed Identity auth. No agents required.
Real resource consumption compared to popular alternatives.
| Metric | ZenoLog | Loki | ELK |
|---|---|---|---|
| Container Image | 17 MB | 65 MB | 900 MB |
| Memory (idle) | 15 MB | 512 MB | 2 GB |
| Memory (10 services) | ~150 MB | ~1 GB | ~3 GB |
| Disk Required | None | 10 GB+ | 50 GB+ |
| Startup Time | <100 ms | ~5 s | ~30 s |
| Pods (Kubernetes) | 1 | 2–3 | 3–5 |
| External Dependencies | None | Object storage | JVM, storage |
Loki and ELK measurements based on minimal single-node deployments with default configuration.
Four stages from source to screen — all in one process.
OTel SDKs send logs via OTLP gRPC/HTTP. K8s container logs are streamed via the pods/log API. Both paths feed the same pipeline.
Per-source severity thresholds and probabilistic sampling decide what to keep. Drop noise before it enters the buffer.
Per-source circular ring buffers with dual-limit eviction (count + bytes). Old logs fall off automatically.
Search, live tail, and trace correlation via the REST API — rendered in the Web UI or Terminal UI.
Choose your path — all roads lead to logs.
Fastest path. Pull and run.
docker run -d \ -p 4317:4317 \ -p 4318:4318 \ -p 8080:8080 \ -p 8081:8081 \ jimmytoenners/zenolog:0.3.4
Single-pod deployment with optional K8s log discovery.
apiVersion: apps/v1
kind: Deployment
metadata:
name: zenolog
spec:
replicas: 1
selector:
matchLabels:
app: zenolog
template:
metadata:
labels:
app: zenolog
spec:
serviceAccountName: zenolog
containers:
- name: zenolog
image: jimmytoenners/zenolog:0.3.4
env:
- name: ZENOLOG_K8S_ENABLED
value: "true"
ports:
- containerPort: 4317
- containerPort: 4318
- containerPort: 8080
- containerPort: 8081
resources:
requests:
cpu: 50m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
livenessProbe:
httpGet:
path: /healthz
port: 8080
readinessProbe:
httpGet:
path: /readyz
port: 8080Single static binary. No runtime dependencies.
# Download curl -L -o zenolog \ https://get.zenolog.dev/latest chmod +x zenolog # Run ./zenolog # Open Web UI open http://localhost:8081 # Or use the TUI ./zenolog tui
Works with any language. Here's .NET as an example.
// .NET — Program.cs
builder.Logging.AddOpenTelemetry(otel =>
{
otel.SetResourceBuilder(ResourceBuilder.CreateDefault()
.AddService("my-service"));
otel.AddOtlpExporter(o =>
{
o.Endpoint = new Uri("http://localhost:4318/v1/logs");
o.Protocol = OtlpExportProtocol.HttpProtobuf;
});
});
// That's it. Logs appear in ZenoLog instantly.Sensible defaults. Override what you need.
| Variable | Default | Description |
|---|---|---|
| ZENOLOG_GRPC_ADDR | :4317 | OTLP gRPC receiver address |
| ZENOLOG_HTTP_ADDR | :4318 | OTLP HTTP receiver address |
| ZENOLOG_HEALTH_ADDR | :8080 | Health / readiness endpoint |
| ZENOLOG_API_ADDR | :8081 | API + Web UI address |
| ZENOLOG_MAX_SOURCES | 100 | Maximum number of distinct sources |
| ZENOLOG_RING_CAP | 10000 | Ring buffer record capacity per source |
| ZENOLOG_RING_MAX_BYTES | 10485760 | Ring buffer byte limit per source (10 MB) |
| ZENOLOG_SOURCE_RATE_LIMIT | 10 | Max new sources per minute (0 = unlimited) |
| ZENOLOG_CORS_ORIGINS | * | Comma-separated CORS allowed origins |
| ZENOLOG_K8S_ENABLED | false | Enable K8s pod discovery (true, auto, false) |
| ZENOLOG_K8S_LOG_SINCE | 5m | How far back to read on stream activation |
| ZENOLOG_K8S_MAX_STREAMS | 100 | Max concurrent container log streams |
Free forever. No credit card, no limits, no catch.
Full feature set. No limits. No catch.
Deploy ZenoLog in seconds. Point your OTel SDKs. Open the Web UI. That's the entire setup.
Get Started Now