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

update readmes for flame and error #695

Merged
merged 7 commits into from
May 4, 2020
Merged
Show file tree
Hide file tree
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
114 changes: 96 additions & 18 deletions tracing-error/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# tracing-error

Utilities for instrumenting errors with [`tracing`].
Utilities for enriching error handling with [`tracing`] diagnostic
information.

[![Crates.io][crates-badge]][crates-url]
[![Documentation][docs-badge]][docs-url]
Expand All @@ -26,7 +27,7 @@ Utilities for instrumenting errors with [`tracing`].
[discord-url]: https://discord.gg/EeF3cQw
[maint-badge]: https://img.shields.io/badge/maintenance-experimental-blue.svg

## Overview
# Overview

[`tracing`] is a framework for instrumenting Rust programs to collect
scoped, structured, and async-aware diagnostics. This crate provides
Expand All @@ -47,14 +48,9 @@ The crate provides the following:

## Usage

Currently, `tracing-error` provides the [`SpanTrace`] type, which captures
the current `tracing` span context when it is constructed and allows it to
be displayed at a later time.

This crate does not _currently_ provide any actual error types implementing
`std::error::Error`. Instead, user-constructed errors or libraries
implementing error types may capture a [`SpanTrace`] and include it as part
of their error types.
`tracing-error` provides the [`SpanTrace`] type, which captures the current
`tracing` span context when it is constructed and allows it to be displayed
at a later time.

For example:

Expand All @@ -71,8 +67,11 @@ pub struct MyError {
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// ... format other parts of the error ...

self.context.fmt(f)?;

// ... format other error context information, cause chain, etc ...
# Ok(())
}
}

Expand All @@ -88,8 +87,68 @@ impl MyError {
}
```

In the future, this crate may also provide its own `Error` types as well,
for users who do not wish to use other error-handling libraries.
This crate also provides [`TracedError`], for attaching a [`SpanTrace`] to an
existing error. The easiest way to wrap errors in `TracedError` is to either
use the [`InstrumentResult`] and [`InstrumentError`] traits or the `From`/`Into`
traits.

```rust
use tracing_error::prelude::*;

std::fs::read_to_string("myfile.txt").in_current_span()?;
```

Once an error has been wrapped with with a [`TracedError`], the [`SpanTrace`]
can be extracted one of three ways: either via [`TracedError`]'s
`Display`/`Debug` implementations, or via the [`ExtractSpanTrace`] trait.

For example, here is how one might print the errors but specialize the
printing when the error is a placeholder for a wrapping [`SpanTrace`]:

```rust
use std::error::Error;
use tracing_error::ExtractSpanTrace as _;

