Expand description

Slog - Structured, extensible, composable logging for Rust

slog-rs is an ecosystem of reusable components for structured, extensible, composable logging for Rust.

slog is slog-rs’s main crate providing core components shared between all other parts of slog-rs ecosystem.

This is auto-generated technical documentation of slog. For information about project organization, development, help, etc. please see slog github page

Core advantages over log crate

  • extensible - slog crate provides core functionality: a very basic and portable standard feature-set based on open traits. This allows implementing new features that can be independently published.
  • composable - traits that slog exposes to provide extensibility are designed to be easy to efficiently reuse and combine. By combining different functionalities, each application can specify precisely when, where, and how to process logging data from an application and its dependencies.
  • flexible - slog does not constrain logging to just one globally registered backend. Parts of your application can handle logging in a customized way, or completely independently.
  • structured and both human and machine readable - By using the key-value data format and retaining its type information, the meaning of logging data is preserved. Data can be serialized to machine readable formats like JSON and sent to data-mining systems for further analysis, etc. On the other hand, when presenting on screen, logging information can be presented in aesthetically pleasing and easy to understand ways.
  • contextual - slog’s Logger objects carry set of key-value data pairs that contain the context of logging - information that otherwise would have to be repeated in every logging statement.

slog features

  • performance oriented; read what makes slog fast and see: slog bench log
    • lazily evaluation through closure values
    • async IO support included: see slog-async crate
  • #![no_std] support (with opt-out std cargo feature flag)
  • support for named format arguments (e.g. info!(logger, "printed {line_count} lines", line_count = 2);) for easy bridging between the human readable and machine-readable outputs
  • tree-structured loggers
  • modular, lightweight and very extensible
    • tiny core crate that does not pull any dependencies
    • feature-crates for specific functionality
    • using slog in library does not force users of the library to use slog (but provides additional functionality); see example how to use slog in library
  • backwards and forwards compatibility with log crate: see slog-stdlog crate
  • convenience crates:
  • many existing core & community provided features:
    • multiple outputs
    • filtering control
      • compile-time log level filter using cargo features (same as in log crate)
      • by level, msg, and any other meta-data
      • slog-envlogger - port of env_logger
      • terminal output, with color support: see slog-term crate
  • json
  • syslog and journald support
  • run-time configuration:

Notable details

Note: At compile time slog by default removes trace and debug level statements in release builds, and trace level records in debug builds. This makes trace and debug level logging records practically free, which should encourage using them freely. If you want to enable trace/debug messages or raise the compile time logging level limit, use the following in your Cargo.toml:

slog = { version = ... ,
         features = ["max_level_trace", "release_max_level_warn"] }

Root drain (passed to Logger::root) must be one that does not ever return errors. This forces user to pick error handing strategy. Drain::fuse() or Drain::ignore_res().

Where to start

Drain, Logger and log macro are the most important elements of slog. Make sure to read their respective documentation

Typically the biggest problem is creating a Drain

Logging to the terminal

#[macro_use]
extern crate slog;
extern crate slog_term;
extern crate slog_async;

use slog::Drain;

fn main() {
    let decorator = slog_term::TermDecorator::new().build();
    let drain = slog_term::FullFormat::new(decorator).build().fuse();
    let drain = slog_async::Async::new(drain).build().fuse();

    let _log = slog::Logger::root(drain, o!());
}

Logging to a file

#[macro_use]
extern crate slog;
extern crate slog_term;
extern crate slog_async;

use std::fs::OpenOptions;
use slog::Drain;

fn main() {
   let log_path = "target/your_log_file_path.log";
   let file = OpenOptions::new()
      .create(true)
      .write(true)
      .truncate(true)
      .open(log_path)
      .unwrap();

    let decorator = slog_term::PlainDecorator::new(file);
    let drain = slog_term::FullFormat::new(decorator).build().fuse();
    let drain = slog_async::Async::new(drain).build().fuse();

    let _log = slog::Logger::root(drain, o!());
}

You can consider using slog-json instead of slog-term. slog-term only coincidently fits the role of a file output format. A proper slog-file crate with suitable format, log file rotation and other file-logging related features would be awesome. Contributions are welcome!

Change logging level at runtime

#[macro_use]
extern crate slog;
extern crate slog_term;
extern crate slog_async;

use slog::Drain;

use std::sync::{Arc, atomic};
use std::sync::atomic::Ordering;
use std::result;

/// Custom Drain logic
struct RuntimeLevelFilter<D>{
   drain: D,
   on: Arc<atomic::AtomicBool>,
}

