Skip to content
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
15 changes: 11 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "fastrace-tracing"
version = "0.1.0"

categories = ["development-tools::debugging"]
description = "A Poem middleware for propagating trace context for fastrace"
description = "A compatibility layer that connects tokio-tracing with fastrace tracing library."
keywords = ["tracing", "fastrace", "compatible", "tokio"]
readme = "README.md"

Expand All @@ -14,10 +14,17 @@ rust-version = "1.80"

[dependencies]
fastrace = "0.7"
tracing = { version = "0.1.35", default-features = false, features = ["std", "attributes"] }
tracing-subscriber = { version = "0.3.0", default-features = false, features = ["registry", "std", "fmt"] }
tracing-core = "0.1.28"
take_mut = "0.2.2"
tracing = { version = "0.1.35", default-features = false, features = [
"std",
"attributes",
] }
tracing-core = "0.1.28"
tracing-subscriber = { version = "0.3.0", default-features = false, features = [
"registry",
"std",
"fmt",
] }

[dev-dependencies]
fastrace = { version = "0.7", features = ["enable"] }
60 changes: 60 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,66 @@
[![CI Status](https://img.shields.io/github/actions/workflow/status/fast/fastrace-tracing/ci.yml?style=flat-square&logo=github)](https://github.com/fast/fastrace-tracing/actions)
[![License](https://img.shields.io/crates/l/fastrace-tracing?style=flat-square)](https://github.com/fast/fastrace-tracing/blob/main/LICENSE)

A compatibility layer that connects [toiok-tracing](https://github.com/tokio-rs/tracing) with the [fastrace](https://github.com/fast/fastrace) tracing library.

## Overview

`fastrace-tracing` allows you to capture spans and events from libraries that use `tokio-tracing` and forward them to `fastrace`. This is particularly useful when:

- You're using `fastrace` in your application but depend on libraries instrumented with `tokio-tracing`
- You want to migrate from `tokio-tracing` to `fastrace` incrementally

## Getting Started

Add `fastrace-tracing` to your project:

```toml
[dependencies]
fastrace = { version = "0.7", features = ["enable"] }
fastrace-tracing = "0.1"
tracing = "0.1"
tracing-subscriber = "0.3"
```

Set up the compatibility layer:

```rust
use fastrace::collector::{Config, ConsoleReporter};
use fastrace::prelude::*;
use tracing_subscriber::layer::SubscriberExt;

// Initialize fastrace.
fastrace::set_reporter(ConsoleReporter, Config::default());

// Set up tokio-tracing with the fastrace compatibility layer.
let subscriber = tracing_subscriber::Registry::default()
.with(fastrace_tracing::FastraceCompatLayer::new());
tracing::subscriber::set_global_default(subscriber).unwrap();

{
// Create a fastrace root span.
let root = Span::root("my-application", SpanContext::random());

// Set a fastrace span as the local parent - this is critical for connecting the
// tokio-tracing spans with the fastrace span.
let _guard = root.set_local_parent();

// Spans from tokio-tracing will be captured by fastrace.
let span = tracing::span!(tracing::Level::INFO, "my_operation");
let _enter = span.enter();

// Events from tokio-tracing will also be captured by fastrace.
tracing::info!("This will be captured by fastrace");
}

// Don't forget to flush before your application exits.
fastrace::flush();
```

## Examples

Check out the [examples directory](https://github.com/fast/fastrace-tracing/tree/main/examples) for more detailed usage examples.

## License

This project is licensed under the [Apache-2.0](./LICENSE) license.
13 changes: 13 additions & 0 deletions examples/basic.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//! This example demonstrates how to use fastrace-tracing to capture spans
//! generated by the tracing library and forward them to fastrace.

use fastrace::collector::Config;
use fastrace::collector::ConsoleReporter;
use fastrace::prelude::SpanContext;
Expand All @@ -6,24 +9,34 @@ use tracing_subscriber::Registry;
use tracing_subscriber::layer::SubscriberExt;

fn main() {
// Set up fastrace with the console reporter.
fastrace::set_reporter(ConsoleReporter, Config::default());

// Create a tracing subscriber with FastraceCompatLayer.
let subscriber = Registry::default().with(FastraceCompatLayer::new());
tracing::subscriber::set_global_default(subscriber).unwrap();

{
// Create a fastrace root span that will start a new trace.
let root = fastrace::Span::root("root", SpanContext::random());

// Set a fastrace span as the local parent - this is critical for connecting the
// tokio-tracing spans with the fastrace span.
let _guard = root.set_local_parent();

// Call a function that will create tokio-tracing spans.
make_traces();
}

// Make sure all spans are flushed to the reporter.
fastrace::flush();
}

fn make_traces() {
// Create a tokio-tracing span.
let span = tracing::span!(tracing::Level::TRACE, "send request", work_units = 2);
let _enter = span.enter();

// Create a tokio-tracing event.
tracing::error!("This event will be logged in the root span.");
}
76 changes: 56 additions & 20 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![doc = include_str!("../README.md")]

use std::borrow::Cow;
use std::cell::LazyCell;
use std::fmt;
Expand All @@ -19,6 +21,42 @@ use tracing_subscriber::registry::LookupSpan;
const FIELD_EXCEPTION_MESSAGE: &str = "exception.message";
const FIELD_EXCEPTION_STACKTRACE: &str = "exception.stacktrace";

/// A compatibility layer for using libraries instrumented with
/// `tokio-tracing` in applications using `fastrace`.
///
/// This layer collects spans and events created using the tokio-tracing ecosystem and
/// forwards them to fastrace's collectors.
///
/// # Example
///
/// ```
/// use fastrace::collector::Config;
/// use fastrace::collector::ConsoleReporter;
/// use fastrace::prelude::SpanContext;
/// use fastrace_tracing::FastraceCompatLayer;
/// use tracing_subscriber::layer::SubscriberExt;
///
/// // Set up fastrace reporter.
/// fastrace::set_reporter(ConsoleReporter, Config::default());
///
/// // Create a tracing subscriber with the FastraceCompatLayer.
/// let subscriber = tracing_subscriber::Registry::default().with(FastraceCompatLayer::new());
/// tracing::subscriber::set_global_default(subscriber).unwrap();
///
/// // Create a fastrace root span.
/// let root = fastrace::Span::root("root", SpanContext::random());
///
/// // Set a fastrace span as the local parent - this is critical for connecting the
/// // tokio-tracing spans with the fastrace span.
/// let _guard = root.set_local_parent();
///
/// // Spans from tokio-tracing will be captured by fastrace.
/// let span = tracing::span!(tracing::Level::TRACE, "my_span");
/// let _enter = span.enter();
///
/// // Events from tokio-tracing will also be captured by fastrace.
/// tracing::info!("This event will be captured by fastrace");
/// ```
pub struct FastraceCompatLayer<S> {
location: bool,
with_threads: bool,
Expand Down Expand Up @@ -229,6 +267,7 @@ impl field::Visit for SpanAttributeVisitor<'_> {
impl<S> FastraceCompatLayer<S>
where S: Subscriber + for<'span> LookupSpan<'span>
{
/// Creates a new [`FastraceCompatLayer`] with default settings.
pub fn new() -> Self {
FastraceCompatLayer {
location: true,
Expand All @@ -238,41 +277,38 @@ where S: Subscriber + for<'span> LookupSpan<'span>
}
}

/// Sets whether or not span and event metadata should include OpenTelemetry
/// attributes with location information, such as the file, module and line number.
///
/// These attributes follow the [OpenTelemetry semantic conventions for
/// source locations][conv].
/// Configures whether source code location information is included in spans.
///
/// By default, locations are enabled.
/// When enabled, span properties will include:
/// - `code.filepath`: The file where the span was created
/// - `code.namespace`: The module path where the span was created
/// - `code.lineno`: The line number where the span was created
///
/// [conv]: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/general/attributes.md#source-code-attributes/
/// Default is `true`.
pub fn with_location(self, location: bool) -> Self {
Self { location, ..self }
}

/// Sets whether or not spans record additional attributes for the thread
/// name and thread ID of the thread they were created on, following the
/// [OpenTelemetry semantic conventions for threads][conv].
/// Configures whether thread information is included in spans.
///
/// By default, thread attributes are enabled.
/// When enabled, span properties will include:
/// - `thread.id`: The numeric ID of the thread
/// - `thread.name`: The name of the thread (if available)
///
/// [conv]: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/general/attributes.md#general-thread-attributes/
/// Default is `true`.
pub fn with_threads(self, threads: bool) -> Self {
Self {
with_threads: threads,
..self
}
}

/// Sets whether or not span metadata should include the `tracing` verbosity level information
/// as a `level` field.
/// Configures whether level information is included in span properties.
///
/// The level is always added to events, and based on
/// [`OpenTelemetryLayer::with_error_events_to_status`] error-level events will mark the
/// span status as an error.
/// When enabled, spans will include the tracing level (trace, debug, info, etc.)
/// as a property named `level`.
///
/// By default, level information is disabled.
/// Default is `false`.
pub fn with_level(self, level: bool) -> Self {
Self {
with_level: level,
Expand Down Expand Up @@ -395,8 +431,8 @@ where S: Subscriber + for<'span> LookupSpan<'span>

fn on_record(&self, id: &Id, values: &Record<'_>, ctx: Context<'_, S>) {
let span = ctx.span(id).expect("Span not found, this is a bug");
let mut extenstion = span.extensions_mut();
let Some(fastrace_span) = extenstion.get_mut::<fastrace::Span>() else {
let mut extension = span.extensions_mut();
let Some(fastrace_span) = extension.get_mut::<fastrace::Span>() else {
return;
};
values.record(&mut SpanAttributeVisitor { fastrace_span });
Expand Down
Loading