rust-flexi_logger

flexi_logger 是字节开源的rust日志库。目前有log4rs、env_log 等库,综合比较下来,还是flexi_logger简单容易上手,而且自定义很方便,以及在效率方面感觉也会高,下篇文章我们来测试下。
下面来看下怎么使用
关注 vx golang技术实验室,获取更多好文

一、启动日志的三种方式

引入包

flexi_logger = { version = "0.25.3", features = ["specfile", "compress"] }

通过选择三个选项之一来指定您想要查看的日志输出进行初始化,并start()立即调用:

  • 在环境变量中提供日志规范RUST_LOG

    Logger::try_with_env()?.start()?;
    
  • 以编程方式提供日志规范:

    Logger::try_with_str("info")?.start()?;
    
  • 结合两个选项:

    Logger::try_with_env_or_str("info")?.start()?;
    

之后,您只需使用日志箱中的日志宏即可。然后,那些与日志规范匹配的日志行将被写入默认输出通道 (stderr)。

二、日志输出通道

2.1 写入到文件

assert_eq!(
    FileSpec::default()
        .directory("/a/b/c")//输出的目录
        .basename("foo")//输出的文件名
        .suppress_timestamp()//是否添加时间
        .suffix("bar"),//添加的后缀
        .discriminant("Sample4711A") .//使用FileSpec::discriminant 您可以向日志文件名添加有区别的中缀。
    FileSpec::try_from("/a/b/c/foo.bar").unwrap()//
);
$ ll log_files
total 16
-rw-r--r--  1 xxx  staff  70 Oct 27 16:47 foo.bar //使用suppress_timestamp
-rw-r--r--  1 xxx  staff  70 Oct 27 16:47 foo_2023-10-27_16-47-53.bar
-rw-r--r--  1 xxx  staff  70 Oct 27 17:01 foo_Sample4711A_2023-10-27_17-01-11.bar

如果给定路径的基本名称没有文件名,则会发生恐慌

三、写入模式

默认情况下,每个日志行都直接写入输出,而不进行缓冲。这允许实时查看新的日志行。

您有Logger::write_mode 一些选择来改变这种行为,例如

-

pub enum WriteMode {
    Direct,
    SupportCapture,
    BufferAndFlush,
    BufferAndFlushWith(usize, Duration),
    BufferDontFlush,
    BufferDontFlushWith(usize),
    Async,
    AsyncWith {
        pool_capa: usize,
        message_capa: usize,
        flush_interval: Duration,
    },
}
  • Direct

    不缓冲(默认)。

    每个日志行都直接写入输出,无需缓冲。这允许实时查看新的日志行,并且不需要额外的线程。

  • SupportCapture

​ 不缓冲和支持cargo test捕获。

​ 很像Direct,只是慢一点,并且允许 cargo test捕获日志输出并仅在失败的测试时打印它。

  • BufferAndFlush

BufferAndFlushWith与默认容量 ( DEFAULT_BUFFER_CAPACITY) 和默认间隔 ( )相同DEFAULT_FLUSH_INTERVAL

pub const DEFAULT_BUFFER_CAPACITY: usize = _; // 8_192usize 8k
pub const DEFAULT_FLUSH_INTERVAL: Duration;//1s
  • BufferAndFlushWith(usize, Duration)
元组字段
0: usize
缓冲能力。

1: Duration
冲洗间隔。

以给定的缓冲区容量和刷新间隔进行缓冲和刷新。
和上面的一样,是指指定size和刷新时间
  • BufferDontFlush

BufferDontFlushWith与默认容量相同( DEFAULT_BUFFER_CAPACITY)。达到8k刷新

  • BufferDontFlushWith(usize)

​ 元组字段

0: usize

​ 缓冲能力。

​ 具有给定缓冲区容量的缓冲区,但不刷新。

​ 如果您想最大程度地减少 I/O 工作量并且不想创建额外的线程用于刷新并且不关心日志行是否出现延迟,这可能会很方便。

  • Async

与 相同AsyncWith,所有参数均使用默认值。

  • AsyncWith
Fields
pool_capa: usize
消息缓冲区池的容量。

message_capa: usize
单个消息缓冲区的容量。

