feat(logs): syslog-tail.sh fuer Docker-Nodes (kein journalctl im Image, /hostfs read-only)
This commit is contained in:
1 parent
e6aa70d5c7
commit
8d331abe8b
1 file changed
+127
@@ -0,0 +1,127 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# syslog-tail.sh — Syslog-Dateien inkrementell als Influx Line Protocol.
|
||||||
|
#
|
||||||
|
# WOFUER: Telegraf laeuft auf imac/kalina/x05 als DOCKER-CONTAINER. Dort gibt es
|
||||||
|
# kein journalctl (Image = Debian ohne systemd) und der Host ist nur read-only
|
||||||
|
# unter /hostfs gemountet. Journal-Logs sind auf diesem Weg nicht erreichbar.
|
||||||
|
# Ersatz: die Syslog-Dateien des Hosts, die im Container lesbar sind
|
||||||
|
# (/hostfs/var/log/syslog, /hostfs/var/log/kern.log) — vorausgesetzt, rsyslog
|
||||||
|
# laeuft auf dem Host (auf imac und kalina der Fall).
|
||||||
|
#
|
||||||
|
# ACHTUNG: Auf PVE gibt es KEIN rsyslog -> dort ist journal-tail.sh der Weg,
|
||||||
|
# nicht dieses Script. Fehlt die Datei, endet der Lauf ohne Ausgabe.
|
||||||
|
#
|
||||||
|
# ZUSTAND: Byte-Offset je Datei in $STATE_DIR/offset-<name>. Beim ersten Lauf
|
||||||
|
# beginnt es am DATEIENDE (keine Altlasten), danach wird nur Neues gelesen.
|
||||||
|
# Rotation: schrumpft die Datei unter den gemerkten Offset, wird neu bei 0
|
||||||
|
# begonnen.
|
||||||
|
#
|
||||||
|
# Telegraf:
|
||||||
|
# [[inputs.exec]]
|
||||||
|
# interval = "30s"
|
||||||
|
# timeout = "25s"
|
||||||
|
# data_format = "influx"
|
||||||
|
# commands = ["/etc/telegraf/syslog-tail.sh"]
|
||||||
|
|
||||||
|
set -u
|
||||||
|
|
||||||
|
FILES="${SYSLOG_FILES:-/hostfs/var/log/syslog /hostfs/var/log/kern.log}"
|
||||||
|
MAX_LINES="${SYSLOG_MAX_LINES:-500}"
|
||||||
|
STATE_DIR="${SYSLOG_STATE_DIR:-/var/lib/telegraf-syslog}"
|
||||||
|
|
||||||
|
mkdir -p "$STATE_DIR" 2>/dev/null || true
|
||||||
|
|
||||||
|
for f in $FILES; do
|
||||||
|
[ -r "$f" ] || continue
|
||||||
|
|
||||||
|
base="$(basename "$f")"
|
||||||
|
off_file="$STATE_DIR/offset-$base"
|
||||||
|
|
||||||
|
# Aktuelle Dateigroesse; Rotation erkennen
|
||||||
|
size="$(stat -c %s "$f" 2>/dev/null || wc -c < "$f" 2>/dev/null || echo 0)"
|
||||||
|
first=0
|
||||||
|
from=0
|
||||||
|
if [ -s "$off_file" ]; then
|
||||||
|
from="$(cat "$off_file" 2>/dev/null || echo 0)"
|
||||||
|
[ "$from" -gt "$size" ] 2>/dev/null && from=0 # Rotation: kleiner geworden
|
||||||
|
else
|
||||||
|
first=1
|
||||||
|
from="$size" # Erstanlauf: nur Neues
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Erstanlauf: Startpunkt SOFORT merken. Sonst springt der naechste Lauf auf 0
|
||||||
|
# und schuettet die komplette Datei aus (Bug in der ersten Fassung).
|
||||||
|
if [ "$first" -eq 1 ]; then
|
||||||
|
printf '%s' "$size" > "$off_file.tmp" 2>/dev/null && mv -f "$off_file.tmp" "$off_file" 2>/dev/null
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ "$from" -ge "$size" ] && continue
|
||||||
|
|
||||||
|
# Ab Offset lesen, maximal MAX_LINES Zeilen
|
||||||
|
tail -c +$((from + 1)) "$f" 2>/dev/null \
|
||||||
|
| head -n "$MAX_LINES" \
|
||||||
|
| awk -v SRC="$base" '
|
||||||
|
# WICHTIG: im Telegraf-Image ist mawk der Standard — der versteht KEINE
|
||||||
|
# Intervall-Regexe ({4}). Positionsbasiert parsen, nie mit {n}.
|
||||||
|
function etag(s) { gsub(/[ ,=]/, "\\\\&", s); return s }
|
||||||
|
function estr(s) { gsub(/\\/, "\\\\", s); gsub(/"/, "\\\"", s); return s }
|
||||||
|
function isdig(s, i, c) {
|
||||||
|
if (length(s) == 0) return 0
|
||||||
|
for (i = 1; i <= length(s); i++) { c = substr(s, i, 1); if (c < "0" || c > "9") return 0 }
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
# "2026-09-13T22:52:10..." -> Sekunden seit Epoche (mktime braucht "Y M D H M S")
|
||||||
|
function ts2epoch(t, y, mo, d, h, mi, se) {
|
||||||
|
if (length(t) < 19) return 0
|
||||||
|
if (substr(t, 5, 1) != "-" || substr(t, 8, 1) != "-" || substr(t, 11, 1) != "T") return 0
|
||||||
|
y = substr(t, 1, 4); mo = substr(t, 6, 2); d = substr(t, 9, 2)
|
||||||
|
h = substr(t, 12, 2); mi = substr(t, 15, 2); se = substr(t, 18, 2)
|
||||||
|
if (!isdig(y) || !isdig(mo) || !isdig(d) || !isdig(h) || !isdig(mi) || !isdig(se)) return 0
|
||||||
|
# mktime ist bei mawk vorhanden; sonst Fallback auf jetzt
|
||||||
|
e = mktime(y " " mo " " d " " h " " mi " " se)
|
||||||
|
return (e > 0) ? e : 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/./ {
|
||||||
|
line = $0
|
||||||
|
host = "unknown"; ident = "syslog"; msg = line; ns = ""; prio = "6"
|
||||||
|
|
||||||
|
# Fuehrendes "zeitstempel host ident: rest" abtrennen — positionsbasiert.
|
||||||
|
if (substr(line, 5, 1) == "-" && substr(line, 8, 1) == "-" && substr(line, 11, 1) == "T") {
|
||||||
|
sp1 = index(line, " ")
|
||||||
|
if (sp1 > 0) {
|
||||||
|
ts = substr(line, 1, sp1 - 1)
|
||||||
|
rest = substr(line, sp1 + 1)
|
||||||
|
sp2 = index(rest, " ")
|
||||||
|
if (sp2 > 0) { host = substr(rest, 1, sp2 - 1); rest = substr(rest, sp2 + 1) }
|
||||||
|
msg = rest
|
||||||
|
# Praefix "ident[pid]: " bzw. "ident: " abtrennen
|
||||||
|
colon = index(msg, ": ")
|
||||||
|
if (colon > 1 && colon <= 64) {
|
||||||
|
head = substr(msg, 1, colon - 1)
|
||||||
|
if (index(head, " ") == 0 && index(head, "=") == 0) {
|
||||||
|
br = index(head, "[")
|
||||||
|
ident = (br > 1) ? substr(head, 1, br - 1) : head
|
||||||
|
msg = substr(msg, colon + 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
e = ts2epoch(ts)
|
||||||
|
if (e > 0) ns = e "000000000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ns == "") ns = sprintf("%.0f000000000", systime())
|
||||||
|
|
||||||
|
# Tag heisst jhost, NICHT host: Telegraf setzt host=<node> als global_tag.
|
||||||
|
printf "journal,source=%s,ident=%s,priority=%s,jhost=%s message=\"%s\" %s\n", \
|
||||||
|
etag(SRC), etag(ident), etag(prio), etag(host), estr(msg), ns
|
||||||
|
}
|
||||||
|
'
|
||||||
|
|
||||||
|
# Neuen Offset merken (Dateigroesse am Ende des Lesens)
|
||||||
|
newsize="$(stat -c %s "$f" 2>/dev/null || echo "$size")"
|
||||||
|
printf '%s' "$newsize" > "$off_file.tmp" 2>/dev/null && mv -f "$off_file.tmp" "$off_file" 2>/dev/null
|
||||||
|
done
|
||||||
|
|
||||||
|
exit 0
|
||||||
Reference in new issue
Block a user