#logging #log-level #logger #trace-logging #error-logging #log #debug-info

logkit

为 Rust 提供的超级快速、结构化、可扩展的日志库

10 个版本

0.3.7 2024 年 7 月 13 日
0.3.6 2024 年 7 月 12 日
0.3.5 2024 年 5 月 18 日
0.3.4 2024 年 3 月 13 日
0.1.0 2024 年 1 月 24 日

#150 in 调试

Download history 7/week @ 2024-04-29 19/week @ 2024-05-06 199/week @ 2024-05-13 107/week @ 2024-05-20 26/week @ 2024-05-27 53/week @ 2024-06-03 80/week @ 2024-06-10 99/week @ 2024-06-17 225/week @ 2024-06-24 242/week @ 2024-07-01 411/week @ 2024-07-08 192/week @ 2024-07-15 102/week @ 2024-07-22 158/week @ 2024-07-29 104/week @ 2024-08-05 153/week @ 2024-08-12

537 每月下载量
用于 fibra

MIT 许可证

44KB
548 代码行

Logkit

为 Rust 提供的超级快速、结构化、可扩展的日志库

Crates.io MIT licensed Documentation Build Status Build Status Build Status

你好世界

#[macro_use] extern crate logkit;

fn main() {
    let mut logger = logkit::Logger::new(Some(&logkit::StdoutTarget));
    logger.mount(logkit::TimePlugin::from_millis());
    logger.mount(logkit::LevelPlugin);
    logger.mount(logkit::SourcePlugin::new());
    logkit::set_default_logger(logger);

    trace!("hello, this is a trace log");
    debug!("hello, this is a debug log");
    info!(version = "0.1.0", commit = "3291cc60"; "this is a log with two string fields");
    warn!(address = "127.0.0.1", port = 3000; "this is a log with a string and a numeric field");
    error!("this is a log with a 'println' style string {}:{}", "127.0.0.1", 3000.0);
}

输出示例

{"time":"2024-06-30T14:43:33.236+08:00","level":"trace","msg":"hello, this is a trace log","src":"examples/hello_world.rs:10"}
{"time":"2024-06-30T14:43:33.236+08:00","level":"debug","msg":"hello, this is a debug log","src":"examples/hello_world.rs:11"}
{"time":"2024-06-30T14:43:33.236+08:00","level":"info","msg":"this is a log with two string fields","version":"0.1.0","commit":"3291cc60","src":"examples/hello_world.rs:12"}
{"time":"2024-06-30T14:43:33.236+08:00","level":"warn","msg":"this is a log with a string and a numeric field","address":"127.0.0.1","port":3000,"src":"examples/hello_world.rs:13"}
{"time":"2024-06-30T14:43:33.236+08:00","level":"error","msg":"this is a log with a 'println' style string 127.0.0.1:3000","src":"examples/hello_world.rs:14"}

基本语法

提供五个方便的宏供使用: tracedebuginfowarnerror。这些支持以下日志格式,并在必要时可以定义自定义宏。

#[macro_use] extern crate logkit;

trace!(); // outputs just a linebreak
trace!("plain message");
trace!("println-like message {} {}!", "Hello", "World");
trace!(name = "Alice", age = 20); // outputs only fields, no message
trace!(name = "Alice", age = 20; "separate fields and messages with semicolon");
trace!(name = "Alice", age = 20; "println-like message {} {}! with fields", "Hello", "World");

默认日志记录器

为了方便,我们已经定义了一个默认的日志记录器,该记录器将消息输出到 stderr。

#[macro_use] extern crate logkit;

assert_eq!(logkit::default_logger().level(), logkit::LEVEL_TRACE);
trace!("hello, this is a trace log");
debug!("hello, this is a debug log");

自定义日志记录器

fn main() {
    let mut logger = logkit::Logger::new(None);
    logger.mount(logkit::LevelPlugin); // you can add your own plugin
    logger.route(logkit::StderrTarget); // and add your custom target

    // replace the default logger
    logkit::set_default_logger(logger);
    // or use it directly like built-in macros
}

自定义级别

有五个内置的日志级别: TRACEDEBUGINFOWARNERROR。您可以定义自己的级别,因为该类型只是 i32 的别名,而不是枚举。

pub const LEVEL_CUSTOM : logkit::Level = 10; // use any number distinct from the built-ins