flush_interval: Duration
刷新输出的时间间隔。

随着Duration::ZERO冲洗被抑制。

日志行通过无界通道发送到输出线程,该线程执行 I/O,如果log_to_file()选择的话,还执行轮换和清理。

使用缓冲输出来减少开销,并使用有界消息池来减少分配。日志输出按照给定的时间间隔定期刷新。

  • 使用WriteMode::BufferAndFlush、 或WriteMode::BufferAndFlushWith,您可以减少程序的 I/O 开销,从而提高整体性能,如果大量使用日志记录,这可能是相关的。此外,为了在日志行在输出通道中可见之前保持较短的最大等待时间,会创建一个额外的线程来定期刷新缓冲区。

    fn main() -> Result<(), Box<dyn std::error::Error>> {
        let _logger = Logger::try_with_str("info")?
           .log_to_file(FileSpec::default())
           .write_mode(WriteMode::BufferAndFlush)
           .start()?;
        // ... do all your work ...
        Ok(())
    }
    
  • 使用WriteMode::Async 或 时WriteMode::AsyncWith,日志通过无界通道从应用程序线程发送到输出线程,该输出线程执行输出(以及轮换和清理,如果适用)。此外,输出被缓冲,并且使用有界消息池来减少分配,并使用刷新来避免长时间延迟。如果使用复制,则消息将同步写入stdoutstderr

    fn main() -> Result<(), Box<dyn std::error::Error>> {
        let _logger = Logger::try_with_str("info")?
           .log_to_file(FileSpec::default())
           .write_mode(WriteMode::Async)
           .start()?;
        // ... do all your work ...
        Ok(())
    }
    

四、日志格式

4.1 自定义输出格式

use flexi_logger::{ DeferredNow, Record};

fn custom_format(
    w: &mut dyn std::io::Write,
    now: &mut DeferredNow,
    record: &Record,
) -> Result<(), std::io::Error> {
    write!(
        w,
        "[{}] [{}] {}: {}",
        now.now().format("%Y-%m-%d %H:%M:%S"),
        record.level(),
        record.module_path().unwrap_or("<unnamed>"),
        record.args()
    )
}

   let _logger = Logger::try_with_str("debug, my::critical::module=trace").unwrap()
        .log_to_file(
            FileSpec::default().
                directory("./log_files").
                basename("foo").
                // suppress_timestamp().
                suffix("bar").
                discriminant("Sample4711A")
        )
        .duplicate_to_stderr(Duplicate::Debug)// print warnings and errors also to the console
        .write_mode(WriteMode::BufferAndFlush).
        format(custom_format)//定义的输出格式
            .start().

        unwrap();

[2023-10-27 17:32:08] [DEBUG] my_test: s
[2023-10-27 17:32:08] [INFO] my_test: s
[2023-10-27 17:32:08] [WARN] my_test: s
[2023-10-27 17:32:08] [ERROR] my_test: s

        

4. 2 使用默认的日志格式

## opt_format
[2023-10-27 17:34:23.438382 +08:00] DEBUG [src/main.rs:50] s
[2023-10-27 17:34:23.439057 +08:00] INFO [src/main.rs:51] s
[2023-10-27 17:34:23.439078 +08:00] WARN [src/main.rs:52] s
[2023-10-27 17:34:23.439091 +08:00] ERROR [src/main.rs:53] s

## default_format
DEBUG [my_test] s
INFO [my_test] s
WARN [my_test] s
ERROR [my_test] s

## detailed_format
[2023-10-27 17:36:12.719699 +08:00] DEBUG [my_test] src/main.rs:50: s
[2023-10-27 17:36:12.719948 +08:00] INFO [my_test] src/main.rs:51: s
[2023-10-27 17:36:12.719964 +08:00] WARN [my_test] src/main.rs:52: s
[2023-10-27 17:36:12.719978 +08:00] ERROR [my_test] src/main.rs:53: s

## with_thread
[2023-10-27 17:36:41.542709 +08:00] T[main] DEBUG [src/main.rs:50] s
[2023-10-27 17:36:41.542968 +08:00] T[main] INFO [src/main.rs:51] s
[2023-10-27 17:36:41.542984 +08:00] T[main] WARN [src/main.rs:52] s
[2023-10-27 17:36:41.542997 +08:00] T[main] ERROR [src/main.rs:53] s

