dkstr commited on
Commit
cffd96a
·
verified ·
1 Parent(s): 46c818d

Fix: eng.update=False before detect; m3.drain.clusters; rarity signal added to BGL axis

Browse files
Files changed (1) hide show
  1. 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+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,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 first."""
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
- nov = 1.0 if tid not in seen else 0.0
245
- seen.add(tid)
 
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
  }