rootcause-tracing
Tracing span support for the rootcause error reporting library.
Overview
This crate provides automatic tracing span capture for rootcause error reports. When an error occurs, it captures the current tracing span information, helping you understand which operation was being performed when the error occurred.
This is especially useful for:
- Identifying which instrumented function failed
- Debugging errors in async/concurrent code where stack traces are less useful
- Complementing backtraces with high-level operation context
Quick Start
Add to your Cargo.toml:
[]
= "0.11.1"
= "0.11.1"
= "0.1.44"
= "0.3.22"
How it works: rootcause-tracing needs two things:
RootcauseLayer- A tracing layer that quietly captures span field values in the backgroundSpanCollector(optional) - A rootcause hook that automatically attaches captured spans to all rootcause reports
You add RootcauseLayer to your tracing subscriber alongside your existing layers (formatting, filtering, log forwarding, etc.). Each layer operates independently - RootcauseLayer captures span data for error reports while your other layers continue their normal work.
Complete example with automatic span capture:
use Hooks;
use ;
use ;
Output: Errors automatically show span context with field values:
● Failed to process request
├ src/main.rs:45:10
╰ Tracing spans
│ process_request{user_id=42 session="abc-123"}
╰─
Alternative: Manual Span Attachment
If you prefer to attach spans selectively, use the SpanExt trait:
use SpanExt;
let result = operation.attach_span; // Manually attach span to this error
Note: You still need RootcauseLayer in your subscriber setup (see above).
Migrating from tracing_subscriber::fmt::init()
If you currently use tracing_subscriber::fmt::init(), you need to set up your subscriber manually to add RootcauseLayer.
Before:
After:
use RootcauseLayer;
use ;
What changed: Instead of fmt::init() creating a subscriber for you, you create it yourself with Registry::default(). This lets you add multiple layers. Add RootcauseLayer alongside your existing layers (formatting, filtering, etc.).
Nested Spans
With nested instrumented functions, each error captures the full span hierarchy from the active span to the root:
● Request failed
├ Tracing spans
│ │ handle_request{request_id="abc"}
│ ╰─
│
● Auth check failed
├ Tracing spans
│ │ check_auth{user_id=42}
│ │ handle_request{request_id="abc"}
│ ╰─
│
● Database error
╰ Tracing spans
│ query_db{query="SELECT..."}
│ check_auth{user_id=42}
│ handle_request{request_id="abc"}
╰─
Spans are ordered innermost to outermost. See examples/tracing_spans.rs for a complete example.
Configuration
Environment Variables
Control tracing span capture behavior at runtime:
ROOTCAUSE_TRACING- Comma-separated options:leafs- Only capture tracing spans for leaf errors (errors without children)
Example:
# Only capture tracing spans for leaf errors
ROOTCAUSE_TRACING=leafs
Programmatic Configuration
Customize when tracing spans are captured:
use Hooks;
use SpanCollector;
let collector = SpanCollector ;
new
.report_creation_hook
.install
.expect;
Comparison with Backtraces
rootcause-backtrace and rootcause-tracing serve complementary purposes:
| Feature | rootcause-backtrace | rootcause-tracing |
|---|---|---|
| What it captures | Stack frames / function calls | Tracing spans / logical operations |
| Best for | Understanding call paths | Understanding business logic flow |
| Information type | Technical: file:line, function names | Semantic: operation names, contextual metadata |
| Overhead | Moderate (symbol resolution) | Low (span metadata already exists) |
For maximum debugging power, use both together!
Requirements
RootcauseLayermust be added to your tracing subscriber- A tracing subscriber must be configured (e.g.,
tracing-subscriber::Registry) - Spans must be entered for context to be captured (use
#[tracing::instrument]or manual span entry)