tracing-scribe 0.1.0

A tracing-subscriber layer for beautifully printing spans and events to the terminal as a hierarchical tree.
Documentation

tracing-scribe

Crates.io Docs.rs License

A tracing-subscriber layer for beautifully printing spans and events to the terminal.

This crate provides a ConsoleLayer that can be used with tracing to format and display log messages in a hierarchical and easy-to-read format. It is designed to make command line applications more pleasant by providing clear visual cues for different log levels, tracking the duration of spans, and indicating success or failure states.

Features

  • Pretty Printing: Spans and events are displayed with icons, colors, and indentation to create a clear visual hierarchy.
  • Automatic Result Handling: The console! macro automatically logs the outcome of a Result, indicating success or failure.
  • Span Timings: The layer automatically tracks and displays the execution time of each span.
  • Error Propagation: Errors inside spans are propagated to parent spans, marking them as failed.

Installation

[dependencies]
tracing-scribe = "0.1"

Usage

To use ConsoleLayer, add it to your tracing subscriber registry. The console! macro can then be used to log events with different status levels.

Example

Here is a complete example demonstrating a successful execution with nested spans and #[tracing::instrument].

use tracing::info_span;
use tracing_scribe::console;
use tracing_subscriber::prelude::*;
use tracing_subscriber::registry::Registry;

#[tracing::instrument]
fn outer_task() {
    inner_task();
}

#[tracing::instrument]
fn inner_task() {
    console!(notice, "generating unicorns");
    std::thread::sleep(std::time::Duration::from_millis(100));
    console!(info, "unicorns generation completed");
}

let subscriber = Registry::default().with(tracing_scribe::ConsoleLayer::default());
tracing::subscriber::with_default(subscriber, || {
    let _span = info_span!("main").entered();
    outer_task();
});

This will produce the following output:

Successful nested spans output

Error Handling

The ConsoleLayer also handles errors gracefully. When a span instrumented with #[tracing::instrument(err)] returns an error, the span and its parents are marked as failed.

use std::error::Error;
use std::fmt;

use tracing::info_span;
use tracing_scribe::console;
use tracing_subscriber::prelude::*;
use tracing_subscriber::registry::Registry;

#[derive(Debug)]
struct MyError;

impl Error for MyError {}

impl fmt::Display for MyError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "something went wrong")
    }
}

#[tracing::instrument(err)]
fn failing_task() -> Result<(), MyError> {
    console!(error, "this task is about to fail");
    Err(MyError)
}

let subscriber = Registry::default().with(tracing_scribe::ConsoleLayer::default());
tracing::subscriber::with_default(subscriber, || {
    let _span = info_span!("main").entered();
    failing_task().ok();
});

This will produce the following output:

Error handling output

Asynchronous tasks

Asynchronous tasks are handled their own way by tracing. To make sure they end up with the right indentation, you might have to wrap them with a tracing instrumentation call.

use tracing::Instrument;
use tracing_scribe::console;

#[tracing::instrument]
async fn outer_task() {
    tokio::spawn(
        inner_task().instrument(tracing::Span::current())
    );
}

#[tracing::instrument]
async fn inner_task() {
    console!(notice, "generating async unicorns");
    tokio::time::sleep(std::time::Duration::from_millis(100)).await;
    console!(info, "async unicorns generation completed");
}

Attaching Extra Information

The extra field can be used to attach additional context to a span, which will be displayed alongside the span name.

use tracing::info_span;
use tracing_scribe::console;
use tracing_subscriber::prelude::*;
use tracing_subscriber::registry::Registry;

#[tracing::instrument(fields(extra = "some extra info"))]
fn task_with_extra() {
    console!(info, "this task has extra information");
}

let subscriber = Registry::default().with(tracing_scribe::ConsoleLayer::default());
tracing::subscriber::with_default(subscriber, || {
    let _span = info_span!("main").entered();
    task_with_extra();
});

This will produce the following output:

Extra information output

Custom Colors

You can customize colors via the ColorScheme builder.

use owo_colors::colors;
use tracing_scribe::{ColorScheme, ConsoleLayer};

let colors = ColorScheme::default()
    .with_success_color(colors::BrightGreen)
    .with_error_color(colors::BrightRed)
    .with_tree_color(colors::Cyan);

let layer = ConsoleLayer::default().with_colors(colors);

See examples/custom_colors.rs for a full example:

Custom colours output

Custom Status

The with_status method allows you to customize the icons used for the different statuses. See the API documentation for the Status and StatusFactory traits.

Examples

Run the bundled examples to see the layer in action:

cargo run --example full
cargo run --example custom_colors

License

Licensed under the Apache License, Version 2.0 (LICENSE or http://www.apache.org/licenses/LICENSE-2.0).