Rust的高效易用日志库—tklog

很多人习惯于python,go等语言基础工具库的简单易用;在使用rust时,可能感觉比较麻烦,类似日志库这样的基础性工具库。tklog提供用法上,非常类似python等Logger的日志库用法,用法简洁;基于rust的高效性和一些优化策略,tklog的性能非常好,在压测中,可以达到 3-4 µs/op (微妙/次),这个效率比go最高的性能时候都高一些;在相同的环境下,对go进行无格式日志输出压测,可以达到 3-4µs/op,如果是格式化日志输出,则为4µs/op以上。(可以参考《 高性能日志库go-logger v2.0.3》中对各日志库的压测数据)。
在异步场景中,tklog提供了对应的方法,支持异步调用。异步方法最大的好处并非在性能上,而是它不会阻塞所在线程。但是由于 tklog的常规日志方法默认使用延迟策略,实际上也不会阻塞所在线程,或者准确说影响非常小,可以忽略不计。所以,异步场景一般也可以直接使用常规日志打印方法。
相关连接
  • 项目源码
  • 官网
  • 仓库
项目引入
[dependencies]
tklog = "0.0.2"   #使用时的实际最新版本;当前0.0.2版本

tklog是rust高性能结构化日志库
易用,高效,结构化,控制台日志,文件日志,文件切割,文件压缩,同步打印,异步打印

功能
  • 功能支持:控制台日志,文件日志,同步日志,异步日志
  • 日志级别设置:提供与标准库同级别日志打印: trace,debug,info,warn,error,fatal
  • 格式化输出:支持自定义日志的输出格式,包括日志级别标识、格式化时间、日志文件位置 等元素,并支持自定义格式调整。
  • 按时间文件切割:按小时,天,月份切割日志文件
  • 按大小文件切割:按指定大小切割日志文件
  • 文件数回滚:指定最大备份文件数,支持自动删除旧日志文件,并防止日志文件数过多。
  • 文件压缩:支持压缩归档备份日志文件。

使用方法简述

最简单常用的方法:直接调用

use tklog::{trace,debug, error, fatal, info,warn}
fn testlog() {trace!("trace>>>>", "aaaaaaaaa", 1, 2, 3, 4);debug!("debug>>>>", "bbbbbbbbb", 1, 2, 3, 5);info!("info>>>>", "ccccccccc", 1, 2, 3, 5);warn!("warn>>>>", "dddddddddd", 1, 2, 3, 6);error!("error>>>>", "eeeeeeee", 1, 2, 3, 7);fatal!("fatal>>>>", "ffffffff", 1, 2, 3, 8);
}

说明:默认打开控制台日志,没有写日志文件。打印结果:

[TRACE] 2024-05-26 11:47:22 testlog.rs 27:trace>>>>,aaaaaaaaa,1,2,3,4
[DEBUG] 2024-05-26 11:47:22 testlog.rs 28:debug>>>>,bbbbbbbbb,1,2,3,5
[INFO] 2024-05-26 11:47:22 testlog.rs 29:info>>>>,ccccccccc,1,2,3,5
[WARN] 2024-05-26 11:47:22 testlog.rs 30:warn>>>>,dddddddddd,1,2,3,6
[ERROR] 2024-05-26 11:47:22 testlog.rs 31:error>>>>,eeeeeeee,1,2,3,7
[FATAL] 2024-05-26 11:47:22 testlog.rs 32:fatal>>>>,ffffffff,1,2,3,8

说明:直接调用 debug!等宏进行打印,默认调用全局静态LOG对象。LOG对象支持初始化。

use tklog::{sync::Logger,LEVEL, LOG,Format,MODE,
};fn log_init() {LOG.set_console(true)  //设置控制台日志.set_level(LEVEL::Info)  //日志级别,默认Debug.set_format(Format::LevelFlag | Format::Time | Format::ShortFileName)  //结构化日志,定义输出的日志信息.set_cutmode_by_size("tklogsize.txt", 1<<20, 10, true)  //日志文件切割模式为文件大小,每1M文件切分一次,保留10个备份日志文件,并压缩备份日志.set_formatter("{level}{time} {file}:{message}")   //自定义日志输出格式。默认:{level}{time} {file}:{message}
}fn testlog() {log_init()  //调用初始化方法trace!("trace>>>>", "aaaaaaaaa", 1, 2, 3, 4);   //track日志级别小于设置的LEVEL::Info ,故无输出info!("info>>>>", "ccccccccc", 1, 2, 3, 5);
}

以上是全局单实例打印的示例。tklog支持自定义多实例打印。多实例一般应用在系统要求不同打印结构的场景中。