4.2 默认的彩色输出

## colored_default_format

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

## colored_detailed_format

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

## colored_opt_format

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

和上面的是一一对应的

4.4 日志文件截取

无论Logger::log_to_file是否进行轮换, flexi_logger默认情况下都会使用名称中带有时间戳的文件,例如 foo_2020-11-16_08-37-44.log(对于名为 的程序foo),这些文件对于每个程序启动来说都是非常唯一的。

这样FileSpec::suppress_timestamp 您就可以获得一个简单的固定文件名,例如foo.log.

在这种情况下,重新启动程序将截断现有日志文件。

另外使用Logger::append 将每次新运行的日志附加到现有文件中。

Logger::try_with_str("info")? // Write all error, warn, and info messages
    // use a simple filename without a timestamp
    .log_to_file(
        FileSpec::default().suppress_timestamp()
    )
    // do not truncate the log file when the program is restarted
    .append()
    .start()?;

通过轮换,日志始终会写入带有中缀的文件中rCURRENT,例如foo_rCURRENT.log

Logger::rotate 采用三个定义其行为的枚举参数:

  • Criterion

    • Criterion::Age当时钟切换到新的一天、小时、分钟或秒时,就会发生旋转
    • Criterion::Size当当前日志文件超过指定限制时发生轮转
    • Criterion::AgeOrSize当达到两个限制中的任何一个时,就会发生旋转
  • Naming
    然后将当前文件重命名

    • Naming::Timestamps类似的东西foo_r2020-11-16_08-56-52.log
    • Naming::Numbers类似的东西foo_r00000.log

    rCURRENT创建一个新文件。

  • Cleanup定义是否以及如何避免无限期累积日志文件:

    • 您指定Cleanup::KeepLogFiles应保留的日志文件的数量;如果有更多,较旧的将被删除
    • 您指定Cleanup::KeepCompressedFiles应保留的日志文件的数量,并且这些文件将被额外压缩
    • 您可以Cleanup::KeepLogAndCompressedFiles 指定应按原样保留的日志文件数量以及正在压缩的附加数量
    • 如果Cleanup::Never不进行清理,所有文件都会保留。

案例

Logger::try_with_str("info")?      // Write all error, warn, and info messages
    .log_to_file(
        FileSpec::default()
    )
    .rotate(                      // If the program runs long enough,
        Criterion::Age(Age::Day), // - create a new file every day
        Naming::Timestamps,       // - let the rotated files have a timestamp in their name
        Cleanup::KeepLogFiles(7), // - keep at most 7 log files
    )
    .start()?;
    
-rw-r--r--  1 xxx  staff  1508 Oct 27 18:46 foo_Sample4711A_rCURRENT.bar

五、代码方式启动

5.1 程序中设置

    let _logger = Logger::try_with_str("debug, my::critical::module=trace").unwrap()
        .log_to_file(
            FileSpec::default().
                directory("./log_files").
                basename("foo").
                suppress_timestamp().
                suffix("bar").
                discriminant("Sample4711A")
        )
        .duplicate_to_stderr(Duplicate::Debug)// print warnings and errors also to the console
        .write_mode(WriteMode::BufferAndFlush).
        format(colored_opt_format).
        append()
        .rotate(                      // If the program runs long enough,
                                      Criterion::AgeOrSize(Age::Day,10000000000000), // - create a new file every day
                                      Naming::Timestamps,       // - let the rotated files have a timestamp in their name
                                      Cleanup::KeepLogFiles(7), // - keep at most 7 log files
        )
        .start().
        unwrap();

这里我们使用了配置字符串 "debug, my::critical::module=trace",表示全局默认日志级别为 debug,而模块路径为 my::critical::module 的日志级别为 trace

5.2 文件设置

Logger::try_with_str("info").unwrap()
    // ... logger configuration ...
   .start_with_specfile("./server/config/logspec.toml")
   .unwrap();


将创建包含以下内容的文件logspecification.toml(如果尚不存在):

