Files
Eliza Weisman b1baa6c2ef subscriber: add lifetime parameter to MakeWriter (#781)
## 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>
2020-11-21 10:42:25 -08:00
..

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 demo Collect implementation that mimics the output of slog-term's Compact formatter.
  • 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 the fmt module in tracing-subscriber, which provides a collector implementation that logs traces to the console.
    • fmt-stderr: Demonstrates overriding the output stream used by the fmt collector.
    • fmt-custom-field: Demonstrates overriding how the fmt collector formats fields on spans and events.
    • fmt-custom-event: Demonstrates overriding how the fmt collector formats events.
    • fmt-multiple-writers.rs: demonstrates how fmt::Subcriber can write to multiple destinations (in this instance, stdout and a file) simultaneously.
    • subscriber-filter: Demonstrates the tracing-subscriber::filter module, 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 use fmt and journald subscribers to output to both the terminal and the system journal.
    • toggle-subscribers : Demonstrates how subscribers can be wrapped with an Option allowing them to be dynamically toggled.
  • tracing-futures:
    • spawny-thing: Demonstrates the use of the #[instrument] attribute macro asynchronous functions.
    • tokio-spawny-thing.rs: Similar to spawny-thingy, but with the additional demonstration instrumenting concurrent tasks created with tokio::spawn.
    • futures-proxy-server: Demonstrates the use of tracing-futures by implementing a simple proxy server, based on this example from tokio.
    • async_fn: Demonstrates how asynchronous functions can be instrumented.
    • echo: Demonstrates a tracing-instrumented variant of Tokio's echo example.
  • tracing-flame:
    • infero-flame: Demonstrates the use of tracing-flame to generate a flamegraph from spans.
  • tracing-tower:
    • tower-client: Demonstrates the use of tracing-tower to instrument a simple tower HTTP/1.1 client.
    • tower-server: Demonstrates the use of tracing-tower to instrument a simple tower HTTP/1.1 server.
  • tracing-serde:
    • serde-yak-shave: Demonstrates the use of tracing-serde by implementing a collector that emits trace output as JSON.
  • tracing-log:
    • hyper-echo: Demonstrates how tracing-log can be used to record unstructured logs from dependencies as tracing events, by instrumenting this example from hyper, and using tracing-log to record logs emitted by hyper.
  • tracing-opentelemetry:
    • opentelemetry: Demonstrates how tracing-opentelemetry can be used to export and visualize tracing span data.
    • opentelemetry-remote-context: Demonstrates how tracing-opentelemetry can be used to extract and inject remote context when traces span multiple systems.