多实例打印
use tklog::{debugs, errors, fatals, infos,sync::Logger,LEVEL, LOG,traces, warns, Format, MODE,
};
fn testmutlilog() {let mut log = Logger::new();log.set_console(true).set_level(LEVEL::Debug) //定义日志级别为Debug.set_cutmode_by_time("tklogs.log", MODE::DAY, 10, true)   //分割日志文件的方式为按天分割,保留最多10个备份,并压缩备份文件.set_formatter("{message} | {time} {file}{level}")   //自定义日志结构信息的输入顺序与附加内容let mut logger = Arc::clone(&Arc::new(Mutex::new(log)));let log = logger.borrow_mut();traces!(log, "traces>>>>", "AAAAAAAAA", 1, 2, 3, 4);debugs!(log, "debugs>>>>", "BBBBBBBBB", 1, 2, 3, 5);infos!(log, "infos>>>>", "CCCCCCCCC", 1, 2, 3, 5);warns!(log, "warns>>>>", "DDDDDDDDDD", 1, 2, 3, 6);errors!(log, "errors>>>>", "EEEEEEEE", 1, 2, 3, 7);fatals!(log, "fatals>>>>", "FFFFFFFF", 1, 2, 3, 8);thread::sleep(Duration::from_secs(1))
}

执行结果:

debugs>>>>,BBBBBBBBB,1,2,3,5 | 2024-05-26 14:13:25 testlog.rs 70[DEBUG]
infos>>>>,CCCCCCCCC,1,2,3,5 | 2024-05-26 14:13:25 testlog.rs 71[INFO]
warns>>>>,DDDDDDDDDD,1,2,3,6 | 2024-05-26 14:13:25 testlog.rs 72[WARN]
errors>>>>,EEEEEEEE,1,2,3,7 | 2024-05-26 14:13:25 testlog.rs 73[ERROR]
fatals>>>>,FFFFFFFF,1,2,3,8 | 2024-05-26 14:13:25 testlog.rs 74[FATAL]

注意:以上输入结构化信息由 "{message} | {time} {file}{level} " formatter决定。formatter中除了关键标识 {message}  {time}  {file}  {level} 外,其他内容原样输出,如 | , 空格,换行  等。


tklog使用详细说明

1. 日志级别 : Trace < Debug < Info < Warn < Error < Fatal

示例:

LOG.set_level(LEVEL::Info)  //日志级别,设置为Info
2. 控制台日志

调用 .set_console(bool) 函数

LOG.set_console(false)   // false表示不打印控制台日志。默认为true
3. 日志格式
  • Format::Nano                            无格式
  • Format::Date                             输出日期 :2024-05-26
  • Format::Time                             输出时间,精确到秒:14:13:25
  • Format::Microseconds              输出时间,精确到微妙:18:09:17.462245    
  • Format::LongFileName             长文件信息+行号:tests estlog.rs 25
  • Format::ShortFileName             短文件信息+行号:testlog.rs 25
  • Format::LevelFlag                      日志级别信息: [Debug]
LOG.set_format(Format::LevelFlag | Format::Time | Format::ShortFileName)  
4.自定义格式输出

默认:"{level}{time} {file}:{message} "

  • {level}            日志级别信息:如[Debug]
  • {time}            日志时间信息
  • {file}               文件位置行号信息
  • {message}      日志内容
LOG.set_formatter("{message} | {time} {file}{level}");  //自定义日志结构信息的输入顺序与附加内容

说明:除了关键标识 {message}  {time}  {file}  {level} 外,其他内容原样输出,如 | , 空格,换行  等。

5.按时间分割日志文件

时间标识:MODE::HOUR,MODE::DAY,MODE::MONTH

分别是:小时,天,月份

调用 .set_cutmode_by_time() 函数,参数:

  1. 文件路径
  2. 时间模式
  3. 最大备份日志文件数
  4. 是否压缩备份的日志文件

示例

let mut log = Logger::new();
log.set_cutmode_by_time("/usr/local/tklogs.log", MODE::DAY, 0, false)

说明:备份文件路径为: /usr/local/tklogs.log  ,时间模式为:按天备份,参数0表示不限制备份文件数,false表示不压缩备份的日志文件

备份的文件格式:

  1. 按天备份日期文件,如:
    • tklogs_20240521.log
    • tklogs_20240522.log
  2. 按小时备份日志文件,如:
    • tklogs_2024052110.log
    • tklogs_2024052211.log
  3. 按月份备份日志文件,如:
    • tklogs_202403.log
    • tklogs_202404.log
