From bddb3cf1e975fcf2b70ca0eda713522b47a924b0 Mon Sep 17 00:00:00 2001 From: h0tznpl0tz Date: Thu, 11 Sep 2025 12:35:48 +0200 Subject: [PATCH] Add exitrace tool and improve documentation - Add exitrace: Enhanced Exim log analyzer with status classification - Add Maintainer: ljp to all ljp-owned scripts - Update READMEs: Use installer-compatible command examples - Update main and legacy READMEs to include exitrace tool --- README.md | 5 +- install.sh | 1 + legacy/README.md | 5 + legacy/checkms/README.md | 27 ++- legacy/checkms/checkms.sh | 1 + legacy/exitrace/README.md | 169 +++++++++++++++++ legacy/exitrace/exitrace.sh | 368 ++++++++++++++++++++++++++++++++++++ legacy/go/README.md | 11 +- legacy/go/go.sh | 1 + update.sh | 1 + 10 files changed, 567 insertions(+), 22 deletions(-) create mode 100644 legacy/exitrace/README.md create mode 100755 legacy/exitrace/exitrace.sh diff --git a/README.md b/README.md index 6c35b76..4e49c80 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,9 @@ Optimierte Bash-Konfigurationen für verschiedene Support-Umgebungen: - [`pincMails`](./legacy/pincMails) Sucht nach versendeten PINC Mails einer bestimmten Kundennummer und kopiert diese in einen lokalen Unterordner +- [`exitrace`](./legacy/exitrace) + Exim-Log-Trace & Status für einzelne Mails/Adressen/Domain-Ziele mit Status-Klassifikation (OK/PARTIAL/DELAY/FAIL) + ## WH20 Snippets - [`plesk`](./wh20/plesk) @@ -116,7 +119,7 @@ cd /pfad/zu/esn-support-tools **Verfügbare Kategorien:** - **Bash-Profile**: .bashrc Optimierungen und modulare Konfiguration -- **Legacy Tools**: checkms, go, pincMails für Legacy-Infrastruktur +- **Legacy Tools**: checkms, go, pincMails, exitrace für Legacy-Infrastruktur - **WH20 Tools**: plesk für WH20-Infrastruktur diff --git a/install.sh b/install.sh index 47a4eac..5fd2bd6 100755 --- a/install.sh +++ b/install.sh @@ -1,5 +1,6 @@ #!/usr/bin/env bash # install.sh - Installationsscript für easyname Support Bash-Snippets +# Maintainer: ljp # Modular erweiterbar für neue Tools und Kategorien set -euo pipefail diff --git a/legacy/README.md b/legacy/README.md index 3bc9df1..55c8599 100644 --- a/legacy/README.md +++ b/legacy/README.md @@ -36,6 +36,11 @@ Sucht nach versendeten PINC Mails einer bestimmten Kundennummer und kopiert dies - [Dokumentation & Beispiele](./pincMails/README.md) +### [`exitrace`](./exitrace) +Exim-Log-Trace & Status für einzelne Mails/Adressen/Domain-Ziele. Durchsucht und analysiert Exim-Logs nach Message-IDs und gruppiert alle Ereignisse einer Mail. + +- [Dokumentation & Beispiele](./exitrace/README.md) + --- ## Voraussetzungen diff --git a/legacy/checkms/README.md b/legacy/checkms/README.md index 2e3b53d..8f638c6 100644 --- a/legacy/checkms/README.md +++ b/legacy/checkms/README.md @@ -24,11 +24,10 @@ Neben der Auswertung kann das Skript auch die Konfiguration (Fehlercodes, SSH-Us ## Installation -1. Repository klonen: +1. Installation über Installer: ```bash - git clone /esn-support-bash-snippets.git - cd esn-support-bash-snippets/legacy/checkms - chmod +x checkms + # Im Repository-Hauptverzeichnis + ./install.sh ``` 2. Beim ersten Start erstellt `checkms` automatisch die Konfiguration unter: @@ -46,21 +45,21 @@ Neben der Auswertung kann das Skript auch die Konfiguration (Fehlercodes, SSH-Us ### Standardanalyse ```bash -./checkms +checkms ``` → analysiert das heutige Logfile komplett. ### Tageslog ```bash -./checkms 2025-09-08 +checkms 2025-09-08 ``` → analysiert das Logfile vom 08.09.2025 (automatisch `.log` oder `.log.gz`). ### Zeitfenster ```bash -./checkms --minutes 30 # letzte 30 Minuten -./checkms --hours 2 # letzte 2 Stunden +checkms --minutes 30 # letzte 30 Minuten +checkms --hours 2 # letzte 2 Stunden ``` --- @@ -69,7 +68,7 @@ Neben der Auswertung kann das Skript auch die Konfiguration (Fehlercodes, SSH-Us ### Aktuelle Config ansehen ```bash -./checkms --show-config +checkms --show-config ``` Beispielausgabe: @@ -96,18 +95,18 @@ ID CODE ### SSH-User ändern ```bash -./checkms --set-user alice --show-config +checkms --set-user alice --show-config ``` ### Code hinzufügen ```bash -./checkms --add-code S77714 -./checkms --add-code 'S77[0-9]{3}' --show-config +checkms --add-code S77714 +checkms --add-code 'S77[0-9]{3}' --show-config ``` ### Code löschen ```bash -./checkms --del-code 2 --show-config +checkms --del-code 2 --show-config ``` → löscht den Code mit ID `2` (siehe `--show-config`). @@ -116,7 +115,7 @@ ID CODE ## Optionen ``` -Usage: ./checkms [OPTIONS] [YYYY-MM-DD] +Usage: checkms [OPTIONS] [YYYY-MM-DD] Analyse von MS-Fehlercodes im Exim-Log und Pflege der Codes. diff --git a/legacy/checkms/checkms.sh b/legacy/checkms/checkms.sh index 266762f..1cb8e60 100644 --- a/legacy/checkms/checkms.sh +++ b/legacy/checkms/checkms.sh @@ -1,5 +1,6 @@ #!/usr/bin/env bash # checkms - Analyse von MS-Fehlercodes im Exim-Log + Code-Management +# Maintainer: ljp set -euo pipefail diff --git a/legacy/exitrace/README.md b/legacy/exitrace/README.md new file mode 100644 index 0000000..f5536ed --- /dev/null +++ b/legacy/exitrace/README.md @@ -0,0 +1,169 @@ +# exitrace + +Exim-Log-Trace & Status für einzelne Mails/Adressen/Domain-Ziele: +Durchsucht Exim-Logs nach Message-IDs, gruppiert alle Ereignisse und klassifiziert den Delivery-Status + +--- + +## Features + +- Sucht in `/var/log/easyname/YYYY/MM/YYYY-MM-DD.log(.gz)` (konfigurierbar via `$LOGROOT`) +- Zeitfenster: letzte N Stunden/Tage ODER konkretes Datum/Datumsbereich +- Filter: Absender, Empfänger (Regex), Domain, Message-ID, zusätzliche Regex +- Gruppiert alle Treffer pro Exim-Message-ID und fasst Status zusammen +- **Status-Klassifikation**: OK / PARTIAL / DELAY / FAIL / UNKNOWN +- **MX-Records**: Optional DNS-Abfragen für Ziel-Domain (--mx) +- Markiert häufige Fehler (z. B. "all hosts for 'domain' have been failing") +- Sortierte chronologische Ausgabe pro Message-ID +- **Komprimierte Logs**: Automatischer Support für .gz-Archive + +--- + +## Installation + +1. Repository klonen oder Skript kopieren: + ```bash + git clone /esn-support-bash-snippets.git + cd esn-support-bash-snippets/legacy/exitrace + chmod +x exitrace.sh + ``` + +2. Abhängigkeiten: + - Standard Unix-Tools (awk, grep, date, zcat) + - `dig` (optional, für --mx Feature) + - Lesezugriff auf `/var/log/easyname/` (oder custom `$LOGROOT`) + +--- + +## Nutzung + +### Standardaufruf +```bash +exitrace +``` +(durchsucht heutiges Log ohne Filter) + +### Beispiele +```bash +# Mail-Trace einer konkreten Message-ID +exitrace -m 1uwRvz-000Fz2-CI + +# Alle Mails von bestimmtem Absender in den letzten 48 Stunden +exitrace -f sender@example.com -H 48 + +# Empfänger-Domain in Zeitspanne +exitrace -D example.de -r 2025-09-09..2025-09-11 + +# Regex-Filter auf Empfänger + konkretes Datum +exitrace -t '.*@example\.de' -d 2025-09-10 + +# Kombinierte Filter: Absender + Domain + Zeitfenster + MX-Info +exitrace -f sender@example.com -D example.de -H 48 --mx + +# Dry-Run: zeigt nur, welche Logfiles durchsucht würden +exitrace -n -H 24 +``` + +--- + +## Optionen + +``` +Usage: exitrace [OPTS] + +Zeitfenster (eine Option wählen): + -H, --hours N Letzte N Stunden durchsuchen + -DAYS, --days N Letzte N Tage durchsuchen + -d, --date YYYY-MM-DD Exaktes Datum + -r, --range A..B Datumsbereich (inkl.): YYYY-MM-DD..YYYY-MM-DD + +Filter (beliebig kombinierbar): + -f, --from ADDR Envelope-From / "from <...>" + -t, --to REGEX Empfänger (Regex, matcht nach " for " oder in "** ...") + -D, --domain NAME Ziel-Domain (z. B. example.de), prüft auf Zustellungen/Fehler dorthin + -m, --msgid ID Exim-Message-ID (z. B. 1uwRvz-000Fz2-CI) + -G, --grep REGEX Zusätzlicher Regex auf Logzeilen + +Sonstiges: + --mx Zeigt MX-Einträge (und A/AAAA) für --domain + -n, --dry-run Zeigt nur, welche Logfiles untersucht würden + -h, --help Diese Hilfe +``` + +--- + +## Beispielausgabe + +``` +[OK] ID=1uwRvz-000Fz2-CI | First=2025-09-10 14:32:15 | From=sender@example.com | Rcpts=recipient@example.de | Delivered=1 Deferred=0 Failed=0 +------------------------------------------------------------------------ +ID: 1uwRvz-000Fz2-CI +First: 2025-09-10 14:32:15 +Last: 2025-09-10 14:32:47 +From: sender@example.com +Rcpts: recipient@example.de +Status: OK (Delivered=1, Deferred=0, Failed=0) +Log: +2025-09-10 14:32:15 | <= sender@example.com H=mail.example.com [10.0.0.1] P=esmtp S=1234 +2025-09-10 14:32:47 | => recipient@example.de R=dnslookup T=remote_smtp H=mx.example.de [10.0.0.2] +------------------------------------------------------------------------ +``` + +**Status-Klassifikation:** +- `OK`: Alle Mails erfolgreich zugestellt +- `PARTIAL`: Teilweise zugestellt, aber auch Fehler/Delays +- `DELAY`: Noch in Warteschlange (Deferred) +- `FAIL`: Permanent fehlgeschlagen +- `UNKNOWN`: Status unklar + +Bei MX-Abfrage (--mx) wird zusätzlich angezeigt: +``` +== MX für example.de == +10 mx1.example.de. +20 mx2.example.de. +-- A/AAAA der MX: +mx1.example.de. | 192.0.2.1,192.0.2.2 +mx2.example.de. | 192.0.2.3 +======================================================================== +``` + +Bei Delivery-Stalls: +``` + Note: DELIVERY STALL erkannt: 'all hosts for domain failing (retry/backoff)' +``` + +--- + +## Setup-Hinweise + +Nach Installation über `./install.sh` ist das Script direkt verfügbar: +```bash +exitrace -m 1uwRvz-000Fz2-CI +``` + +Das Installationsscript erstellt automatisch einen Symlink in `~/bin` (ohne `.sh` Extension). + +Umgebungsvariable für abweichenden Logpfad: +```bash +export LOGROOT="/var/log/custom" +``` + +Logger-spezifisch ggf. in `~/.profile` ergänzen: +```bash +cd /var/log/easyname/$(date +%Y)/$(date +%m)/ +``` + +--- + +## Notes + +- Das Skript analysiert Exim-Logs im Format `/var/log/easyname/YYYY/MM/YYYY-MM-DD.log(.gz)` +- **Komprimierte Archive**: Automatische Erkennung und Verarbeitung von .gz-Dateien +- **Status-Logik**: Basiert auf SMTP-Response-Codes und typischen Exim-Nachrichten +- Bei größeren Zeiträumen kann die Verarbeitung länger dauern +- Regex-Filter (-t, -G) sollten sorgfältig formuliert werden, um false positives zu vermeiden +- Die Ausgabe ist nach chronologischem Erstkontakt der Message-ID sortiert +- **MX-Feature**: Benötigt `dig` für DNS-Abfragen +- Exit-Codes: 0 = OK (auch bei 0 Treffern), 1 = Fehlerhafte Parameter/Umgebung + +Built with the help of Claude Code \ No newline at end of file diff --git a/legacy/exitrace/exitrace.sh b/legacy/exitrace/exitrace.sh new file mode 100755 index 0000000..87ef40a --- /dev/null +++ b/legacy/exitrace/exitrace.sh @@ -0,0 +1,368 @@ +#!/usr/bin/env bash +# exitrace - Exim-Log-Trace & Status für einzelne Mails/Adressen/Domain-Ziele +# Maintainer: ljp +# ----------------------------------------------------------------------------- +# Features: +# - Sucht in /var/log/easyname/YYYY/MM/YYYY-MM-DD.log(.gz) (anpassbar mit $LOGROOT) +# - Zeitfenster: letzte N Stunden/Tage ODER konkretes Datum/Spanne +# - Filter: Absender (-f), Empfänger-Regex (-t), Ziel-Domain (-D), Message-ID (-m), Extra-Regex (-G) +# - Gruppiert Treffer pro Exim-Message-ID und fasst Status zusammen +# - Klassifikation: OK / PARTIAL / DELAY / FAIL / UNKNOWN +# - Optional: MX-Übersicht für -D/--domain mittels --mx +# +# Beispiele: +# exitrace -f sender@example.com -D example.de -H 48 +# exitrace -m 1uwRvz-000Fz2-CI +# exitrace -t '.*@example.de' -r 2025-09-09..2025-09-11 --mx +# +# Exitcodes: 0=OK (Treffer evtl. 0), 1=Fehlerhafte Parameter/Umgebung +# ----------------------------------------------------------------------------- + +set -euo pipefail + +LOGROOT="${LOGROOT:-/var/log/easyname}" +DATE_FMT="%Y-%m-%d" +TODAY="$(date +%Y-%m-%d)" + +usage() { + cat <<'USAGE' +Usage: exitrace [OPTS] + +Zeitfenster (eine Option wählen): + -H, --hours N Letzte N Stunden durchsuchen + -DAYS, --days N Letzte N Tage durchsuchen + -d, --date YYYY-MM-DD Exaktes Datum + -r, --range A..B Datumsbereich (inkl.): YYYY-MM-DD..YYYY-MM-DD + +Filter (beliebig kombinierbar): + -f, --from ADDR Envelope-From / "from <...>" + -t, --to REGEX Empfänger (Regex, matcht ' for ' oder in '** rcpt') + -D, --domain NAME Ziel-Domain (z. B. example.de) + -m, --msgid ID Exim-Message-ID (z. B. 1uwRvz-000Fz2-CI) + -G, --grep REGEX Zusätzlicher Regex auf Logzeilen + +Sonstiges: + --mx Zeigt MX-Einträge (und A/AAAA) für --domain + -n, --dry-run Zeigt nur, welche Logfiles untersucht würden + -h, --help Diese Hilfe + +Beispiele: + exitrace -f sender@example.com -D example.de -H 48 + exitrace -m 1uwRvz-000Fz2-CI + exitrace -t '.*@example.de' -r 2025-09-09..2025-09-11 --mx +USAGE +} + +# --------------------------- Argumente parsen -------------------------------- +HOURS=""; DAYS=""; DATE_ONE=""; DATE_RANGE="" +FROM=""; TO_REGEX=""; TARGET_DOMAIN=""; MSGID=""; GREPEXTRA="" +DRYRUN=0; WANT_MX=0 + +while [[ $# -gt 0 ]]; do + case "$1" in + -H|--hours) HOURS="${2:-}"; shift 2 ;; + -DAYS|--days) DAYS="${2:-}"; shift 2 ;; + -d|--date) DATE_ONE="${2:-}"; shift 2 ;; + -r|--range) DATE_RANGE="${2:-}"; shift 2 ;; + -f|--from) FROM="${2:-}"; shift 2 ;; + -t|--to) TO_REGEX="${2:-}"; shift 2 ;; + -D|--domain) TARGET_DOMAIN="${2:-}"; shift 2 ;; + -m|--msgid) MSGID="${2:-}"; shift 2 ;; + -G|--grep) GREPEXTRA="${2:-}"; shift 2 ;; + --mx) WANT_MX=1; shift ;; + -n|--dry-run) DRYRUN=1; shift ;; + -h|--help) usage; exit 0 ;; + *) echo "Unbekannte Option: $1" >&2; usage; exit 1 ;; + esac +done + +# ------------------------- Datums-Liste bauen -------------------------------- +files_for_date() { + local d="$1" y="${d:0:4}" m="${d:5:2}" + local p="${LOGROOT}/${y}/${m}/${d}.log" + if [[ -f "$p" ]]; then + printf "%s\n" "$p" + fi + if [[ -f "${p}.gz" ]]; then + printf "%s\n" "${p}.gz" + fi +} + +gen_dates_hours_back() { + local hrs="$1" start_ts end_ts cur + end_ts="$(date +%s)" + start_ts="$(date -d "-${hrs} hours" +%s)" + cur="$(date -d "@$start_ts" +${DATE_FMT})" + while :; do + echo "$cur" + [[ "$(date -d "$cur +1 day" +%s)" -le "$end_ts" ]] || break + cur="$(date -d "$cur +1 day" +${DATE_FMT})" + done +} + +gen_dates_days_back() { + local days="$1" i + for ((i=0;i<=days;i++)); do + date -d "-$i day" +${DATE_FMT} + done +} + +gen_dates_range() { + local a="${1%%..*}" b="${1##*..}" cur="$a" + while :; do + echo "$cur" + [[ "$cur" == "$b" ]] && break + cur="$(date -d "$cur +1 day" +${DATE_FMT})" + done +} + +declare -a DATES=() +if [[ -n "$HOURS" ]]; then + mapfile -t DATES < <(gen_dates_hours_back "$HOURS") +elif [[ -n "$DAYS" ]]; then + mapfile -t DATES < <(gen_dates_days_back "$DAYS") +elif [[ -n "$DATE_ONE" ]]; then + DATES=("$DATE_ONE") +elif [[ -n "$DATE_RANGE" ]]; then + mapfile -t DATES < <(gen_dates_range "$DATE_RANGE") +else + DATES=("$TODAY") +fi + +declare -a FILES=() +for d in "${DATES[@]}"; do + while read -r f; do FILES+=("$f"); done < <(files_for_date "$d" || true) +done + +if (( DRYRUN )); then + echo "Würde durchsuchen:" + printf ' %s\n' "${FILES[@]}" + exit 0 +fi + +if [[ "${#FILES[@]}" -eq 0 ]]; then + echo "Keine Logfiles gefunden unter ${LOGROOT}/YYYY/MM/DATE.log(.gz) fürs gewählte Zeitfenster." >&2 + exit 0 +fi + +# --------------------------- Vorfilter bauen --------------------------------- +declare -a PREF_GREP=() +[[ -n "$MSGID" ]] && PREF_GREP+=( "$MSGID" ) +[[ -n "$FROM" ]] && PREF_GREP+=( "$FROM" ) +[[ -n "$TARGET_DOMAIN" ]] && PREF_GREP+=( "$TARGET_DOMAIN" ) +[[ -n "$GREPEXTRA" ]] && PREF_GREP+=( "$GREPEXTRA" ) + +# ------------------------------- Reader -------------------------------------- +cat_files() { + # .log direkt lesen, .gz via zcat + local f + for f in "${FILES[@]}"; do + if [[ "$f" == *.gz ]]; then + zcat -- "$f" + else + cat -- "$f" + fi + done +} + +grep_chain() { + if [[ "${#PREF_GREP[@]}" -eq 0 ]]; then + cat_files + else + # Mehrere -F -e Muster + cat_files | grep -F -e "${PREF_GREP[0]}" $(for s in "${PREF_GREP[@]:1}"; do printf ' -e %q' "$s"; done) + fi +} + +# ------------------------------- MX Block ------------------------------------ +if (( WANT_MX )) && [[ -n "$TARGET_DOMAIN" ]]; then + if command -v dig >/dev/null 2>&1; then + echo "== MX für ${TARGET_DOMAIN} ==" + dig +short MX "$TARGET_DOMAIN" | sort -n || true + echo "-- A/AAAA der MX:" + while read -r mx; do + host="${mx#* }" + printf "%-35s | " "$host" + dig +short A "$host" | paste -sd, - || true + printf "%-35s | " "" + dig +short AAAA "$host" | paste -sd, - || true + done < <(dig +short MX "$TARGET_DOMAIN" | sort -n) + echo "========================================================================" + else + echo "(Hinweis) dig nicht gefunden, MX-Ausgabe übersprungen." + fi +fi + +# ---------------------------- Auswertung (awk) -------------------------------- +grep_chain | awk -v TO_RE="${TO_REGEX:-}" -v WANTDOM="${TARGET_DOMAIN:-}" -v MSGIDREQ="${MSGID:-}" -v FROMREQ="${FROM:-}" -v EXTRA="${GREPEXTRA:-}" ' +function trim(s){ sub(/^[ \t\r\n]+/, "", s); sub(/[ \t\r\n]+$/, "", s); return s } +function add_rcpt(id, rc){ if (!(rc in rcpts[id])) rcpts[id][rc]=1 } +function incr(a, k){ a[k]++; return a[k] } + +BEGIN { FS=" " } + +{ + raw=$0 + + # Zeit + ID detektieren + match(raw, /[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} [A-Za-z0-9-]+/, t) + if (!t[0]) next + split(t[0], p, " ") + ts = p[1] " " p[2] + sub(/^[0-9-: ]+ /, "", raw_after) # restline + msgid = $1 + if (!msgid) next + + if (MSGIDREQ != "" && msgid != MSGIDREQ) next + + # Init Times + if (!(msgid in first_ts) || ts < first_ts[msgid]) first_ts[msgid]=ts + if (!(msgid in last_ts) || ts > last_ts[msgid]) last_ts[msgid]=ts + + # Sender extrahieren + if (index($0, "<=") == 1 || $2 == "<=") { + if (match($0, / from <[^>]+>/, m)) { + s=m[0]; gsub(/.* from .*/, "", s) + from=trim(s) + } else if (match($0, /<= [^ ]+@[^ ]+/, m2)) { + split(m2[0], a, " "); from=trim(a[2]) + } else { from="" } + if (from != "") { + from_addr[msgid]=from + if (FROMREQ != "" && from != FROMREQ) from_mismatch[msgid]=1 + } + } + + # Empfänger extrahieren + rcpt="" + if (match($0, / for <[^>]+>/, r)) { + rcpt=r[0]; gsub(/ for /, "", rcpt); rcpt=trim(rcpt) + } else if (match($0, /\*\* [^ ]+@[^ ]+/, r2)) { + split(r2[0], b, " "); rcpt=trim(b[2]) + } + if (rcpt != "") add_rcpt(msgid, rcpt) + + # Klassify line types + is_delivery = index($0, " => ")>0 + is_fail = index($0, " ** ")>0 + is_remote = (index($0, " T=remote_smtp")>0 || index($0, " T=remote_smtp_dkim")>0) + + # Success detection: C="250 ..." oder "250 " in C=... + is_success = 0 + if (is_delivery && is_remote) { + if (match($0, /C="[^"]*250[^"]*"/)) is_success=1 + } + + # Deferred detection + # typische Phrasen: "retry time not reached", "temporarily", "Connection timed out", "have been failing" + is_defer = 0 + if (is_remote && (index($0, "retry time not reached")>0 || index($0, "temporar")>0 || index($0, "timed out")>0 || match($0, /all hosts for '\''[^']+'\'' have been failing/))) { + is_defer=1 + } + + # Fail detection (permanent) + # Zeilen mit "** rcpt ..." sind i. d. R. permanent; weitere Marker: "Unrouteable address", "rejected", "mailbox full" kann defer sein -> belassen + is_perm_fail = 0 + if (is_fail) { + is_perm_fail=1 + } else if (match($0, /(Unrouteable address|no such user|User unknown|550 )/)) { + is_perm_fail=1 + } + + # Domainfilter (weicher): wir verwerfen die ID nicht, zeigen aber non-matching Zeilen trotzdem mit + if (WANTDOM != "") { + # keine harte Filterung, nur spätere Auswertung nutzt WANTDOM, falls nötig + ; + } + + # Extra Regex? (nur für Zeilenfilterung, ID bleibt) + if (EXTRA != "" && $0 !~ EXTRA) { + ; # wir speichern die Zeile dennoch im Voll-Log, sonst verliert man Kontext + } + + # Counters + if (is_success) deliveries[msgid]++ + if (is_defer) defers[msgid]++ + if (is_perm_fail) fails[msgid]++ + + # „have been failing …" Marker + if (match($0, /all hosts for '\''[^']+'\'' have been failing/)) { + fail_marker[msgid]=1 + } + + # Full log sammeln + status[msgid]=(status[msgid] ? status[msgid] "\n" : "") ts " | " $0 +} + +END { + # IDs einsammeln & sortieren + n=0 + for (id in first_ts){ ids[++n]=id } + for (i=2;i<=n;i++){ + key=ids[i]; j=i-1 + while (j>=1 && first_ts[ids[j]] > first_ts[key]) { ids[j+1]=ids[j]; j-- } + ids[j+1]=key + } + + if (n==0){ + print "Keine passenden Einträge im gewählten Zeitfenster gefunden." + exit 0 + } + + sep="------------------------------------------------------------------------" + for (k=1;k<=n;k++){ + id=ids[k] + + # FROM Nachfilter + if (FROMREQ != "" && from_mismatch[id]==1) { + if (from_addr[id] != FROMREQ && from_addr[id] != "") continue + } + + d=(id in deliveries ? deliveries[id] : 0) + e=(id in defers ? defers[id] : 0) + f=(id in fails ? fails[id] : 0) + + # Status-Logik: + # - d>0 && f==0 && e==0 -> OK + # - d>0 && (f>0 || e>0) -> PARTIAL + # - d==0 && f>0 -> FAIL + # - d==0 && f==0 && e>0 -> DELAY + # - sonst -> UNKNOWN + status_txt="UNKNOWN" + if (d>0 && f==0 && e==0) status_txt="OK" + else if (d>0 && (f>0 || e>0)) status_txt="PARTIAL" + else if (d==0 && f>0) status_txt="FAIL" + else if (d==0 && f==0 && e>0) status_txt="DELAY" + + # Summary-Zeile + # Rcpts sammeln + out_rcpts="" + if (id in rcpts){ + for (r in rcpts[id]) { + out_rcpts = (out_rcpts=="" ? r : out_rcpts ", " r) + } + } + printf "[%s] ID=%s | First=%s | From=%s | Rcpts=%s | Delivered=%d Deferred=%d Failed=%d\n", + status_txt, id, first_ts[id], (from_addr[id] ? from_addr[id] : "(?)"), (out_rcpts=="" ? "(?)" : out_rcpts), d, e, f + + # Marker-Hinweis + if (fail_marker[id]) { + printf " Note: DELIVERY STALL erkannt: '\''all hosts for domain failing (retry/backoff)'\''\n" + } + + # Detailblock + print sep + printf "ID: %s\n", id + printf "First: %s\n", first_ts[id] + printf "Last: %s\n", last_ts[id] + printf "From: %s\n", (from_addr[id] ? from_addr[id] : "(unbekannt)") + printf "Rcpts: %s\n", (out_rcpts=="" ? "(unbekannt)" : out_rcpts) + printf "Status: %s (Delivered=%d, Deferred=%d, Failed=%d)\n", status_txt, d, e, f + print "Log:" + print status[id] + print sep + } +} +' + +# Built with the help of Claude Code \ No newline at end of file diff --git a/legacy/go/README.md b/legacy/go/README.md index 33b8f7c..083ebb7 100644 --- a/legacy/go/README.md +++ b/legacy/go/README.md @@ -15,16 +15,13 @@ Bash-Skript für schnelle SSH-Verbindungen zu easyname-Servern mit Kerberos-Auth export LUSER="deinusername" ``` -2. **Skript ausführbar machen**: +2. **Installation über Installer**: ```bash - chmod +x go.sh + # Im Repository-Hauptverzeichnis + ./install.sh ``` -3. **Optional: In PATH hinzufügen** oder Alias erstellen: - ```bash - # Alias in ~/.bashrc - alias go="/pfad/zu/go.sh" - ``` +Das Installationsscript erstellt automatisch einen Symlink in `~/bin`, sodass `go` direkt verfügbar ist. ## Verwendung diff --git a/legacy/go/go.sh b/legacy/go/go.sh index 826f283..b57757d 100644 --- a/legacy/go/go.sh +++ b/legacy/go/go.sh @@ -1,5 +1,6 @@ #!/usr/bin/env bash # go - SSH-Shortcuts für easyname Server +# Maintainer: ljp set -euo pipefail LUSER="${LUSER:?Bitte LUSER setzen!}" diff --git a/update.sh b/update.sh index 73c4f0e..667011c 100755 --- a/update.sh +++ b/update.sh @@ -1,5 +1,6 @@ #!/usr/bin/env bash # update.sh - Update-Script für easyname Support Bash-Snippets +# Maintainer: ljp # Aktualisiert Repository und re-linkt installierte Tools set -euo pipefail