slog-rs - Structured, composable logging for Rust

Travis CI Build Status crates.io Gitter Chat
Documentation (master branch) Documentation (release) FAQ

Status & news

Testing, feedback, PRs, etc. are very welcome. I'd be also very happy to share the ownership of the project with other people to make it more community-driven.

Long term goal is to make it a go-to logging crate for Rust.

Features

Advantages over log crate

Terminal output example

Full mode:

slog-rs terminal full-format output

Compact mode:

slog-rs terminal compact output

Using & help

Code snippet

Excerpt from examples/features.rs:

``rust fn main() { // Create a new drain hierarchy, for the need of your program. // Choose from collection of existing drains, or write your own //struct-s implementingDrain` trait. let drain = slog_term::streamer().async().full().build();

// `AtomicSwitch` is a drain that wraps other drain and allows to change
// it atomically in runtime.
let ctrl = AtomicSwitchCtrl::new(drain);
let drain = ctrl.drain();

// Get a root logger that will log into a given drain.
//
// Note `o!` macro for more natural `OwnedKeyValue` sequence building.
let root = Logger::root(drain.fuse(), o!("version" => VERSION, "build-id" => "8dfljdf"));

// Build logging context as data becomes available.
//
// Create child loggers from existing ones. Children clone `key: value`
// pairs from their parents.
let log = root.new(o!("child" => 1));

// Closures can be used for values that change at runtime.
// Data captured by the closure needs to be `Send+Sync`.
let counter = Arc::new(AtomicUsize::new(0));
let log = log.new(o!("counter" => {
    let counter = counter.clone();
    // Note the `move` to capture `counter`,
    // and unfortunate `|_ : &_|` that helps
    // current `rustc` limitations. In the future,
    // a `|_|` could work.
    move |_ : &Record| { counter.load(SeqCst)}
}));

// Loggers  can be cloned, passed between threads and stored without hassle.
let join = thread::spawn({
    let log = log.clone();
    move || {

        info!(log, "before-fetch-add"); // counter == 0
        counter.fetch_add(1, SeqCst);
        info!(log, "after-fetch-add"); // counter == 1

        // `AtomicSwitch` drain can swap it's interior atomically (race-free).
        ctrl.set(
            // drains are composable and reusable
            level_filter(
                Level::Info,
                async_stream(
                    std::io::stderr(),
                    // multiple outputs formats are supported
                    slog_json::new(),
                ),
            ),
        );

        // Closures can be used for lazy evaluation:
        // This `slow_fib` won't be evaluated, as the current drain discards
        // "trace" level logging records.
        debug!(log, "debug"; "lazy-closure" => |_ : &Record| slow_fib(40));

        info!(log, "subthread"; "stage" => "start");
        thread::sleep(Duration::new(1, 0));
        info!(log, "subthread"; "stage" => "end");
    }
});

join.join().unwrap();

} ```

See examples/features.rs for full code.

Read Documentation for details and features.

See [faq] for answers to common questions. If you want to say hi, or need help use #slog-rs gitter.im.

To report a bug or ask for features use github issues.

Building & running

If you need to install Rust (come on, you should have done that long time ago!), use rustup.

In your project

In Cargo.toml:

[dependencies] slog = "*"

In your main.rs:

```

[macro_use]

extern crate slog; ```

Alternatives

Please fill an issue if slog does not fill your needs. I will appreciate any feedback. You might look into issue discussing slog-rs alternatives too.