6.按大小分割日志文件

调用 .set_cutmode_by_size() 函数,参数:

  1. 文件路径
  2. 指定文件滚动大小
  3. 最大备份日志文件数
  4. 是否压缩备份的日志文件

示例

let mut log = Logger::new();
log.set_cutmode_by_time("tklogs.log", 100<<20, 10, true)

说明:备份文件路径为:tklogs.log  ,按100M大小备份文件,参数10表示只保留最新10个备份文件,true表示压缩备份的日志文件

备份的文件格式:

  • tklogs_1.log.gz
  • tklogs_2.log.gz
  • tklogs_3.log.gz

tklog提供常规日志打印 方法为:

  • 全局单例打印
    1. trace!
    2. debug!
    3. info!
    4. warn!
    5. error!
    6. fatal!
  • 多实例打印
    1. traces!
    2. debugs!
    3. infos!
    4. warns!
    5. errors!
    6. fatals!

异步日志

  • 全局异步单例打印
    1. async_trace!
    2. async_debug!
    3. async_info!
    4. async_warn!
    5. async_error!
    6. async_fatal!
  • 多实例异步打印
    1. async_traces!
    2. async_debugs!
    3. async_infos!
    4. async_warns!
    5. async_errors!
    6. async_fatals!
异步方法使用示例

全局单例异步调用

