Skip to content
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

feat(lib): Move from log to tracing in a backwards-compatible way #2204

Merged
merged 7 commits into from
Jul 7, 2020
Merged

feat(lib): Move from log to tracing in a backwards-compatible way #2204

merged 7 commits into from
Jul 7, 2020

Conversation

davidbarsky
Copy link
Contributor

I've moved Hyper from log to tracing. Existing log-based users shouldn't notice a difference, but tracing users will see higher performance when filtering data. This isn't the end of the tracing integration that can happen in Hyper (e.g., Hyper can start using spans, typed fields, etc.), but something is better than nothing. I'd rather address those points, including examples, in followups.

I've attached a screenshot of the hello example working, but the logged information is pulled from tracing, not log.

Screen Shot 2020-05-16 at 1 23 19 PM

@@ -29,7 +29,7 @@ http-body = "0.3.1"
httparse = "1.0"
h2 = "0.2.2"
itoa = "0.4.1"
log = "0.4"
tracing = { version = "0.1", default-features = false, features = ["log", "std"] }
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be good to expose the log feature optionally (though it should default to on so we don't break existing code that expects log records emitted by Hyper), so that tracing users who don't need log can disable it. Otherwise, depending on Hyper will always enable the log feature, even when users don't need it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

hmm, solid point. will fix.

Copy link
Member

Choose a reason for hiding this comment

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

Something to consider, though, is that if the logging enabled becomes an optional feature, then those who have default-features = false will have the logs disabled when they upgrade.

(I find cargo's default-features to be annoying in this regard, but what we gonna do.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Darn, that's an annoying thing. Are you okay with breaking those people in a minor release? Or more generally, how should this be handled?

Cargo.toml Outdated
@@ -70,6 +71,10 @@ tcp = [
"tokio/tcp",
"tokio/time",
]
log = [
"tracing/log",
"tracing/std"
Copy link
Contributor

Choose a reason for hiding this comment

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

i suspect that tracing/std can always be on, but i don't actually think hyper needs any of the functionality behind that feature, so we really don't care if it's enabled or not

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it might be off is default-features is set to false; I suspect that pulling in syn + quote via instrument might be a bigger issue for hyper. In either case, I don't care too much.

@seanmonstar
Copy link
Member

As an update, I'm personally fine with proceeding here, as long as we don't break people who already have default-features = false. We can't make it so a a simple cargo update means their logs suddenly disappear.

Is having the tracing/log feature required on a deal breaker (at least until the next breaking release)?

@hawkw
Copy link
Contributor

hawkw commented Jul 6, 2020

Is having the tracing/log feature required on a deal breaker (at least until the next breaking release)?

In my book, it's totally fine to always the tracing/log feature, now that it no longer breaks the build if the tracing import is renamed (we fixed the macro issue that caused this in tokio-rs/tracing#740).

As long as Hyper doesn't also enable the tracing/log-always feature, the logs will still be disabled by default for users who have set a tracing subscriber, so they won't have to pay the performance cost of filtering out duplicate log records. When no subscriber has been set, the log records will still be emitted normally. And, users who are using both tracing and log and want to emit both can enable tracing/log-always.

The only added cost of the tracing/log feature now is that the log crate will always be compiled in, but it's widespread enough that I think it's probably pretty hard to avoid. In the future, it would be nice if users could opt out of it entirely if they are using tracing exclusively, but I don't think that's a dealbreaker.

@davidbarsky
Copy link
Contributor Author

Personally, it’s not a dealbreaker. Most users of tracing already have log somewhere in their dependency graph.

@davidbarsky
Copy link
Contributor Author

davidbarsky commented Jul 7, 2020

I've rebased and explicitly opted-in into log in tracing. I've also opted into the std feature to enable recording errors as values, but still set default-values = false to avoid pulling in syn if its unneeded.

EDIT: I think that pulling in syn via tracing-attributes is okay because pin-project is already pulling in syn.

Cargo.toml Outdated Show resolved Hide resolved
Cargo.toml Outdated Show resolved Hide resolved
Cargo.toml Outdated Show resolved Hide resolved
Cargo.toml Outdated Show resolved Hide resolved
@seanmonstar
Copy link
Member

Let me just confirm here, this is the dependency line that should be merged?

tracing = { version = "0.1", default-features = false, features = ["log", "std"] }

The default-features should be disabled, and std should be enabled?

@davidbarsky
Copy link
Contributor Author

The default-features should be disabled, and std should be enabled?

Yup! Conversation I had with Eliza:

endsofthreads: just to be clear on hyper: `default-features = false, features = ["std", "log"]`, right
mycoliza: should work

Sorry about the back and forth!

@seanmonstar seanmonstar merged commit 9832aef into hyperium:master Jul 7, 2020
@seanmonstar
Copy link
Member

Thanks David!

@davidbarsky davidbarsky deleted the davidbarsky/add-tracing-to-hyper branch July 7, 2020 01:43
@hawkw
Copy link
Contributor

hawkw commented Jul 7, 2020

Yay! 🙌

hawkw added a commit to tokio-rs/tokio that referenced this pull request Jul 13, 2020
## Motivation

When debugging asynchronous systems, it can be very valuable to inspect
what tasks are currently active (see #2510). The [`tracing` crate] and
related libraries provide an interface for Rust libraries and
applications to emit and consume structured, contextual, and async-aware
diagnostic information. Because this diagnostic information is
structured and machine-readable, it is a better fit for the
task-tracking use case than textual logging — `tracing` spans can be
consumed to generate metrics ranging from a simple counter of active
tasks to histograms of poll durations, idle durations, and total task
lifetimes. This information is potentially valuable to both Tokio users
*and* to maintainers.

Additionally, `tracing` is maintained by the Tokio project and is
becoming widely adopted by other libraries in the "Tokio stack", such as
[`hyper`], [`h2`], and [`tonic`] and in [other] [parts] of the broader Rust
ecosystem. Therefore, it is suitable for use in Tokio itself.

[`tracing` crate]: https://github.com/tokio-rs/tracing
[`hyper`]: hyperium/hyper#2204
[`h2`]: hyperium/h2#475
[`tonic`]: https://github.com/hyperium/tonic/blob/570c606397e47406ec148fe1763586e87a8f5298/tonic/Cargo.toml#L48
[other]: rust-lang/chalk#525
[parts]: rust-lang/compiler-team#331

## Solution

This PR is an MVP for instrumenting Tokio with `tracing` spans. When the
"tracing" optional dependency is enabled, every spawned future will be
instrumented with a `tracing` span.

The generated spans are at the `TRACE` verbosity level, and have the
target "tokio::task", which may be used by consumers to filter whether
they should be recorded. They include fields for the type name of the
spawned future and for what kind of task the span corresponds to (a
standard `spawn`ed task, a local task spawned by `spawn_local`, or a
`blocking` task spawned by `spawn_blocking`). Because `tracing` has
separate concepts of "opening/closing" and "entering/exiting" a span, we
enter these spans every time the spawned task is polled. This allows
collecting data such as:

 - the total lifetime of the task from `spawn` to `drop`
 - the number of times the task was polled before it completed
 - the duration of each individual time that the span was polled (and
   therefore, aggregated metrics like histograms or averages of poll
   durations)
 - the total time a span was actively being polled, and the total time
   it was alive but **not** being polled
 - the time between when the task was `spawn`ed and the first poll

As an example, here is the output of a version of the `chat` example
instrumented with `tracing`:
![image](https://user-images.githubusercontent.com/2796466/87231927-e50f6900-c36f-11ea-8a90-6da9b93b9601.png)
And, with multiple connections actually sending messages:
![trace_example_1](https://user-images.githubusercontent.com/2796466/87231876-8d70fd80-c36f-11ea-91f1-0ad1a5b3112f.png)


I haven't added any `tracing` spans in the example, only converted the
existing `println!`s to `tracing::info` and `tracing::error` for
consistency. The span durations in the above output are generated by
`tracing-subscriber`. Of course, a Tokio-specific subscriber could
generate even more detailed statistics, but that's follow-up work once
basic tracing support has been added.

Note that the `Instrumented` type from `tracing-futures`, which attaches
a `tracing` span to a future, was reimplemented inside of Tokio to avoid
a dependency on that crate. `tracing-futures` has a feature flag that
enables an optional dependency on Tokio, and I believe that if another
crate in a dependency graph enables that feature while Tokio's `tracing`
support is also enabled, it would create a circular dependency that
Cargo wouldn't be able to handle. Also, it avoids a dependency for a
very small amount of code that is unlikely to ever change.

There is, of course, room for plenty of future work here. This might 
include:

 - instrumenting other parts of `tokio`, such as I/O resources and 
   channels (possibly via waker instrumentation)
 - instrumenting the threadpool so that the state of worker threads
   can be inspected
 - writing `tracing-subscriber` `Layer`s to collect and display
   Tokio-specific data from these traces
 - using `track_caller` (when it's stable) to record _where_ a task 
   was `spawn`ed from

However, this is intended as an MVP to get us started on that path.

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
BenxiangGe pushed a commit to BenxiangGe/hyper that referenced this pull request Jul 26, 2021
…hyperium#2204)

I've moved Hyper from `log` to `tracing`. Existing `log`-based users shouldn't notice a difference, but `tracing` users will see higher performance when filtering data. This isn't the _end_  of the `tracing` integration that can happen in `Hyper` (e.g., Hyper can start using spans, typed fields, etc.), but _something_ is better than nothing. I'd rather address those points, including examples, in followups.

I've attached a screenshot of the `hello` example working, but the logged information is pulled from `tracing`, not `log`.

<img width="514" alt="Screen Shot 2020-05-16 at 1 23 19 PM" src="https://user-images.githubusercontent.com/2067774/82126298-d8103800-9779-11ea-8f0b-57c632c684d6.png">
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants