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。如:

nohup command > myout.log 2>&1 &

Rust中的日志库

通常在Rust中有日志库基本上都是基于log库去做实现,他定义了日志的等级,总共5个级别

pub enum Level {
Error = 1,
Warn,
Info,
Debug,
Trace,
}

通常用宏来进行输出,下面来看下输出宏的定义:

#[macro_export]
macro_rules! info {
(target: $target:expr, $($arg:tt)+) => ($crate::log!(target: $target, $crate::Level::Info, $($arg)+)); ($($arg:tt)+) => ($crate::log!($crate::Level::Info, $($arg)+))
}

他分为两种情况,一种是有目标target,一种是默认target为root

在wmproxy中,我们通过服务的类型,找到日志输出的不同target,就可以控制输出目录一致或者不一致的控制,如:

log::info!(target: "access", "{}", String::from_utf8_lossy(&buf[..]));

此外设定日志的等级,如果设定为等级为Level::Info那么log::trace!log::debug!的日志将不会做任何输出。

以下是我用过的两个日志库:

  1. env_logger

    这是一个根据环境变量来控制日志等级,并可以自由设置target输出的日志库,我们需要手动调用初始化:
env_logger::init();

  以下是如何启动控制最简单版:

RUST_LOG=debug cargo run

# windows
$env:RUST_LOG="debug"
cargo run

此外还可以设定特定库的日志等级:

当前库默认的日志等级是info,但是wenmeng及webparse库的日志等级为warn,可以有效的过滤第三方库日志信息又不影响自身的信息

RUST_LOG="info,wenmeng=warn,webparse=warn" cargo run
  1. log4rs

    这是一个根据配置文件来控制日志输出到控制台或者输出到文件及文件是否压缩是否切割等数据,也可以同时输出到控制台及文件中。

    他通常通过配置文件来加载配置,以下是他的配置内容
# 每隔30秒检查当前文件
refresh_rate: 30 seconds appenders:
# 标准输出的类型设置为控制台
stdout:
kind: console # 请求数据放置在log/requests.log文件中
requests:
kind: file
path: "log/requests.log"
encoder:
# 输出格式d为日期,m为内容,n为换行符
pattern: "{d} - {m}{n}" root:
# 默认的日志等级为warn
level: warn
# 标准输出只输到stdout的配置,即上面配置的控制台
appenders:
- stdout loggers:
app::backend::db:
level: info app::requests:
level: info
appenders:
- requests
# 是否追加到root里,如果配置为true他将同时输出两个
additive: false

然后调用初始化:

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大小的日志,多余数据全部删除的配置:

kind: rolling_file

path: log/foo.log

append: true

encoder:
kind: pattern policy:
kind: compound trigger:
kind: size
limit: 10 mb roller:
kind: delete

如果要保留旧数据,可以修改roller的配置:

kind: fixed_window

pattern: archive/foo.{}.log

count: 5

base: 1

旧文件将会保持archive/foo.0.logarchive/foo.1.log……archive/foo.4.log

如果配置的后缀名称为.gz且开始了gzip的特征,那么目标文件将会被自动压缩成gz格式,如archive/foo.{}.log.gz。如:

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})} -

      <code style="color: red; font-weight: bold">the level is ERROR</code>
  • 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_logerror_log的功能。

