Skip to content

Commit

Permalink
docs: better docs on async usage; fancy warning formatting, etc (#769)
Browse files Browse the repository at this point in the history
This branch makes the following changes:

 - Add a new section to the `Span::enter` docs that explains why 
   it should be avoided in async code, and suggests alternatives.
 - Add links to the new section elsewhere.
 - Add new formatting for "Notes" and "Warnings" in the documentation,
   by (mis?)using existing styles from the RustDoc stylesheet.
 - Fixed a handful of inaccuracies or outdated statements I noticed
   while making other changes.

Fixes  #667

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
  • Loading branch information
hawkw committed Jun 29, 2020
1 parent 8628f89 commit ef8efaa
Show file tree
Hide file tree
Showing 11 changed files with 448 additions and 107 deletions.
54 changes: 34 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,20 @@ idiomatic `tracing`.)

In order to record trace events, executables have to use a `Subscriber`
implementation compatible with `tracing`. A `Subscriber` implements a way of
collecting trace data, such as by logging it to standard output. [`tracing_subscriber`](https://docs.rs/tracing-subscriber/)'s
[`fmt` module](https://docs.rs/tracing-subscriber/0.2.6/tracing_subscriber/fmt/index.html) provides reasonable defaults.
Additionally, `tracing-subscriber` is able to consume messages emitted by `log`-instrumented libraries and modules.
collecting trace data, such as by logging it to standard output.
[`tracing_subscriber`]'s [`fmt` module][fmt] provides a subscriber for logging
traces with reasonable defaults. Additionally, `tracing-subscriber` is able to
consume messages emitted by `log`-instrumented libraries and modules.

The simplest way to use a subscriber is to call the `set_global_default` function.
To use `tracing-subscriber`, add the following to your `Cargo.toml`:

```toml
[dependencies]
tracing = "0.1"
tracing-subscriber = "0.2"
```

To set a global subscriber for the entire program, use the `set_global_default` function:

```rust
use tracing::{info, Level};
Expand All @@ -57,8 +66,11 @@ fn main() {
// all spans/events with a level higher than TRACE (e.g, debug, info, warn, etc.)
// will be written to stdout.
.with_max_level(Level::TRACE)
// completes the builder and sets the constructed `Subscriber` as the default.
.init();
// completes the builder
.finish();
// and sets the constructed `Subscriber` as the default.
tracing::subscriber::set_global_default(subscriber)
.expect("no global subscriber has been set")

let number_of_yaks = 3;
// this creates a new event, outside of any spans.
Expand All @@ -72,11 +84,9 @@ fn main() {
}
```

```toml
[dependencies]
tracing = "0.1"
tracing-subscriber = "0.2.6"
```
[`tracing-subscriber`]: https://docs.rs/tracing-subscriber/
[fmt]: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/fmt/index.html
[`set_global_default`]: https://docs.rs/tracing/latest/tracing/subscriber/fn.set_global_default.html

This subscriber will be used as the default in all threads for the remainder of the duration
of the program, similar to how loggers work in the `log` crate.
Expand Down Expand Up @@ -186,10 +196,9 @@ conflicts when executables try to set the default later.
### In Asynchronous Code

If you are instrumenting code that make use of
[`std::future::Future`](https://doc.rust-lang.org/stable/std/future/trait.Future.html)
or async/await, be sure to use the
[`tracing-futures`](https://docs.rs/tracing-futures) crate. This is needed
because the following example _will not_ work:
[`std::future::Future`][std-future] or async/await, be sure to use the
[`tracing-futures`] crate. This is needed because the following example _will
not_ work:

```rust
async {
Expand All @@ -202,10 +211,10 @@ The span guard `_s` will not exit until the future generated by the `async` bloc
Since futures and spans can be entered and exited _multiple_ times without them completing,
the span remains entered for as long as the future exists, rather than being entered only when
it is polled, leading to very confusing and incorrect output.
For more details, see [the documentation on closing spans](https://tracing.rs/tracing/span/index.html#closing-spans).
For more details, see [the documentation on closing spans][closing].

There are two ways to instrument asynchronous code. The first is through the
[`Future::instrument`](https://docs.rs/tracing-futures/0.2.1/tracing_futures/trait.Instrument.html#method.instrument) combinator:
[`Future::instrument`] combinator:

```rust
use tracing_futures::Instrument;
Expand All @@ -222,9 +231,7 @@ my_future
`Future::instrument` attaches a span to the future, ensuring that the span's lifetime
is as long as the future's.

The second, and preferred, option is through the
[`#[instrument]`](https://docs.rs/tracing/0.1.11/tracing/attr.instrument.html)
attribute:
The second, and preferred, option is through the [`#[instrument]`] attribute:

```rust
use tracing::{info, instrument};
Expand All @@ -242,6 +249,13 @@ async fn write(stream: &mut TcpStream) -> io::Result<usize> {
Under the hood, the `#[instrument]` macro performs same the explicit span
attachment that `Future::instrument` does.

[std-future]: https://doc.rust-lang.org/stable/std/future/trait.Future.html
[`tracing-futures`]: https://docs.rs/tracing-futures
[closing]: https://docs.rs/tracing/latest/span/index.html#closing-spans
[`Future::instrument`]: https://docs.rs/tracing-futures/latest/tracing_futures/trait.Instrument.html#method.instrument
[`#[instrument]`]: https://docs.rs/tracing/0.1.11/tracing/attr.instrument.html


## Getting Help

First, see if the answer to your question can be found in the API documentation.
Expand Down
53 changes: 43 additions & 10 deletions tracing-core/src/dispatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,16 @@
//! // `my_subscriber` is now the default
//! ```
//!
//! **Note**: the thread-local scoped dispatcher (`with_default`) requires the
//! Rust standard library. `no_std` users should use [`set_global_default`]
//! <div class="information">
//! <div class="tooltip ignore" style="">ⓘ<span class="tooltiptext">Note</span></div>
//! </div>
//! <div class="example-wrap" style="display:inline-block">
//! <pre class="ignore" style="white-space:normal;font:inherit;">
//! <strong>Note</strong>:the thread-local scoped dispatcher <code>with_default</code>
//! requires the Rust standard library. <code>no_std</code> users should use
//! <a href="#fn.set_global_default"><code>set_global_default</code></a>
//! instead.
//! </pre></div>
//!
//! Finally, `tokio` users should note that versions of `tokio` >= 0.1.22
//! support an `experimental-tracing` feature flag. When this flag is enabled,
Expand Down Expand Up @@ -204,8 +211,15 @@ pub struct DefaultGuard(Option<Dispatch>);
/// The default dispatcher is used when creating a new [span] or
/// [`Event`].
///
/// **Note**: This function requires the Rust standard library. `no_std` users
/// should use [`set_global_default`] instead.
/// <div class="information">
/// <div class="tooltip ignore" style="">ⓘ<span class="tooltiptext">Note</span></div>
/// </div>
/// <div class="example-wrap" style="display:inline-block">
/// <pre class="ignore" style="white-space:normal;font:inherit;">
/// <strong>Note</strong>: This function required the Rust standard library.
/// <code>no_std</code> users should use <a href="../fn.set_global_default.html">
/// <code>set_global_default</code></a> instead.
/// </pre></div>
///
/// [span]: ../span/index.html
/// [`Subscriber`]: ../subscriber/trait.Subscriber.html
Expand All @@ -225,8 +239,15 @@ pub fn with_default<T>(dispatcher: &Dispatch, f: impl FnOnce() -> T) -> T {
/// Sets the dispatch as the default dispatch for the duration of the lifetime
/// of the returned DefaultGuard
///
/// **Note**: This function required the Rust standard library. `no_std` users
/// should use [`set_global_default`] instead.
/// <div class="information">
/// <div class="tooltip ignore" style="">ⓘ<span class="tooltiptext">Note</span></div>
/// </div>
/// <div class="example-wrap" style="display:inline-block">
/// <pre class="ignore" style="white-space:normal;font:inherit;">
/// <strong>Note</strong>: This function required the Rust standard library.
/// <code>no_std</code> users should use <a href="../fn.set_global_default.html">
/// <code>set_global_default</code></a> instead.
/// </pre></div>
///
/// [`set_global_default`]: ../fn.set_global_default.html
#[cfg(feature = "std")]
Expand All @@ -246,8 +267,14 @@ pub fn set_default(dispatcher: &Dispatch) -> DefaultGuard {
/// Can only be set once; subsequent attempts to set the global default will fail.
/// Returns `Err` if the global default has already been set.
///
/// Note: Libraries should *NOT* call `set_global_default()`! That will cause conflicts when
/// executables try to set them later.
///
/// <div class="information">
/// <div class="tooltip compile_fail" style="">&#x26a0; &#xfe0f;<span class="tooltiptext">Warning</span></div>
/// </div><div class="example-wrap" style="display:inline-block"><pre class="compile_fail" style="white-space:normal;font:inherit;">
/// <strong>Warning</strong>: In general, libraries should <em>not</em> call
/// <code>set_global_default()</code>! Doing so will cause conflicts when
/// executables that depend on the library try to set the default later.
/// </pre></div>
///
/// [span]: ../span/index.html
/// [`Subscriber`]: ../subscriber/trait.Subscriber.html
Expand Down Expand Up @@ -525,8 +552,14 @@ impl Dispatch {
/// This calls the [`drop_span`] function on the [`Subscriber`] that this
/// `Dispatch` forwards to.
///
/// **Note:** the [`try_close`] function is functionally identical, but
/// returns `true` if the span is now closed.
/// <div class="information">
/// <div class="tooltip compile_fail" style="">&#x26a0; &#xfe0f;<span class="tooltiptext">Warning</span></div>
/// </div>
/// <div class="example-wrap" style="display:inline-block"><pre class="compile_fail" style="white-space:normal;font:inherit;">
/// <strong>Deprecated</strong>: The <a href="#method.try_close"><code>try_close</code></a>
/// method is functionally identical, but returns <code>true</code> if the span is now closed.
/// It should be used instead of this method.
/// </pre>
///
/// [span ID]: ../span/struct.Id.html
/// [`Subscriber`]: ../subscriber/trait.Subscriber.html
Expand Down
37 changes: 30 additions & 7 deletions tracing-core/src/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,15 @@ pub struct Iter {
/// `examples/counters.rs`, which demonstrates a very simple metrics system
/// implemented using `tracing`.
///
/// **Note:** the `record_error` trait method is only available when the Rust
/// standard library is present, as it requires the `std::error::Error` trait.
/// <div class="information">
/// <div class="tooltip ignore" style="">ⓘ<span class="tooltiptext">Note</span></div>
/// </div>
/// <div class="example-wrap" style="display:inline-block">
/// <pre class="ignore" style="white-space:normal;font:inherit;">
/// <strong>Note</strong>: The <code>record_error</code> trait method is only
/// available when the Rust standard library is present, as it requires the `
/// <code>std::error::Error</code> trait.
/// </pre></div>
///
/// [`Value`]: trait.Value.html
/// [recorded]: trait.Value.html#method.record
Expand Down Expand Up @@ -202,8 +209,15 @@ pub trait Visit {

/// Records a type implementing `Error`.
///
/// **Note**: this is only enabled when the Rust standard library is
/// <div class="information">
/// <div class="tooltip ignore" style="">ⓘ<span class="tooltiptext">Note</span></div>
/// </div>
/// <div class="example-wrap" style="display:inline-block">
/// <div class="example-wrap" style="display:inline-block">
/// <pre class="ignore" style="white-space:normal;font:inherit;">
/// <strong>Note</strong>: This is only enabled when the Rust standard library is
/// present.
/// </pre>
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
fn record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static)) {
Expand Down Expand Up @@ -604,11 +618,20 @@ impl FieldSet {

/// Returns `true` if `self` contains the given `field`.
///
/// **Note**: If `field` shares a name with a field in this `FieldSet`, but
/// was created by a `FieldSet` with a different callsite, this `FieldSet`
/// does _not_ contain it. This is so that if two separate span callsites
/// define a field named "foo", the `Field` corresponding to "foo" for each
/// <div class="information">
/// <div class="tooltip ignore" style="">ⓘ<span class="tooltiptext">Note</span></div>
/// </div>
/// <div class="example-wrap" style="display:inline-block">
/// <div class="example-wrap" style="display:inline-block">
/// <pre class="ignore" style="white-space:normal;font:inherit;">
/// <strong>Note</strong>: If <code>field</code> shares a name with a field
/// in this <code>FieldSet</code>, but was created by a <code>FieldSet</code>
/// with a different callsite, this <code>FieldSet</code> does <em>not</em>
/// contain it. This is so that if two separate span callsites define a field
/// named "foo", the <code>Field</code> corresponding to "foo" for each
/// of those callsites are not equivalent.
/// </pre>
/// </div>
pub fn contains(&self, field: &Field) -> bool {
field.callsite() == self.callsite() && field.i <= self.len()
}
Expand Down
15 changes: 11 additions & 4 deletions tracing-core/src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,18 @@ use crate::stdlib::{fmt, str::FromStr};
/// _significantly_ lower than that of creating the actual span. Therefore,
/// filtering is based on metadata, rather than on the constructed span.
///
/// **Note**: Although instances of `Metadata` cannot be compared directly, they
/// provide a method [`id`] which returns an opaque [callsite identifier]
/// which uniquely identifies the callsite where the metadata originated.
/// This can be used for determining if two Metadata correspond to
/// <div class="information">
/// <div class="tooltip ignore" style="">ⓘ<span class="tooltiptext">Note</span></div>
/// </div>
/// <div class="example-wrap" style="display:inline-block">
/// <pre class="ignore" style="white-space:normal;font:inherit;">
/// <strong>Note</strong>: Although instances of <code>Metadata</code> cannot
/// be compared directly, they provide a method <a href="struct.Metadata.html#method.id">
/// <code>id</code></a>, returning an opaque <a href="../callsite/struct.Identifier.html">
/// callsite identifier</a> which uniquely identifies the callsite where the metadata
/// originated. This can be used to determine if two <code>Metadata</code> correspond to
/// the same callsite.
/// </pre></div>
///
/// [span]: ../span/index.html
/// [event]: ../event/index.html
Expand Down
8 changes: 7 additions & 1 deletion tracing-core/src/span.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,13 @@ enum CurrentInner {
impl Id {
/// Constructs a new span ID from the given `u64`.
///
/// **Note**: Span IDs must be greater than zero.
/// <div class="information">
/// <div class="tooltip ignore" style="">ⓘ<span class="tooltiptext">Note</span></div>
/// </div>
/// <div class="example-wrap" style="display:inline-block">
/// <div class="example-wrap" style="display:inline-block">
/// <pre class="ignore" style="white-space:normal;font:inherit;">
/// <strong>Note</strong>: Span IDs must be greater than zero.</pre></div>
///
/// # Panics
/// - If the provided `u64` is 0
Expand Down
Loading

0 comments on commit ef8efaa

Please sign in to comment.