5.4 KiB
076 — log stream declared columns get contaminated with garbage on non-columnar lines
Summary
Wishlist feedback, verbatim: "The log stream type whitespace-separated
formatting is not working at all. I have a session suited-gyrfalcon
running, please investigate."
Investigated directly against the live suited-gyrfalcon instance
(ottyl sessions → port 62059 → /api/params, /api/logs,
/api/stats; 236,069 ingested log lines, real log stream output).
Root cause confirmed — this is not a gap in header/column detection
(ticket 059's detector itself works correctly on genuine log stream
rows), it's that the declared params it produces get applied far too
broadly once they exist.
What's actually happening: auto_declare_log_stream_params
(engine.rs:472-497) correctly gates declaration on
is_log_stream_line(text) (:484) — so it only fires column
declarations the first time it sees a genuine columnar data row. But
the resulting ParamDeclaration.message_match_regex for each column is
a pure fixed character-offset pattern with no content anchor at all
— e.g. observed live: Activity → ^.{55}(?P<Activity>\S(?:.{0,19}\S)?),
PID → ^.{76}(?P<PID>\S(?:.{0,5}\S)?), Thread →
^.{32}(?P<Thread>\S(?:.{0,9}\S)?) (from log_stream_column_pattern,
logfmt.rs:287-303). Once declared, these are ordinary
ParamDeclarations: the general per-line param-derivation path
(auto_declare_params/extract_param_raw) applies every declared
param's regex to every ingested line, with no re-check that the
line is actually log-stream-shaped — there's no gate equivalent to
is_log_stream_line at derivation time, only at first-declaration time.
Confirmed impact from the live instance:
- Sampling ~1000-line windows at several points across the 236k-line
stream, roughly 1-2% of lines get a garbage
Timestampvalue that isn't a real timestamp — e.g. line 306:"so_gencnt: 4042707 so_state: 0x0"(a continuation line from a wrapped multi-line network-stats dump, no relation to the columnar format at all) gotTimestamp: "so_gencnt: 4042707 so_state: 0x0",Activity/PID/etc sliced from arbitrary character offsets of that unrelated text. Same for bracket/brace-only continuation lines ("}","]") inside pretty-printed dumps. - Even the header line itself (sequence 0,
"Timestamp Thread Type Activity PID TTL") ends up withActivity: "Activity",Thread: "Thread",Timestamp: "Timestamp",Type: "Type"as its own param values — because ticket 052's retroactive re-derivation (engine.rs:540, re-runningauto_declare_paramsover every retained line whenever a new param is declared) re-applies the newly-declared fixed-offset regexes back over already-ingested lines, including the header line, with no exemption for it. - This directly undermines ticket 074's "sorting is broken" complaint
too: sorting by
Timestampmixes ~1-2% garbage string values in among otherwise lexically-sortable ISO timestamps, which would visibly scramble ordering — worth re-checking ticket 074 once this is fixed, the two may partially be the same underlying issue.
This explains "not working at all" better than a full parse failure
would: the common case (genuine columnar rows) parses fine — it's that
the contamination on the ~1-2% of non-columnar lines interleaved
throughout every real log stream capture (multi-line dumps are
common) makes every declared log-stream column look untrustworthy.
Scope
- Make the per-column
message_match_regexself-verifying, not purely positional: either (a) prefix each generated column/message pattern (log_stream_column_pattern/log_stream_message_pattern,logfmt.rs:287-320) with the same shape checkis_log_stream_lineuses so the regex only matches on a genuinely columnar line, or (b) gate the general param-derivation path itself so a param declared viaauto_declare_log_stream_paramsis only evaluated against lines whereis_log_stream_lineholds — (a) is likely simpler since it keeps the gate local to the declaration rather than adding a special case to the generic derivation path. - Fix ticket 052's retroactive re-derivation (
engine.rs:540) to respect that same gate, so the header line (and any other non-columnar retained line) doesn't retroactively pick up columnar param values. - Add a regression test using the real contaminated lines captured
above (continuation lines like
"so_gencnt: ... so_state: ..."and the header line itself) alongside the existinglog_stream_sample.txtfixture — the current fixture and its tests don't include a multi-line-dump continuation line, which is why ticket 059's tests passed despite this.
Acceptance criteria
- Ingesting a
log streamcapture that includes multi-line continuation content (network stat dumps, bracketed/braced pretty-printed blocks) does not populateTimestamp/Thread/Type/Activity/PID/TTLparams on those continuation lines. - The header line itself never ends up with its own column names as values.
- Existing correctly-parsed columnar rows are unaffected.
- A regression test using real captured contamination examples (not just the original fixture) passes.
Depends on
Builds on ticket 059 (commit de9ba6f) and ticket 052's retroactive
re-derivation. Related to ticket 074 (timeline sort) — re-verify that
complaint after this fix lands, since garbage Timestamp values are a
plausible contributor to it.