### Optional: Default log level
global_level = 'info'
### Optional: specify a regular expression to suppress all messages that don't match
#global_pattern = 'foo'

### Specific log levels per module are optionally defined in this section
[modules]
#'mod1' = 'warn'
#'mod2' = 'debug'
#'mod2::mod3' = 'trace'

随后,您可以根据需要编辑和修改该文件,在程序运行时,它将立即考虑您的更改。

目前仅支持 toml 文件,因此文件后缀必须是.toml.

如果无法读取文件,则初始规范仍然有效。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/195208.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于M估计样本一致性算法的点云平面拟合

平面拟合 1、算法简介2、参考文献3、实现效果4、相关代码 1、算法简介 RANSAC 是在给定模型和距离阈值 T T T的情况下&#xff0c;通过寻找最小代价 C C C来确定内点数据并拟合模型。如式&#xff08;1&#xff09;所示的代价函数&#xff0c;当点到模型的距离 e e e小于阈值 T…

服务器运行情况及线上排查问题常用命令

一、top命令 指令行&#xff1a; top返回&#xff1a; 返回分为两部分 &#xff08;一&#xff09;系统概览&#xff0c;见图知意 以下是几个需要注意的参数 1、load average&#xff1a; 系统负载&#xff0c;即任务队列的平均长度。三个数值分别为 1分钟、5分钟、15分…

华为拆分零部件业务,长安入股,赛力斯接洽中

作者 |德新 编辑 |王博 11月26日&#xff0c;长安汽车官宣与华为在智能汽车零部件业务上的投资与合作&#xff1a; 华为拟成立一家新的公司&#xff0c;并将其在智能汽车解决方案业务上的核心技术和资源注入新公司&#xff0c;长安汽车及关联方有意投资该新公司。 参照目前长…

基于Webserver的工业数据采集控制

http协议 http简介 HTTP协议是Hyper Text Transfer Protocol&#xff08;超文本传输协议&#xff09;的缩写&#xff0c;是用于Web Browser&#xff08;浏览器&#xff09;到Web Server&#xff08;服务器&#xff09;进行数据交互的传输协议。 HTTP是应用层协议 HTTP是一个基于…

【日常总结】Swagger 3.0 + 集成 knife4j ,并设置header入参

一、场景 环境&#xff1a; 二、问题 思路 &#xff1a; 三、解决方案 &#xff08;推荐&#xff09; Stage 1&#xff1a;接入knife4j 依赖 Stage 2&#xff1a;修改 yaml 配置 Stage 3&#xff1a;修改 swagger 3 配置文件 Stage 4&#xff1a;查看效果 Swagger UI …

Spring源码解读之创建bean

本文章我们会解读一下Spring如何根据beanDefinition创建bean的&#xff1b; 代码入口&#xff1a; AnnotationConfigApplicationContext applicationContext new AnnotationConfigApplicationContext(AppConfig.class);applicationContext.refresh(); 当spring执行refresh(…

使用vscode中编写c语言——无法打开 源 文件 “stdlib.h“C/C++(1696)问题

出现这个问题原因如下&#xff1a; 1、没有下载编辑器或者是没有配置好该编辑器的环境变量。 可以通过如下方法检查是否安装并配置好编辑器&#xff1a;打开终端&#xff1a;按winR cmd&#xff0c;然后输入gcc-v&#xff0c;查看是否有mingw64编辑器&#xff0c;如下图是已经…

什么是yum?

&#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;推荐专栏1: &#x1f354;&#x1f35f;&#x1f32f;C语言初阶 &#x1f43b;推荐专栏2: &#x1f354;&#x1f35f;&#x1f32f;C语言进阶 &#x1f511;个人信条: &#x1f335;知行合一 &#x1f…

JAVA进阶之路JVM-2:类加载机制,类的生命周期,类加载过程,类加载时机,类加载器,双亲委派模型,对象创建过程

JVM类加载机制 类加载 ​ 在JVM虚拟机实现规范中&#xff0c;通过ClassLoader类加载把*.class字节码文件&#xff08;文件流&#xff09;加载到内存&#xff0c;并对字节码文件内容进行验证&#xff0c;准备&#xff0c;解析和初始化&#xff0c;最终形成可以被虚拟机直接使用…

