# 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.
```rust
use linux_kernel_panic_parser::{parse, LineKind};
let input = "[ 2.125000] Kernel panic - not syncing: fatal exception\n";
let log = parse(input);
assert_eq!(log.panic_messages().collect::<Vec<_>>(), ["fatal exception"]);
assert!(matches!(log.lines()[0].kind(), LineKind::Panic { .. }));
assert_eq!(log.to_string(), input);
assert_eq!(parse(log.to_string()), log);
```
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 through `LogLine::timestamp()` and `LogLine::uptime()`.
- `CPU: … [UID: …] PID: … Comm: …` records, preserving command and trailing
metadata, including command names with spaces.
- Call-trace headings and `symbol+0xoffset/0xsize` frames, 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
```sh
cargo run --example parse -- path/to/panic.log
# Inspect the parsed Rust structure (also works with stdin).
cargo run --example parse -- --debug example-logs/1.log
# Or pipe UTF-8 log text into the example.
cargo test --all-targets
cargo test --doc
cargo clippy --all-targets -- -D warnings
cargo doc --no-deps
```
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.