fn print_extracted_spantraces(error: &(dyn Error + 'static)) {
let mut error = Some(error);
let mut ind = 0;

eprintln!("Error:");

while let Some(err) = error {
if let Some(spantrace) = err.span_trace() {
eprintln!("found a spantrace:\n{}", spantrace);
} else {
eprintln!("{:>4}: {}", ind, err);
}

error = err.source();
ind += 1;
}
}

```

Whereas here, we can still display the content of the `SpanTraces` without
any special casing by simply printing all errors in our error chain.

```rust
use std::error::Error;

fn print_naive_spantraces(error: &(dyn Error + 'static)) {
let mut error = Some(error);
let mut ind = 0;

eprintln!("Error:");

while let Some(err) = error {
eprintln!("{:>4}: {}", ind, err);
error = err.source();
ind += 1;
}
}
```

Applications that wish to use `tracing-error`-enabled errors should
construct an [`ErrorLayer`] and add it to their [`Subscriber`] in order to
enable capturing [`SpanTrace`]s. For example:
Expand All @@ -103,17 +162,20 @@ fn main() {
// any number of other subscriber layers may be added before or
// after the `ErrorLayer`...
.with(ErrorLayer::default());

// set the subscriber as the default for the application
tracing::subscriber::set_global_default(subscriber);
}
```

[`SpanTrace`]: https://docs.rs/tracing-error/0.1.2/tracing_error/struct.SpanTrace.html
[`ErrorLayer`]: https://docs.rs/tracing-error/0.1.2/tracing_error/struct.ErrorLayer.html
[span]: https://docs.rs/tracing/latest/tracing/span/index.html
[event]: https://docs.rs/tracing/latest/tracing/struct.Event.html
[subscriber layer]: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/layer/trait.Layer.html
[`tracing`]: https://crates.io/tracing
## Feature Flags

- `traced-error` - Enables the [`TracedError`] type and related traits
- [`InstrumentResult`] and [`InstrumentError`] extension traits, which
provide an [`in_current_span()`] method for bundling errors with a
[`SpanTrace`].
- [`ExtractSpanTrace`] extension trait, for extracting `SpanTrace`s from
behind `dyn Error` trait objects.

## License

Expand All @@ -124,3 +186,19 @@ This project is licensed under the [MIT license](LICENSE).
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in Tracing by you, shall be licensed as MIT, without any additional
terms or conditions.

[`SpanTrace`]: https://docs.rs/tracing-error/*/tracing_error/struct.SpanTrace.html
[`ErrorLayer`]: https://docs.rs/tracing-error/*/tracing_error/struct.ErrorLayer.html
[`TracedError`]: https://docs.rs/tracing-error/*/tracing_error/struct.TracedError.html
[`InstrumentResult`]: https://docs.rs/tracing-error/*/tracing_error/trait.InstrumentResult.html
[`InstrumentError`]: https://docs.rs/tracing-error/*/tracing_error/trait.InstrumentError.html
[`ExtractSpanTrace`]: https://docs.rs/tracing-error/*/tracing_error/trait.ExtractSpanTrace.html
[`in_current_span()`]: https://docs.rs/tracing-error/*/tracing_error/trait.InstrumentResult.html#tymethod.in_current_span
[span]: https://docs.rs/tracing/latest/tracing/span/index.html
[events]: https://docs.rs/tracing/latest/tracing/struct.Event.html
[`Subscriber`]: https://docs.rs/tracing/latest/tracing/trait.Subscriber.html
[subscriber layer]: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/layer/trait.Layer.html
[`tracing`]: https://docs.rs/tracing
[`std::error::Error`]: https://doc.rust-lang.org/stable/std/error/trait.Error.html
[`SpanTrace`]: https://docs.rs/tracing-error/0.1.2/tracing_error/struct.SpanTrace.html
[`ErrorLayer`]: https://docs.rs/tracing-error/0.1.2/tracing_error/struct.ErrorLayer.html
7 changes: 4 additions & 3 deletions tracing-error/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,10 @@
//! }
//! ```
//!
//! This crate also provides the [`InstrumentResult`] and [`InstrumentError`]
//! traits, which can be used to wrap errors with a [`TracedError`] which
//! bundles the inner error with a [`SpanTrace`].
//! This crate also provides [`TracedError`], for attaching a [`SpanTrace`] to
//! an existing error. The easiest way to wrap errors in `TracedError` is to
//! either use the [`InstrumentResult`] and [`InstrumentError`] traits or the
//! `From`/`Into` traits.
//!
//! ```rust
//! # use std::error::Error;
Expand Down
127 changes: 127 additions & 0 deletions tracing-flame/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# tracing-flame

A [tracing] [`Layer`][`FlameLayer`] for generating a folded stack trace for generating flamegraphs
and flamecharts with [`inferno`]
Copy link
Member

Choose a reason for hiding this comment

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

this isn't strictly inferno-specific; it emits the perf output format, right? so technically any flamegraph tool that expects that can use this crate's output.

i'm not sure if this is worth stating here though, for the sake of brevity...

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't think its the same format that perf emits, my understanding is that with perf normally you take the output and pass it through another script that folds the stack traces, and then you pass the folded representation into the flamegraph generating scripts. With tracing-flame we skip straight to emitting a folded representation. I think it might be cool to investigate if we can emit perf's exact format so we can be compatible with more tools, but I think it would be the same as writing a script to fake a bunch of stack traces that reproduce the folded repr, so for now I don't think we should bother with it.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, this is the folded output produced by flamegraph, inferno, and some newer eBPF perf tracing tools. perf's output (by which you're probably referring to perf script's output) is probably not something we want to mirror. The collapsed output is decently standard, enough so that eBPF also produces the same thing.


[![Crates.io][crates-badge]][crates-url]
[![Documentation][docs-badge]][docs-url]
[![Documentation (master)][docs-master-badge]][docs-master-url]
[![MIT licensed][mit-badge]][mit-url]
[![Build Status][actions-badge]][actions-url]
[![Discord chat][discord-badge]][discord-url]
![maintenance status][maint-badge]

[Documentation][docs-url] | [Chat][discord-url]

# Overview

[`tracing`] is a framework for instrumenting Rust programs to collect
scoped, structured, and async-aware diagnostics. `tracing-flame` provides helpers
for consuming `tracing` instrumentation that can later be visualized as a
flamegraph/flamechart. Flamegraphs/flamecharts are useful for identifying performance
bottlenecks in an application. For more details, see Brendan Gregg's [post]
on flamegraphs.

[post]: http://www.brendangregg.com/flamegraphs.html

## Usage

This crate is meant to be used in a two step process:

1. Capture textual representation of the spans that are entered and exited
with [`FlameLayer`].
2. Feed the textual representation into `inferno-flamegraph` to generate the
flamegraph or flamechart.

*Note*: when using a buffered writer as the writer for a `FlameLayer`, it is necessary to
ensure that the buffer has been flushed before the data is passed into
[`inferno-flamegraph`]. For more details on how to flush the internal writer
of the `FlameLayer`, see the docs for [`FlushGuard`].

## Layer Setup

```rust
use std::{fs::File, io::BufWriter};
use tracing_flame::FlameLayer;
use tracing_subscriber::{registry::Registry, prelude::*, fmt};

fn setup_global_subscriber() -> impl Drop {
let fmt_layer = fmt::Layer::default();

let (flame_layer, _guard) = FlameLayer::with_file("./tracing.folded").unwrap();

tracing_subscriber::registry()
.with(fmt_layer)
.with(flame_layer)
.init().
_guard
}

// your code here ..
```

As an alternative, you can provide _any_ type that implements `std::io::Write` to
`FlameLayer::new`.

## Generating the Image

To convert the textual representation of a flamegraph to a visual one, first install `inferno`:

```console
cargo install inferno
```

Then, pass the file created by `FlameLayer` into `inferno-flamegraph`:

```console
# flamegraph
cat tracing.folded | inferno-flamegraph > tracing-flamegraph.svg

# flamechart
cat tracing.folded | inferno-flamegraph --flamechart > tracing-flamechart.svg
```

## Differences between `flamegraph`s and `flamechart`s

By default, `inferno-flamegraph` creates flamegraphs. Flamegraphs operate by
that collapsing identical stack frames and sorting them on the frame's names.

This behavior is great for multithreaded programs and long-running programs
where the same frames occur _many_ times, for short durations, because it reduces
noise in the graph and gives the reader a better idea of the
overall time spent in each part of the application.

However, it is sometimes desirable to preserve the _exact_ ordering of events
as they were emitted by `tracing-flame`, so that it is clear when each
span is entered relative to others and get an accurate visual trace of
the execution of your program. This representation is best created with a
_flamechart_, which _does not_ sort or collapse identical stack frames.

## License

This project is licensed under the [MIT license](LICENSE).

### Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in Tracing by you, shall be licensed as MIT, without any additional
terms or conditions.

[`inferno`]: https://docs.rs/inferno
[`FlameLayer`]: https://docs.rs/tracing-flame/*/tracing_flame/struct.FlameLayer.html
[`FlushGuard`]: https://docs.rs/tracing-flame/*/tracing_flame/struct.FlushGuard.html
[`inferno-flamegraph`]: https://docs.rs/inferno/0.9.5/inferno/index.html#producing-a-flame-graph
[`tracing`]: https://github.com/tokio-rs/tracing/tree/master/tracing
[crates-badge]: https://img.shields.io/crates/v/tracing-flame.svg
[crates-url]: https://crates.io/crates/tracing-flame
[docs-badge]: https://docs.rs/tracing-flame/badge.svg
[docs-url]: https://docs.rs/tracing-flame/0.2.4
[docs-master-badge]: https://img.shields.io/badge/docs-master-blue
[docs-master-url]: https://tracing-rs.netlify.com/tracing_flame
[mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg
[mit-url]: LICENSE
[actions-badge]: https://github.com/tokio-rs/tracing/workflows/CI/badge.svg
[actions-url]:https://github.com/tokio-rs/tracing/actions?query=workflow%3ACI
[discord-badge]: https://img.shields.io/discord/500028886025895936?logo=discord&label=discord&logoColor=white
[discord-url]: https://discord.gg/EeF3cQw
[maint-badge]: https://img.shields.io/badge/maintenance-experimental-blue.svg
6 changes: 3 additions & 3 deletions tracing-flame/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
//!
//! This crate is meant to be used in a two step process:
//!
//! 1. A textual representation of the spans that are entered and exited are
//! captured with [`FlameLayer`].
//! 1. Capture textual representation of the spans that are entered and exited
//! with [`FlameLayer`].
//! 2. Feed the textual representation into `inferno-flamegraph` to generate the
//! flamegraph or flamechart.
//!
Expand Down Expand Up @@ -66,7 +66,7 @@
//! # flamegraph
//! cat tracing.folded | inferno-flamegraph > tracing-flamegraph.svg
//!
//! #flamechart
//! # flamechart
//! cat tracing.folded | inferno-flamegraph --flamechart > tracing-flamechart.svg
//! ```
//!
Expand Down