use tklog::{async_debug,  async_error,  async_fatal,  async_info,  async_trace,  async_warn,  LEVEL, Format, ASYNC_LOG};async fn async_log_init() {// 全局单例设置参数ASYNC_LOG.set_console(false)   //控制台.set_level(LEVEL::Trace)  //日志级别.set_format(Format::LevelFlag | Format::Time | Format::ShortFileName)  //结构化日志,定义输出的日志信息.set_cutmode_by_size("tklog_async.txt", 10000, 10, false).await;  //日志文件切割模式为文件大小,每10000字节切割一次,保留10个备份日志文件#[tokio::test]
async fn testlog() {async_log_init().await;  //参数设置async_trace!("trace>>>>", "aaaaaaa", 1, 2, 3);async_debug!("debug>>>>", "aaaaaaa", 1, 2, 3);async_info!("info>>>>", "bbbbbbbbb", 1, 2, 3);async_warn!("warn>>>>", "cccccccccc", 1, 2, 3);async_error!("error>>>>", "ddddddddddddd", 1, 2, 3);async_fatal("fatal>>>>", "eeeeeeeeeeeeee", 1, 2, 3);tokio::time::sleep(tokio::time::Duration::from_secs(3)).await;
}

输出结果:

[TRACE] 20:03:32 testasynclog.rs 20:trace>>>>,aaaaaaa,1,2,3
[DEBUG] 20:03:32 testasynclog.rs 21:debug>>>>,aaaaaaa,1,2,3
[INFO] 20:03:32 testasynclog.rs 22:info>>>>,bbbbbbbbb,1,2,3
[WARN] 20:03:32 testasynclog.rs 23:warn>>>>,cccccccccc,1,2,3
[ERROR] 20:03:32 testasynclog.rs 24:error>>>>,ddddddddddddd,1,2,3
[FATAL] 20:03:32 testasynclog.rs 25:fatal>>>>,eeeeeeeeeeeeee,1,2,3

多实例异步

use std::sync::Arc;use tklog::{async_debugs,  async_errors,  async_fatals,  async_infos,  async_traces,  async_warns, LEVEL, Format, ASYNC_LOG, MODE
};
#[tokio::test]
async fn testmultilogs() {//新建 Async::Logger 对象let mut log = tklog::Async::Logger::new();log.set_console(false).set_level(LEVEL::Debug).set_cutmode_by_time("tklogasync.log", MODE::DAY, 10, true) .await.set_formatter("{message} | {time} {file}{level}");let mut logger = Arc::clone(&Arc::new(Mutex::new(log)));let log = logger.borrow_mut();async_traces!(log, "async_traces>>>>", "AAAAAAAAAA", 1, 2, 3);async_debugs!(log, "async_debugs>>>>", "BBBBBBBBBB", 1, 2, 3);async_infos!(log, "async_infos>>>>", "CCCCCCCCCC", 1, 2, 3);async_warns!(log, "async_warns>>>>", "DDDDDDDDDD", 1, 2, 3);async_errors!(log, "async_errors>>>>", "EEEEEEEEEEE", 1, 2, 3);async_fatals!(log, "async_fatals>>>>", "FFFFFFFFFFFF", 1, 2, 3);tokio::time::sleep(tokio::time::Duration::from_secs(3)).await;
}

输出结果:

async_debugs>>>>,BBBBBBBBBB,1,2,3 | 2024-05-26 20:10:24 testasynclog.rs 45[DEBUG]
async_infos>>>>,CCCCCCCCCC,1,2,3 | 2024-05-26 20:10:24 testasynclog.rs 46[INFO]
async_warns>>>>,DDDDDDDDDD,1,2,3 | 2024-05-26 20:10:24 testasynclog.rs 47[WARN]
async_errors>>>>,EEEEEEEEEEE,1,2,3 | 2024-05-26 20:10:24 testasynclog.rs 48[ERROR]
async_fatals>>>>,FFFFFFFFFFFF,1,2,3 | 2024-05-26 20:10:24 testasynclog.rs 49[FATAL]


基准压力测试
test_debug              time:   [3.3747 µs 3.4599 µs 3.5367 µs]change: [-69.185% -68.009% -66.664%] (p = 0.00 < 0.05)Performance has improved.
Found 9 outliers among 100 measurements (9.00%)6 (6.00%) high mild3 (3.00%) high severe

说明:时间范围给出了三个数据点,分别代表了测试执行时间的最小值(3.3747微秒)、平均值附近的值(3.4599微秒)、以及最大值(3.5367微秒)

test_debug              time:   [3.8377 µs 3.8881 µs 3.9408 µs]change: [-66.044% -65.200% -64.363%] (p = 0.00 < 0.05)Performance has improved.
Found 2 outliers among 100 measurements (2.00%)2 (2.00%) high mild

说明:测试运行的时间范围是从3.8377微秒到3.9408微秒,覆盖了一个大概的分布情况,其中3.8881微秒大约是这段时间内的平均或中位数执行时间

结论:日志打印函数性能:3 µs/op — 4 µs/op   (微妙/次)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

多线程笔记

1. run() VS start() run()方法&#xff1a; run()方法是java.lang.Runnable接口中定义的一个方法。当一个类实现了Runnable接口&#xff0c;并创建了一个线程对象时&#xff0c;你需要覆盖run()方法来定义线程要执行的任务。run()方法定义了线程的主体逻辑&#xff0c;当线程…

【详细介绍下PostgreSQL】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

Java面试八股之Synchronized锁升级的原理

Synchronized锁升级的原理 Synchronized锁升级是Java为了提高并发性能而引入的一项优化措施&#xff0c;这一机制主要发生在JDK 1.6及之后的版本中。Synchronized锁升级旨在减少锁带来的性能开销&#xff0c;通过从低开销的锁逐步升级到高开销的锁&#xff0c;以适应不同的竞争…

I/O '24|学习资源焕新,技术灵感升级

2024 年 5 月 15 日凌晨举行的 Google I/O 大会为各地的开发者们带来了新的灵感。面对技术革新&#xff0c;相信各位开发者们都迫不及待想要自己上手试一试。 别急&#xff0c;Google 谷歌今年为中国的开发者们准备了一份特别的学习资源&#xff0c;让开发者们自由探索新知。 G…

什么是数字签名,数字签名详解。

数字签名详解 数字签名是一种用于验证数字信息的真实性和完整性的技术&#xff0c;广泛应用于电子商务、软件分发、合同签署等领域。它通过加密技术确保信息在传输过程中未被篡改&#xff0c;并确认发送者的身份。以下是对数字签名的详细介绍。 一、数字签名的基本概念 数字…

蓝桥杯2023(十四届)省赛——岛屿个数(DFS+BFS)

岛屿个数&#xff08;DFSBFS&#xff09; 1.岛屿个数 - 蓝桥云课 (lanqiao.cn) **法一&#xff1a;**本题很妙啊&#xff0c;你发现没有。反向操作&#xff0c;不是直接算岛屿数量&#xff0c;而是先将最外层的海洋给标注出来&#xff08;DFS&#xff0c;visit[i][j]2&#x…

笔记-python有三种导入模块的方法

其一, import modname &#xff1a; 模块是指一个可以交互使用&#xff0c;或者从另一Python 程序访问的代码段。只要导入了一个模块&#xff0c;就可以引用它的任何公共的函数、类或属性。模块可以通过这种方法来使用其它模块的功能。 用import语句导入模块&#xff0c;就在…

NAT简介

一、NAT 概念定义 NAT&#xff08;Network Address Translation&#xff0c;网络地址转换&#xff09;是一种将私有 IP 地址转换为公有 IP 地址的技术。 允许一个组织内部使用私有 IP 地址的网络通过少量的公有 IP 地址连接到互联网。实现了私有网络与外部网络的通信&#xf…

Angular安装与基础语法

安装Angular cli npm i -g angular-cli 创建项目 npm new project_name(项目名称) 启动项目 cd project_name(j进入新创建的项目) ng serve --open 创建组件 ng g c xxx 会在根组件的统计生成一个组件xxx文件夹&#xff0c;比如ng g c hello 就会生成一个hello组件文件…

夜骑,是探索城市的另一种维度,是与自我对话的静谧时光

月光下的骑行浪漫主义者 想象一下&#xff0c;当白日的喧嚣退去&#xff0c;城市的霓虹开始闪烁&#xff0c;你跨上心爱的自行车&#xff0c;迎着凉爽的晚风&#xff0c;穿梭于灯火阑珊之中。夜骑&#xff0c;不仅仅是一场运动&#xff0c;更是一种逃离日常、探索未知的冒险。但…

【Ambari】Docker 安装Ambari 大数据单机版本

目录 一、前期准备 1.1 部署 docker 1.2 部署 docker-compose 1.3 版本说明 二 、镜像构建启动 2.1 系统镜像构建 2.2 安装包源镜像构建 2.3 kdc镜像构建 2.4 集群安装 2.5 容器导出为镜像 三、Ubuntu环境安装测试 3.1 环境准备 3.2 集群容器启动 一、前期准备 1.…

git多人开发,不用merge的操作方法,阿里codeup

阿里云效 Codeup 是阿里云提供的一款代码托管平台&#xff0c;它集成了代码仓库管理、代码审查、持续集成等功能&#xff0c;非常适合团队协作开发。 通过 Codeup 的合并申请&#xff08;Merge Request&#xff0c;MR&#xff09;功能&#xff0c;可以方便地进行代码合并和审查…

如何在OrangePi AIpro智能小车上实现安全强化学习算法

随着人工智能和智能移动机器人的广泛应用&#xff0c;智能机器人的安全性和高效性问题受到了广泛关注。在实际应用中&#xff0c;智能小车需要在复杂的环境中自主导航和决策&#xff0c;这对算法的安全性和可靠性提出了很高的要求。传统的强化学习算法在处理安全约束时存在一定…

享受当下,还是留待未来?一项fMRI与眼动追踪技术的联合研究

摘要 时间贴现(temporal discount)是指个体对奖励的估计会随着时间流逝而下降的心理现象。具体而言&#xff0c;当获得奖励的时间以日期(日期条件&#xff1b;例如&#xff0c;2023年6月8日)而不是延迟(延迟条件&#xff1b;例如&#xff0c;30天)呈现时&#xff0c;贴现率较低…

免费,Python蓝桥杯等级考试真题--第14级(含答案解析和代码)

Python蓝桥杯等级考试真题–第14级 一、 选择题 答案&#xff1a;B 解析&#xff1a;键为‘B’对应的值为602&#xff0c;故答案为B。 答案&#xff1a;A 解析&#xff1a;字典的符合为花括号&#xff0c;先键后值&#xff0c;故答案为A。 答案&#xff1a;C 解析&#xff1a…

Stable Diffusion 字体和场景结合【把四季藏在海里】

把四季藏在海里&#xff0c;话不多说&#xff0c;上教程。 一、花瓣找字 打开花瓣找下字&#xff0c;也可以自己做&#xff0c;我不会&#xff0c;谢谢。本文用到的字&#xff0c;版权归原作者所有。 白底黑字&#xff1a;那么就是浪花占主要部分&#xff0c;字就是海的效果&…

【改进】YOLOv8 AND YOLOv9 总目录

说明&#xff1a;本专栏为YOLOV8和YOLOV9的使用以及改进的方法。平时比较忙&#xff0c;只能随缘回答问题哈&#xff0c;谨慎订阅&#xff01; &#x1f49b; &#x1f499; &#x1f49c; ❤️ &#x1f49a; &#x1f49b; &#x1f499; &#x1f49c; ❤️ &#x1f49a; &…

sdut java lab 7.1(法二好理解)

7-1 sdut-JAVA-Pig Latin 分数 12 全屏浏览 切换布局 作者 马新娟 单位 山东理工大学 Write a program that requests a word as input, translates the word into Pig Latin and outputs the word input and its equivalent in Pig Latin. The rules for translating a …

C++:STL容器的学习-->string

C:STL容器的学习-->string 1. 构造方法2. string的赋值操作3. string字符串的拼接4. string 查找和替换5. string字符串的比较6. string字符存取7. string 插入和删除8. string截取 需要添加头文件#include <string> 1. 构造方法 string() 创建空的字符串 string(c…