Files
Timmy-time-dashboard/deploy/elk/logstash.conf

79 lines
2.6 KiB
Plaintext

# ── 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)(?<log_level>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 }
}