1![Tracing — Structured, application-level diagnostics][splash] 2 3[splash]: https://raw.githubusercontent.com/tokio-rs/tracing/master/assets/splash.svg 4 5# tracing 6 7Application-level tracing for Rust. 8 9[![Crates.io][crates-badge]][crates-url] 10[![Documentation][docs-badge]][docs-url] 11[![Documentation (master)][docs-master-badge]][docs-master-url] 12[![MIT licensed][mit-badge]][mit-url] 13[![Build Status][actions-badge]][actions-url] 14[![Discord chat][discord-badge]][discord-url] 15 16[Documentation][docs-url] | [Chat][discord-url] 17 18[crates-badge]: https://img.shields.io/crates/v/tracing.svg 19[crates-url]: https://crates.io/crates/tracing 20[docs-badge]: https://docs.rs/tracing/badge.svg 21[docs-url]: https://docs.rs/tracing 22[docs-master-badge]: https://img.shields.io/badge/docs-master-blue 23[docs-master-url]: https://tracing-rs.netlify.com/tracing 24[mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg 25[mit-url]: LICENSE 26[actions-badge]: https://github.com/tokio-rs/tracing/workflows/CI/badge.svg 27[actions-url]:https://github.com/tokio-rs/tracing/actions?query=workflow%3ACI 28[discord-badge]: https://img.shields.io/discord/500028886025895936?logo=discord&label=discord&logoColor=white 29[discord-url]: https://discord.gg/EeF3cQw 30 31## Overview 32 33`tracing` is a framework for instrumenting Rust programs to collect 34structured, event-based diagnostic information. 35 36In asynchronous systems like Tokio, interpreting traditional log messages can 37often be quite challenging. Since individual tasks are multiplexed on the same 38thread, associated events and log lines are intermixed making it difficult to 39trace the logic flow. `tracing` expands upon logging-style diagnostics by 40allowing libraries and applications to record structured events with additional 41information about *temporality* and *causality* — unlike a log message, a span 42in `tracing` has a beginning and end time, may be entered and exited by the 43flow of execution, and may exist within a nested tree of similar spans. In 44addition, `tracing` spans are *structured*, with the ability to record typed 45data as well as textual messages. 46 47The `tracing` crate provides the APIs necessary for instrumenting libraries 48and applications to emit trace data. 49 50*Compiler support: [requires `rustc` 1.63+][msrv]* 51 52[msrv]: #supported-rust-versions 53 54## Usage 55 56(The examples below are borrowed from the `log` crate's yak-shaving 57[example](https://docs.rs/log/0.4.10/log/index.html#examples), modified to 58idiomatic `tracing`.) 59 60### In Applications 61 62In order to record trace events, executables have to use a `Subscriber` 63implementation compatible with `tracing`. A `Subscriber` implements a way of 64collecting trace data, such as by logging it to standard output. [`tracing_subscriber`](https://docs.rs/tracing-subscriber/)'s 65[`fmt` module](https://docs.rs/tracing-subscriber/0.3/tracing_subscriber/fmt/index.html) provides reasonable defaults. 66Additionally, `tracing-subscriber` is able to consume messages emitted by `log`-instrumented libraries and modules. 67 68The simplest way to use a subscriber is to call the `set_global_default` function. 69 70```rust 71use tracing::{info, Level}; 72use tracing_subscriber::FmtSubscriber; 73 74fn main() { 75 // a builder for `FmtSubscriber`. 76 let subscriber = FmtSubscriber::builder() 77 // all spans/events with a level higher than TRACE (e.g, debug, info, warn, etc.) 78 // will be written to stdout. 79 .with_max_level(Level::TRACE) 80 // completes the builder. 81 .finish(); 82 83 tracing::subscriber::set_global_default(subscriber) 84 .expect("setting default subscriber failed"); 85 86 let number_of_yaks = 3; 87 // this creates a new event, outside of any spans. 88 info!(number_of_yaks, "preparing to shave yaks"); 89 90 let number_shaved = yak_shave::shave_all(number_of_yaks); 91 info!( 92 all_yaks_shaved = number_shaved == number_of_yaks, 93 "yak shaving completed." 94 ); 95} 96``` 97 98```toml 99[dependencies] 100tracing = "0.1" 101tracing-subscriber = "0.3.0" 102``` 103 104This subscriber will be used as the default in all threads for the remainder of the duration 105of the program, similar to how loggers work in the `log` crate. 106 107In addition, you can locally override the default subscriber. For example: 108 109```rust 110use tracing::{info, Level}; 111use tracing_subscriber::FmtSubscriber; 112 113fn main() { 114 let subscriber = tracing_subscriber::FmtSubscriber::builder() 115 // all spans/events with a level higher than TRACE (e.g, debug, info, warn, etc.) 116 // will be written to stdout. 117 .with_max_level(Level::TRACE) 118 // builds the subscriber. 119 .finish(); 120 121 tracing::subscriber::with_default(subscriber, || { 122 info!("This will be logged to stdout"); 123 }); 124 info!("This will _not_ be logged to stdout"); 125} 126``` 127 128This approach allows trace data to be collected by multiple subscribers 129within different contexts in the program. Note that the override only applies to the 130currently executing thread; other threads will not see the change from with_default. 131 132Any trace events generated outside the context of a subscriber will not be collected. 133 134Once a subscriber has been set, instrumentation points may be added to the 135executable using the `tracing` crate's macros. 136 137### In Libraries 138 139Libraries should only rely on the `tracing` crate and use the provided macros 140and types to collect whatever information might be useful to downstream consumers. 141 142```rust 143use std::{error::Error, io}; 144use tracing::{debug, error, info, span, warn, Level}; 145 146// the `#[tracing::instrument]` attribute creates and enters a span 147// every time the instrumented function is called. The span is named after the 148// the function or method. Parameters passed to the function are recorded as fields. 149#[tracing::instrument] 150pub fn shave(yak: usize) -> Result<(), Box<dyn Error + 'static>> { 151 // this creates an event at the DEBUG level with two fields: 152 // - `excitement`, with the key "excitement" and the value "yay!" 153 // - `message`, with the key "message" and the value "hello! I'm gonna shave a yak." 154 // 155 // unlike other fields, `message`'s shorthand initialization is just the string itself. 156 debug!(excitement = "yay!", "hello! I'm gonna shave a yak."); 157 if yak == 3 { 158 warn!("could not locate yak!"); 159 // note that this is intended to demonstrate `tracing`'s features, not idiomatic 160 // error handling! in a library or application, you should consider returning 161 // a dedicated `YakError`. libraries like snafu or thiserror make this easy. 162 return Err(io::Error::new(io::ErrorKind::Other, "shaving yak failed!").into()); 163 } else { 164 debug!("yak shaved successfully"); 165 } 166 Ok(()) 167} 168 169pub fn shave_all(yaks: usize) -> usize { 170 // Constructs a new span named "shaving_yaks" at the TRACE level, 171 // and a field whose key is "yaks". This is equivalent to writing: 172 // 173 // let span = span!(Level::TRACE, "shaving_yaks", yaks = yaks); 174 // 175 // local variables (`yaks`) can be used as field values 176 // without an assignment, similar to struct initializers. 177 let _span_ = span!(Level::TRACE, "shaving_yaks", yaks).entered(); 178 179 info!("shaving yaks"); 180 181 let mut yaks_shaved = 0; 182 for yak in 1..=yaks { 183 let res = shave(yak); 184 debug!(yak, shaved = res.is_ok()); 185 186 if let Err(ref error) = res { 187 // Like spans, events can also use the field initialization shorthand. 188 // In this instance, `yak` is the field being initialized. 189 error!(yak, error = error.as_ref(), "failed to shave yak!"); 190 } else { 191 yaks_shaved += 1; 192 } 193 debug!(yaks_shaved); 194 } 195 196 yaks_shaved 197} 198``` 199 200```toml 201[dependencies] 202tracing = "0.1" 203``` 204 205Note: Libraries should *NOT* call `set_global_default()`, as this will cause 206conflicts when executables try to set the default later. 207 208### In Asynchronous Code 209 210If you are instrumenting code that make use of 211[`std::future::Future`](https://doc.rust-lang.org/stable/std/future/trait.Future.html) 212or async/await, avoid using the `Span::enter` method. The following example 213_will not_ work: 214 215```rust 216async { 217 let _s = span.enter(); 218 // ... 219} 220``` 221```rust 222async { 223 let _s = tracing::span!(...).entered(); 224 // ... 225} 226``` 227 228The span guard `_s` will not exit until the future generated by the `async` block is complete. 229Since futures and spans can be entered and exited _multiple_ times without them completing, 230the span remains entered for as long as the future exists, rather than being entered only when 231it is polled, leading to very confusing and incorrect output. 232For more details, see [the documentation on closing spans](https://tracing.rs/tracing/span/index.html#closing-spans). 233 234There are two ways to instrument asynchronous code. The first is through the 235[`Future::instrument`](https://docs.rs/tracing/latest/tracing/trait.Instrument.html#method.instrument) combinator: 236 237```rust 238use tracing::Instrument; 239 240let my_future = async { 241 // ... 242}; 243 244my_future 245 .instrument(tracing::info_span!("my_future")) 246 .await 247``` 248 249`Future::instrument` attaches a span to the future, ensuring that the span's lifetime 250is as long as the future's. 251 252The second, and preferred, option is through the 253[`#[instrument]`](https://docs.rs/tracing/0.1.41/tracing/attr.instrument.html) 254attribute: 255 256```rust 257use tracing::{info, instrument}; 258use tokio::{io::AsyncWriteExt, net::TcpStream}; 259use std::io; 260 261#[instrument] 262async fn write(stream: &mut TcpStream) -> io::Result<usize> { 263 let result = stream.write(b"hello world\n").await; 264 info!("wrote to stream; success={:?}", result.is_ok()); 265 result 266} 267``` 268 269Under the hood, the `#[instrument]` macro performs the same explicit span 270attachment that `Future::instrument` does. 271 272### Concepts 273 274This crate provides macros for creating `Span`s and `Event`s, which represent 275periods of time and momentary events within the execution of a program, 276respectively. 277 278As a rule of thumb, _spans_ should be used to represent discrete units of work 279(e.g., a given request's lifetime in a server) or periods of time spent in a 280given context (e.g., time spent interacting with an instance of an external 281system, such as a database). In contrast, _events_ should be used to represent 282points in time within a span — a request returned with a given status code, 283_n_ new items were taken from a queue, and so on. 284 285`Span`s are constructed using the `span!` macro, and then _entered_ 286to indicate that some code takes place within the context of that `Span`: 287 288```rust 289use tracing::{span, Level}; 290 291// Construct a new span named "my span". 292let mut span = span!(Level::INFO, "my span"); 293span.in_scope(|| { 294 // Any trace events in this closure or code called by it will occur within 295 // the span. 296}); 297// Dropping the span will close it, indicating that it has ended. 298``` 299 300The [`#[instrument]`](https://docs.rs/tracing/0.1.41/tracing/attr.instrument.html) attribute macro 301can reduce some of this boilerplate: 302 303```rust 304use tracing::{instrument}; 305 306#[instrument] 307pub fn my_function(my_arg: usize) { 308 // This event will be recorded inside a span named `my_function` with the 309 // field `my_arg`. 310 tracing::info!("inside my_function!"); 311 // ... 312} 313``` 314 315The `Event` type represent an event that occurs instantaneously, and is 316essentially a `Span` that cannot be entered. They are created using the `event!` 317macro: 318 319```rust 320use tracing::{event, Level}; 321 322event!(Level::INFO, "something has happened!"); 323``` 324 325Users of the [`log`] crate should note that `tracing` exposes a set of macros for 326creating `Event`s (`trace!`, `debug!`, `info!`, `warn!`, and `error!`) which may 327be invoked with the same syntax as the similarly-named macros from the `log` 328crate. Often, the process of converting a project to use `tracing` can begin 329with a simple drop-in replacement. 330 331## Supported Rust Versions 332 333Tracing is built against the latest stable release. The minimum supported 334version is 1.42. The current Tracing version is not guaranteed to build on Rust 335versions earlier than the minimum supported version. 336 337Tracing follows the same compiler support policies as the rest of the Tokio 338project. The current stable Rust compiler and the three most recent minor 339versions before it will always be supported. For example, if the current stable 340compiler version is 1.45, the minimum supported version will not be increased 341past 1.42, three minor versions prior. Increasing the minimum supported compiler 342version is not considered a semver breaking change as long as doing so complies 343with this policy. 344 345## Ecosystem 346 347### Related Crates 348 349In addition to `tracing` and `tracing-core`, the [`tokio-rs/tracing`] repository 350contains several additional crates designed to be used with the `tracing` ecosystem. 351This includes a collection of `Subscriber` implementations, as well as utility 352and adapter crates to assist in writing `Subscriber`s and instrumenting 353applications. 354 355In particular, the following crates are likely to be of interest: 356 357- [`tracing-futures`] provides a compatibility layer with the `futures` 358 crate, allowing spans to be attached to `Future`s, `Stream`s, and `Executor`s. 359- [`tracing-subscriber`] provides `Subscriber` implementations and 360 utilities for working with `Subscriber`s. This includes a [`FmtSubscriber`] 361 `FmtSubscriber` for logging formatted trace data to stdout, with similar 362 filtering and formatting to the [`env_logger`] crate. 363- [`tracing-log`] provides a compatibility layer with the [`log`] crate, 364 allowing log messages to be recorded as `tracing` `Event`s within the 365 trace tree. This is useful when a project using `tracing` have 366 dependencies which use `log`. Note that if you're using 367 `tracing-subscriber`'s `FmtSubscriber`, you don't need to depend on 368 `tracing-log` directly. 369 370Additionally, there are also several third-party crates which are not 371maintained by the `tokio` project. These include: 372 373- [`tracing-timing`] implements inter-event timing metrics on top of `tracing`. 374 It provides a subscriber that records the time elapsed between pairs of 375 `tracing` events and generates histograms. 376- [`tracing-opentelemetry`] provides a subscriber for emitting traces to 377 [OpenTelemetry]-compatible distributed tracing systems. 378- [`tracing-honeycomb`] Provides a layer that reports traces spanning multiple machines to [honeycomb.io]. Backed by [`tracing-distributed`]. 379- [`tracing-distributed`] Provides a generic implementation of a layer that reports traces spanning multiple machines to some backend. 380- [`tracing-actix`] provides `tracing` integration for the `actix` actor 381 framework. 382- [`axum-insights`] provides `tracing` integration and Application insights export for the `axum` web framework. 383- [`tracing-gelf`] implements a subscriber for exporting traces in Greylog 384 GELF format. 385- [`tracing-coz`] provides integration with the [coz] causal profiler 386 (Linux-only). 387- [`test-log`] takes care of initializing `tracing` for tests, based on 388 environment variables with an `env_logger` compatible syntax. 389- [`tracing-unwrap`] provides convenience methods to report failed unwraps on `Result` or `Option` types to a `Subscriber`. 390- [`diesel-tracing`] provides integration with [`diesel`] database connections. 391- [`tracing-tracy`] provides a way to collect [Tracy] profiles in instrumented 392 applications. 393- [`tracing-elastic-apm`] provides a layer for reporting traces to [Elastic APM]. 394- [`tracing-etw`] provides a layer for emitting Windows [ETW] events. 395- [`tracing-fluent-assertions`] provides a fluent assertions-style testing 396 framework for validating the behavior of `tracing` spans. 397- [`sentry-tracing`] provides a layer for reporting events and traces to [Sentry]. 398- [`tracing-loki`] provides a layer for shipping logs to [Grafana Loki]. 399- [`tracing-logfmt`] provides a layer that formats events and spans into the logfmt format. 400- [`json-subscriber`] provides a layer for emitting JSON logs. The output can be customized much more than with [`FmtSubscriber`]'s JSON output. 401 402If you're the maintainer of a `tracing` ecosystem crate not listed above, 403please let us know! We'd love to add your project to the list! 404 405[`tracing-timing`]: https://crates.io/crates/tracing-timing 406[`tracing-opentelemetry`]: https://crates.io/crates/tracing-opentelemetry 407[OpenTelemetry]: https://opentelemetry.io/ 408[`tracing-honeycomb`]: https://crates.io/crates/tracing-honeycomb 409[`tracing-distributed`]: https://crates.io/crates/tracing-distributed 410[honeycomb.io]: https://www.honeycomb.io/ 411[`tracing-actix`]: https://crates.io/crates/tracing-actix 412[`axum-insights`]: https://crates.io/crates/axum-insights 413[`tracing-gelf`]: https://crates.io/crates/tracing-gelf 414[`tracing-coz`]: https://crates.io/crates/tracing-coz 415[coz]: https://github.com/plasma-umass/coz 416[`test-log`]: https://crates.io/crates/test-log 417[`tracing-unwrap`]: https://docs.rs/tracing-unwrap 418[`diesel`]: https://crates.io/crates/diesel 419[`diesel-tracing`]: https://crates.io/crates/diesel-tracing 420[`tracing-tracy`]: https://crates.io/crates/tracing-tracy 421[Tracy]: https://github.com/wolfpld/tracy 422[`tracing-elastic-apm`]: https://crates.io/crates/tracing-elastic-apm 423[Elastic APM]: https://www.elastic.co/apm 424[`tracing-etw`]: https://github.com/microsoft/tracing-etw 425[ETW]: https://docs.microsoft.com/en-us/windows/win32/etw/about-event-tracing 426[`tracing-fluent-assertions`]: https://crates.io/crates/tracing-fluent-assertions 427[`sentry-tracing`]: https://crates.io/crates/sentry-tracing 428[Sentry]: https://sentry.io/welcome/ 429[`tracing-loki`]: https://crates.io/crates/tracing-loki 430[Grafana Loki]: https://grafana.com/oss/loki/ 431[`tracing-logfmt`]: https://crates.io/crates/tracing-logfmt 432[`json-subscriber`]: https://crates.io/crates/json-subscriber 433 434**Note:** that some of the ecosystem crates are currently unreleased and 435undergoing active development. They may be less stable than `tracing` and 436`tracing-core`. 437 438[`log`]: https://docs.rs/log/0.4.6/log/ 439[`tokio-rs/tracing`]: https://github.com/tokio-rs/tracing 440[`tracing-futures`]: https://github.com/tokio-rs/tracing/tree/master/tracing-futures 441[`tracing-subscriber`]: https://github.com/tokio-rs/tracing/tree/master/tracing-subscriber 442[`tracing-log`]: https://github.com/tokio-rs/tracing/tree/master/tracing-log 443[`env_logger`]: https://crates.io/crates/env_logger 444[`FmtSubscriber`]: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/fmt/struct.Subscriber.html 445[`examples`]: https://github.com/tokio-rs/tracing/tree/master/examples 446 447## Supported Rust Versions 448 449Tracing is built against the latest stable release. The minimum supported 450version is 1.63. The current Tracing version is not guaranteed to build on Rust 451versions earlier than the minimum supported version. 452 453Tracing follows the same compiler support policies as the rest of the Tokio 454project. The current stable Rust compiler and the three most recent minor 455versions before it will always be supported. For example, if the current stable 456compiler version is 1.69, the minimum supported version will not be increased 457past 1.66, three minor versions prior. Increasing the minimum supported compiler 458version is not considered a semver breaking change as long as doing so complies 459with this policy. 460 461## License 462 463This project is licensed under the [MIT license](LICENSE). 464 465### Contribution 466 467Unless you explicitly state otherwise, any contribution intentionally submitted 468for inclusion in Tokio by you, shall be licensed as MIT, without any additional 469terms or conditions. 470