点击 [关注][在看][点赞] 是对作者最大的支持

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

  1. (转)Spring Boot干货系列:(七)默认日志logback配置解析

    转:http://tengj.top/2017/04/05/springboot7/ 前言 今天来介绍下Spring Boot如何配置日志logback,我刚学习的时候,是带着下面几个问题来查资料的, ...

  2. (转)Spring Boot干货系列:(四)开发Web应用之Thymeleaf篇

    转:http://tengj.top/2017/03/13/springboot4/ 前言 Web开发是我们平时开发中至关重要的,这里就来介绍一下Spring Boot对Web开发的支持. 正文 Sp ...

  3. 【转】Spring Boot干货系列:(一)优雅的入门篇

    转自Spring Boot干货系列:(一)优雅的入门篇 前言 Spring一直是很火的一个开源框架,在过去的一段时间里,Spring Boot在社区中热度一直很高,所以决定花时间来了解和学习,为自己做 ...

  4. Spring Boot干货系列:(八)数据存储篇-SQL关系型数据库之JdbcTemplate的使用

    Spring Boot干货系列:(八)数据存储篇-SQL关系型数据库之JdbcTemplate的使用 原创 2017-04-13 嘟嘟MD 嘟爷java超神学堂 前言 前面几章介绍了一些基础,但都是静 ...

  5. Spring Boot干货系列:(七)默认日志框架配置

    Spring Boot干货系列:(七)默认日志框架配置 原创 2017-04-05 嘟嘟MD 嘟爷java超神学堂 前言 今天来介绍下Spring Boot如何配置日志logback,我刚学习的时候, ...

  6. Spring Boot干货系列:(五)开发Web应用JSP篇

    Spring Boot干货系列:(五)开发Web应用JSP篇 原创 2017-04-05 嘟嘟MD 嘟爷java超神学堂 前言 上一篇介绍了Spring Boot中使用Thymeleaf模板引擎,今天 ...

  7. Spring Boot干货系列:(四)Thymeleaf篇

    Spring Boot干货系列:(四)Thymeleaf篇 原创 2017-04-05 嘟嘟MD 嘟爷java超神学堂 前言 Web开发是我们平时开发中至关重要的,这里就来介绍一下Spring Boo ...

  8. Spring Boot干货系列:(一)优雅的入门篇

    Spring Boot干货系列:(一)优雅的入门篇 2017-02-26 嘟嘟MD 嘟爷java超神学堂   前言 Spring一直是很火的一个开源框架,在过去的一段时间里,Spring Boot在社 ...

  9. Java多线程干货系列—(四)volatile关键字

    原文地址:http://tengj.top/2016/05/06/threadvolatile4/ <h1 id="前言"><a href="#前言&q ...

  10. Spring Boot干货系列:(十二)Spring Boot使用单元测试(转)

    前言这次来介绍下Spring Boot中对单元测试的整合使用,本篇会通过以下4点来介绍,基本满足日常需求 Service层单元测试 Controller层单元测试 新断言assertThat使用 单元 ...

随机推荐

  1. Magick.NET跨平台压缩图片的用法

    //首先NuGet安装:Magick.NET.Core,Magick.NET-Q16-AnyCPUusing ImageMagick; /// <summary> /// 压缩图片 /// ...

  2. [golang]推送钉钉机器人消息

    前言 通过钉钉群机器人的webhook,实现消息推送. 本文代码仅示例markdown格式的消息. 示例代码 注意修改钉钉机器人的webhook package main import ( " ...

  3. CAP 7.2 版本发布通告

    前言 今天,我们很高兴宣布 CAP 发布 7.2 版本正式版,我们在这个版本中主要致力于 Dashboard 对 k8s 服务发现的支持. 从 7.1 版本以来,我们发布了4个小版本,在这些版本中我们 ...

  4. Javascript执行原理 网页引入javascript的三种方式* javascript核心语法 数据类型 Typeof运算符

    Javascript执行原理: 用户端发送请求到服务器端 将js解析出来的数据(用户身份表示)绑定在请求路径中 服务器端获取到参数后会响应客户端 客户端通过浏览器解析响应的数据并将数据展现在浏览器上 ...

  5. python 面试题第一弹

    1. 如何理解Python中的深浅拷贝 浅拷贝(Shallow Copy)创建一个新的对象,该对象的内容是原始对象的引用.这意味着新对象与原始对象共享相同的内存地址,因此对于可变对象来说,如果修改了其 ...

  6. Esxi 8 更换Nvme硬盘后 如何迁移Esxi主机和虚拟机到新硬盘

    Esxi 8 更换Nvme硬盘后 如何迁移Esxi主机和虚拟机到新硬盘 因为去年底开始SSD和内存大幅降价,ITGeeker技术奇客就想着给自己的小主机升个级,换个三星1G的980硬盘,再加了一根32 ...

  7. 这个 AI 机器人会怼人,它是怎么做到的?

    近期,机器人"Ameca"接入了 Stable Diffusion,它一边与旁边的人类工程师谈笑风生,一边熟练地用马克笔在白板上画出一只简笔的猫,最后还在白板右下角签名. 当 Am ...

  8. npm install xxx 后加上-s、-d、-g之间的区别?

    1.npm install xxx -s npm install xxx -s.npm install xxx -S是npm install xxx --save的简写形式 局部安装,记录在packa ...

  9. ReactPortals传送门

    ReactPortals传送门 React Portals提供了一种将子节点渲染到父组件以外的DOM节点的解决方案,即允许将JSX作为children渲染至DOM的不同部分,最常见用例是子组件需要从视 ...

  10. Learning Hard C# 学习笔记: 6.C#中的接口

    目的: 由于C#中的类只能单个继承, 为了满足多重继承(一个子类可以继承多个父类)的需求, 所以产生了接口. 多重继承是指一个类可以从多个父类继承属性和方法.在C#中,只允许单继承,即一个类只能有一个 ...