trackerr 0.1.0

Error tracker library with location capture and context
Documentation
# TrackErr

A Rust error tracking library that captures error propagation with file locations, and optional timestamps, and contextual messages.

## Getting Started

Try the runnable example:
```bash
cargo run --example getting_started
```

Here's a realistic example of using TrackErr to track errors through multiple layers of an application:

```rust
use std::fs;
use std::path::Path;
use trackerr::{ErrorExt, Result, ResultExt};

// Define error types however preferred (using thiserror for convenience)

#[derive(thiserror::Error, Debug)]
pub enum ConfigError {
    #[error("Failed to read config file: {0}")]
    Io(#[from] std::io::Error),
    
    #[error("Invalid config format: missing required field '{0}'")]
    InvalidFormat(String),
}

#[derive(thiserror::Error, Debug)]
pub enum DatabaseError {
    #[error("Connection failed: {0}")]
    Connection(String),
    
    #[error("Query failed: {0}")]
    Query(String),
    
    #[error("Configuration error: {0}")]
    Config(#[from] ConfigError),
}

#[derive(thiserror::Error, Debug)]
pub enum AppError {
    #[error("Database error: {0}")]
    Database(#[from] DatabaseError),
}


fn load_config(path: &Path) -> Result<String, ConfigError> {
    // Convert std::io::Error to ConfigError and track the location
    let content = fs::read_to_string(path)
        .map_err(|e| ConfigError::from(e).track().msg("Reading database config"))?;
    
    // Validate config format
    if !content.contains("host") {
        Err(ConfigError::InvalidFormat("host".into()).track())?
    }
    
    Ok(content)
}

fn connect_database(config_path: &Path) -> Result<(), DatabaseError> {
    // .track() converts between error types and captures the location
    let config = load_config(config_path)
        .track()
        .ts()?;  // Add timestamp to the error frame
    
    if config.trim().is_empty() {
        // Track new errors with .track()
        Err(DatabaseError::Connection("Empty configuration".into()).track())?
    }
    
    Ok(())
}

fn run_app() -> Result<(), AppError> {
    connect_database(Path::new("config.json"))
        .track()
        .msg("Initializing application database")?;
    
    Ok(())
}

fn main() {
    match run_app() {
        Ok(_) => println!("Application started successfully"),
        Err(e) => {
            // Simple display - just the error message
            eprintln!("Error: {}", e);
            
            // Detailed display - full error chain with locations and context
            eprintln!("\nFull error trace:\n{:#}", e);
        }
    }
}
```

Example output when an error occurs:
```
Error: Database error: Configuration error: Failed to read config file: No such file or directory (os error 2)

Full error trace:
Database error: Configuration error: Failed to read config file: No such file or directory (os error 2)
  @ src/main.rs:65:10
    Initializing application database
Configuration error: Failed to read config file: No such file or directory (os error 2)
  @ src/main.rs:50:10
    2026-02-07T10:30:45Z
Failed to read config file: No such file or directory (os error 2)
  @ src/main.rs:37:43
    Reading database config
No such file or directory (os error 2)
  @ UNKNOWN:0:0
```

## API Overview

### ErrorExt Trait

Add `.track()` to any error to capture its location:

```rust
.map_err(|e| e.track())  // Capture location when error occurs
```

### ResultExt Trait

Methods for `Result<T, Error<E>>`:

- **`.track()`** - Propagate error, convert type, and capture location
- **`.ts()`** - Add timestamp to the current frame
- **`.msg(message)`** - Add contextual message to the current frame

```rust
some_result
    .track()               // Convert error type and capture location
    .ts()                  // Add timestamp
    .msg("context info")?; // Add message
```

### Display Formats

- **Normal**: `format!("{}", error)` - Shows only the error message
- **Alternate**: `format!("{:#}", error)` - Shows full error chain with locations, timestamps, and messages

## Error Flow Example

```rust
fn level_3() -> Result<(), IoError> {
    file_operation().track()?  // Frame 1: captured here
}

fn level_2() -> Result<(), ParseError> {
    level_3().track().msg("parsing data")?  // Frame 2: captured here + message
}

fn level_1() -> Result<(), AppError> {
    level_2().track().ts()?  // Frame 3: captured here + timestamp
}
```

When printed with `{:#}`, shows the complete call stack with location tracking.