slog 1.0.0-alpha2

Structured, composable logging for Rust
Documentation
use std::cell::RefCell;
use std::borrow::Cow;
use std::io::Write;

thread_local! {
    static TL_BUF: RefCell<Vec<u8>> = RefCell::new(Vec::with_capacity(128))
}

/// Logger
///
/// Loggers are thread-safe and reference counted, so can be freely
/// passed around the code.
///
/// Each logger is built with a set of key-values.
///
/// Child loggers are build from existing loggers, and copy
/// all the key-values from their parents
///
/// Loggers form hierarchies sharing a drain. Setting a drain on
/// any logger will change it on all loggers in given hierarchy.
#[derive(Clone)]
pub struct Logger {
    drain: Arc<Drain>,
    values: Arc<OwnedKeyValueList>,
}

/// Log Record message
pub trait Message {
    /// Take a string
    fn as_str(&self) -> Cow<str>;

    /// Write it into `io` (which might be fast than `as_str()` it does not
    /// need to allocate anything in certain cases.
    fn write_to(&self, io : &mut Write) -> Result<()> {
        try!(write!(io, "{}", self.as_str()));
        Ok(())
    }

}

// TODO: why does this conflict with &'a str?
// impl<T : AsRef<str>> Into<Cow<'a, str>> for T {
// fn as_str(&self) -> Cow<str> {
// Cow::Borrowed(self.as_ref())
// }
// }
//

impl<'a> Message for &'a str {
    fn as_str(&self) -> Cow<str> {
        Cow::Borrowed(self)
    }
}

impl Message for String {
    fn as_str(&self) -> Cow<str> {
        Cow::Borrowed(self.as_str())
    }
}

impl<'a> Message for fmt::Arguments<'a> {
    fn as_str(&self) -> Cow<str> {
        let mut s = String::new();
        fmt::write(&mut s, *self).unwrap();
        Cow::Owned(s)
    }

    fn write_to(&self, io : &mut Write) -> Result<()> {
        try!(write!(io, "{}", self));
        Ok(())
    }
}

impl Logger {
    /// Build a root logger
    ///
    /// All children and their children and so on form one hierarchy
    /// sharing a common drain.
    ///
    /// Use `o!` macro to help build `values`
    ///
    /// ```
    /// #[macro_use]
    /// extern crate slog;
    ///
    /// fn main() {
    ///     let root = slog::Logger::root(
    ///         slog::discard(),
    ///         o!("key1" => "value1", "key2" => "value2"),
    ///     );
    /// }
    pub fn root<D: 'static + Drain + Sized>(d: D, values: Vec<OwnedKeyValue>) -> Logger {
        Logger {
            drain: Arc::new(d),
            values: Arc::new(OwnedKeyValueList::root(values)),
        }
    }

    /// Build a child logger
    ///
    /// Child logger copies all existing values from the parent.
    ///
    /// All children, their children and so on, form one hierarchy sharing
    /// a common drain.
    ///
    /// Use `o!` macro to help build `values`
    ///
    /// ```
    /// #[macro_use]
    /// extern crate slog;
    ///
    /// fn main() {
    ///     let root = slog::Logger::root(slog::discard(),
    ///         o!("key1" => "value1", "key2" => "value2"));
    ///     let log = root.new(o!("key" => "value"));
    /// }
    pub fn new(&self, values: Vec<OwnedKeyValue>) -> Logger {
        Logger {
            drain: self.drain.clone(),
            values: Arc::new(OwnedKeyValueList::new(values, self.values.clone())),
        }
    }

    /// Log one logging record
    ///
    /// Use specific logging functions instead.
    pub fn log(&self, record: &Record) {

        // By default errors in loggers are ignored
        TL_BUF.with(|buf| {
            let mut buf = buf.borrow_mut();
            let _ = self.drain.log(&mut *buf, &record, &*self.values);
            // TODO: Double check if this will not zero the old bytes as it costs time
            debug_assert!(buf.is_empty());
        });
    }
}

/// Logging record
pub struct Record<'a> {
    /// Lazily initialized timestamp
    ///
    /// Since getting current time requires a
    /// syscall and most log records won't make it to the final drain it will be
    /// delayed until ts is actually needed.
    ts: RefCell<Option<chrono::DateTime<chrono::UTC>>>,
    /// Logging level
    level: Level,
    /// Message
    msg: &'a Message,
    /// File
    file: &'a str,
    /// Line
    line: u32,
    /// Module
    module: &'a str,
    /// Values
    values: &'a [BorrowedKeyValue<'a>],
}

impl<'a> Record<'a> {
    /// Create a new `Record`
    #[inline]
    pub fn new(level: Level,
               msg: &'a Message,
               file: &'a str,
               line: u32,
               module: &'a str,
               values: &'a [BorrowedKeyValue<'a>])
               -> Self {
        Record {
            ts: RefCell::new(None),
            level: level,
            msg: msg,
            file: file,
            line: line,
            module: module,
            values: values,
        }
    }

    /// Timestamp
    ///
    /// Lazily evaluated timestamp
    pub fn ts(&self) -> chrono::DateTime<chrono::UTC> {
        let mut ts = self.ts.borrow_mut();
        match *ts {
            None => {
                let now = chrono::UTC::now();
                *ts = Some(now);
                now
            }
            Some(ts) => ts,
        }
    }


    /// Set timestamp
    ///
    /// Useful for manually forcing timestamp value (eg. in testing).
    pub fn set_ts(&self, ts: chrono::DateTime<chrono::UTC>) {
        *self.ts.borrow_mut() = Some(ts);
    }

    /// Get a log record message
    pub fn msg(&self) -> Cow<str> {
        self.msg.as_str()
    }

    /// Get record logging level
    pub fn level(&self) -> Level {
        self.level
    }

    /// Get line number
    pub fn line(&self) -> u32 {
        self.line
    }

    /// Get file path
    pub fn file(&self) -> &str {
        self.file

    }

    /// Get module
    pub fn module(&self) -> &str {
        self.module
    }

    /// Record value-key pairs
    pub fn values(&self) -> &'a [BorrowedKeyValue<'a>] {
        self.values
    }
}