#[macro_export]
macro_rules! custom {
    ($($arg:tt)*) => {{
        logkit::record!(logkit::default_logger(), LEVEL_CUSTOM, $($arg)*)
    }};
}

custom!("this is a custom log level");

自定义编码

我们支持所有标量类型和许多 std 集合,如果您想将自定义类型编码到 json 中,可以实现 Encode 特性。

pub struct CustomStruct {
    pub key1: i32,
    pub key2: bool,
    pub key3: String,
}

impl logkit::Encode for CustomStruct {
    #[inline]
    fn encode(&self, buf: &mut Vec<u8>) {
        // format your struct into buf
        unimplemented!()
    }
}

日志插件

插件也称为中间件,为 prepost 步骤添加钩子。当日志记录器创建一个记录时,在添加任何字段之前会调用 pre 方法。当记录准备好刷新时,在输出到目标之前会调用 post 方法。您可以向记录中添加任何字段。如果您决定不继续处理记录,只需在 prepost 中返回 false 即可。如果返回 false,则记录将不再进一步处理。

#[macro_use] extern crate logkit;

// custom plugin to add 'pid' to record
pub struct PidPlugin { pub pid: u32 }

impl logkit::Plugin for PidPlugin {
    #[inline]
    fn post(&self, record: &mut logkit::Record) -> bool {
        record.append("pid", &self.pid);
        true
    }
}

fn main() {
    let mut logger = logkit::Logger::new(Some(&logkit::StderrTarget));
    logger.mount(PidPlugin { pid: std::process::id() });
    logkit::set_default_logger(logger);

    info!("you will see this log with a process id");
}
#[macro_use] extern crate logkit;

// custom plugin to filter all levels below 'info'
pub struct LimitPlugin;

impl logkit::Plugin for LimitPlugin {
    #[inline]
    fn pre(&self, record: &mut logkit::Record) -> bool {
        record.level() >= logkit::LEVEL_INFO
    }
}

fn main() {
    let mut logger = logkit::Logger::new(Some(&logkit::StderrTarget));
    logger.mount(LimitPlugin);
    logkit::set_default_logger(logger);

    debug!("this log is ignored");
    info!("you can see this log");
}

输出目标

完成后,记录将路由到各种目标,这些目标定义了输出内容的方法。记录可以指向多个目标,每个目标只需要实现 Target 特性。

#[macro_use] extern crate logkit;

pub struct CustomTarget;

impl logkit::Target for CustomTarget {
    #[inline]
    fn write(&self, buf: &[u8]) {
        use std::io::Write;
        let _ = std::io::stdout().write_all(buf);
    }
}

fn main() {
    let mut logger = logkit::Logger::new(Some(&logkit::StderrTarget));
    logger.route(CustomTarget);
    logkit::set_default_logger(logger);

    info!("record will be output to both stderr and stdout now");
}

基准测试

  • MacBook Air,Apple M2 24G,Sonoma 14.2.1
名称 时间
empty_log [22.526 纳秒 22.541 纳秒 22.560 纳秒]
关闭级别 [1.6941 纳秒 1.6989 纳秒 1.7050 纳秒]
仅消息 [63.166 纳秒 63.172 纳秒 63.177 纳秒]
消息格式 [63.238 纳秒 63.373 纳秒 63.548 纳秒]
仅字段 [96.944 纳秒 96.974 纳秒 97.005 纳秒]
字段消息 [147.03 纳秒 147.26 纳秒 147.56 纳秒]
字段消息格式 [146.44 纳秒 146.51 纳秒 146.58 纳秒]
字段十字段 [395.31 纳秒 395.35 纳秒 395.40 纳秒]
  • AWS c5.2xlarge, 8C 16G, Ubuntu 22.04
名称 时间
empty_log [50.761 纳秒 50.764 纳秒 50.768 纳秒]
关闭级别 [4.1800 纳秒 4.1804 纳秒 4.1810 纳秒]
仅消息 [121.12 纳秒 121.14 纳秒 121.16 纳秒]
消息格式 [121.18 纳秒 121.20 纳秒 121.23 纳秒]
仅字段 [177.70 纳秒 177.74 纳秒 177.77 纳秒]
字段消息 [264.25 纳秒 264.33 纳秒 264.45 纳秒]
字段消息格式 [261.80 纳秒 261.89 纳秒 261.98 纳秒]
字段十字段 [654.11 纳秒 654.31 纳秒 654.51 纳秒]

依赖关系

~11MB
~211K SLoC