Log Management for Self-Hosted Apps: Loki, Promtail, and Grafana
Application logs are your first debugging tool. Loki collects, stores, and lets you search logs from all your self-hosted applications.
The Problem
Each container has its own logs. Debugging means SSH into the server, docker logs container-name, scroll through output. With 10 apps, this is painful.
The Solution: Centralized Logging
Collect all logs in one place. Search, filter, and correlate across applications.
The Loki Stack
Loki
The log database. Inspired by Prometheus but for logs. Indexes metadata (labels) but stores log lines as-is. Much more efficient than Elasticsearch for most use cases.
Promtail
The log collector. Runs on your server, reads container logs, and ships them to Loki.
Grafana
The dashboard. Query and visualize logs. You probably already have Grafana for metrics — Loki integrates seamlessly.
Why Loki over Elasticsearch?
Resource Usage
Simplicity
Cost
Trade-off
Elasticsearch has faster full-text search. Loki is better for label-based filtering and recent log queries.
Deployment
1. Deploy Loki + Promtail on TinyPod
2. Configure Promtail to read Docker/Podman logs
3. Add Loki as a data source in Grafana
4. Start querying logs
Querying Logs
Loki uses LogQL (similar to PromQL):
All logs from the app container:
{container="myapp"}
Filter for errors:
{container="myapp"} |= "error"
Parse JSON logs:
{container="myapp"} | json | status >= 500
Best Practices
Structured Logging
Log in JSON format. Loki can parse fields for filtering:
{"level": "error", "msg": "database connection failed", "service": "api"}
Log Levels
Use consistent levels: debug, info, warn, error, fatal. Filter by level in queries.
Retention
Keep logs for 30-90 days. Longer if compliance requires it. Configure Loki's retention policy to auto-delete old logs.
Alerts on Logs
Create Grafana alerts on log patterns: