A procedural macro for tracing the execution of functions.
Adding #[trace] to the top of any function will insert println! statements at the beginning and the end of that function, notifying you of when that function was entered and exited and printing the argument and return values.
This is useful for quickly debugging whether functions that are supposed to be called are actually called without manually inserting print statements.
Note that this macro requires all arguments to the function and the return value to have types that implement Debug. You can disable the printing of certain arguments if necessary (described below).
Add trace = "*" to your Cargo.toml.
Here is an example you can find in the examples folder. If you've cloned the project, you can run this with cargo run --example example.
extern crate trace;
use trace::trace;
trace::init_depth_var!();
fn main() {
foo(1, 2);
}
#[trace]
fn foo(a: i32, b: i32) {
println!("I'm in foo!");
bar((a, b));
}
#[trace(prefix_enter="[ENTER]", prefix_exit="[EXIT]")]
fn bar((a, b): (i32, i32)) -> i32 {
println!("I'm in bar!");
if a == 1 {
2
} else {
b
}
}Output:
[+] Entering foo(a = 1, b = 2)
I'm in foo!
[ENTER] Entering bar(a = 1, b = 2)
I'm in bar!
[EXIT] Exiting bar = 2
[-] Exiting foo = ()
-
Note the convenience
trace::init_depth_var!()macro which declares and initializes the thread-localDEPTHvariable that is used for indenting the output. Callingtrace::init_depth_var!()is equivalent to writing:use std::cell::Cell; thread_local! { static DEPTH: Cell<usize> = Cell::new(0); }
The only time it can be omitted is when
#[trace]is applied tomods, as described below. -
Warning: due to stabilizing only a part of proc macro functionality in Rust 1.30,
#[trace]can be used onmodonly on nightly, and there is currently no way to use#![trace]as an outer attribute.You can use
#[trace]onmods as well. To apply#[trace]to all functions in the currentmod, put# at the top of the file. When using#[trace]onmods, theDEPTHvariable doesn't need to be defined (it's defined for you automatically). Note that theDEPTHvariable isn't shared betweenmods, so indentation won't be perfect when tracing functions in multiplemods. -
You can also use
#[trace]on entireimpls or individualimplmethods. See theexamplesfolder for more details. -
If you use
#[trace]on amodorimplas well as on a method or function inside one of those structures, then only the outermost#[trace]is used.
Trace takes a few optional arguments, described below:
-
prefix_enter- The prefix of theprintln!statement when a function is entered. Defaults to[+]. -
prefix_exit- The prefix of theprintln!statement when a function is exited. Defaults to[-]. -
enable- When applied to amodorimpl,enabletakes a list of function names to print, not printing any functions that are not part of this list. All functions are enabled by default. When applied to animplmethod or a function,enabletakes a list of arguments to print, not printing any arguments that are not part of the list. All arguments are enabled by default. -
disable- When applied to amodorimpl,disabletakes a list of function names to not print, printing all other functions in themodorimpl. No functions are disabled by default. When applied to animplmethod or a function,disabletakes a list of arguments to not print, printing all other arguments. No arguments are disabled by default. -
pause- When given as an argument to#[trace], execution is paused after each line of tracing output until enter is pressed. This allows you to trace through a program step by step.
Note that enable and disable can not be used together, and doing so will result in an error.
All of these options are covered in the examples folder.