From da3f221c8d3a7f45f88c08eb2ff5aa4f8011748f Mon Sep 17 00:00:00 2001 From: mm Date: Mon, 14 Sep 2026 00:14:45 +0200 Subject: [PATCH] fix(apache): from_beginning existiert bei inputs.tail nicht (Dienststart scheiterte) + COMMON/COMBINED_LOG_FORMAT; Logpfad-Autoerkennung --- README.md | 42 +++++++++++++++++++++++++ install.sh | 20 +++++++++++- telegraf/apache.conf | 73 +++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 129 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 57e2a51..017c176 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,48 @@ Der Ausgang läuft über den **NetBird-Reverse-Proxy** (`imac-prometheus.x05.idx mit **Bearer-Token** — dadurch funktioniert der Installer auch auf Maschinen, die **kein NetBird-Peer** sind (Büro-LAN, Kundenlaptop, CGNAT, VM ohne Client). +## Apache-Logs + +Mit `--role apache` (oder automatisch, wenn `apache2ctl`/`httpd` gefunden wird) bindet der Installer Apache ein — auf **zwei** Wegen aus derselben Datei: + +| Ziel | Was | Wofür | +|---|---|---| +| **Loki** | jede Zeile roh | Fehlersuche im Einzelfall | +| **Prometheus** | `apache_access` mit Tags `resp_code`, `verb` | Request-Rate, Status-Klassen, Error-Rate — Panels und Alerts | + +**Logpfad wird automatisch ermittelt:** `/var/log/apache2/access.log` (Debian/Ubuntu/KeyHelp), `/var/log/httpd/access_log` (RHEL/Rocky), sonst aus der `CustomLog`-Direktive der Apache-Config. Überschreiben mit `--apache-log `. + +### Zwei Fallstricke + +**1. `from_beginning` existiert bei `inputs.tail` nicht.** Ein solcher Block lässt den Dienst beim Start hart scheitern — `systemctl start` schlägt fehl und **alle** Metriken fallen aus, nicht nur die Apache-Logs: + +``` +E! loading config file /etc/telegraf/telegraf.d/apache.conf failed: + plugin inputs.tail: line 2: configuration specified the fields ["from_beginning"], + but they were not used ... does not exist in this version +``` + +Richtig ist `initial_read_offset = "saved-or-end"` (Default) — damit wird beim ersten Lauf nicht die komplette Historie ausgeschüttet. Für einen Test gegen eine vorgefüllte Datei `"beginning"` setzen. + +**2. Die Grok-Muster heißen `COMMON_LOG_FORMAT` und `COMBINED_LOG_FORMAT`** — nicht `HTTPD_COMMON_LOG`/`HTTPD_COMBINED_LOG_FORMAT`. Die `HTTPD_*`-Namen aus anderen Grok-Sammlungen kennt Telegraf nicht: + +``` +E! [inputs.tail] Creating parser: no pattern found for %{HTTPD_COMBINED_LOG_FORMAT} +``` + +Die Reihenfolge in `grok_patterns` ist spezifisch → allgemein, damit die VHost-Varianten (`example.com:80 ...`) vor der einfachen Form greifen. + +### Response-Time + +Common und Combined Log Format enthalten **keine** Antwortzeit. Für `resp_time` in den Metriken muss das LogFormat in Apache erweitert werden: + +```apache +LogFormat "%h %l %u %t \"%r\" %>s %b \"%D\" \"%{User-agent}i\"" combined_time +CustomLog ${APACHE_LOG_DIR}/access.log combined_time +``` + +`%D` = Dauer in Mikrosekunden. Danach im Grok-Muster als Feld ergänzen. Ohne diese Änderung sind alle anderen Werte trotzdem verfügbar — nur die Antwortzeit fehlt. + ## Auto-Updater und Force-Updater Der Installer hält sich auf den Nodes selbst aktuell. diff --git a/install.sh b/install.sh index 18327af..74c9968 100755 --- a/install.sh +++ b/install.sh @@ -44,7 +44,10 @@ ROLE="auto" PVE_TOKEN="${PVE_TOKEN:-}" PVE_NODE="${PVE_NODE:-}" PVE_URL="${PVE_URL:-}" -APACHE_LOG="/var/log/apache2/access.log" +# Apache-Logpfad: Distributionen unterscheiden sich — Debian/Ubuntu/KeyHelp +# nutzen /var/log/apache2/, RHEL/Rocky /var/log/httpd/. Der Installer sucht beim +# ersten Lauf; --apache-log ueberschreibt. +APACHE_LOG="" TELEGRAF_VERSION="${TELEGRAF_VERSION:-1.40.0}" # Ueberschreibbar (Tests/Mirror): REPO_RAW=... sh install.sh REPO_RAW="${REPO_RAW:-https://gitea.m-m.bio/mm/netbird-telegraf-installer/raw/branch/main}" @@ -149,6 +152,21 @@ elif [ -e /dev/dri/renderD128 ]; then GPU="intel" fi HAS_APACHE=0; { command -v apache2ctl >/dev/null 2>&1 || command -v httpd >/dev/null 2>&1; } && HAS_APACHE=1 +# Apache-Logpfad ermitteln: erst explizit gesetzter Wert, dann uebliche Orte, +# dann die von Apache selbst konfigurierte CustomLog-Direktive. +if [ "$HAS_APACHE" -eq 1 ] && [ -z "$APACHE_LOG" ]; then + for _p in /var/log/apache2/access.log /var/log/httpd/access_log \ + /var/log/apache2/other_vhosts_access.log /var/log/httpd/access.log; do + [ -r "$_p" ] && { APACHE_LOG="$_p"; break; } + done + if [ -z "$APACHE_LOG" ]; then + # Aus der Config lesen (KeyHelp/Plesk setzen eigene Pfade) + _cl="$(grep -rhoE '^\s*CustomLog\s+\S+' /etc/apache2/ /etc/httpd/ 2>/dev/null \ + | awk '{print $2}' | grep -v '^|' | head -1)" + [ -n "$_cl" ] && [ -r "$_cl" ] && APACHE_LOG="$_cl" + fi + [ -n "$APACHE_LOG" ] || APACHE_LOG="/var/log/apache2/access.log" +fi if [ "$ROLE" = "auto" ]; then ROLE="none" [ "$IS_PVE" -eq 1 ] && ROLE="proxmox" diff --git a/telegraf/apache.conf b/telegraf/apache.conf index 48a0743..e0f285d 100644 --- a/telegraf/apache.conf +++ b/telegraf/apache.conf @@ -1,13 +1,76 @@ -# Apache: Access-Log → Loki (roh) + optional Request-Metriken → Prometheus +# 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 +# -------------------------------------------------------------------------- [[inputs.tail]] files = ["${APACHE_LOG}"] - from_beginning = false - name_override = "apache_log" + 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" -# Optional: mod_status (a2enmod status; ExtendedStatus On; /server-status?auto lokal freigeben) +[[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_LOG}"] + 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. + grok_patterns = [ + "%{HOSTNAME:vh}:%{NUMBER:vport} %{COMBINED_LOG_FORMAT}", + "%{HOSTNAME:vh} %{COMBINED_LOG_FORMAT}", + "%{COMBINED_LOG_FORMAT}", + "%{COMMON_LOG_FORMAT}", + ] + grok_timezone = "UTC" + # Kein Tag-Wildwuchs: nur das Noetige als Tag, der Rest als Feld. + [inputs.tail.tags] + source = "apache" + +# -------------------------------------------------------------------------- +# 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://localhost/server-status?auto"] +# urls = ["http://127.0.0.1/server-status?auto"]