mirror of
https://github.com/tokio-rs/tracing.git
synced 2026-03-19 06:12:30 +00:00
## Motivation
Currently, the `tracing-subscriber` crate has the `MakeWriter` trait for
customizing the io writer used by `fmt`. This trait is necessary (rather
than simply using a `Write` instance) because the default implementation
performs the IO on the thread where an event was recorded, meaning that
a separate writer needs to be acquired by each thread (either by calling
a function like `io::stdout`, by locking a shared `Write` instance,
etc).
Right now there is a blanket impl for `Fn() -> T where T: Write`. This
works fine with functions like `io::stdout`. However, the _other_ common
case for this trait is locking a shared writer.
Therefore, it makes sense to see an implementation like this:
``` rust
impl<'a, W: io::Write> MakeWriter for Mutex<W>
where
W: io::Write,
{
type Writer = MutexWriter<'a, W>;
fn make_writer(&self) -> Self::Writer {
MutexWriter(self.lock().unwrap())
}
}
pub struct MutexWriter<'a, W>(MutexGuard<'a, W>);
impl<W: io::Write> io::Write for MutexWriter<'_, W> {
// write to the shared writer in the `MutexGuard`...
}
```
Unfortunately, it's impossible to write this. Since `MakeWriter` always
takes an `&self` parameter and returns `Self::Writer`, the generic
parameter is unbounded:
```
Checking tracing-subscriber v0.2.4 (/home/eliza/code/tracing/tracing-subscriber)
error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
--> tracing-subscriber/src/fmt/writer.rs:61:6
|
61 | impl<'a, W: io::Write> MakeWriter for Mutex<W>
| ^^ unconstrained lifetime parameter
error: aborting due to previous error
```
This essentially precludes any `MakeWriter` impl where the writer is
borrowed from the type implementing `MakeWriter`. This is a significant
blow to the usefulness of the trait. For example, it prevented the use
of `MakeWriter` in `tracing-flame` as suggested in
https://github.com/tokio-rs/tracing/pull/631#discussion_r391138233.
## Proposal
This PR changes `MakeWriter` to be generic over a lifetime `'a`:
```rust
pub trait MakeWriter<'a> {
type Writer: io::Write;
fn make_writer(&'a self) -> Self::Writer;
}
```
The `self` parameter is now borrowed for the `&'a` lifetime, so it is
okay to return a writer borrowed from `self`, such as in the `Mutex`
case.
I've also added an impl of `MakeWriter` for `Mutex<T> where T: Writer`.
Unfortunately, this is a breaking change and will need to wait until we
release `tracing-subscriber` 0.3.
Fixes #675.
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Tracing Examples
This directory contains a collection of examples that demonstrate the use of the
tracing ecosystem:
- tracing:
counters: Implements a very simple metrics system to demonstrate how collectors can consume field values as typed data.sloggish: A demoCollectimplementation that mimics the output ofslog-term'sCompactformatter.
- tracing-attributes:
attrs-basic: A simple example of the#[instrument]attribute.attrs-literal-field-names: Demonstrates using literal field names rather than rust tokens..attrs-args: An example implementing a simple recursive calculation of Fibonacci numbers, to demonstrate how the#[instrument]attribute can record function arguments.
- tracing-subscriber:
fmt: Demonstrates the use of thefmtmodule intracing-subscriber, which provides a collector implementation that logs traces to the console.fmt-stderr: Demonstrates overriding the output stream used by thefmtcollector.fmt-custom-field: Demonstrates overriding how thefmtcollector formats fields on spans and events.fmt-custom-event: Demonstrates overriding how thefmtcollector formats events.fmt-multiple-writers.rs: demonstrates howfmt::Subcribercan write to multiple destinations (in this instance, stdout and a file) simultaneously.subscriber-filter: Demonstrates thetracing-subscriber::filtermodule, which provides a subscriber which adds configurable filtering to a collector implementation.tower-load: Demonstrates how dynamically reloadable filters can be used to debug a server under load in production.journald: Demonstrates how to usefmtandjournaldsubscribers to output to both the terminal and the system journal.toggle-subscribers: Demonstrates how subscribers can be wrapped with anOptionallowing them to be dynamically toggled.
- tracing-futures:
spawny-thing: Demonstrates the use of the#[instrument]attribute macro asynchronous functions.tokio-spawny-thing.rs: Similar tospawny-thingy, but with the additional demonstration instrumenting concurrent tasks created withtokio::spawn.futures-proxy-server: Demonstrates the use oftracing-futuresby implementing a simple proxy server, based on this example fromtokio.async_fn: Demonstrates how asynchronous functions can be instrumented.echo: Demonstrates atracing-instrumented variant of Tokio'sechoexample.
- tracing-flame:
infero-flame: Demonstrates the use oftracing-flameto generate a flamegraph from spans.
- tracing-tower:
tower-client: Demonstrates the use oftracing-towerto instrument a simpletowerHTTP/1.1 client.tower-server: Demonstrates the use oftracing-towerto instrument a simpletowerHTTP/1.1 server.
- tracing-serde:
serde-yak-shave: Demonstrates the use oftracing-serdeby implementing a collector that emits trace output as JSON.
- tracing-log:
hyper-echo: Demonstrates howtracing-logcan be used to record unstructured logs from dependencies astracingevents, by instrumenting this example fromhyper, and usingtracing-logto record logs emitted byhyper.
- tracing-opentelemetry:
opentelemetry: Demonstrates howtracing-opentelemetrycan be used to export and visualizetracingspan data.opentelemetry-remote-context: Demonstrates howtracing-opentelemetrycan be used to extract and inject remote context when traces span multiple systems.