Echte x22-Logs: 2000 Zeilen -> 286 Kollisionen (duplicate sample). Telegraf uebernimmt den Log-Zeitstempel; bei mehreren Treffern pro Sekunde kollidiert der +1ms-Aufschlag mit echten Zeilen. Prometheus weist den Batch ab, Telegraf retryt endlos -> FIFO steht -> Node liefert GAR NICHTS mehr. Fix: eigenes Grok-Muster mit log_time als Feld (Telegraf nutzt eigene ns-Uhr) + processors.converter, damit resp_code/verb Tags bleiben. Gemessen: 2000/2000 Samples, 0 Kollisionen. Ausserdem: Einheiten-Waechter im Archiver (ms statt s -> Abbruch statt nutzloser Block).
101 lines
4.9 KiB
ApacheConf
101 lines
4.9 KiB
ApacheConf
# Apache: Access-Logs → Loki (roh) UND Request-Metriken → Prometheus
|
|
#
|
|
# Zwei Wege aus einem Log — sie ergaenzen sich:
|
|
# inputs.tail : jede Zeile roh nach Loki (fuer die Fehlersuche im Einzelfall)
|
|
# inputs.logparser: dieselben Zeilen als Metriken (Request-Rate, Status-Klassen,
|
|
# Antwortzeit) — das ist, was Panels und Alerts brauchen
|
|
#
|
|
# Die Logs landen NICHT in Prometheus: der Remote-Write-Output hat
|
|
# `namedrop = ["docker_log", "journal"]` — hier kommt `apache_log` dazu.
|
|
#
|
|
# FALLE: `from_beginning` existiert bei inputs.tail NICHT (weder im Docker-Image
|
|
# noch im InfluxData-Paket 1.40). Ein solcher Block laesst den Dienst beim Start
|
|
# hart scheitern: "plugin inputs.tail: configuration specified the fields
|
|
# [from_beginning]" → systemctl start schlaegt fehl, ALLE Metriken aus.
|
|
# Stattdessen: initial_read_offset = "saved-or-end" (Default), damit beim ersten
|
|
# Lauf nicht die komplette Historie ausgeschuettet wird.
|
|
|
|
# --------------------------------------------------------------------------
|
|
# 1) Roh-Logs → Loki
|
|
# --------------------------------------------------------------------------
|
|
# ${APACHE_FILES} rendert zu einer echten TOML-Liste — der Installer baut sie
|
|
# aus allen gefundenen Logpfaden (Panel-Hoster haben pro VHost eigene Dateien).
|
|
# Ein einzelner String mit Leerzeichen ("/a.log /b.log") waere ein ungueltiger
|
|
# Pfad und der Input liefe still leer.
|
|
[[inputs.tail]]
|
|
files = ${APACHE_FILES}
|
|
name_override = "journal"
|
|
# Beim Erstanlauf nur Neues lesen; danach Position merken.
|
|
initial_read_offset = "saved-or-end"
|
|
data_format = "value"
|
|
data_type = "string"
|
|
# Vereinheitlicht den Feldnamen auf `message` — das Logs-Panel in Grafana
|
|
# erwartet es; `value` wuerde als value="…" erscheinen.
|
|
path_tag = "logfile"
|
|
[inputs.tail.tags]
|
|
source = "apache"
|
|
|
|
[[processors.rename]]
|
|
namepass = ["journal"]
|
|
order = 1
|
|
[[processors.rename.replace]]
|
|
field = "value"
|
|
dest = "message"
|
|
|
|
# --------------------------------------------------------------------------
|
|
# 2) Request-Metriken (Common/Combined Log Format) → Prometheus
|
|
# --------------------------------------------------------------------------
|
|
# Common Log Format:
|
|
# 127.0.0.1 - frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326
|
|
# VHost-Apache (Debian-Default) stellt den Hostnamen voran:
|
|
# example.com:80 127.0.0.1 - - [10/Oct/2000:13:55:36 -0700] "GET / HTTP/1.0" 200 2326
|
|
[[inputs.tail]]
|
|
files = ${APACHE_FILES}
|
|
name_override = "apache_access"
|
|
initial_read_offset = "saved-or-end"
|
|
data_format = "grok"
|
|
# Korrekte Namen der Telegraf-Grok-Sammlung: COMMON_LOG_FORMAT und
|
|
# COMBINED_LOG_FORMAT — NICHT HTTPD_* (das sind andere Muster, Telegraf kennt
|
|
# sie nicht: "no pattern found for %{HTTPD_COMBINED_LOG_FORMAT}").
|
|
# Reihenfolge: spezifischste zuerst — VHost-Varianten vor der einfachen Form.
|
|
# EIGENES MUSTER statt %{COMBINED_LOG_FORMAT} — wegen eines realen Ausfalls:
|
|
# Die Log-Zeile hat nur SEKUNDEN-Aufloesung. Telegraf uebernimmt einen
|
|
# erkannten Zeitstempel als Sample-Zeit; bei mehreren Treffern pro Sekunde
|
|
# vergibt es +1 ms Aufschlag. Bei hoher Last (>1000 Zeilen/s) laeuft dieser
|
|
# Aufschlag in die naechste Sekunde und kollidiert mit echten Zeilen:
|
|
# "duplicate sample for timestamp ...; overrides not allowed"
|
|
# Gemessen an echten x22-Logs: 2000 Zeilen -> 286 Kollisionen.
|
|
# Prometheus weist den Batch ab, Telegraf wiederholt ihn endlos — der Node
|
|
# liefert dann GAR NICHTS mehr (auch keine Systemmetriken).
|
|
#
|
|
# Der Fix: das Zeitfeld heisst `log_time` (kein `ts`), darum nutzt Telegraf
|
|
# seine EIGENE Uhr mit Nanosekunden-Aufloesung. Die Log-Zeit bleibt als Feld
|
|
# erhalten, der Zeitstempel ist eindeutig.
|
|
grok_custom_patterns = '''
|
|
APACHE_LINE (?:%{HOSTNAME:vh}(?::%{NUMBER:vport})? )?%{IPORHOST:client_ip} %{USER:ident} %{USER:auth} \[%{HTTPDATE:log_time}\] "(?:%{WORD:verb} %{NOTSPACE:request}(?: HTTP/%{NUMBER:http_version})?|-)" %{NUMBER:resp_code:int} (?:%{NUMBER:resp_bytes:int}|-)(?: "%{DATA:referrer}" "%{DATA:agent}")?
|
|
'''
|
|
grok_patterns = ["%{APACHE_LINE}"]
|
|
grok_timezone = "UTC"
|
|
# Kein Tag-Wildwuchs: nur das Noetige als Tag, der Rest als Feld.
|
|
[inputs.tail.tags]
|
|
source = "apache"
|
|
|
|
# resp_code und verb waren im eingebauten Muster TAGS. Das eigene Muster
|
|
# liefert sie als Felder — ohne diesen Schritt haetten die Grafana-Panels,
|
|
# die nach resp_code filtern, plotzlich keine Daten mehr.
|
|
[[processors.converter]]
|
|
namepass = ["apache_access"]
|
|
order = 1
|
|
[processors.converter.fields]
|
|
tag = ["resp_code", "verb"]
|
|
|
|
# --------------------------------------------------------------------------
|
|
# 3) mod_status (optional, auskommentiert)
|
|
# --------------------------------------------------------------------------
|
|
# Liefert Auslastung (BusyWorkers, ReqPerSec) — nuetzlich, braucht aber
|
|
# `a2enmod status`, `ExtendedStatus On` und eine lokale Freigabe von
|
|
# /server-status in der Apache-Config.
|
|
#
|
|
# [[inputs.apache]]
|
|
# urls = ["http://127.0.0.1/server-status?auto"]
|