#logger #logging #log #simple-log

已删除 nolog-plain

一个用于写入文件的简单nolog日志记录器的非彩色版本

0.2.1 2022年7月10日
0.2.0 2022年7月10日
0.1.2 2022年7月9日
0.1.1 2022年7月9日
0.1.0 2022年7月9日

#303 in #logger

MIT 许可证

86KB

nolog-plain 日志记录器

20行代码,无依赖。

一个用于写入文件的简单 nolog 日志记录器的非彩色版本。如果您需要彩色输出,请参考 nolog 包(有相同的20行代码,但带有彩色输出)。

  • 支持命名格式参数 info!("{line_count} lines.");
  • 显示代码位置 [src/main.rs 15:5]
  • 易于添加时间戳 [2022-07-10 06:49:33.646361181 UTC]
  • 在发布构建中自动禁用 cargo run --release。您可以修改代码来禁用此功能。请参阅“如果您不需要在发布构建中禁用日志”部分。
  • log 包具有相同的语法。随着项目的增长,可以在不更改代码的情况下迁移到高级日志记录器(使用 log 包外观)。
  • 可以直接构建到项目中,而不是作为依赖项。
  • 使用Rust的内置宏。
  • 易于修改以重定向日志输出(到 stderrfile)。
  • MIT 许可证。

nolog

将 nolog-plain 作为文件日志记录的依赖项

Cargo.toml

nolog-plain = "0.2.1"

下载下面的示例

git clone https://github.com/vglinka/nolog-plain
cd ./nolog-plain/
cargo run --example base
cargo run --example to-file
cargo run --example to-stderr

cargo run --example to-file-debug-plus-release
cargo run --example to-file-debug-plus-release --release
cd ./examples/as-dep-to-file-timestamp-chrono/
cargo run 
cd ./examples/as-dep-to-file/
cargo run 

logger.rs:

/* ----------------------------------------------------------------------------
MIT License

Copyright (c) 2022 Vadim Glinka

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---------------------------------------------------------------------------- */

pub use nolog_plain::{crit, debug, error, info, trace, warn /* writelog */};
// We don't import writelog because we want to override it --- ^^^^^^^^

#[rustfmt::skip] #[macro_export] #[cfg(debug_assertions)] macro_rules!
writelog { ( $msg:expr ) => { log($msg) } }
//                            ^^^
// function `log` instead of `println` macro.

use std::fmt::Arguments;
use std::fs::OpenOptions;
use std::io::{BufWriter, Write};
use std::path::PathBuf;

pub struct LogFile;

impl LogFile {
    pub fn path() -> PathBuf {
        PathBuf::from("log.txt")
    }
}

#[rustfmt::skip]
pub fn log(msg: Arguments) {
//              ^^^^^^^^^ std::fmt::Arguments
    let path = LogFile::path();
    let open_file = |path| { OpenOptions::new()
        .create(true)
        .write(true)
        .append(true)
        .open(&path)
    };
    if let Ok(file) = open_file(path) {
        let mut buf = BufWriter::new(file);
        writeln!(buf, "{msg}").ok();
        buf.flush().ok();
    };
}

main.rs:

mod logger;

use crate::logger::*;
//         ^^^^^^^^^
// It must be imported in each module in which we will use logging.

use std::fs::OpenOptions;
use std::io;
use std::io::prelude::*;

fn main() -> io::Result<()> {
    let path = LogFile::path();
    let mut file = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .truncate(true)
        //^^^^^^^ truncate the file to 0 length if it already exists.
        .open(&path)?;

    let a = 42;
    trace!("text {a},{a},{a}");
    debug!("text {a},{},{}", a, 24);
    info!("text {},{},{}", a, 24, "42");
    warn!("text {a},{},{}", 'a', "422");
    error!("text {a},{a},{}", a);
    crit!("text {a},{a},{a}");

    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    println!("-- In {path:?} --");
    println!("{contents}");

    /* Output:
    -- In "log.txt" --
    TRCE: text 42,42,42 [src/main.rs 29:5]
    DEBG: text 42,42,24 [src/main.rs 30:5]
    INFO: text 42,24,42 [src/main.rs 31:5]
    WARN: text 42,a,422 [src/main.rs 32:5]
    ERRO: text 42,42,42 [src/main.rs 33:5]
    CRIT: text 42,42,42 [src/main.rs 34:5]
    */

    Ok(())
}

直接使用 nolog-plain

同样的事情,只是在 Cargo.toml 中我们不添加 nolog-plain 作为依赖,在 logger.rs 中我们复制这个库的全部代码(所有20行)

/* ----------------------------------------------------------------------------
MIT License

Copyright (c) 2022 Vadim Glinka

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---------------------------------------------------------------------------- */

#[rustfmt::skip] #[macro_export] #[cfg(debug_assertions)] macro_rules!
trace { ( $($msg:expr),* ) => { writelog!(format_args!("TRCE: {} [{} {}:{}]", format_args!($($msg),*), file!(), line!(), column!())) } }
#[rustfmt::skip] #[macro_export] #[cfg(debug_assertions)] macro_rules!
debug { ( $($msg:expr),* ) => { writelog!(format_args!("DEBG: {} [{} {}:{}]", format_args!($($msg),*), file!(), line!(), column!())) } }
#[rustfmt::skip] #[macro_export] #[cfg(debug_assertions)] macro_rules!
info { ( $($msg:expr),* )  => { writelog!(format_args!("INFO: {} [{} {}:{}]", format_args!($($msg),*), file!(), line!(), column!())) } }
#[rustfmt::skip] #[macro_export] #[cfg(debug_assertions)] macro_rules!
warn { ( $($msg:expr),* )  => { writelog!(format_args!("WARN: {} [{} {}:{}]", format_args!($($msg),*), file!(), line!(), column!())) } }
#[rustfmt::skip] #[macro_export] #[cfg(debug_assertions)] macro_rules!
error { ( $($msg:expr),* ) => { writelog!(format_args!("ERRO: {} [{} {}:{}]", format_args!($($msg),*), file!(), line!(), column!())) } }
#[rustfmt::skip] #[macro_export] #[cfg(debug_assertions)] macro_rules!
crit { ( $($msg:expr),* )  => { writelog!(format_args!("CRIT: {} [{} {}:{}]", format_args!($($msg),*), file!(), line!(), column!())) } }

