Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Log levels

Levels describe the significance of a log event in a coarse-grained way that's easy to organize and filter on. emit doesn't bake in the concept of log levels directly, but supports them through the lvl well-known property. emit defines four well-known levels; a strong and a weak variant of informative and erroneous events:

  • "debug": for events supporting live debugging. These events are likely to be filtered out, or only retained for a short period.
  • "info": for most events. These events are the core diagnostics of your applications that give you a good picture of what's happening.
  • "warn": for recoverable or non-esential erroneous events. They may help explain some unexpected behavior or point to issues to investigate.
  • "error": for erroneous events that cause degraded behavior and need to be investigated.

When emitting events, you can use a macro corresponding to a given level to have it attached automatically:

Custom levels

emit's well-known levels are intentionally very coarse-grained and aren't intended to be extended. If you need finer grained levels, you can define your own scheme. Your scheme should integrate with the debug, info, warn, and error scheme emit uses by default, but doesn't technically have to either.

To use a custom level, you can specify your own value for the lvl well-known property when emitting an event:

#![allow(unused)]
fn main() {
extern crate emit;
emit::emit!("Some noteworthy event", lvl: "notice");
}

If you define your own level type, you can also use it when constructing a level filter:

#![allow(unused)]
fn main() {
extern crate emit;
// Define your custom level as a struct or enum
//
// To use your level in a `MinLevelPathMap`, it needs to implement the following traits:
// - `Default`
// - `FromValue`
// - `Ord`
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum MyLevel {
    Debug,
    Info,
    Notice,
    Warn,
    Error,
    Critical,
    Alert,
    Emergency,
}

impl Default for MyLevel {
    fn default() -> Self {
        MyLevel::Info
    }
}

// The `FromStr` impl here is primitive, but makes the `FromValue` impl able
// to parse levels supplied as strings
impl std::str::FromStr for MyLevel {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match &*s.to_ascii_lowercase() {
            "debug" => Ok(MyLevel::Debug),
            "info" => Ok(MyLevel::Info),
            "notice" => Ok(MyLevel::Notice),
            "warn" => Ok(MyLevel::Warn),
            "error" => Ok(MyLevel::Error),
            "critical" => Ok(MyLevel::Critical),
            "alert" => Ok(MyLevel::Alert),
            "emergency" => Ok(MyLevel::Emergency),
            _ => Err(format!("'{s}' was not recognized as a level")),
        }
    }
}

impl<'a> emit::value::FromValue<'a> for MyLevel {
    fn from_value(value: emit::Value<'a>) -> Option<Self> {
        value.downcast_ref().copied().or_else(|| value.parse())
    }
}

let rt = emit::setup()
    .emit_when({
        // If you're using a custom level, you need to construct your `MinLevelPathMap` manually
        let mut filter = emit::level::MinLevelPathMap::new();

        filter.min_level(
            emit::path!("level_custom::noisy"),
            emit::level::MinLevelFilter::new(MyLevel::Notice),
        );

        filter
    })
    .init();

// Your app code goes here

rt.blocking_flush(std::time::Duration::from_secs(5));
}