易基因: MeRIP-seq等从m6A RNA甲基化角度揭示NFATc1对破骨细胞的调控机制|研究速递

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 双膦酸盐类药物是强效骨吸收抑制剂&#xff0c;是治疗骨质疏松症、多发性骨髓瘤、骨转移等疾病的首选药物。这些药物通过抑制甲羟戊酸通路和促进破骨细胞凋亡来促进骨吸收。双膦酸盐类药…

计算机网络:快速了解网络框架

文章目录 前言一、什么是Internet&#xff1f;1.从具体构成角度什么是协议&#xff1f; 2.从服务角度3小结 二、网络边缘1.采用网络设施面向连接服务&#xff08;TCP&#xff09;2.采用基础设施的无连接服务&#xff08;UDP&#xff09; 三、网络的核心1.电路交换2.分组交换3.分…

如何在外远程访问本地NAS威联通QNAP?

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;数据结构、Cpolar杂谈 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. 威联通安装cpolar内网穿透二. 内网穿透2.1 创建隧道2.2 测试公网远程访问 三.…

DDD全网最通俗易懂讲解(二)

领域事件相关案例 我来给你介绍一个保险承保业务过程中有关领域事件的案例。 一个保单的生成&#xff0c;经历了很多子域、业务状态变更和跨微服务业务数据的传递。这个过程会产生很多的领域事件&#xff0c;这些领域事件促成了保险业务数据、对象在不同的微服务和子域之间的…

数据库基础入门 — 关联查询

我是南城余&#xff01;阿里云开发者平台专家博士证书获得者&#xff01; 欢迎关注我的博客&#xff01;一同成长&#xff01; 一名从事运维开发的worker&#xff0c;记录分享学习。 专注于AI&#xff0c;运维开发&#xff0c;windows Linux 系统领域的分享&#xff01; 本…

docker容器运维操作命令

docker exec &#xff1a;在运行的容器中执行命令 docker exec [OPTIONS] CONTAINER COMMAND [ARG...] OPTIONS说明&#xff1a; -d :分离模式: 在后台运行 -i :即使没有附加也保持STDIN 打开 -t :分配一个伪终端docker ps : 列出容器 docker ps [OPTIONS] OPTIONS说明&#…

P8安全基本理论A001-CIA安全模型-使用PGP描述网络安全CIA模型之私密性、完整性案例

【教学资源名称】 CIA安全模型-使用PGP描述网络安全CIA模型之私密性、完整性案例 【预备知识】 在信息安全等级保护工作中&#xff0c;根据信息系统的机密性&#xff08;Confidentiality&#xff09;、完整性&#xff08;Integrity&#xff09;、可用性&#xff08;Availabilit…

MySQL的索引

&#x1f4d1;打牌 &#xff1a; da pai ge的个人主页 &#x1f324;️个人专栏 &#xff1a; da pai ge的博客专栏 ☁️宝剑锋从磨砺出&#xff0c;梅花香自苦寒来 目录 &#x1f324;️概念 &#x1f…

vue3安装eslint和prettier,最简单的步骤

第1步&#xff1a; 安装eslint yarn add eslint -D 第2步&#xff1a; 在根文件夹中&#xff0c;创建.eslintrc.js文件 第3步&#xff1a; 在package.json文件中新增命令 "lint": "eslint --fix --ext .ts,.tsx,.vue src --quiet","prettier"…

Day49:647. 回文子串、516.最长回文子序列

文章目录 647. 回文子串思路代码实现 516.最长回文子序列思路代码实现 647. 回文子串 题目链接 思路 确定dp数组&#xff08;dp table&#xff09;以及下标的含义 布尔类型的dp[i][j]&#xff1a;表示区间范围[i,j] &#xff08;注意是左闭右闭&#xff09;的子串是否是回文…

第20章 多线程

创建线程 继承Thread 类 Thread 类时 java.lang 包中的一个类&#xff0c;从类中实例化的对象代表线程&#xff0c;程序员启动一个新线程需要建立 Thread 实例。 Thread 对象需要一个任务来执行&#xff0c;任务是指线程在启动时执行的工作&#xff0c;start() 方法启动线程&am…