Files
netbird-telegraf-installer/scripts/raw-log-backfill.sh
T
Kalina f8c5f2eb3c feat(rawlogs): Rohlogs fuer den Loki-Import sammeln
Der Prometheus-Archiv-Import verdichtet auf Stunde/Domain/Status und
verwirft Referrer, User-Agent und Client-IP. Fragen nach der Herkunft
liessen sich damit nicht rueckwirkend beantworten.

- raw-log-collect.py: liest access+error (inkl. .gz, rotierte Dateien),
  schreibt ts_ns/labels/rohzeile und meldet Zeilen ohne Zeitstempel
  statt sie still zu verwerfen. Error-Logs ohne Zeitzone (Apache-
  Standard) werden korrekt nach UTC verschoben.
- raw-log-backfill.sh: Wrapper mit Messmodus; sammelt auf dem Host,
  importiert selbst NICHTS.
2026-09-14 17:31:14 +02:00

141 lines
6.2 KiB
Bash

#!/bin/bash
# raw-log-backfill.sh — Rohlogs eines KeyHelp-Hosts fuer den LOKI-Import sammeln.
#
# Warum es dieses Skript gibt:
# Der Prometheus-Archiv-Import verdichtet jede Logzeile auf Stunde/Domain/
# Status und VERWIRFT dabei Referrer, User-Agent und Client-IP. Fragen nach
# Herkunft ("woher kommen die Besucher") liessen sich damit nicht
# rueckwirkend beantworten. Lokis Rohzeilen koennen es — aber die
# Live-Sammlung reicht nur bis zur Installation zurueck.
# Dieses Skript holt die Historie in eine Datei, die Loki aufnehmen kann.
#
# DIESES SKRIPT AENDERT NICHTS AM LAUFENDEN DIENST. Es liest nur Logdateien,
# es stoppt nichts, es loescht nichts.
#
# AUFRUF (auf dem Host, als root):
# curl -fsSL https://gitea.m-m.bio/mm/netbird-telegraf-installer/raw/branch/main/scripts/raw-log-backfill.sh -o /root/raw-backfill.sh
# bash /root/raw-backfill.sh # MESSEN (aendert nichts)
# bash /root/raw-backfill.sh --collect # Rohdatei bauen
# bash /root/raw-backfill.sh --collect --since 2025-01-01
# bash /root/raw-backfill.sh --collect --tarball /root/apache-archive/apache-archive.tar.gz
#
# Am Ende steht der exakte Befehl fuer den imac.
set -eu
REPO_RAW="${REPO_RAW:-https://gitea.m-m.bio/mm/netbird-telegraf-installer/raw/branch/main}"
OUT_DIR="${OUT_DIR:-/root/apache-archive}"
NODE="${NODE:-$(hostname -f 2>/dev/null || hostname)}"
COLLECT=0
SINCE=""
UNTIL=""
TARBALL=""
ROOTS="/var/log/apache2 /home/users"
while [ $# -gt 0 ]; do
case "$1" in
--collect) COLLECT=1 ;;
--since) SINCE="${2:?Datum fehlt}"; shift ;;
--until) UNTIL="${2:?Datum fehlt}"; shift ;;
--tarball) TARBALL="${2:?Pfad fehlt}"; shift ;;
--node) NODE="${2:?Name fehlt}"; shift ;;
--roots) ROOTS="${2:?Pfade fehlen}"; shift ;;
*) echo "Unbekannte Option: $1" >&2; exit 2 ;;
esac
shift
done
log() { printf '\033[1;34m[raw-backfill]\033[0m %s\n' "$*"; }
warn() { printf '\033[1;33m[raw-backfill] WARNUNG:\033[0m %s\n' "$*" >&2; }
die() { printf '\033[1;31m[raw-backfill] FEHLER:\033[0m %s\n' "$*" >&2; exit 1; }
[ "$(id -u)" -eq 0 ] || die "Bitte als root ausfuehren (die Logs liegen unter /home/users mit 0700)."
mkdir -p "$OUT_DIR"
COLLECTOR="$OUT_DIR/raw-log-collect.py"
if [ -r "$COLLECTOR" ] && [ -n "${SKIP_FETCH:-}" ]; then
log "Collector lokal uebernommen: $COLLECTOR"
else
log "Lade Collector vom Repo …"
curl -fsSL -m 30 "$REPO_RAW/scripts/raw-log-collect.py" -o "$COLLECTOR" \
|| die "raw-log-collect.py konnte nicht geladen werden."
fi
python3 -c "import sys; sys.exit(0)" || die "python3 fehlt auf diesem Host."
# --------------------------------------------------------------------------
# 1) MESSEN — was ist ueberhaupt da? (aendert nichts)
# --------------------------------------------------------------------------
log "Bestandsaufnahme der Apache-Logs (liest nur) …"
FILES=$(find $ROOTS -name 'access.log*' -o -name 'error.log*' 2>/dev/null | wc -l)
GZ=$(find $ROOTS -name '*.log*.gz' 2>/dev/null | wc -l)
RAW_BYTES=$(find $ROOTS -name 'access.log*' -o -name 'error.log*' 2>/dev/null -printf '%s\n' 2>/dev/null | awk '{s+=$1} END {print s+0}')
log " Logdateien: $FILES (davon komprimiert: $GZ)"
log " Rohgroesse: $(( RAW_BYTES / 1024 / 1024 )) MB"
log " Aelteste Datei: $(find $ROOTS -name 'access.log*' -printf '%TY-%Tm-%Td %p\n' 2>/dev/null | sort | head -1 | cut -c1-10)"
if [ -n "$TARBALL" ] && [ -r "$TARBALL" ]; then
log " Tarball: $TARBALL ($(( $(stat -c%s "$TARBALL") / 1024 / 1024 )) MB)"
log " Rohlogs im Tar: $(tar -tzf "$TARBALL" 2>/dev/null | grep -c 'raw/.*log' || echo 0) Dateien"
fi
if [ "$COLLECT" -eq 0 ]; then
echo
log "Das war NUR die Messung — es wurde nichts geschrieben."
echo " Weiter mit: bash $0 --collect${SINCE:+ --since $SINCE}"
echo " Optional zusaetzlich Rohlogs aus dem Archiv-Tarball:"
echo " --tarball $OUT_DIR/apache-archive.tar.gz"
exit 0
fi
# --------------------------------------------------------------------------
# 2) SAMMELN
# --------------------------------------------------------------------------
ARGS="--node $NODE --out $OUT_DIR --roots $ROOTS"
[ -n "$SINCE" ] && ARGS="$ARGS --since $SINCE"
[ -n "$UNTIL" ] && ARGS="$ARGS --until $UNTIL"
[ -n "$TARBALL" ] && [ -r "$TARBALL" ] && ARGS="$ARGS --include-tarball $TARBALL"
log "Sammle Rohlogs … (bei viel Historie dauert das einige Minuten)"
# shellcheck disable=SC2086
python3 "$COLLECTOR" $ARGS 2>&1 | tee "$OUT_DIR/collect.log"
RC=${PIPESTATUS[0]}
[ "$RC" -eq 0 ] || die "Collector brach ab (Code $RC). Siehe $OUT_DIR/collect.log"
PART=$(ls -t "$OUT_DIR"/loki-raw-*/raw.tsv 2>/dev/null | head -1)
STATE=$(ls -t "$OUT_DIR"/loki-raw-*/state.json 2>/dev/null | head -1)
[ -n "$PART" ] && [ -r "$PART" ] || die "Keine Rohdatei gefunden."
[ -n "$STATE" ] && [ -r "$STATE" ] || die "Keine Zustandsdatei gefunden."
LINES=$(wc -l < "$PART")
SIZE=$(( $(stat -c%s "$PART") / 1024 / 1024 ))
log "Rohdatei: $PART"
log " $LINES Zeilen, $SIZE MB"
# Gegenprobe: stimmt die Zeilenzahl mit der Zustandsdatei ueberein?
EXPECT=$(python3 -c "import json,sys; print(json.load(open('$STATE'))['lines'])")
if [ "$LINES" != "$EXPECT" ]; then
warn "Zeilenzahl weicht ab: Datei=$LINES, Auftrag=$EXPECT — bitte pruefen."
else
log " Gegenprobe: Zeilenzahl stimmt mit dem Auftrag ueberein ($LINES)."
fi
echo
log "NAECHSTER SCHRITT — diese beiden Zeilen auf dem imac ausfuehren:"
echo
echo " # 1) Rohdatei und Auftrag uebertragen"
echo " scp $PART $STATE mm@100.83.134.46:/tmp/"
echo
echo " # 2) Einlesen (der Import laeuft LOKAL auf dem imac — kein Token noetig)"
echo " ssh mm@100.83.134.46 \\"
echo " 'python3 /usr/local/bin/loki-raw-import.py \\"
echo " --file /tmp/$(basename "$PART") --state /tmp/$(basename "$STATE") \\"
echo " --url http://127.0.0.1:3100'"
echo
echo " # Vorher pruefen (empfohlen, aendert nichts):"
echo " ssh mm@100.83.134.46 \\"
echo " 'python3 /usr/local/bin/loki-raw-import.py \\"
echo " --file /tmp/$(basename "$PART") --state /tmp/$(basename "$STATE") \\"
echo " --url http://127.0.0.1:3100 --dry-run'"
echo
log "Danach im Grafana pruefen: {imported=\"1\"} (Dashboard: Weblogs-Analyse)"
warn "Das Skript selbst schreibt NICHTS nach Loki — der Import ist ein eigener Schritt."