Aller au contenu

Log Aggregation

Pipeline

Docker containers → Alloy (auto-discovery) → Loki → Grafana (Explore)

Alloy connects to the Docker socket, discovers all running containers, and ships their stdout/stderr logs to Loki. No per-container configuration needed — new containers are picked up automatically.

How It Works

Alloy (Collector)

  • Config: monitoring/alloy/config.alloy
  • Discovers containers via /var/run/docker.sock
  • Extracts labels: Docker Compose project name, service name
  • Forwards to Loki at http://loki:3100/loki/api/v1/push
  • Internal state stored at /var/lib/alloy/data/

Loki (Storage & Query)

  • Config: monitoring/loki/loki-config.yml
  • Storage: filesystem-based (chunks in /loki/chunks/)
  • Retention: 7 days (compactor deletes after 2h grace period)
  • Schema: v13 (TSDB backend), 24-hour index periods
  • Single node (no clustering)

Querying Logs

In Grafana → Explore → select Loki datasource.

Common LogQL queries

# All logs from a specific container
{compose_service="aletheia-prod-web"}

# Error-level logs across all Aletheia containers
{compose_project="aletheia-prod"} |= "ERROR"

# Celery task failures
{compose_service=~"aletheia-.*-celery"} |= "Task" |= "raised"

# Nginx access logs with 5xx status
{compose_service="nginx-proxy"} |~ "HTTP/[12].\" 5[0-9]{2}"

# Slow requests (> 1 second)
{compose_service="aletheia-prod-web"} | json | response_time > 1000

Useful filters

Operator Purpose Example
\|= Contains string \|= "ERROR"
\|~ Matches regex \|~ "5[0-9]{2}"
!= Does not contain != "healthcheck"
\| json Parse JSON logs \| json \| level="error"

Retention & Storage

  • Logs are kept for 7 days
  • Storage is filesystem-based — check disk usage if Loki volume grows unexpectedly
  • No log parsing/structuring is applied by Alloy (logs are shipped as-is)
  • No remote write — logs are lost if the Loki container is destroyed