Skip to content

Improve README for first time users #825

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 5, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 41 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@ Tokio project, but does _not_ require the `tokio` runtime to be used.

## Usage

(The examples below are borrowed from the `log` crate's yak-shaving
[example](https://docs.rs/log/0.4.10/log/index.html#examples), modified to
idiomatic `tracing`.)

### In Applications

In order to record trace events, executables have to use a `Subscriber`
Expand All @@ -55,23 +51,15 @@ tracing = "0.1"
tracing-subscriber = "0.2"
```

To set a global subscriber for the entire program, use the `set_global_default` function:
Then create and install a `Subscriber`, for example using [`init()`]:

```rust
use tracing::{info, Level};
use tracing::info;
use tracing_subscriber;

fn main() {
// a builder for `FmtSubscriber`.
let subscriber = tracing_subscriber::fmt()
// 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
.finish();
// and sets the constructed `Subscriber` as the default.
tracing::subscriber::set_global_default(subscriber)
.expect("no global subscriber has been set")
// install global subscriber configured based on RUST_LOG envvar.
tracing_subscriber::init()

let number_of_yaks = 3;
// this creates a new event, outside of any spans.
Expand All @@ -85,25 +73,27 @@ fn main() {
}
```

Using `init()` calls [`set_global_default()`] so 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.

[tracing-subscriber-docs]: 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.

In addition, you can locally override the default subscriber. For example:
For more control, a subscriber can be built in stages and not set globally,
but instead used to locally override the default subscriber. For example:

```rust
use tracing::{info, Level};
use tracing_subscriber;

fn main() {
let subscriber = tracing_subscriber::fmt()
// all spans/events with a level higher than TRACE (e.g, debug, info, warn, etc.)
// will be written to stdout.
// filter spans/events with level TRACE or higher.
.with_max_level(Level::TRACE)
// builds the subscriber.
// build but do not install the subscriber.
.finish();

tracing::subscriber::with_default(subscriber, || {
Expand All @@ -122,6 +112,11 @@ currently executing thread; other threads will not see the change from with_defa
Once a subscriber has been set, instrumentation points may be added to the
executable using the `tracing` crate's macros.

[`tracing-subscriber`]: https://docs.rs/tracing-subscriber/
[fmt]: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/fmt/index.html
[`init()`]: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/fmt/fn.init.html
[`set_global_default()`]: https://docs.rs/tracing/latest/tracing/subscriber/fn.set_global_default.html

### In Libraries

Libraries should only rely on the `tracing` crate and use the provided macros
Expand Down Expand Up @@ -191,14 +186,32 @@ pub fn shave_all(yaks: usize) -> usize {
tracing = "0.1"
```

Note: Libraries should *NOT* call `set_global_default()`, as this will cause
conflicts when executables try to set the default later.
Note: Libraries should *NOT* install a subscriber by using a method than calls
[`set_global_default()`], as this will cause conflicts when executables try to
set the default later.

### In Asynchronous Code

If you are instrumenting code that make use of
[`std::future::Future`][std-future] or async/await, be sure to use the
[tracing-futures][tracing-futures-docs] crate. This is needed because the
To trace `async fn`s, the preferred method is using the [`#[instrument]`] attribute:

```rust
use tracing::{info, instrument};
use tokio::{io::AsyncWriteExt, net::TcpStream};
use std::io;

#[instrument]
async fn write(stream: &mut TcpStream) -> io::Result<usize> {
let result = stream.write(b"hello world\n").await;
info!("wrote to stream; success={:?}", result.is_ok());
result
}
```

The [`tracing-futures`] crate must be specified as a dependency to enable
`async` support.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And then maybe put the example with the instrument combinator here as well, before discussing the reasons for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was an awkward join between the examples still. I've reworked the language here but left the motivation in the middle, as it helps understand the combinator (though you can arrive here without really having taken in what a span is yet).

Special handling is needed for the general case of code using
[`std::future::Future`][std-future] or blocks with `async`/`await`, as the
following example _will not_ work:

```rust
Expand All @@ -214,8 +227,7 @@ the span remains entered for as long as the future exists, rather than being ent
it is polled, leading to very confusing and incorrect output.
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`] combinator:
This problem can be solved using the [`Future::instrument`] combinator:

```rust
use tracing_futures::Instrument;
Expand All @@ -232,21 +244,6 @@ 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]`][instrument] attribute:

```rust
use tracing::{info, instrument};
use tokio::{io::AsyncWriteExt, net::TcpStream};
use std::io;

#[instrument]
async fn write(stream: &mut TcpStream) -> io::Result<usize> {
let result = stream.write(b"hello world\n").await;
info!("wrote to stream; success={:?}", result.is_ok());
result
}
```

Under the hood, the `#[instrument]` macro performs same the explicit span
attachment that `Future::instrument` does.

Expand Down