27. 干货系列从零用Rust编写正反向代理,Rust中日志库的应用基础准备 ...

打印 上一主题 下一主题

主题 880|帖子 880|积分 2640

wmproxy

wmproxy已用Rust实现http/https代理, socks5代理, 反向代理, 静态文件服务器,四层TCP/UDP转发,内网穿透,后续将实现websocket代理等,会将实现过程分享出来,感兴趣的可以一起造个轮子
项目地址

国内: https://gitee.com/tickbh/wmproxy
github: https://github.com/tickbh/wmproxy
日志

日志在程序中的重要性非常的重要,当系统发生故障时,我们要随时能排查出相关的日志,所以通常有了日志分级的概念(如错误error,警告warn,信息info,调试debug,追踪trace),如果系统出了严重的Bug,那我们此时应该排查warn及error看是否有相应的错误信息。如果是程序流程上的问题,可能会很琐碎,那我们可能需要排查trace的消息。
相对来说,trace的日志数据量极大,当然也最琐碎,排查起来会极难排查,要根据相关的关键字来定位相关日志,通常一个类型的日志会定义相同的关键字,在Java中类似Tag这种,在Rust库中日志会根据库自动显示出来,我们可以轻松的根据库名定位同一个库的问题。同一个库内可根据关键字来定位。
日志分类

标准输出

程序中存在标准输出(stdout)及错误输出(stderr),通常程序的运行中会将标准输出的内容显示在控制台上,我们就可以根据输出的内容来判定程序是否正常执行。在Rust中,最常用的是宏println!()。
文件输出

如果是服务类型的程序,常常会将数据输出到文件中,因为它运行时间通常按天或者月甚至是年来计算。产生的日志量也极为庞大,通常要按天来切割日志,且单文件可能上GB大小,在后台运行时,通过也会通过重定向将控制台的内容输出到文件上。
后台执行command命令,并将内容输出到myout.log,且将stderr重定向到stdout。如:
  1. nohup command > myout.log 2>&1 &
复制代码
Rust中的日志库

通常在Rust中有日志库基本上都是基于log库去做实现,他定义了日志的等级,总共5个级别
  1. pub enum Level {
  2.     Error = 1,
  3.     Warn,
  4.     Info,
  5.     Debug,
  6.     Trace,
  7. }
复制代码
通常用宏来进行输出,下面来看下输出宏的定义:
  1. #[macro_export]
  2. macro_rules! info {
  3.     (target: $target:expr, $($arg:tt)+) => ($crate::log!(target: $target, $crate::Level::Info, $($arg)+));
  4.     ($($arg:tt)+) => ($crate::log!($crate::Level::Info, $($arg)+))
  5. }
复制代码
他分为两种情况,一种是有目标target,一种是默认target为root
在wmproxy中,我们通过服务的类型,找到日志输出的不同target,就可以控制输出目录一致或者不一致的控制,如:
  1. log::info!(target: "access", "{}", String::from_utf8_lossy(&buf[..]));
复制代码
此外设定日志的等级,如果设定为等级为Level::Info那么log::trace!及log::debug!的日志将不会做任何输出。
以下是我用过的两个日志库:

  • env_logger
    这是一个根据环境变量来控制日志等级,并可以自由设置target输出的日志库,我们需要手动调用初始化:
  1. env_logger::init();
复制代码
  以下是如何启动控制最简单版:
  1. RUST_LOG=debug cargo run
  2. # windows
  3. $env:RUST_LOG="debug"
  4. cargo run
复制代码
此外还可以设定特定库的日志等级:
当前库默认的日志等级是info,但是wenmeng及webparse库的日志等级为warn,可以有效的过滤第三方库日志信息又不影响自身的信息
  1. RUST_LOG="info,wenmeng=warn,webparse=warn" cargo run
