4个版本 (2个破坏性更新)

0.3.1 2023年11月20日
0.3.0 2023年11月20日
0.2.0 2023年11月15日
0.1.0 2023年11月11日

#279 in 调试

Download history 47/week @ 2024-04-14 48/week @ 2024-04-21 56/week @ 2024-04-28 69/week @ 2024-05-05 44/week @ 2024-05-12 37/week @ 2024-05-19 30/week @ 2024-05-26 28/week @ 2024-06-02 119/week @ 2024-06-09 89/week @ 2024-06-16 63/week @ 2024-06-23 76/week @ 2024-06-30 79/week @ 2024-07-07 61/week @ 2024-07-14 73/week @ 2024-07-21 167/week @ 2024-07-28

每月383次下载

AGPL-3.0

21KB
248

带压缩的滚动日志文件

此库提供了LogFileInitializer结构体,用于在日志目录内获取日志文件。它使用类似于上方轮盘图的滚动策略 🎡

初始化器包含字段directoryfilenamemax_n_old_filespreferred_max_file_size_mib

以下所有条件都为真时,将对文件directory/file应用滚动

  • 文件已存在。
  • 文件大小 >= preferred_max_file_size_mib(以MiB计)。
  • 今天尚未进行滚动。

在滚动的情况下,文件将被压缩为GZIP格式并保存为directory/filename-YYYYMMDD.gz,日期为今天的UTC日期。

如果应用了滚动并且旧文件数量超过max_n_old_files,则最旧的文件将被删除。

重要的是要知道,滚动只发生在初始化时init方法返回一个正常的File。如果程序连续运行多日而不重启,则不会应用滚动。这有以下优点

  • 写入时无需检查何时滚动,无开销。
  • 实际滚动过程中不会出现延迟峰值。
  • 整个运行日志(从开始到终止)都在一个文件中。

程序应该每隔几天重启一次,当系统更新后重启主机。但是,如果您希望在程序运行期间每隔固定天数进行滚动,则可以使用自己的类型,在该类型中,当滚动发生时,在内部调用init方法,然后交换文件。

有关更多详细信息,请阅读 LogFileInitializer 结构体 及其 init 方法 的文档。

示例

我们将看到当使用以下初始化器字段值调用 init 方法 时会发生什么。

use logs_wheel::LogFileInitializer;

let log_file = LogFileInitializer {
  directory: "logs",
  filename: "test",
  max_n_old_files: 2,
  preferred_max_file_size_mib: 1,
}.init()?;

Ok::<(), std::io::Error>(())

该方法调用将始终在结束时返回文件 logs/test。但我们将讨论其副作用。

第一次调用

第一次调用将在当前目录中创建目录 logs/(因为我们指定了相对路径),并在其中创建文件 test

logs/ 的内容

  • test

后续调用

如果我们再次在 2023-11-12(UTC 时间)调用该函数,并且文件 logs/test 的大小大于 1 MiB,则该文件将被压缩为 logs/test-20231112.gz

在截断(空文件)后,将返回文件 logs/test

logs/ 的内容

  • test
  • test-20231112.gz

同一天调用

如果我们再次在同一天调用该函数,即使文件 logs/test 的大小大于 1 MiB,也不会有任何变化。

文件 logs/test 将以追加模式打开。

logs/ 的内容

  • test
  • test-20231112.gz

晚些时候的调用

如果我们第二天再次调用该函数,并且文件 logs/test 的大小大于 1 MiB,则该文件将被压缩为 logs/test-20231113.gz

截断后,将返回文件 logs/test

logs/ 的内容

  • test
  • test-20231113.gz
  • test-20231112.gz

超过旧文件数量的调用

现在,我们已经有 2 个旧文件,这意味着我们达到了限制 max_n_old_files。如果我们第二天再次调用该函数,并且文件 logs/test 的大小大于 1 MiB,则该文件将被压缩为 logs/test-20231114.gz。最旧的文件 test-20231112.gz 将被删除。

截断后,将返回文件 logs/test

logs/ 的内容

  • test
  • test-20231114.gz
  • test-20231113.gz

跟踪订阅者

您可以使用此库与 tracing 生态系统一起使用!

以下是如何将返回的文件用作 tracing subscriber 的示例。

use logs_wheel::LogFileInitializer;
use std::sync::Mutex;

let log_file = LogFileInitializer {
  directory: "logs",
  filename: "test",
  max_n_old_files: 2,
  preferred_max_file_size_mib: 1,
}.init()?;

let writer = Mutex::new(log_file);
let subscriber = tracing_subscriber::fmt()
  .with_writer(writer)
  // … (other `SubscriberBuilder` methods)
  .finish();
# Ok::<(), std::io::Error>(())

类似的项目

  • tracing-appender:在程序运行时提供 RollingFileAppender,每隔固定时间滚动。但它不会压缩旧日志文件,也不会删除任何文件。《tt class="txt-plain">logs-wheel 可以作为替代方案使用。它还可以与 NonBlocking 结合使用,以实现非阻塞写入。
  • rolling-file:在程序运行时提供每隔固定时间的滚动。不进行压缩。在滚动时必须重命名每个文件,因为它们是编号的。

依赖关系

~1MB
~18K SLoC