nom-tracer
nom-tracer is a powerful and flexible tracing utility for the nom parser combinator library. It allows you to easily trace the execution of your parsers, providing invaluable insights for debugging and optimization.
Features
- 🔍 Trace parser execution with minimal code changes
- 🚀 Near-zero overhead when disabled - compile out all tracing code in release builds
- 🎨 Colorized output for easy reading (optional)
- 🏷️ Support for multiple trace tags to organize parser traces
- 📊 Hierarchical view of parser execution
- 🔧 Configurable via Cargo features
Performance
One of the key advantages of nom-tracer is its minimal performance impact:
- When disabled: The tracing code is completely compiled out, resulting in virtually zero overhead. Your parsers will run at full speed in production builds.
- When enabled: The tracing functionality is designed to be as lightweight as possible, allowing for detailed insights with minimal performance cost during development and debugging.
Quick Start
Add nom-tracer to your Cargo.toml:
[]
= "0.1.0"
Then, wrap your parsers with the tr function:
use tr;
use tag;
let result = parse_hello;
println!;
println!;
For production builds, you can disable all tracing features to ensure zero overhead:
[]
= { = "0.1.0", = false }
Advanced Usage
nom-tracer provides several functions for more advanced tracing scenarios. Here's an overview of the main tracing functions:
tr_ctx: Tracing with Context
This function wraps a parser with tracing, using the default tag and providing a context string. The context is useful for adding more detailed information about the parser's purpose or role.
Example:
use tr_ctx;
tr_tag: Tracing with Custom Tags
This function allows you to specify a custom tag for the trace, which is useful for organizing traces into different categories or groups.
Example:
use tr_tag;
tr_tag_ctx: Tracing with Custom Tags and Context
This is the most flexible tracing function, allowing you to specify both a custom tag and an optional context.
Example:
use tr_tag_ctx;
Using Multiple Tags
You can use different tags to organize your traces into separate groups:
use ;
// Later, you can retrieve traces for specific tags:
let name_traces = get_trace_for_tag;
let number_traces = get_trace_for_tag;
Context Information
When using the trace-context feature, you can add context information to your parsers. This is especially useful for error reporting and debugging complex parsers.
The context is included in the trace output and, when the trace-context feature is enabled, it's also added to error messages, making it easier to pinpoint where and why a parser failed.
Cargo Features
trace: Enable tracing (default)trace-color: Enable colorized outputtrace-print: Print trace events in real-time (unbuffered)trace-context: Add context information to error messages
To enable a feature, add it to your Cargo.toml:
[]
= { = "0.1.0", = ["trace-color", "trace-context"] }
For production builds, you can disable all tracing features to ensure zero overhead:
[]
= { = "0.1.0", = false }
Trace
The trace feature is the core functionality of nom-tracer. When enabled, it allows you to wrap your parsers with tracing functions that record the execution flow of your parsing operations.
To use the trace feature, add it to your Cargo.toml:
[]
= { = "0.1.0", = ["trace"] }
Benefits of trace:
- Debugging: Easily identify where and why your parsers fail.
- Performance Analysis: Understand the execution path of your parsers to optimize them.
- Documentation: The trace output can serve as a form of dynamic documentation of your parser's behavior.
Example usage:
use tr;
use tag;
use IResult;
let result = parse_hello;
println!;
When you run this code, you'll get a trace output showing the execution of your parser:
parse_hello("hello world")
parse_hello -> Ok("hello")
The trace feature is enabled by default. If you want to disable it in production builds for zero overhead, you can use:
[]
= { = "0.1.0", = false }
This will compile out all tracing code, ensuring your parsers run at full speed in production.
Trace Color
The trace-color feature enhances the readability of your trace output by adding color coding. This is particularly useful when dealing with complex parsers or large trace outputs.
To use the trace-color feature, add it to your Cargo.toml:
[]
= { = "0.1.0", = ["trace-color"] }
Benefits of trace-color:
- Improved Readability: Different colors for different types of events make it easier to scan and understand the trace output.
- Quick Identification: Easily spot successes, errors, and other important events in your trace.
- Hierarchy Visualization: Indentation and colors help visualize the hierarchical structure of your parsers.
Example usage:
use tr;
use tuple;
use ;
use IResult;
let result = parse_alpha_num;
println!;
When you run this code with trace-color enabled, you'll get a colorized output similar to:
alpha_num("abc123xyz")
| alpha("abc123xyz")
| alpha -> Ok("abc")
| digit("123xyz")
| digit -> Ok("123")
alpha_num -> Ok(("abc", "123"))
In the actual output, different colors will be used for:
- Parser names (e.g., "alpha_num", "alpha", "digit")
- Input strings
- Successful results (in green)
- Errors (in red)
- Incomplete results (in yellow)
Note that the colors may not display correctly in all terminals or when redirecting output to a file. In such cases, you might want to disable this feature.
Trace Context
The trace-context feature allows you to add contextual information to your parsers. This context is included in the trace output and, more importantly, in error messages. This feature is particularly useful for complex parsers where you need more information about where and why a parsing operation failed.
To use the trace-context feature, add it to your Cargo.toml:
[]
= { = "0.1.0", = ["trace-context"] }
Benefits of trace-context:
- Rich Error Messages: Errors include the context of where they occurred, making debugging easier.
- Improved Trace Output: Trace events include the context, providing more detailed information about the parser's execution.
- Self-Documenting Code: The context can serve as inline documentation of your parser's structure and purpose.
Example usage:
use tr_ctx;
use tag;
use IResult;
use ;
type VerboseResult<I, O> = ;
let result = parse_greeting;
println!;
println!;
When you run this code, if there's an error, you'll get a more informative error message:
Result: Err(Error(VerboseError { errors: [("Hi, world!", Nom(Tag)), ("Hi, world!", Context("Parsing a formal greeting"))] }))
Trace:
parse_greeting[Parsing a formal greeting]("Hi, world!")
parse_greeting -> Error(VerboseError { errors: [("Hi, world!", Nom(Tag)), ("Hi, world!", Context("Parsing a formal greeting"))] })
In this example, the error message includes both the specific parsing error (failed to match the tag "Hello, ") and the context ("Parsing a formal greeting"). This additional information can be invaluable when debugging complex parsers.
The trace-context feature works best when combined with nom's VerboseError type, which can accumulate multiple error contexts. However, it will also work with other error types, adding the context information where possible.
Real-time Tracing with trace-print
The trace-print feature is particularly useful for debugging complex parsers, especially those that might cause stack overflows. When enabled, this feature prints trace events to the console in real-time, without buffering.
To use trace-print, add it to your Cargo.toml:
[]
= { = "0.1.0", = ["trace-print"] }
Benefits of trace-print:
- Immediate Feedback: See trace events as they happen, helping you pinpoint where issues occur.
- Stack Overflow Debugging: If your parser is causing a stack overflow, you'll see the trace up to the point of the overflow, which can be crucial for identifying the problem.
- Performance Insights: Observe in real-time how your parser progresses through the input, which can help identify performance bottlenecks.
Example usage:
use tr;
use many1;
use alpha1;
// This will print trace events in real-time
let result = parse_many_alpha;
When running this code with the trace-print feature enabled, you'll see trace events printed to the console as the parser executes, even if it encounters an issue like a stack overflow.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the Apache License, Version 2.0 - see the LICENSE file for details.