Best practise for error handling?

I've learned from book (and other resources), which suggested that it's better to split a program into a library and a binary which using this library.

So I have the following code:

  1. main.rs
let client = Client::new(address)?;
client.sync_forever()?
  1. lib.rs
struct Client {
    ..
}

impl Client {
    pub fn new(..) {}

    pub fn sync_forever() -> Result<()> {
        // so much logic in the sync forever, let's says that there are 100 lines inside here.
        // and many function call can return a result.
        let file = open(file_name)?;
        // ....
        let conn = connect(address)?;
        // ....
        let file2 = open(file_name2)?;
        // ...
        // interactive with server..
        Ok()
    }
}

What I'm trying to to is delegate the main login to Client::sync_forever, which means that Client::sync_forever do so..so many things, includes:

  1. open the local cache file.
  2. make connection to server.
  3. interactive with server to sync data from server.

The problem is that when sync_forever is very likely to return a Err, which can because of server is down, or file doesn't exists, or something else.

But in the binary, it can just show me that the sync_forever failed. And I don't know which line in the sync_forever cause it returns a Err, and it makes me extremely hard to debug for my code.

In other languages(like python), I have a backtrace, which helps me to identify which line cause the problem, but in here, if I'm using client.sync_forever().unwrap(), the backtrace just stop on this statement, and I'm hardly to know what happened inside client.sync_forever()

I think I'm doing something wrong here, but I don't know how to make it right, would you please give me any advice about this kind of error handling?

Consider using a crate like anyhow for the error type. On nightly compilers it stores a backtrace in the error.

If I just use thiserror in lib code, and anyhow in binary. (as the crate main page suggested)

Does it means that I need to move some code in sync_forever() to main function?

Have you tried running your program with RUST_BACKTRACE=1?

This way:

RUST_BACKTRACE=1 ./my_program

or with cargo:

RUST_BACKTRACE=1 cargo run my_program

A question on StackOverflow that might help

1 Like

Thanks, I think this link is actually what I need