impl<D> Drain for RuntimeLevelFilter<D>
    where D : Drain {
    type Ok = Option<D::Ok>;
    type Err = Option<D::Err>;

    fn log(&self,
          record: &slog::Record,
          values: &slog::OwnedKVList)
          -> result::Result<Self::Ok, Self::Err> {
          let current_level = if self.on.load(Ordering::Relaxed) {
              slog::Level::Trace
          } else {
              slog::Level::Info
          };

          if record.level().is_at_least(current_level) {
              self.drain.log(
                  record,
                  values
              )
              .map(Some)
              .map_err(Some)
          } else {
              Ok(None)
          }
      }
  }

fn main() {
    // atomic variable controlling logging level
    let on = Arc::new(atomic::AtomicBool::new(false));

    let decorator = slog_term::TermDecorator::new().build();
    let drain = slog_term::FullFormat::new(decorator).build();
    let drain = RuntimeLevelFilter {
        drain: drain,
        on: on.clone(),
    }.fuse();
    let drain = slog_async::Async::new(drain).build().fuse();

    let _log = slog::Logger::root(drain, o!());

    // switch level in your code
    on.store(true, Ordering::Relaxed);
}

Why is this not an existing crate? Because there are multiple ways to achieve the same result, and each application might come with its own variation. Supporting a more general solution is a maintenance effort. There is also nothing stopping anyone from publishing their own crate implementing it.

Alternative to the above approach is slog-atomic crate. It implements swapping whole parts of Drain logging hierarchy.

Examples & help

Basic examples that are kept up-to-date are typically stored in respective git repository, under examples/ subdirectory. Eg. slog-term examples.

slog-rs wiki pages contain some pages about slog-rs technical details.

Source code of other software using slog-rs can be an useful reference.

Visit slog-rs gitter channel for immediate help.

Migrating from slog v1 to slog v2

Key-value pairs come now after format string

#[macro_use]
extern crate slog;

fn main() {
    let drain = slog::Discard;
    let root = slog::Logger::root(drain, o!());
    info!(root, "formatted: {}", 1; "log-key" => true);
}

See more information about format at log.

slog-streamer is gone

Create simple terminal logger like this:

#[macro_use]
extern crate slog;
extern crate slog_term;
extern crate slog_async;

use slog::Drain;

fn main() {
    let decorator = slog_term::TermDecorator::new().build();
    let drain = slog_term::FullFormat::new(decorator).build().fuse();
    let drain = slog_async::Async::new(drain).build().fuse();

    let _log = slog::Logger::root(drain, o!());
}

Logging macros now takes ownership of values.

Pass them by reference: &x.

Modules

serDeprecated
Compatibility name to ease upgrading from slog v1

Macros

Macro for building group of key-value pairs in BorrowedKV
Log critical level record
Log debug level record
Log error level record
Log info level record
Macro for build KV implementing type
Log message a logging record
Macro for building group of key-value pairs: OwnedKV
Create Record at the given code location
Create RecordStatic at the given code location
Alias of b
Log critical level record (alias)
Log debug level record (alias)
Log error level record
Log info level record (alias)
Alias of kv
Log message a logging record (alias)
Macro for building group of key-value pairs (alias)
Create Record at the given code location (alias)
Create RecordStatic at the given code location (alias)
Log trace level record (alias)
Log warning level record (alias)
Log trace level record
Log warning level record

Structs

Borrowed KV
Drain discarding everything
Drain duplicating records into two other Drains
A wrapper struct for serializing errors
Drain filtering records
Explicit lazy-closure Value
Drain panicking on error
Drain ignoring result
Drain filtering records by Record logging level
Logging handle used to execute logging statements
Drain mapping error returned by another Drain
Owned KV
Chain of SyncMultiSerialize-s of a Logger and its ancestors
Lazy Value that writes to Serializer
Handle passed to PushFnValue closure
One logging record
Information that can be static in the given record thus allowing to optimize record creation to be done mostly at compile-time.
Single pair Key and Value

Enums

Serialization Error
Logging filtering level
Logging level associated with a logging Record
Error returned by Mutex<D : Drain>

Statics

Official capitalized logging (and logging filtering) level names
Official capitalized logging (and logging filtering) short level names

Traits

Logging drain
Function that can be used in Filter drain
Key-value pair(s) for log events
Function that can be used in MapErr drain
Drain + Send + RefUnwindSafe bound
Drain + Send + Sync + RefUnwindSafe bound
This type is used to enforce KVs stored in Loggers are thread-safe.
Send + Sync + UnwindSafe bound
Drain + Send + Sync + UnwindSafe bound
Serializer
Value that can be serialized

Type Definitions

Key type
Compatibility name to ease upgrading from slog v1
Old name of PushFnValueSerializer
PushLazyDeprecated
Compatibility name to ease upgrading from slog v1
Serialization Result
SerializeDeprecated
Compatibility name to ease upgrading from slog v1
ValueSerializerDeprecated
Compatibility name to ease upgrading from slog v1