Module tracing_forest::runtime

source ·
Expand description

Run asynchronous code in the context of a tracing-forest subscriber.

This module provides useful abstractions for executing async code: worker_task for main functions, and capture for unit tests, both of which return a configurable Builder object.

Nonblocking log processing with worker_task

tracing-forest collects trace data into trees, and can sometimes produce large trees that need to be processed. To avoid blocking the main task in these cases, a common strategy is to send this data to a worker task for formatting and writing.

The worker_task function provides this behavior as a first-class feature of this crate, and handles the configuration, initialization, and graceful shutdown of a subscriber with an associated worker task for formatting and writing.

Unlike tracing-appender which uses a writer thread for formatted logs, this module allows for log trees to be sent to a worker task before formatting, allowing more log-related work to be offloaded to the worker task.

Examples

use tracing::{info, info_span};
 
#[tokio::main]
async fn main() {
    tracing_forest::worker_task()
        .build()
        .on(async {
            info!("Hello, world!");

            info_span!("my_span").in_scope(|| {
                info!("Relevant information");
            })
        })
        .await;
}

Produces the output:

INFO     i [info]: Hello, world!
INFO     my_span [ 26.0µs | 100.000% ]
INFO     ┕━ i [info]: Relevant information

For full configuration options, see the Builder documentation.

Inspecting trace data in unit tests with capture

The capture function offers the ability to programmatically inspect log trees generated by tracing-forest. It is the unit testing analog of worker_task, except it returns Vec<Tree> after the future is completed, which can be then be inspected.

Examples

use tracing_forest::tree::{Tree, Event, Span};
use tracing::{info, info_span};
 
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let logs: Vec<Tree> = tracing_forest::capture()
        .build()
        .on(async {
            info!("Hello, world!");

            info_span!("my_span").in_scope(|| {
                info!("Relevant information");
            })
        })
        .await;
     
    // There is one event and one span at the root level
    assert!(logs.len() == 2);
     
    // Inspect the first event
    let hello_world: &Event = logs[0].event()?;
    assert!(hello_world.message() == Some("Hello, world!"));

    // Inspect the span
    let my_span: &Span = logs[1].span()?;
    assert!(my_span.name() == "my_span");
 
    // Only the `info` event is recorded
    assert!(my_span.nodes().len() == 1);
 
    let relevant_info: &Event = my_span.nodes()[0].event()?;
 
    assert!(relevant_info.message() == Some("Relevant information"));
 
    Ok(())
}

Additional options for tree inspection can be found in the tree module-level documentation

For full configuration options, see the Builder documentation.

Structs

  • Return type of worker_task and capture.
  • A marker type indicating that trace data should be captured for later use.
  • The Processor used within a tracing-forest subscriber for sending logs to a processing task.
  • Execute a Future in the context of a subscriber with a ForestLayer.
  • A marker type indicating that trace data should be processed.

Functions

  • Begins the configuration of a ForestLayer subscriber that sends log trees to a buffer that can later be inspected programatically.
  • Begins the configuration of a ForestLayer subscriber that sends log trees to a processing task for formatting and writing.