linux-kernel-panic-parser
An owned, lossless Linux kernel panic log parser built with winnow. Uptime uses jiff::SignedDuration, with exact nanosecond arithmetic. Wall-clock prefixes use jiff::Timestamp.
AI was used to write this library, including its implementation, tests, documentation, and examples.
use ;
let input = "[ 2.125000] Kernel panic - not syncing: fatal exception\n";
let log = parse;
assert_eq!;
assert!;
assert_eq!;
assert_eq!;
Accepts &str, String, &String, Box<str>, Cow<str>, Arc<str>, and other
AsRef<str> types. PanicLog also implements FromStr. The result owns its data
and outlives the input. Parsing is infallible: an empty log, an excerpt without a
panic, a truncated line, or an unfamiliar format is valid input. Use has_panic()
when you need to check for a recognized terminal panic marker.
What is extracted
Kernel panic - not syncing:reasons, including markers inside log wrappers.- Leading printk priority prefixes (
<0>) and dmesg uptime ([seconds.fraction]). - Paired
[unix_seconds][seconds.fraction]prefixes, exposing wall time and uptime separately throughLogLine::timestamp()andLogLine::uptime(). CPU: … [UID: …] PID: … Comm: …records, preserving command and trailing metadata, including command names with spaces.- Call-trace headings and
symbol+0xoffset/0xsizeframes, optional[<address>], uncertainty markers, and module/annotation suffixes. - Named faulting symbols such as
RIP: 0010:symbol+0xoffset/0xsize. - Register and page-table entry/value records with arbitrary names and widths, including segment selectors and parenthesized flags.
- Loaded module lists, taint annotations, wrapped continuations, and last unloaded module names.
- Labeled diagnostics (
Oops,BUG,#PF,Tainted,Hardware name,Workqueue,Code,Kernel Offset), preserving their details as text. - Announced reboot delays as
jiff::SignedDuration.
No x86 register list, host architecture detection, or fixed address width is used.
Logs from any Linux architecture are accepted and preserved. Structured
recognition is best effort, rather than a promise to decode every architecture's
crash format. Unknown lines (including architecture-specific register layouts,
unrecognized fault details, kernel versions, and log transport wrappers) remain accessible via
LogLine::as_str() and LogLine::message().
Round-trip contract
For every UTF-8 input, printing preserves every byte, including whitespace,
unknown records, LF/CRLF/CR line endings, and a missing final newline. Parsing
that output produces an equal PanicLog, including its structured fields.
Models expose read-only access to lines so the original text and interpretation
cannot drift apart. This is a parser and lossless printer, not a log editor.
Uptime is elapsed time since boot, not a wall-clock timestamp. Fractions support one to nine digits. Malformed or out-of-range timestamps remain raw text instead of being rounded or rejected. Syslog/journal wall-clock prefixes are not decoded. Non-UTF-8 bytes require an explicit conversion by the caller; a lossy conversion cannot preserve the original bytes.
Example and development
# Inspect the parsed Rust structure (also works with stdin).
# Or pipe UTF-8 log text into the example.
The example prints the exact original log to stdout and panic/frame summaries to
stderr. With --debug, it instead prints the complete parsed structure using
Rust's alternate Debug format ({:#?}), including raw lines and extracted fields,
to stdout. Run with --help for usage.
Tests include synthetic fixtures for multiple architectures, malformed
and incomplete records, string input types, and generated UTF-8 round trips.
The regression suite also uses both real logs in example-logs/, from x86-64
builds 6.12.67-6.12.2.3-amd64-dee77ff0713177fc and
6.12.67-amd64-9efba7083c7. Every nonblank record in those logs
is classified, and both reproduce their original text exactly. Diagnostic
details are retained rather than fully decoded. These fixtures establish tested
coverage for those reports, not every Linux release or architecture.
Licensed under the MIT license.