Skip to main content

parse/
parse.rs

1//! Run with `cargo run --example parse -- path/to/panic.log`.
2//! Add `--debug` to output the parsed Rust structure instead of the original log.
3use linux_kernel_panic_parser::{LineKind, parse};
4use std::{
5    env,
6    error::Error,
7    fs,
8    io::{self, Read},
9};
10
11fn main() -> Result<(), Box<dyn Error>> {
12    let mut debug = false;
13    let mut path = None;
14    let mut positional_only = false;
15    for argument in env::args_os().skip(1) {
16        if !positional_only && argument == "--debug" {
17            debug = true;
18        } else if !positional_only && argument == "--" {
19            positional_only = true;
20        } else if !positional_only && (argument == "--help" || argument == "-h") {
21            println!(
22                "Usage: parse [--debug] [--] [path/to/panic.log]\nReads stdin when no path is supplied.\n--debug prints the parsed Rust structure to stdout."
23            );
24            return Ok(());
25        } else if (!positional_only && argument.to_string_lossy().starts_with('-'))
26            || path.is_some()
27        {
28            return Err(io::Error::new(
29                io::ErrorKind::InvalidInput,
30                "Usage: parse [--debug] [--] [path/to/panic.log]",
31            )
32            .into());
33        } else {
34            path = Some(argument);
35        }
36    }
37    let text = if let Some(path) = path {
38        fs::read_to_string(path)?
39    } else {
40        let mut text = String::new();
41        io::stdin().read_to_string(&mut text)?;
42        text
43    };
44    let log = parse(text);
45    if debug {
46        println!("{log:#?}");
47        return Ok(());
48    }
49    for line in log.lines() {
50        match line.kind() {
51            LineKind::Panic { message } => eprintln!("panic: {message}"),
52            LineKind::Cpu {
53                cpu,
54                uid,
55                pid,
56                details,
57            } => {
58                eprintln!("cpu: {cpu}, uid: {uid:?}, pid: {pid}, {details}");
59                if let Some(time) = line.timestamp() {
60                    eprintln!("wall time: {time}");
61                }
62                if let Some(uptime) = line.uptime() {
63                    eprintln!("uptime: {uptime}");
64                }
65            }
66            LineKind::Symbol {
67                label,
68                segment,
69                frame,
70            } => {
71                eprintln!(
72                    "{label}: segment {segment:?}, {}+{}/{}",
73                    frame.symbol, frame.offset, frame.size
74                );
75            }
76            LineKind::Diagnostic { label, details }
77                if matches!(label.as_str(), "Oops" | "BUG" | "#PF") =>
78            {
79                eprintln!("{label}: {details}");
80            }
81            LineKind::Frame(frame) => {
82                eprintln!("frame: {}+{}/{}", frame.symbol, frame.offset, frame.size)
83            }
84            _ => {}
85        }
86    }
87    // Original log goes to stdout; summaries go to stderr.
88    print!("{log}");
89    Ok(())
90}