rust-lang-deprecated / error-chain

Error boilerplate for Rust
Apache License 2.0
729 stars 111 forks source link

Get location information when printing the errors? #223

Open Ploppz opened 6 years ago

Ploppz commented 6 years ago

I have this function to print errors:

pub fn print_err<T>(err: Error) -> T {
    println!("\n === \nError: {}", err);
    for e in err.iter().skip(1) {
        println!("  caused by: {}", e);
    }
    println!(" === \n");

    if let Some(backtrace) = err.backtrace() {
        println!("backtrace: {:?}", backtrace);
    }

    println!(" === \n");
    panic!("Exiting");
}

Example output:

 === 
Error: Key Root: cannot convert from primitive to type Catalog
  caused by: Key Pages: cannot convert from primitive to type PageTree
  caused by: Key Kids: cannot convert from primitive to type Vec < PagesNode >
  caused by: Key Resources: cannot convert from primitive to type Option < Resources >
  caused by: Key XObject: cannot convert from primitive to type Option < BTreeMap < String , XObject > >
  caused by: Cannot follow reference during parsing (most likely /Length of Stream).
 === 

backtrace: stack backtrace:
[...]
   7:     0x564923cef8d0 - pdf::parser::parse_with_lexer
                        at src/parser/mod.rs:47
   8:     0x564923cf6e0a - pdf::parser::parse_object::parse_indirect_object
                        at src/parser/parse_object.rs:22
   9:     0x564923c6a1cb - pdf::backend::Backend::resolve<alloc::vec::Vec<u8>>
                        at /home/ploppz/work/rust/pdf-rs/pdf2/src/backend.rs:82
  10:     0x564923c7d97d - pdf::file::{{impl}}::open::{{closure}}<alloc::vec::Vec<u8>>
                        at /home/ploppz/work/rust/pdf-rs/pdf2/src/file.rs:98
  11:     0x564923c7e32d - pdf::object::{{impl}}::resolve<closure>
                        at /home/ploppz/work/rust/pdf-rs/pdf2/src/object/mod.rs:27
  12:     0x564923cb3f0e - pdf::primitive::{{impl}}::to_stream
                        at src/primitive.rs:244
  13:     0x564923cd1292 - pdf::object::types::{{impl}}::from_primitive
                        at src/object/types.rs:170
  14:     0x564923d23a71 - pdf::object::{{impl}}::from_primitive<pdf::object::types::XObject>
                        at src/object/mod.rs:226
  15:     0x564923d5ccea - pdf::primitive::{{impl}}::from_primitive<alloc::btree::map::BTreeMap<alloc::string::String, pdf::object::types::XObject>>
                        at src/primitive.rs:309
  16:     0x564923cda312 - pdf::object::types::{{impl}}::from_primitive
                        at src/object/types.rs:137
  17:     0x564923d5d6da - pdf::primitive::{{impl}}::from_primitive<pdf::object::types::Resources>
                        at src/primitive.rs:309
  18:     0x564923cd8263 - pdf::object::types::{{impl}}::from_primitive
                        at src/object/types.rs:92
  19:     0x564923cd092c - pdf::object::types::{{impl}}::from_primitive
                        at src/object/types.rs:24
[...]

I would really like if I could just have the information about where the error occurred, per error in the for e in err.iter().skip(1) loop, so that the output could just be e.g.

  caused by: Key Pages: cannot convert from primitive to type PageTree (src/object/types.rs:92
ETC...

Is this possible?

Or any other idea how to make it easier to immediately see the places in my code the error has jumped?

Yamakaky commented 6 years ago

Interesting idea! It's not possible now, but it would definitively be an improvement. Do you want to try a PR?

Ploppz commented 6 years ago

I can certainly give it a try. I looked at the code. My first take: I guess that location information should go into State. Then perhaps this line should include both self.0 and self.1 (the State) in a write! statement, e.g. write!(f, "{}, {}", self.0, self.1.get_location()).

Thoughts? Any better ideas?

Yamakaky commented 6 years ago

You can't just take the top of the backtrace, since it would point to panic or something instead of where you want.

Ploppz commented 6 years ago

Another idea: use std::line!() etc in bail!(), storing the line number, file and function name in the State. Meaning this will only work when you use bail!() to return an error. Thoughts about this?