Expand description
A scoped, structured logging and diagnostics system.
§Overview
tracing is a framework for instrumenting Rust programs to collectstructured, event-based diagnostic information.
In asynchronous systems like Tokio, interpreting traditional log messages canoften be quite challenging. Since individual tasks are multiplexed on the samethread, associated events and log lines are intermixed making it difficult totrace the logic flow.tracing expands upon logging-style diagnostics byallowing libraries and applications to record structured events with additionalinformation abouttemporality andcausality — unlike a log message, a spanintracing has a beginning and end time, may be entered and exited by theflow of execution, and may exist within a nested tree of similar spans. Inaddition,tracing spans arestructured, with the ability to record typeddata as well as textual messages.
Thetracing crate provides the APIs necessary for instrumenting librariesand applications to emit trace data.
Compiler support:requiresrustc 1.63+
§Core Concepts
The core oftracing’s API is composed ofspans,events andsubscribers. We’ll cover these in turn.
§Spans
To record the flow of execution through a program,tracing introduces theconcept ofspans. Unlike a log line that represents amoment intime, a span represents aperiod of time with a beginning and an end. When aprogram begins executing in a context or performing a unit of work, itenters that context’s span, and when it stops executing in that context,itexits the span. The span in which a thread is currently executing isreferred to as that thread’scurrent span.
For example:
usetracing::{span, Level};letspan =span!(Level::TRACE,"my_span");// `enter` returns a RAII guard which, when dropped, exits the span. this// indicates that we are in the span for the current lexical scope.let_enter = span.enter();// perform some work in the context of `my_span`...Thespan module’s documentation provides further details on how touse spans.
Warning: In asynchronous code that uses async/await syntax,
Span::entermay produce incorrect traces if the returned dropguard is held across an await point. Seethe method documentation for details.
§Events
AnEvent represents amoment in time. It signifies something thathappened while a trace was being recorded.Events are comparable to the logrecords emitted by unstructured logging code, but unlike a typical log line,anEvent may occur within the context of a span.
For example:
usetracing::{event, span, Level};// records an event outside of any span context:event!(Level::INFO,"something happened");letspan =span!(Level::INFO,"my_span");let_guard = span.enter();// records an event within "my_span".event!(Level::DEBUG,"something happened inside my_span");In general, events should be used to represent points in timewithin aspan — a request returned with a given status code,n new items weretaken from a queue, and so on.
TheEvent struct documentation provides further details on usingevents.
§Subscribers
AsSpans andEvents occur, they are recorded or aggregated byimplementations of theSubscriber trait.Subscribers are notifiedwhen anEvent takes place and when aSpan is entered or exited. Thesenotifications are represented by the followingSubscriber trait methods:
event, called when anEventtakes place,enter, called when execution enters aSpan,exit, called when execution exits aSpan
In addition, subscribers may implement theenabled function tofilterthe notifications they receive based onmetadata describing eachSpanorEvent. If a call toSubscriber::enabled returnsfalse for a givenset of metadata, thatSubscriber willnot be notified about thecorrespondingSpan orEvent. For performance reasons, if no currentlyactive subscribers express interest in a given set of metadata by returningtrue, then the correspondingSpan orEvent will never be constructed.
§Usage
First, add this to yourCargo.toml:
[dependencies]tracing = "0.1"§Recording Spans and Events
Spans and events are recorded using macros.
§Spans
Thespan! macro expands to aSpan struct which is used torecord a span. TheSpan::enter method on that struct records that thespan has been entered, and returns aRAII guard object, which will exitthe span when dropped.
For example:
usetracing::{span, Level};// Construct a new span named "my span" with trace log level.letspan =span!(Level::TRACE,"my span");// Enter the span, returning a guard object.let_enter = span.enter();// Any trace events that occur before the guard is dropped will occur// within the span.// Dropping the guard will exit the span.The#[instrument] attribute provides an easy way toaddtracing spans to functions. A function annotated with#[instrument]will create and enter a span with that function’s name every time thefunction is called, with arguments to that function will be recorded asfields usingfmt::Debug.
For example:
usetracing::{Level, event, instrument};#[instrument]pub fnmy_function(my_arg: usize) {// This event will be recorded inside a span named `my_function` with the // field `my_arg`.event!(Level::INFO,"inside my_function!");// ...}For functions which don’t have built-in tracing support and can’t havethe#[instrument] attribute applied (such as from an external crate),theSpan struct has ain_scope() methodwhich can be used to easily wrap synchronous code in a span.
For example:
usetracing::info_span;letjson =info_span!("json.parse").in_scope(|| serde_json::from_slice(&buf))?;You can find more examples showing how to use this cratehere.
§Events
Events are recorded using theevent! macro:
usetracing::{event, Level};event!(Level::INFO,"something has happened!");§Using the Macros
Thespan! andevent! macros as well as the#[instrument] attributeuse fairly similar syntax, with some exceptions.
§Configuring Attributes
Both macros require aLevel specifying the verbosity of the span orevent. Optionally, the,target andparent span may be overridden. If thetarget and parent span are not overridden, they will default to themodule path where the macro was invoked and the current span (as determinedby the subscriber), respectively.
For example:
span!(target:"app_spans", Level::TRACE,"my span");event!(target:"app_events", Level::INFO,"something has happened!");letspan =span!(Level::TRACE,"my span");event!(parent:&span, Level::INFO,"something has happened!");The span macros also take a string literal after the level, to set the nameof the span (as above). In the case of the event macros, the name of the event canbe overridden (the default isevent file:line) using thename: specifier.
span!(Level::TRACE,"my span");event!(name:"some_info", Level::INFO,"something has happened!");§Recording Fields
Structured fields on spans and events are specified using the syntaxfield_name = field_value. Fields are separated by commas.
// records an event with two fields:// - "answer", with the value 42// - "question", with the value "life, the universe and everything"event!(Level::INFO, answer =42, question ="life, the universe, and everything");As shorthand, local variables may be used as field values without anassignment, similar tostruct initializers. For example:
letuser ="ferris";span!(Level::TRACE,"login", user);// is equivalent to:span!(Level::TRACE,"login", user = user);Field names can include dots, but should not be terminated by them:
letuser ="ferris";letemail ="ferris@rust-lang.org";span!(Level::TRACE,"login", user, user.email = email);Since field names can include dots, fields on local structs can be usedusing the local variable shorthand:
letuser = User { name:"ferris", email:"ferris@rust-lang.org",};// the span will have the fields `user.name = "ferris"` and// `user.email = "ferris@rust-lang.org"`.span!(Level::TRACE,"login", user.name, user.email);Fields with names that are not Rust identifiers, or with names that are Rust reserved words,may be created using quoted string literals. However, this may not be used with the localvariable shorthand.
// records an event with fields whose names are not Rust identifiers// - "guid:x-request-id", containing a `:`, with the value "abcdef"// - "type", which is a reserved word, with the value "request"span!(Level::TRACE,"api","guid:x-request-id"="abcdef","type"="request");Constant expressions can also be used as field names. Constantsmust be enclosed in curly braces ({}) to indicate that thevalueof the constant is to be used as the field name, rather than theconstant’s name. For example:
constRESOURCE_NAME:&str ="foo";// this span will have the field `foo = "some_id"`span!(Level::TRACE,"get", { RESOURCE_NAME } ="some_id");The? sigil is shorthand that specifies a field should be recorded usingitsfmt::Debug implementation:
#[derive(Debug)]structMyStruct { field:&'staticstr,}letmy_struct = MyStruct { field:"Hello world!"};// `my_struct` will be recorded using its `fmt::Debug` implementation.event!(Level::TRACE, greeting =?my_struct);// is equivalent to:event!(Level::TRACE, greeting = tracing::field::debug(&my_struct));The% sigil operates similarly, but indicates that the value should berecorded using itsfmt::Display implementation:
// `my_struct.field` will be recorded using its `fmt::Display` implementation.event!(Level::TRACE, greeting = %my_struct.field);// is equivalent to:event!(Level::TRACE, greeting = tracing::field::display(&my_struct.field));The% and? sigils may also be used with local variable shorthand:
// `my_struct.field` will be recorded using its `fmt::Display` implementation.event!(Level::TRACE, %my_struct.field);Additionally, a span may declare fields with the special valueEmpty,which indicates that that the value for that field does not currently existbut may be recorded later. For example:
usetracing::{trace_span, field};// Create a span with two fields: `greeting`, with the value "hello world", and// `parting`, without a value.letspan =trace_span!("my_span", greeting ="hello world", parting = field::Empty);// ...// Now, record a value for parting as well.span.record("parting",&"goodbye world!");Finally, events may also include human-readable messages, in the form of aformat string and (optional) arguments,after the event’skey-value fields. If a format string and arguments are provided,they will implicitly create a new field namedmessage whose value is theprovided set of format arguments.
For example:
letquestion ="the ultimate question of life, the universe, and everything";letanswer =42;// records an event with the following fields:// - `question.answer` with the value 42,// - `question.tricky` with the value `true`,// - "message", with the value "the answer to the ultimate question of life, the// universe, and everything is 42."event!( Level::DEBUG, question.answer = answer, question.tricky =true,"the answer to {} is {}.", question, answer);Specifying a formatted message in this manner does not allocate by default.
§Shorthand Macros
tracing also offers a number of macros with preset verbosity levels.Thetrace!,debug!,info!,warn!, anderror! behavesimilarly to theevent! macro, but with theLevel argument alreadyspecified, while the correspondingtrace_span!,debug_span!,info_span!,warn_span!, anderror_span! macros are the same,but for thespan! macro.
These are intended both as a shorthand, and for compatibility with thelogcrate (see the next section).
§Forlog Users
Users of thelog crate should note thattracing exposes a set ofmacros for creatingEvents (trace!,debug!,info!,warn!, anderror!) which may be invoked with the same syntax as the similarly-namedmacros from thelog crate. Often, the process of converting a project tousetracing can begin with a simple drop-in replacement.
Let’s consider thelog crate’s yak-shaving example:
usestd::{error::Error, io};usetracing::{debug, error, info, span, warn, Level};// the `#[tracing::instrument]` attribute creates and enters a span// every time the instrumented function is called. The span is named after the// the function or method. Parameters passed to the function are recorded as fields.#[tracing::instrument]pub fnshave(yak: usize) ->Result<(), Box<dynError +'static>> {// this creates an event at the DEBUG level with two fields: // - `excitement`, with the key "excitement" and the value "yay!" // - `message`, with the key "message" and the value "hello! I'm gonna shave a yak." // // unlike other fields, `message`'s shorthand initialization is just the string itself.debug!(excitement ="yay!","hello! I'm gonna shave a yak.");ifyak ==3{warn!("could not locate yak!");// note that this is intended to demonstrate `tracing`'s features, not idiomatic // error handling! in a library or application, you should consider returning // a dedicated `YakError`. libraries like snafu or thiserror make this easy.returnErr(io::Error::new(io::ErrorKind::Other,"shaving yak failed!").into()); }else{debug!("yak shaved successfully"); }Ok(())}pub fnshave_all(yaks: usize) -> usize {// Constructs a new span named "shaving_yaks" at the TRACE level, // and a field whose key is "yaks". This is equivalent to writing: // // let span = span!(Level::TRACE, "shaving_yaks", yaks = yaks); // // local variables (`yaks`) can be used as field values // without an assignment, similar to struct initializers.let_span =span!(Level::TRACE,"shaving_yaks", yaks).entered();info!("shaving yaks");letmutyaks_shaved =0;foryakin1..=yaks {letres = shave(yak);debug!(yak, shaved = res.is_ok());if letErr(referror) = res {// Like spans, events can also use the field initialization shorthand. // In this instance, `yak` is the field being initalized.error!(yak, error = error.as_ref(),"failed to shave yak!"); }else{ yaks_shaved +=1; }debug!(yaks_shaved); } yaks_shaved}§In libraries
Libraries should link only to thetracing crate, and use the providedmacros to record whatever information will be useful to downstreamconsumers.
§In executables
In order to record trace events, executables have to use aSubscriberimplementation compatible withtracing. ASubscriber implements away of collecting trace data, such as by logging it to standard output.
This library does not contain anySubscriber implementations; these areprovided byother crates.
The simplest way to use a subscriber is to call theset_global_defaultfunction:
extern cratetracing;letmy_subscriber = FooSubscriber::new();tracing::subscriber::set_global_default(my_subscriber) .expect("setting tracing default failed");Warning: In general, libraries shouldnot callset_global_default()! Doing so will cause conflicts when executables that depend on the library try to set the default later.This subscriber will be used as the default in all threads for theremainder of the duration of the program, similar to setting the loggerin thelog crate.
In addition, the default subscriber can be set through using thewith_default function. This follows thetokio pattern of usingclosures to represent executing code in a context that is exited at the endof the closure. For example:
letmy_subscriber = FooSubscriber::new();tracing::subscriber::with_default(my_subscriber, || {// Any trace events generated in this closure or by functions it calls // will be collected by `my_subscriber`.})This approach allows trace data to be collected by multiple subscriberswithin different contexts in the program. Note that the override only applies to thecurrently executing thread; other threads will not see the change from with_default.
Any trace events generated outside the context of a subscriber will not be collected.
Once a subscriber has been set, instrumentation points may be added to theexecutable using thetracing crate’s macros.
§log Compatibility
Thelog crate provides a simple, lightweight logging facade for Rust.Whiletracing builds uponlog’s foundation with richer structureddiagnostic data,log’s simplicity and ubiquity make it the “lowest commondenominator” for text-based logging in Rust — a vast majority of Rustlibraries and applications either emit or consumelog records. Therefore,tracing provides multiple forms of interoperability withlog:tracinginstrumentation can emitlog records, and a compatibility layer enablestracingSubscribers to consumelog records astracingEvents.
§Emittinglog Records
This crate provides two feature flags, “log” and “log-always”, which willcausespans andevents to emitlog records. When the “log” feature isenabled, if notracingSubscriber is active, invoking an event macro orcreating a span with fields will emit alog record. This is intendedprimarily for use in libraries which wish to emit diagnostics that can beconsumed by applications usingtracingorlog, without paying theadditional overhead of emitting both forms of diagnostics whentracing isin use.
Enabling the “log-always” feature will causelog records to be emittedeven if atracingSubscriberis set. This is intended to be used inapplications where alogLogger is being used to record a textual log,andtracing is used only to record other forms of diagnostics (such asmetrics, profiling, or distributed tracing data). Unlike the “log” feature,libraries generally shouldnot enable the “log-always” feature, as doingso will prevent applications from being able to opt out of thelog records.
Seehere for more details on this crate’s feature flags.
The generatedlog records’ messages will be a string representation of thespan or event’s fields, and all additional information recorded bylog(target, verbosity level, module path, file, and line number) will also bepopulated. Additionally,log records are also generated when spans areentered, exited, and closed. Since these additional span lifecycle logs havethe potential to be very verbose, and don’t include additional fields, theywill always be emitted at theTrace level, rather than inheriting thelevel of the span that generated them. Furthermore, they are are categorizedunder a separatelog target, “tracing::span” (and its sub-target,“tracing::span::active”, for the logs on entering and exiting a span), whichmay be enabled or disabled separately from otherlog records emitted bytracing.
§Consuminglog Records
Thetracing-log crate provides a compatibility layer whichallows atracingSubscriber to consumelog records as though theyweretracingevents. This allows applications usingtracing to recordthe logs emitted by dependencies usinglog as events within the context ofthe application’s trace tree. Seethat crate’s documentationfor details.
§Related Crates
In addition totracing andtracing-core, thetokio-rs/tracing repositorycontains several additional crates designed to be used with thetracing ecosystem.This includes a collection ofSubscriber implementations, as well as utilityand adapter crates to assist in writingSubscribers and instrumentingapplications.
In particular, the following crates are likely to be of interest:
tracing-futuresprovides a compatibility layer with thefuturescrate, allowing spans to be attached toFutures,Streams, andExecutors.tracing-subscriberprovidesSubscriberimplementations andutilities for working withSubscribers. This includes aFmtSubscriberFmtSubscriberfor logging formatted trace data to stdout, with similarfiltering and formatting to theenv_loggercrate.tracing-logprovides a compatibility layer with thelogcrate,allowing log messages to be recorded astracingEvents within thetrace tree. This is useful when a project usingtracinghavedependencies which uselog. Note that if you’re usingtracing-subscriber’sFmtSubscriber, you don’t need to depend ontracing-logdirectly.tracing-appenderprovides utilities for outputting tracing data,including a file appender and non blocking writer.
Additionally, there are also several third-party crates which are notmaintained by thetokio project. These include:
tracing-timingimplements inter-event timing metrics on top oftracing.It provides a subscriber that records the time elapsed between pairs oftracingevents and generates histograms.tracing-opentelemetryprovides a subscriber for emitting traces toOpenTelemetry-compatible distributed tracing systems.tracing-honeycombProvides a layer that reports traces spanning multiple machines tohoneycomb.io. Backed bytracing-distributed.tracing-distributedProvides a generic implementation of a layer that reports traces spanning multiple machines to some backend.tracing-actix-webprovidestracingintegration for theactix-webweb framework.tracing-actixprovidestracingintegration for theactixactorframework.axum-insightsprovidestracingintegration and Application insights export for theaxumweb framework.tracing-gelfimplements a subscriber for exporting traces in GreylogGELF format.tracing-cozprovides integration with thecoz causal profiler(Linux-only).tracing-bunyan-formatterprovides a layer implementation that reports events and spansinbunyan format, enriched with timing information.tracing-wasmprovides aSubscriber/Layerimplementation that reportsevents and spans via browserconsole.logandUser Timing API (window.performance).tracing-webprovides a layer implementation of level-aware logging of eventsto web browsers’console.*and span events to theUser Timing API (window.performance).tide-tracingprovides atide middleware to trace all incoming requests and responses.test-logtakes care of initializingtracingfor tests, based onenvironment variables with anenv_loggercompatible syntax.tracing-unwrapprovides convenience methods to report failed unwrapsonResultorOptiontypes to aSubscriber.diesel-tracingprovides integration withdieseldatabase connections.tracing-tracyprovides a way to collectTracy profiles in instrumentedapplications.tracing-elastic-apmprovides a layer for reporting traces toElastic APM.tracing-etwprovides a layer for emitting WindowsETW events.tracing-fluent-assertionsprovides a fluent assertions-style testingframework for validating the behavior oftracingspans.sentry-tracingprovides a layer for reporting events and traces toSentry.tracing-forestprovides a subscriber that preserves contextual coherence bygrouping together logs from the same spans during writing.tracing-lokiprovides a layer for shipping logs toGrafana Loki.tracing-logfmtprovides a layer that formats events and spans into the logfmt format.reqwest-tracingprovides a middleware to tracereqwestHTTP requests.tracing-cloudwatchprovides a layer that sends events to AWS CloudWatch Logs.clippy-tracingprovides a tool to add, remove and check fortracing::instrument.json-subscriberprovides a subscriber for emitting JSON logs. The output can be customized much more than withtracing-subscriber’s JSON output.
If you’re the maintainer of atracing ecosystem crate not listed above,please let us know! We’d love to add your project to the list!
Note: Some of these ecosystem crates are currently unreleased and/or in earlier stages of development. They may be less stable thantracingandtracing-core.
§Crate Feature Flags
The following cratefeature flags are available:
A set of features controlling thestatic verbosity level.
log: causes trace instrumentation points to emitlogrecords as wellas trace events, if a defaulttracingsubscriber has not been set. Thisis intended for use in libraries whose users may be using eithertracingorlog.log-always: Emitlogrecords from alltracingspans and events, evenif atracingsubscriber has been set. This should be set only byapplications which intend to collect traces and logs separately; if anadapter is used to convertlogrecords intotracingevents, this willcause duplicate events to occur.attributes: Includes support for the#[instrument]attribute.This is on by default, but does bring in thesyncrate as a dependency,which may add to the compile time of crates that do not already use it.std: Depend on the Rust standard library (enabled by default).no_stdusers may disable this feature withdefault-features = false:[dependencies]tracing = { version = "0.1.38", default-features = false }
Note:tracing'sno_stdsupport requiresliballoc.
§Unstable Features
These feature flags enableunstable features. The public API may break in 0.1.xreleases. To enable these features, the--cfg tracing_unstable must be passed torustc when compiling.
The following unstable feature flags are currently available:
valuable: Enables support for recordingfield values using thevaluablecrate.
§Enabling Unstable Features
The easiest way to set thetracing_unstable cfg is to use theRUSTFLAGSenv variable when runningcargo commands:
RUSTFLAGS="--cfg tracing_unstable" cargo buildAlternatively, the following can be added to the.cargo/config file in aproject to automatically enable the cfg flag for that project:
[build]rustflags = ["--cfg", "tracing_unstable"]§Supported Rust Versions
Tracing is built against the latest stable release. The minimum supportedversion is 1.63. The current Tracing version is not guaranteed to build onRust versions earlier than the minimum supported version.
Tracing follows the same compiler support policies as the rest of the Tokioproject. The current stable Rust compiler and the three most recent minorversions before it will always be supported. For example, if the currentstable compiler version is 1.69, the minimum supported version will not beincreased past 1.66, three minor versions prior. Increasing the minimumsupported compiler version is not considered a semver breaking change aslong as doing so complies with this policy.
Modules§
- dispatcher
- Dispatches trace events to
Subscribers. - event
- Events represent single points in time during the execution of a program.
- field
SpanandEventkey-value data.- instrument
- Attach a span to a
std::future::Future. - level_
filters - Trace verbosity level filtering.
- span
- Spans represent periods of time in which a program was executing in aparticular context.
- subscriber
- Collects and records trace data.
Macros§
- debug
- Constructs an event at the debug level.
- debug_
span - Constructs a span at the debug level.
- enabled
- Checks whether a span or event isenabled based on the providedmetadata.
- error
- Constructs an event at the error level.
- error_
span - Constructs a span at the error level.
- event
- Constructs a new
Event. - event_
enabled - Tests whether an event with the specified level and target would be enabled.
- info
- Constructs an event at the info level.
- info_
span - Constructs a span at the info level.
- span
- Constructs a new span.
- span_
enabled - Tests whether a span with the specified level and target would be enabled.
- trace
- Constructs an event at the trace level.
- trace_
span - Constructs a span at the trace level.
- warn
- Constructs an event at the warn level.
- warn_
span - Constructs a span at the warn level.
Structs§
- Dispatch
Dispatchtrace data to aSubscriber.- Event
Events represent single points in time where something occurred during theexecution of a program.- Level
- Describes the level of verbosity of a span or event.
- Metadata
- Metadata describing aspan orevent.
- Span
- A handle representing a span, with the capability to enter the span if itexists.
Traits§
- Instrument
- Attaches spans to a
std::future::Future. - Subscriber
- Trait representing the functions required to collect trace data.
- Value
- A field value of an erased type.
Attribute Macros§
- instrument
attributes - Instruments a function to create and enter a
tracingspan every timethe function is called.