Anyhow Context Error Chains

Enrich errors with anyhow context layers, converting foreign error types into chains that print root causes and section context.

RustResilience

Code

snippet
use anyhow::{anyhow, Context, Result};
use std::fs;
use std::path::Path;

fn load_config(path: &Path) -> Result<String> {
    fs::read_to_string(path)
        .with_context(|| format!("reading config from {}", path.display()))
}

fn parse_port(raw: &str) -> Result<u16> {
    raw.trim()
        .parse::<u16>()
        .context("port must be 1-65535")
        .with_context(|| format!("invalid port field: {raw:?}"))
}

fn bootstrap(path: &Path) -> Result<()> {
    let content = load_config(path)?;

    let port = content
        .lines()
        .find(|l| l.starts_with("port="))
        .and_then(|l| l.split('=').nth(1))
        .ok_or_else(|| anyhow!("config missing required field: port"))?;

    let parsed = parse_port(port)?;
    println!("bootstrap ok, listening on {parsed}");
    Ok(())
}

fn main() {
    let path = Path::new("app.conf");

    match bootstrap(path) {
        Ok(()) => println!("done"),
        Err(err) => {
            // 链式打印:每层 context 依次列出,根因最后
            let mut chain = err.chain();
            println!("error: {}", chain.next().unwrap());
            for cause in chain {
                println!("  caused by: {cause}");
            }
            println!("backtrace available: {}", err.backtrace().status().is_enabled());
        }
    }
}