Spaces:
Configuration error
Configuration error
Fix: eng.update=False before detect; m3.drain.clusters; rarity signal added to BGL axis
Browse files- drain4/eval_temporal.py +15 -8
drain4/eval_temporal.py
CHANGED
|
@@ -14,7 +14,7 @@ Axis 1 — injected anomalies on a real log stream:
|
|
| 14 |
counts only (what naive alerting gets from stock Drain3).
|
| 15 |
|
| 16 |
Axis 2 — real labels (BGL):
|
| 17 |
-
Rank BGL 2k lines by novelty
|
| 18 |
machine-generated alert labels (Label column, "-" = normal).
|
| 19 |
|
| 20 |
Usage: python eval_temporal.py [--skip-zookeeper] [--skip-bgl]
|
|
@@ -36,7 +36,6 @@ from drain4.parser import TemplateMiner
|
|
| 36 |
from drain4.temporal import SpatioTemporalEngine, SUSPICIOUS_PATTERNS, robust_stats
|
| 37 |
|
| 38 |
LOGHUB = "https://raw.githubusercontent.com/logpai/loghub/master/"
|
| 39 |
-
ZOOKEEPER_2K = LOGHUB + "Zookeeper/Zookeeper_2k.log_structured.csv"
|
| 40 |
ZOOKEEPER_PARQUET = (
|
| 41 |
"https://huggingface.co/datasets/bolu61/loghub_2/resolve/refs%2Fconvert%2Fparquet/"
|
| 42 |
"default/partial-test/0000.parquet"
|
|
@@ -66,7 +65,7 @@ def fetch(url: str, timeout: int = 900) -> bytes:
|
|
| 66 |
|
| 67 |
|
| 68 |
def load_zookeeper():
|
| 69 |
-
"""Full Zookeeper stream (ts, content), chronological. HF parquet
|
| 70 |
raw = fetch(ZOOKEEPER_PARQUET, timeout=300)
|
| 71 |
import pandas as pd
|
| 72 |
|
|
@@ -145,6 +144,10 @@ def axis1() -> dict:
|
|
| 145 |
eng.process(ts, tid, template=tmpl, raw=content)
|
| 146 |
eng.record_entropy(tid, content)
|
| 147 |
continue
|
|
|
|
|
|
|
|
|
|
|
|
|
| 148 |
w = wof(ts)
|
| 149 |
if w in (w_silence, w_silence2) and tid == silence_tid:
|
| 150 |
continue # silence: remove the template's lines for these windows
|
|
@@ -210,7 +213,7 @@ def axis1() -> dict:
|
|
| 210 |
res = {
|
| 211 |
"n_lines": len(lines),
|
| 212 |
"n_templates_ours": len(tids),
|
| 213 |
-
"n_templates_drain3": len(m3.clusters),
|
| 214 |
"injected_windows": labels,
|
| 215 |
"ours_observability": metrics(flagged_obs, labels),
|
| 216 |
"ours_security": metrics(flagged_sec, labels),
|
|
@@ -235,14 +238,16 @@ def axis2() -> dict:
|
|
| 235 |
return {"skipped": "no positive labels"}
|
| 236 |
|
| 237 |
miner = TemplateMiner(similarity="lcs")
|
| 238 |
-
novelty_scores, entropy_scores, combined = [], [], []
|
| 239 |
seen: set = set()
|
|
|
|
| 240 |
ent_hist: dict = {}
|
| 241 |
for content in contents:
|
| 242 |
cluster, _ = miner.add_log_message(content)
|
| 243 |
tid = cluster.template_id
|
| 244 |
-
|
| 245 |
-
|
|
|
|
| 246 |
if any(p.search(content) for p in SUSPICIOUS):
|
| 247 |
ent = 1.0
|
| 248 |
else:
|
|
@@ -257,8 +262,9 @@ def axis2() -> dict:
|
|
| 257 |
else:
|
| 258 |
ent_score = 0.0
|
| 259 |
novelty_scores.append(nov)
|
|
|
|
| 260 |
entropy_scores.append(ent_score)
|
| 261 |
-
combined.append(max(nov, ent_score))
|
| 262 |
|
| 263 |
def auc(scores):
|
| 264 |
pairs = sorted(zip(scores, labels), key=lambda x: x[0])
|
|
@@ -283,6 +289,7 @@ def axis2() -> dict:
|
|
| 283 |
"n_lines": len(contents),
|
| 284 |
"n_alert_lines": n_pos,
|
| 285 |
"auc_novelty": round(auc(novelty_scores), 3),
|
|
|
|
| 286 |
"auc_entropy": round(auc(entropy_scores), 3),
|
| 287 |
"auc_combined": round(auc(combined), 3),
|
| 288 |
}
|
|
|
|
| 14 |
counts only (what naive alerting gets from stock Drain3).
|
| 15 |
|
| 16 |
Axis 2 — real labels (BGL):
|
| 17 |
+
Rank BGL 2k lines by novelty/entropy signals; report AUC against the
|
| 18 |
machine-generated alert labels (Label column, "-" = normal).
|
| 19 |
|
| 20 |
Usage: python eval_temporal.py [--skip-zookeeper] [--skip-bgl]
|
|
|
|
| 36 |
from drain4.temporal import SpatioTemporalEngine, SUSPICIOUS_PATTERNS, robust_stats
|
| 37 |
|
| 38 |
LOGHUB = "https://raw.githubusercontent.com/logpai/loghub/master/"
|
|
|
|
| 39 |
ZOOKEEPER_PARQUET = (
|
| 40 |
"https://huggingface.co/datasets/bolu61/loghub_2/resolve/refs%2Fconvert%2Fparquet/"
|
| 41 |
"default/partial-test/0000.parquet"
|
|
|
|
| 65 |
|
| 66 |
|
| 67 |
def load_zookeeper():
|
| 68 |
+
"""Full Zookeeper stream (ts, content), chronological. HF parquet."""
|
| 69 |
raw = fetch(ZOOKEEPER_PARQUET, timeout=300)
|
| 70 |
import pandas as pd
|
| 71 |
|
|
|
|
| 144 |
eng.process(ts, tid, template=tmpl, raw=content)
|
| 145 |
eng.record_entropy(tid, content)
|
| 146 |
continue
|
| 147 |
+
if not eng.update:
|
| 148 |
+
pass
|
| 149 |
+
else:
|
| 150 |
+
eng.update = False # freeze baselines at the split
|
| 151 |
w = wof(ts)
|
| 152 |
if w in (w_silence, w_silence2) and tid == silence_tid:
|
| 153 |
continue # silence: remove the template's lines for these windows
|
|
|
|
| 213 |
res = {
|
| 214 |
"n_lines": len(lines),
|
| 215 |
"n_templates_ours": len(tids),
|
| 216 |
+
"n_templates_drain3": len(m3.drain.clusters),
|
| 217 |
"injected_windows": labels,
|
| 218 |
"ours_observability": metrics(flagged_obs, labels),
|
| 219 |
"ours_security": metrics(flagged_sec, labels),
|
|
|
|
| 238 |
return {"skipped": "no positive labels"}
|
| 239 |
|
| 240 |
miner = TemplateMiner(similarity="lcs")
|
| 241 |
+
novelty_scores, rarity_scores, entropy_scores, combined = [], [], [], []
|
| 242 |
seen: set = set()
|
| 243 |
+
counts: Counter = Counter()
|
| 244 |
ent_hist: dict = {}
|
| 245 |
for content in contents:
|
| 246 |
cluster, _ = miner.add_log_message(content)
|
| 247 |
tid = cluster.template_id
|
| 248 |
+
counts[tid] += 1
|
| 249 |
+
nov = 1.0 if counts[tid] == 1 else 0.0
|
| 250 |
+
rarity = 1.0 / counts[tid] # decays as the template repeats
|
| 251 |
if any(p.search(content) for p in SUSPICIOUS):
|
| 252 |
ent = 1.0
|
| 253 |
else:
|
|
|
|
| 262 |
else:
|
| 263 |
ent_score = 0.0
|
| 264 |
novelty_scores.append(nov)
|
| 265 |
+
rarity_scores.append(rarity)
|
| 266 |
entropy_scores.append(ent_score)
|
| 267 |
+
combined.append(max(nov, rarity, ent_score))
|
| 268 |
|
| 269 |
def auc(scores):
|
| 270 |
pairs = sorted(zip(scores, labels), key=lambda x: x[0])
|
|
|
|
| 289 |
"n_lines": len(contents),
|
| 290 |
"n_alert_lines": n_pos,
|
| 291 |
"auc_novelty": round(auc(novelty_scores), 3),
|
| 292 |
+
"auc_rarity": round(auc(rarity_scores), 3),
|
| 293 |
"auc_entropy": round(auc(entropy_scores), 3),
|
| 294 |
"auc_combined": round(auc(combined), 3),
|
| 295 |
}
|