trace-tools
Tracing and diagnostic tools for async, using tokio and tracing.
The crate consists of a few components:
- The
Observetrait - A
tracing::Subscriberimplementation, as well as usefulLayers. - Diagnostic utilities (currently just one, in
Flamegrapher). #[observe]attribute procedural macro.
The Observe trait
This trait provides the ability to wrap futures with an instrumentation span, similar to the tracing_futures::Instrument trait. This span has some default properties that make it easy to register and filter in a subscriber:
trace_span!;
Crucially, this span contains identical fields to those generated internally by tokio for task spawns (when compiled with --cfg tokio_unstable, which means that subscribers can interact with spans generated by Observe in the same way that they can with tokios internal spans.
Subscriber implementation
trace-tools provides a subscriber and two Layers for dealing with spans and events:
- Flamegraph layer: produces a folded stack file detailing instrumented span stacks (either instrumented internally by
tokioor bytrace-tools) that can be used to generate a flamegraph of all observed code. - Logging layer: allows
logrecords to be converted intotracingevents, and recreates full logging functionality (equivalent tofern-logger) within the subscriber itself, since it is impossible to set two loggers/subscribers at once. This means that logging remains consistent whether usingtrace-toolsor not. - Console layer (enabled by the
tokio-consolefeature): builds aconsole_subscriber::ConsoleLayer(from tokio'sconsoleproject) to collect task metrics and broadcast them. With this layer enabled, you can run theconsolebinary and observe all asynchronous tasks in real-time. Note: only spans associated with tasks are observed in this way, not all spans;trace_tools::observespans will not appear.
The subscriber can be initialised through a builder that can either set the global subscriber or return a Layered instance that can be further extended with more Layers.
Setting as the default subscriber:
// `Flamegrapher` handle returned, for building a flamegraph at the end of the run.
let flamegrapher = build
.with_flamegraph_layer
.with_log_layer
.init?
.unwrap;
Returning a Layered struct:
let = build
.with_flamegraph_layer
.with_log_layer
.finish?;
// Extend the subscriber with external layers.
let subscriber = subscriber.with;
// Set the global subscriber.
subscriber.init;
Flamegrapher
Produces a flamegraph using the given folded stack file, using the inferno crate.
let flamegrapher = build
.with_flamegraph_layer
.init?
.unwrap;
// Run some instrumented code...
// ...
// ...
// Programatically create the flamegraph file.
flamegrapher
.with_graph_file?
.write_flamegraph?;
#[observe] attribute
trace-tools provides a simple attribute proc-macro for instrumenting functions and futures with a span that specifies the trace_tools::observe target. The location fields in the span will describe the location of the tagged function or future, and the observed.name field will specify the function name:
use observe;
pub async
This is equivalent to the following:
Observe.await;
This macro can be used with regular, non-async functions too, unlike the Observe trait.
tokio-console feature
The tokio-console feature enables the console layer. Note that this makes use of unstable tokio features in order to work. As such, this also crate must be built with RUSTFLAGS="--cfg tokio_unstable" to use the feature.
Examples
There is an example for each layer in trace-tools/examples. The flamegraph example produces this interactive graph: