linux-kernel-panic-parser 0.1.1

Lossless, architecture-neutral parsing of Linux kernel panic logs
Documentation
  • Coverage
  • 100%
    48 out of 48 items documented1 out of 16 items with examples
  • Size
  • Source code size: 61.2 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 373.0 kB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 3s Average build duration of successful builds.
  • all releases: 3s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • adamflott/linux-kernel-panic-parser
    0 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • adamflott

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 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

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.