复制代码

  • log4rs
    这是一个根据配置文件来控制日志输出到控制台或者输出到文件及文件是否压缩是否切割等数据,也可以同时输出到控制台及文件中。
    他通常通过配置文件来加载配置,以下是他的配置内容
  1. # 每隔30秒检查当前文件
  2. refresh_rate: 30 seconds
  3. appenders:
  4.   # 标准输出的类型设置为控制台
  5.   stdout:
  6.     kind: console
  7.   # 请求数据放置在log/requests.log文件中
  8.   requests:
  9.     kind: file
  10.     path: "log/requests.log"
  11.     encoder:
  12.       # 输出格式d为日期,m为内容,n为换行符
  13.       pattern: "{d} - {m}{n}"
  14. root:
  15.   # 默认的日志等级为warn
  16.   level: warn
  17.   # 标准输出只输到stdout的配置,即上面配置的控制台
  18.   appenders:
  19.     - stdout
  20. loggers:
  21.   app::backend::db:
  22.     level: info
  23.   app::requests:
  24.     level: info
  25.     appenders:
  26.       - requests
  27.     # 是否追加到root里,如果配置为true他将同时输出两个
  28.     additive: false
复制代码
然后调用初始化:
  1. log4rs::init_file("log4rs.yml", Default::default()).unwrap();
复制代码
log4rs规则

应用程序获取日志记录并将其记录到某个地方,例如,将其记录到文件、控制台或系统日志中。
实现格式:


  • console: 控制台输出,需要console_appender特征
  • file: 文件输出,需要file_appender特征
  • rolling_file: 滚动文件输出,需要rolling_file_appender特征且必须配置compound_policy

    • compound: 如何触发文件切割

      • Rollers

        • delete: 触发时删除旧数据
        • fixed_window: 将旧数据如何进行存储配置

      • Triggers

        • size: 触发大小的限制



以下是只保留10m大小的日志,多余数据全部删除的配置:
  1. kind: rolling_file
  2. path: log/foo.log
  3. append: true
  4. encoder:
  5.   kind: pattern
  6. policy:
  7.   kind: compound
  8.   trigger:
  9.     kind: size
  10.     limit: 10 mb
  11.   roller:
  12.     kind: delete
复制代码
如果要保留旧数据,可以修改roller的配置:
  1. kind: fixed_window
  2. pattern: archive/foo.{}.log
  3. count: 5
  4. base: 1
复制代码
旧文件将会保持archive/foo.0.log,archive/foo.1.log……archive/foo.4.log
如果配置的后缀名称为.gz且开始了gzip的特征,那么目标文件将会被自动压缩成gz格式,如archive/foo.{}.log.gz。如:
  1. log4rs = { version ="1.0.0", features = ["gzip"] }
复制代码
匹配模型:

这是log4rs的简单模型输出,以{}里面包含目标数据及可能携带的参数:

  • d, date - 当前的日期格式.
    一个自定义的格式,依赖于chrono,获取的日志的写入的当前时间,第一个参数为时间的自定为格式,第二个参数 是utc或者为local。以下参数

    • {d} - 2022-11-15T14:22:20.644420340-08:00
    • {d(%Y-%m-%d %H:%M:%S)} - 2022-11-15 14:22:20
    • {d(%Y-%m-%d %H:%M:%S %Z)(utc)} - 2022-11-15 22:22:20 UTC

  • f, file - 当前打印的源文件,如果没有显示???。
  • h, highlight - 高亮当前日志,如果有错误显示红色,蓝色显示info等

    • {h(the level is {l})} -
      the level is ERROR

  • l, level - 当前日志等级.
  • L, line - 当前打印的源文件的行数,如果没有显示???
  • m, message - 当前的消息详情.
  • M, module -  当前打印的源模块,如果没有显示???
  • P, pid - 当前的进程id.
  • i, tid - 当前的线程id.
  • n - 换行符.
  • t, target - 目标输出的target.
  • T, thread - 当前的线程名称.
  • I, thread_id - pthread的线程id.
结语

log4rs提供了自定义的一些功能,可以友好的设置一些日志的功能,下一篇将讲解如何自定义实现access_log和error_log的功能。
点击 [关注][在看][点赞] 是对作者最大的支持

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

农妇山泉一亩田

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表