#[rustfmt::skip] #[macro_export] #[cfg(not(debug_assertions))] macro_rules! trace { ( $($msg:expr),* ) => () }
#[rustfmt::skip] #[macro_export] #[cfg(not(debug_assertions))] macro_rules! debug { ( $($msg:expr),* ) => () }
#[rustfmt::skip] #[macro_export] #[cfg(not(debug_assertions))] macro_rules! info  { ( $($msg:expr),* ) => () }
#[rustfmt::skip] #[macro_export] #[cfg(not(debug_assertions))] macro_rules! warn  { ( $($msg:expr),* ) => () }
#[rustfmt::skip] #[macro_export] #[cfg(not(debug_assertions))] macro_rules! error { ( $($msg:expr),* ) => () }
#[rustfmt::skip] #[macro_export] #[cfg(not(debug_assertions))] macro_rules! crit  { ( $($msg:expr),* ) => () }

#[rustfmt::skip] #[macro_export] #[cfg(debug_assertions)] macro_rules!
writelog { ( $msg:expr ) => { log($msg) } }
//                            ^^^
// function `log` instead of `println` macro.

use std::fmt::Arguments;
use std::fs::OpenOptions;
use std::io::{BufWriter, Write};
use std::path::PathBuf;

pub struct LogFile;

impl LogFile {
    pub fn path() -> PathBuf {
        PathBuf::from("log.txt")
    }
}

#[rustfmt::skip]
pub fn log(msg: Arguments) {
//              ^^^^^^^^^ std::fmt::Arguments
    let path = LogFile::path();
    let open_file = |path| { OpenOptions::new()
        .create(true)
        .write(true)
        .append(true)
        .open(&path)
    };
    if let Ok(file) = open_file(path) {
        let mut buf = BufWriter::new(file);
        writeln!(buf, "{msg}").ok();
        buf.flush().ok();
    };
}

现在你有了日志记录器,没有新的依赖。

如何添加时间戳

例如,我们将使用 chrono crate

-- In "log.txt" --
[2022-07-10 06:49:33.646361181 UTC] TRCE: text 42,42,42 [src/main.rs 22:5]
[2022-07-10 06:49:33.646393648 UTC] DEBG: text 42,42,24 [src/main.rs 23:5]
[2022-07-10 06:49:33.646405179 UTC] INFO: text 42,24,42 [src/main.rs 24:5]
[2022-07-10 06:49:33.646415125 UTC] WARN: text 42,a,422 [src/main.rs 25:5]
[2022-07-10 06:49:33.646424722 UTC] ERRO: text 42,42,42 [src/main.rs 26:5]
[2022-07-10 06:49:33.646434216 UTC] CRIT: text 42,42,42 [src/main.rs 27:5]

查看示例代码.

如果你不需要在发布构建中禁用日志记录

这将使代码更加简洁

/* ----------------------------------------------------------------------------
MIT License

Copyright (c) 2022 Vadim Glinka

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---------------------------------------------------------------------------- */

#[rustfmt::skip] #[macro_export] macro_rules!
trace { ( $($msg:expr),* ) => { writelog!(format_args!("TRCE: {} [{} {}:{}]", format_args!($($msg),*), file!(), line!(), column!())) } }
#[rustfmt::skip] #[macro_export] macro_rules!
debug { ( $($msg:expr),* ) => { writelog!(format_args!("DEBG: {} [{} {}:{}]", format_args!($($msg),*), file!(), line!(), column!())) } }
#[rustfmt::skip] #[macro_export] macro_rules!
info { ( $($msg:expr),* )  => { writelog!(format_args!("INFO: {} [{} {}:{}]", format_args!($($msg),*), file!(), line!(), column!())) } }
#[rustfmt::skip] #[macro_export] macro_rules!
warn { ( $($msg:expr),* )  => { writelog!(format_args!("WARN: {} [{} {}:{}]", format_args!($($msg),*), file!(), line!(), column!())) } }
#[rustfmt::skip] #[macro_export] macro_rules!
error { ( $($msg:expr),* ) => { writelog!(format_args!("ERRO: {} [{} {}:{}]", format_args!($($msg),*), file!(), line!(), column!())) } }
#[rustfmt::skip] #[macro_export] macro_rules!
crit { ( $($msg:expr),* )  => { writelog!(format_args!("CRIT: {} [{} {}:{}]", format_args!($($msg),*), file!(), line!(), column!())) } }

#[rustfmt::skip] #[macro_export] macro_rules!
writelog { ( $msg:expr ) => { println!("{}", $msg) } }

变更日志

  • 0.2.1 – 修改了 README.md 和示例。
  • 0.2.0 – 将宏调用 format!() 替换为调用 format_args!(),因为 format_args!() 避免了堆分配。所有示例都已更新。使用 std::fmt::Arguments 替代了 String。请参阅 示例
  • 0.1.2 – 修改了 README.md 和示例。
  • 0.1.1 – 修改了 README.md 和示例。

无运行时依赖