Crate slog

source ·
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

use slog::{o, 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

use std::fs::OpenOptions;
use slog::{o, 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

use slog::{o, 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

use slog::{info, o};

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:

use slog::{o, 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
  • Opaque Key is a representation of a key.
  • 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.
  • Use to wrap a value that implements serde::Serialize so it’s written to the log record as an object, rather than a primitive.
  • Single pair Key and Value

Enums

Statics

Traits

Type Aliases

  • 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