BEFUND (x22, gemessen und reproduziert):
Der Aufruf war 'python3 apache-log-survey.py 2>&1 | tee bestand.txt'. Das Skript
gab ALLES erst nach der Scan-Schleife aus (alle print() standen dahinter), und
Python puffert stdout in eine PIPE blockweise (4-8 KB). Die Gesamtausgabe ist
aber nur ~1 KB -> sie landete erst beim Prozessende in der Datei.
Messung mit 2 Mio Zeilen (140 MB):
mit tee: nach 5 s = 0 Bytes, fertig nach 41 s -> dann 1028 Bytes
ohne Pipe: nach 1 s = 0 Bytes
python3 -u: nach 1 s = 0 Bytes
=> Die Datei war leer, weil der Scan LIEF. Auf einem KeyHelp-Host mit tausenden
Logdateien dauert das Minuten und liest sich wie ein Haenger oder Absturz.
FIX (drei Massnahmen, damit das nie wieder passiert):
1. sys.stdout.reconfigure(line_buffering=True) — jede Zeile geht sofort raus,
auch durch eine Pipe.
2. Startbanner VOR dem Scan: Anzahl und Gesamtgroesse der Dateien.
3. Fortschrittszeile pro Datei (Nummer/Gesamtzahl, Zeilen, Groesse, Pfad) plus
eine Zeile fuer nicht lesbare Dateien.
Verifiziert mit 1,4 Mio Zeilen durch eine Pipe: nach 2 s steht das Banner, drei
Fortschrittszeilen erscheinen waehrend des Scans. Gegenprobe mit dem alten Code:
nach 3 s 16 Bytes, alles erst am Ende.
BEFUND (echter Datenverlust, gemessen gegen KeyHelp-Formate):
KeyHelp/Debian schreiben error.log im Access-Format, aber OHNE Zeitzone:
[01/Sep/2026:10:00:05] [core:error] [pid 9] AH00124: ...
TS_FORMATS kannte nur "%d/%b/%Y:%H:%M:%S %z" (MIT Zone). parse_ts() gab None,
hour wurde "unknown", und der Schreiber ueberspringt unknown-Zeilen:
apache_archive_errors_total fehlte KOMPLETT — kein Fehler, kein Log, Panel leer.
Genau die stille Fehlerklasse, die nicht passieren darf.
FIX:
- Format "%d/%b/%Y:%H:%M:%S" (ohne Zone) ergaenzt.
- Unparsbare Zeitstempel werden GEZAEHLT und laut gemeldet (Domain + Beispiel +
Hinweis auf TS_FORMATS) statt still zu verschwinden.
- Neu: scripts/x22-log-backfill.sh — messen (read-only) und parsen in einem
Aufruf, mit Selbstpruefung (Einheiten, Zukunft, Domain-Anzahl) VOR der
Uebergabe und dem sicheren Import-Befehl am Ende.
Verifiziert im Container gegen echte KeyHelp-Formate inkl. rotierter .1 und
.gz-Datei: Messmodus aendert nichts (MD5-Vergleich), Backfill erzeugt alle
fuenf Metriken inkl. errors_total{level=error} und {level=warn}.
x14 sendete 105 Metriken, aber KEINE apache-Metriken und keine Logs. Der
Installer meldete Erfolg. Telegraf selbst nannte den Grund:
W! [inputs.tail] Directory "/home/users" is not readable but is followed
by wildcards, make sure you set read permissions or globbing will not work!
Drei Ursachen, alle behoben:
1. `setfacl -m u:telegraf:x` auf der Glob-Wurzel ist FALSCH. Eine Wildcard wird
per readdir expandiert — dafuer braucht das Verzeichnis `r-x`, nicht nur `x`.
Neue Logik: Muster werden mit `set -f` gelesen, dann je Treffer die Datei mit
`r` und JEDE Ebene zwischen Wurzel und Datei mit `r-x` belegt.
Gemessen: alte ACL -> 1 Warnung, 1 Punkt (nur /var/log/apache2);
neue ACL -> 0 Warnungen, 4 Punkte (alle 3 Dateien inkl. User-Homes).
2. Der Gegentest war blind: er las jede gefundene Datei per `head -c 1` als
telegraf. Das konnte nicht fehlschlagen, weil die Datei vom ROOT-Shell
expandiert wurde — die Glob-Wurzel blieb unlesbar, Telegraf bekam 0 Treffer,
die Meldung sagte trotzdem "alle N Logdateien lesen". Jetzt wird die
GLOB-AUFLOESUNG gemessen: dasselbe Muster im Dienstkontext expandieren und die
Trefferzahl vergleichen. 0 von 0 zaehlt als Fehler, nicht als Erfolg.
3. `for p in $_pfadquelle` ohne `set -f` expandiert die Muster im Root-Shell.
_pattern war danach ein konkreter Dateiname, der Wildcard-Zweig lief nie, und
die ACL landete nur auf den Dateien. Real passiert: "ACL auf 3 Datei(en)",
"kein Glob-Muster gefunden", 0 Treffer im Dienst.
Verifiziert mit echtem Telegraf 1.40.0 und REALEN KeyHelp-Rechten
(/home/users/<user> 0700, logs 0750, Dateien 0640).
Der Trace auf x14 endete exakt hier:
+ envsubst ${NODE_NAME} ... ${APACHE_ERROR_FILES}
root@x14:/home/mm#
Ohne "< \$2.tmp" liest envsubst STDIN. Bei sh install.sh vom Terminal ist stdin
die Konsole -> der Installer wartet auf Eingabe, nach der letzten Meldung
"Schreibe Konfiguration ...". Genau das Bild: Stillstand, ^C, kein Fehler.
Bei curl | sh waere es schlimmer: envsubst wuerde den Rest des Skripts fressen.
Ein frueherer Patch von mir hat die Redirection verschluckt; alle Laeufe mit
vorhandener telegraf.conf (x22) liefen trotzdem, weil dort nur der Fallback
subst_vars() aktiv war. Erst der Erstinstall (x14) traf envsubst.
Verifiziert: vorher Haenger bei envsubst, jetzt vollstaendiger Durchlauf mit
CONFIG_VERSION-Marker und allen Confs.
Zwei reale Fehler, beide still:
1. setfacl -R lief nur ab dem logs/-Verzeichnis. /home/users/<user> ist auf
Panel-Hostern chmod 700 — ohne Durchgangsrecht (x) auf den ELTERNTEIL kommt
telegraf nicht bis zur Datei. Die Meldung sagte trotzdem "ACL gesetzt".
Fix: x auf allen Elternverzeichnissen bis zur Wurzel + Default-ACL, damit
neu angelegte Domain-Ordner erben.
2. Der Gegentest brach beim ERSTEN Treffer ab. Das war
/var/log/apache2/keyhelp/access.log (root:adm, immer lesbar) -> Meldung
"Gegentest OK", waehrend ALLE Domain-Logs in den User-Homes unlesbar
blieben. Fix: jeden Logpfad pruefen und die Anzahl der Fehlschlaege melden.
Verifiziert in Debian-12 mit KeyHelp-aehnlichen Rechten (Home 700, Logs 640).
setfacl -R lief ueber die GANZE Panel-Wurzel (/home/users) — dort liegen auch
Mails, Webinhalte und Backups. Das Recht auf die Logs waere damit teuer und
wirkungslos zugleich. Jetzt werden die logs/-Verzeichnisse eingesammelt
(find -maxdepth 3), und jeder setfacl-Lauf hat ein Timeout von 120 s, damit
ein langsamer Lauf nicht wie ein Haenger aussieht.
x14 blieb nach der letzten Erfolgsmeldung stehen (Abbruch per ^C, kein Fehler).
Ursache: grant_apache_log_access() ruft apt-get install acl auf — OHNE
apt-get update davor und OHNE Timeout. Bei veralteten Paketlisten kann apt in
eine Rueckfrage laufen und unbegrenzt warten. Direkt danach haette der naechste
fetch gehangen: fetch() hatte ueberhaupt kein curl-Timeout.
Fix:
- apt-get update vor dem acl-Install, timeout 180 auf allen Paketmanager-Aufrufen
- fetch() mit -m 30 + 3 Versuchen statt unbegrenztem Warten
- alle weiteren curl-Aufrufe (keyring, Binary, Re-Exec) mit -m/--connect-timeout
- Fortschrittsmeldung vor der ACL-Phase: ein Haenger sah wie ein Absturz aus
Bei `sh install.sh` oder `< eingabe` ist stdin eine Datei — dort kann kein
Unterbefehl das Skript wegfressen. Der Re-Exec war dort unnoetig und kostete
einen Download. Nur `curl … | sh` (echte Pipe) braucht den Neustart.
Auf einem frischen System fehlt curl haeufig — genau dort, wo apt laeuft und
der Schutz am noetigsten ist. Der Re-Exec scheiterte deshalb still und der
Installer lief ohne Schutz weiter.
Jetzt: curl -> wget -> busybox wget -> lokale Quelle (NETBIRD_TG_SOURCE).
Ist keiner verfuegbar, wird das ausdruecklich gemeldet statt still uebergangen.
x14 brach mitten in der Installation ab: der Installer gab seinen eigenen
Quelltext aus ("; then", Kommentarzeilen) und blieb stehen.
Ursache: Bei `curl ... | sh` liest die Shell das Skript aus STDIN. apt startet
auf Ubuntu `needrestart` (Meldung "Scanning processes... / Scanning linux
images..."), und das liest stdin — damit war der Rest des Skripts weg. Die
Shell setzte mitten im Quelltext fort. Bei x22 trat es nicht auf, weil Telegraf
dort schon installiert war (kein apt-Lauf).
Fix, drei Schutzschichten:
1. Re-Exec: laeuft das Skript ueber eine Pipe, laedt es sich frisch von der
Quelle und startet sich neu — mit stdin auf /dev/null. NICHT per cat von
stdin kopieren: die Shell puffert bereits, die Kopie waere unvollstaendig.
2. NEEDRESTART_MODE=a + DEBIAN_FRONTEND=noninteractive fuer alle apt-Aufrufe.
3. </dev/null an jedem Paketmanager (apt, dnf, yum, apk).
Bisher wurden NUR access.log gesammelt — real nachgemessen: 31 logfile-Labels,
0 davon error.log. Bei einem KeyHelp-Host mit PHP/CMS fehlten damit genau die
Fehler, fuer die man ins Monitoring schaut.
Error-Logs jetzt in einem EIGENEN Input (name_override=apache_error), roh nach
Loki, mit Tags logtype=error und logfile=<pfad>. Getrennt vom Access-Grok, weil
das Format nicht passt:
[Mon Sep 14 00:10:01.123456 2026] [core:error] [pid 9] AH00124: ...
Liefen sie durch den Access-Parser, entstuenden keine Metriken, aber der
Aggregator wuerde sie in leere Gruppen einordnen.
DREI STILLE FALLEN dabei gefunden und behoben:
1. processors.rename hatte namepass=["journal"] — apache_error behielt das
Feld value, jede Panel-Query mit {.message} haette es nicht gefunden.
2. outputs.loki namepass enthielt apache_error nicht — Input sammelt ein,
Output verwirft, keine Fehlermeldung, Panels leer (wie bei journal damals).
3. outputs.prometheus namedrop ebenso — sonst wandern Textzeilen in die TSDB.
Verifiziert gegen echte KeyHelp-Formate: access=2 Metriken, error=4 Rohzeilen,
Feld heisst message, 0 Error-Zeilen als Metrik.
Die vorige Massnahme (log_time statt ts) war NICHT ausreichend. Ursache ist
tiefer: Telegraf schreibt pro Sammelzyklus EINEN Zeitstempel fuer den ganzen
Batch, und Remote Write kann nur Millisekunden. Zwei Requests derselben Serie
in derselben Millisekunde -> Prometheus lehnt den ganzen Batch ab -> FIFO-Kopf
sitzt fest -> Node liefert gar nichts mehr (derselbe eingefrorene Timestamp
alle ~15s im Log).
Ein Zeitstempel-Trick kann das nicht loesen. Aggregation schon: basicstats
fasst alle Metriken einer Serie pro 60s zu einem Punkt zusammen. Gemessen an
2000 echten x22-Zeilen: 2000 Punkte -> 4 Punkte, 0 Kollisionen, Requests
vollstaendig gezaehlt (1997).
VERSION 1.2.0, damit der Auto-Updater den Fix ausrollt.
Zwei Fehler, gleiche Wurzel — die Werte aus /etc/default/telegraf wurden nur
vom Auto-Updater gelesen, nicht von einem manuellen --update-only:
1. Abbruch "Kein Token", obwohl der Token auf der Maschine liegt. Der Weg
fuer eine Reparatur auf einer laufenden Node war damit verschlossen.
2. Stiller: ohne --name fiel NODE_NAME auf den Hostnamen zurueck. Auf einem
KeyHelp-Host (x22 vs x22.idx.wf-keyhelp) waere die Node unter falschem
Label registriert worden; ein PVE-Knoten haette seine Rolle verloren
(kein pvesh-Drop-in mehr).
Fix: Token, NODE_NAME, ROLE, COLLECTOR, PVE_* aus der Datei nachladen, aber
nur wenn die Kommandozeile nichts anderes sagt (NAME_GIVEN/ROLE_GIVEN).
Zusaetzlich ein zweiter, ernster Fund aus dem Test:
APACHE_FILES blieb leer, wenn ROLE=apache gesetzt war, Apache aber nicht
erkannt wurde. Die Conf rendert dann zu "files = " -> ungueltiges TOML ->
Telegraf startet nicht -> ALLE Metriken der Node aus. Berechnung jetzt
unabhaengig vom Guard, plus Sicherheitsnetz vor dem Rendern.
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).