# ── Logstash Pipeline — Timmy Time log aggregation ────────────────────────── # # Collects Docker container logs via the GELF input, parses them, # and ships structured events to Elasticsearch. # # Flow: Docker (GELF driver) → Logstash :12201/udp → Elasticsearch input { # GELF (Graylog Extended Log Format) — Docker's native structured log driver. # Each container sends logs here automatically via the logging driver config # in docker-compose.logging.yml. gelf { port => 12201 type => "docker" } } filter { # ── Tag by container name ────────────────────────────────────────────────── # Docker GELF driver populates these fields automatically: # container_name, container_id, image_name, tag, command, created # Strip leading "/" from container_name (Docker convention) if [container_name] { mutate { gsub => ["container_name", "^/", ""] } } # ── Parse JSON log lines (FastAPI/uvicorn emit JSON when configured) ────── if [message] =~ /^\{/ { json { source => "message" target => "log" skip_on_invalid_json => true } } # ── Extract log level ───────────────────────────────────────────────────── # Try structured field first, fall back to regex on raw message if [log][level] { mutate { add_field => { "log_level" => "%{[log][level]}" } } } else if [level] { mutate { add_field => { "log_level" => "%{level}" } } } else { grok { match => { "message" => "(?i)(?DEBUG|INFO|WARNING|ERROR|CRITICAL)" } tag_on_failure => [] } } # Normalise to uppercase if [log_level] { mutate { uppercase => ["log_level"] } } # ── Add service metadata ────────────────────────────────────────────────── mutate { add_field => { "environment" => "production" } add_field => { "project" => "timmy-time" } } } output { elasticsearch { hosts => ["http://elasticsearch:9200"] index => "timmy-logs-%{+YYYY.MM.dd}" # ILM policy: auto-rollover + delete after 30 days ilm_enabled => true ilm_rollover_alias => "timmy-logs" ilm_pattern => "{now/d}-000001" ilm_policy => "timmy-logs-policy" } # Also print to stdout for debugging (disable in production) # stdout { codec => rubydebug } }