fix(backfill): Abdeckung pruefen — "Zeitraum min..max" war irrefuehrend
Der x22-Backfill meldete "Zeitraum: 03.12.2024 .. 14.09.2026" und liest sich damit wie zwei Jahre Historie. Tatsaechlich enthielt die Quelle EINEN einzelnen Punkt vom 03.12.2024 (eine alte Logzeile) und sonst 30 Tage: belegte Stunden: 721 von 15.601 im Zeitraum (4.6 % Abdeckung) groesste Luecke: 620 Tage 03.12.2024 21:00 -> 15.08.2026 22:00 min..max allein sagt nichts ueber die Substanz. Die Selbstpruefung nennt jetzt zusaetzlich die Zahl der belegten Stunden gegen die Spanne, die prozentuale Abdeckung und — bei unter 50 % — die drei groessten Luecken mit Datum, plus den Hinweis auf fehlende/rotierte Logs als typische Ursache. Verifiziert gegen drei Faelle: (A) 1 alter Punkt + 30 Tage -> 4.6 %, Luecke benannt; (B) 15 Tage durchgehend -> 100 %, kein Alarm; (C) 29 Tage mit 20-h- Luecke -> 97.3 %, kein Alarm (echte kleine Luecken sind normal).
This commit is contained in:
1 parent
39e86adfba
commit
33534811cb
1 file changed
+26
-5
@@ -79,11 +79,33 @@ path = sys.argv[1]
|
|||||||
pts = [l.rstrip("\n") for l in open(path) if l and not l.startswith("#") and l.strip()]
|
pts = [l.rstrip("\n") for l in open(path) if l and not l.startswith("#") and l.strip()]
|
||||||
if not pts:
|
if not pts:
|
||||||
print(" FEHLER: keine Datenpunkte"); sys.exit(1)
|
print(" FEHLER: keine Datenpunkte"); sys.exit(1)
|
||||||
ts = sorted(int(l.rsplit(" ", 1)[1]) for l in pts)
|
ts = [int(l.rsplit(" ", 1)[1]) for l in pts]
|
||||||
|
uniq = sorted(set(ts))
|
||||||
now = int(time.time())
|
now = int(time.time())
|
||||||
f = lambda t: time.strftime("%d.%m.%Y %H:%M", time.gmtime(t))
|
f = lambda t: time.strftime("%d.%m.%Y %H:%M", time.gmtime(t))
|
||||||
print(f" Datenpunkte: {len(pts):,}")
|
print(f" Datenpunkte: {len(pts):,}")
|
||||||
print(f" Zeitraum: {f(ts[0])} .. {f(ts[-1])} UTC")
|
print(f" Zeitraum: {f(uniq[0])} .. {f(uniq[-1])} UTC")
|
||||||
|
|
||||||
|
# WICHTIG: min..max allein ist irrefuehrend. Ein EINZELNER Punkt mit altem
|
||||||
|
# Zeitstempel (eine Logzeile von 2024 in einer sonst aktuellen Datei) laesst den
|
||||||
|
# Backfill wie zwei Jahre aussehen, obwohl nur 30 Tage Substanz da sind.
|
||||||
|
# Deshalb die tatsaechlich belegten Stunden nennen und die Abdeckung pruefen.
|
||||||
|
hours = sorted({t - (t % 3600) for t in uniq})
|
||||||
|
span_h = max(1, (hours[-1] - hours[0]) // 3600 + 1)
|
||||||
|
cover = 100.0 * len(hours) / span_h
|
||||||
|
print(f" belegte Stunden: {len(hours):,} von {span_h:,} im Zeitraum ({cover:.1f} % Abdeckung)")
|
||||||
|
if len(hours) < span_h * 0.5:
|
||||||
|
# Die groessten Luecken benennen — das sind meist fehlende/rotierte Logs.
|
||||||
|
gaps = [(hours[i+1] - hours[i], hours[i], hours[i+1]) for i in range(len(hours)-1)]
|
||||||
|
gaps.sort(reverse=True)
|
||||||
|
print(" WARNUNG: die Historie ist lueckenhaft. Groesste Luecken:")
|
||||||
|
for g, a, b in gaps[:3]:
|
||||||
|
if g > 3600:
|
||||||
|
print(f" {g/86400:.0f} Tage {f(a)} -> {f(b)}")
|
||||||
|
print(" Ursache meist: rotierte/alte Logs fehlen auf dem Quellhost.")
|
||||||
|
if len(hours) <= 3:
|
||||||
|
print(" ACHTUNG: nur wenige Stunden — vermutlich einzelne alte Logzeilen,")
|
||||||
|
print(" kein zusammenhaengender Zeitraum. Vor dem Import pruefen.")
|
||||||
|
|
||||||
domains = collections.Counter()
|
domains = collections.Counter()
|
||||||
for l in pts:
|
for l in pts:
|
||||||
@@ -96,21 +118,20 @@ for d, n in domains.most_common(8):
|
|||||||
print(f" {d}: {n} Punkte")
|
print(f" {d}: {n} Punkte")
|
||||||
|
|
||||||
# Einheiten-Wache: alles nach 2100 ist kein Sekundenwert
|
# Einheiten-Wache: alles nach 2100 ist kein Sekundenwert
|
||||||
if ts[-1] > 4102444800:
|
if uniq[-1] > 4102444800:
|
||||||
print(" FEHLER: Zeitstempel nach dem Jahr 2100 -> Millisekunden statt Sekunden")
|
print(" FEHLER: Zeitstempel nach dem Jahr 2100 -> Millisekunden statt Sekunden")
|
||||||
print(" promtool wuerde Bloecke im Jahr 58.660 erzeugen. Abbruch.")
|
print(" promtool wuerde Bloecke im Jahr 58.660 erzeugen. Abbruch.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
print(" Einheit: OK (Sekunden)")
|
print(" Einheit: OK (Sekunden)")
|
||||||
|
|
||||||
# Zukunft: der Fehler, der die Produktion kosten kann
|
# Zukunft: der Fehler, der die Produktion kosten kann
|
||||||
z = [t for t in ts if t > now + 300]
|
z = [t for t in uniq if t > now + 300]
|
||||||
if z:
|
if z:
|
||||||
print(f" FEHLER: {len(z)} Punkte in der ZUKUNFT (max {f(z[-1])}).")
|
print(f" FEHLER: {len(z)} Punkte in der ZUKUNFT (max {f(z[-1])}).")
|
||||||
print(" Ursache: falsche Systemuhr oder Log-Zeitzone. Abbruch.")
|
print(" Ursache: falsche Systemuhr oder Log-Zeitzone. Abbruch.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
print(" Zukunft: OK")
|
print(" Zukunft: OK")
|
||||||
|
|
||||||
# Plausibilitaet: sind die Zahlen aus echten Logs? (nicht alle identisch)
|
|
||||||
if len(domains) < 2:
|
if len(domains) < 2:
|
||||||
print(f" WARNUNG: nur {len(domains)} Domain(s) erkannt — Logs vollstaendig?")
|
print(f" WARNUNG: nur {len(domains)} Domain(s) erkannt — Logs vollstaendig?")
|
||||||
PY
|
PY
|
||||||
|
|||||||
Reference in new issue
Block a user