# ============================================================================= # VECTOR CONFIGURATION # Zweck: Docker-Container-Logs einsammeln, aufbereiten und an Loki (-> Grafana) # senden. Zusätzlich Debug-Ausgabe in der Konsole. # ============================================================================= # ----------------------------------------------------------------------------- # GLOBAL / API (optional, aber praktisch für Monitoring von Vector selbst) # ----------------------------------------------------------------------------- api: enabled: true address: "127.0.0.1:8686" # Vector-eigenes Dashboard/API, nur lokal erreichbar # ============================================================================= # SOURCES: Woher kommen die Daten? # ============================================================================= sources: docker_logs: type: docker_logs # Nur laufende + gestoppte Container-Logs seit Vector-Start (Default: true) #include_containers: [] # leer = alle Container exclude_containers: - "vector" # verhindert, dass Vector seine eigenen Logs einsammelt (Log-Loop!) auto_partial_merge: true # zusammengehörige, von Docker aufgeteilte Zeilen mergen # ============================================================================= # TRANSFORMS: Verarbeitung der Daten # ============================================================================= transforms: # --------------------------------------------------------------------------- # 1. Grundbereinigung + feste Metadaten # --------------------------------------------------------------------------- parse_logs: type: remap inputs: [docker_logs] source: | # --- Message bereinigen (Newlines raus, damit Loki/Grafana sauber anzeigen) --- if is_string(.message) { .message = replace!(.message, "\n", " ") .message = strip_whitespace(.message) } # --- Statisches Service-/Cluster-Label --- .service = "my-cluster" # --- Docker-Metadaten absichern (falls mal Felder fehlen) --- .container_name = .container_name || "unknown" .host = .host || "unknown" # --- Container-Image ohne Tag/Hash extrahieren (weniger Kardinalität) --- if exists(.image) { image_parts = split(string!(.image), ":") .image_name = image_parts[0] } # --- Log-Level heuristisch erkennen (falls die App das nicht strukturiert liefert) --- .level = "info" msg_lower = downcase(to_string(.message) ?? "") if contains(msg_lower, "error") || contains(msg_lower, "err ") || contains(msg_lower, "exception") { .level = "error" } else if contains(msg_lower, "warn") { .level = "warn" } else if contains(msg_lower, "debug") { .level = "debug" } # --------------------------------------------------------------------------- # 2. Versuch, JSON-Logs (strukturierte Logs von Apps) zu parsen # Falls die Message JSON ist, wird sie geflattet -> mehr Kontext in Grafana. # Falls nicht, bleibt .message unverändert (kein Fehler, kein Absturz). # --------------------------------------------------------------------------- parse_json_if_possible: type: remap inputs: [parse_logs] source: | parsed, err = parse_json(.message) if err == null { # nur mergen, wenn wirklich ein Objekt rauskam (kein Array/String/Zahl) if is_object(parsed) { . = merge(., object!(parsed), deep: true) } } # ============================================================================= # SINKS: Wohin sollen die Daten? # ============================================================================= sinks: # --------------------------------------------------------------------------- # Debug-Ausgabe in der Konsole (praktisch zum Testen, kann später raus) # --------------------------------------------------------------------------- stdout_debug: type: console inputs: [parse_json_if_possible] encoding: codec: json # --------------------------------------------------------------------------- # Loki-Sink -> Grafana # --------------------------------------------------------------------------- loki_sink: type: loki inputs: [parse_json_if_possible] endpoint: "http://docker1.lan:3100" # Falls dein Loki Multi-Tenancy nutzt (Standard bei vielen Setups, auch Single-User). # Falls "no org id"-Fehler auftauchen: diese Zeile aktivieren. tenant_id: "fake" encoding: codec: json # Diese Felder werden bereits als Loki-Labels genutzt -> nicht doppelt im JSON-Body except_fields: ["host", "service", "container_name"] # WICHTIG: Nur Felder mit niedriger Kardinalität als Labels verwenden! # container_id, message, timestamp etc. NIEMALS als Label -> "too many streams" in Loki. labels: host: "{{ host }}" service: "{{ service }}" container_name: "{{ container_name }}" level: "{{ level }}" # Reihenfolge der Log-Zeilen pro Stream sicherstellen out_of_order_action: rewrite_timestamp batch: max_bytes: 1048576 # 1 MB pro Batch timeout_secs: 5 request: retry_attempts: 10 retry_max_duration_secs: 30 healthcheck: enabled: true