字节开源RPC框架Kitex的日志库klog源码解读
前言
这篇文章将着重于分析字节跳动开源的RPC
框架Kitex的日志库klog
的源码,通过对比Go原生日志库log
的实现,探究其作出的改进。
为了平滑学习曲线,我写下了这篇分析Go原生log
库的文章,希望你可以对比阅读:https://juejin.cn/post/7103790667595268126
本文的分析基于:github.com/cloudwego/kitex/pkg/klog
的源码。
klog库的使用
结果如下:
klog.xxx能直接打印日志的原因
通过观察源码,klog
包的default.go
文件中,封装了三类日志的打印的函数提供直接使用:普通日志、格式化的日志、格式化的Context日志。
每一类包含了7个的日志输出级别的函数可使用:Info
、Debug
、Notice
、Warn
、Error
、Fatal
、Trace
。
并且这21个函数中频繁使用到了一个logger
实例,只要我们引入klog
包,logger
就会完成初始化,并且作为默认的log
实例。
可以看到logger
实例默认的日志打印级别是LevelInfo
,klog
通过常量计数器定义了0~6
种日志级别:
FullLogger接口
默认的logger
实例是通过defaultLogger
结构初始化的,且defaultLogger
结构实现了FullLogger
接口定义的所有函数(接口定义了上面说的三类,每一类7种日志打印函数)
并且观察defaultLogger
结构的属性stdlog
,就是Go原生的日志库log
定义的Logger
类型,因此klog
的所有日志操作,最终都是借助Go原生log
库实现的。
相当于klog
在Go原生log库
的基础上对格式化输出和日志打印级别作了封装,便于直接使用。
串联一下日志打印函数执行的过程:
main函数
中调用:klog.Info("一条普通的日志")
- 进一步调用初始化好的
defaultLogger
实例(名为logger
)的实现自FullLogger
接口的函数:logger.Info()
- 进一步调用
ll.logf()
函数(下面重点分析)
ll.logf()
上面的这三类共21个日志打印函数最终都调用了ll.logf()
方法,因此ll.logf()
也是klog
库的核心函数,看一下代码:
- 日志过滤:如果调用的打印函数代表的日志级别低于
logger
实例初始化的日志级别,则不会打印(如默认级别是LevelInfo == 2
,则调用klog.Trace()
将被过滤) - 格式化打印信息存入
msg
- 调用Go原生日志库
log
的Output()
函数,打印日志(这一部分在上一篇分析Go的log库的文章中已经充分讲解)
关于calldepth的问题
calldepth
表示调用层数,这里声明了4,是为了配合获取调用日志打印函数的文件名和所在行数。
calldepth == 0
,表示获取调用runtime.Caller(calldepth)
的文件名和行数calldepth == 1
,表示获取调用std.Output()
的文件名和行数calldepth == 2
,表示获取调用ll.logf()
的文件名和行数calldepth == 3
,表示获取调用logger.Info()
的文件名和行数calldepth == 4
,表示获取调用klog.Info()
的文件名和行数(也就是main.go
文件)
基于klog再度进行封装,在打印日志获取文件名时可能会有问题,下面是摘自Kitex文档的一句描述:
猜测原因就是klog
的封装,固定了calldepth == 4
,确保其在获取文件信息时能定位到main.go
文件中,而如果对klog
再封几层,会导致calldepth
需要更大才能定位到最外层main.go
文件,而这个值并不能通过klog
的提供的实现进行修改。
在初始化时通过log.New()
函数指定了日志输出的位置和需要打印的前置信息(文件名、行数、日期)
定制自己的Logger
可以使用klog.SetLogger()
来替换掉默认的logger
实现,需要传入一个实现了所有FullLogger
接口中定义的方法的实例。
值得注意的是:SetLogger()
函数并非是并发安全的,这个方法不应该在你使用了默认的defaultLogger
定义实例之后再去使用(会覆盖掉默认的logger
实例)。
当然完全重新定制比较复杂,大多数时候,我们只需要在默认的logger
基础上重定向日志输出或者修改默认日志级别即可:
下面修改日志打印级别为Notice
(高于Info
),并且重定向日志的输出:
这里指定了日志输出到文件log.txt
中,并且因为Info
级别低于声明的Notice
,因此日志输出操作被忽略:
小结
通过分析,我们发现klog
在Go原生log
库的基础上,进行了精简的二次封装,一定程度上约束了打印的日志的内容为:日期 + 时间微秒级 + 调用文件名 + 所在行数 + 日志级别 + 格式化的日志内容,使用十分便捷。
当然它也提供了SetLogger()
方法去供你自己实现logger
实例,以满足更多的定制化需求。
字节开源RPC框架Kitex的日志库klog源码解读的更多相关文章
- 标准库path源码解读
先看标准库 作用:关于路径的一些实用操作 https://github.com/golang/go/blob/master/src/path/path.go 源码地址 func IsAbs func ...
- Go RPC 框架 KiteX 性能优化实践 原创 基础架构团队 字节跳动技术团队 2021-01-18
Go RPC 框架 KiteX 性能优化实践 原创 基础架构团队 字节跳动技术团队 2021-01-18
- 各大开源rpc 框架 比较
各大开源rpc 框架 比较 1. 前言 随着现在互联网行业的发展,越来越多的框架.中间件.容器等开源技术不断地涌现,更好地来服务于业务,解决实现业务的问题.然而面对众多的技术选择,我们要如何甄别出 ...
- 如何优雅的阅读 GitHub 上开源 js 框架和库的源码
如何优雅的阅读 GitHub 上开源 js 框架和库的源码 step 先总后分,即先了解一下啊框架的大体架构,又一个全局的认识,在选择某些和感兴趣的部分,仔细阅读,各个击破: 带着问题阅读,用到了什么 ...
- 微前端框架 之 qiankun 从入门到源码分析
封面 简介 从 single-spa 的缺陷讲起 -> qiankun 是如何从框架层面解决 single-spa 存在的问题 -> qiankun 源码解读,带你全方位刨析 qianku ...
- Go 源码解读|如何用好 errors 库的 errors.Is() 与 errors.As() 方法
前言 快一个月没有更新技术文章了,这段时间投注了较多的时间学习字节的开源项目 Kitex/Hertz ,并维护一些简单的 issue ,有兴趣的同学也可以去了解: https://www.cloudw ...
- 源码解读SLF4J绑定日志实现的原理
一.导读 我们使用log4j框架时,经常会用slf4j-api.在运行时,经常会遇到如下的错误提示: SLF4J: Class path contains multiple SLF4J binding ...
- 美团动态线程池实践思路开源项目(DynamicTp),线程池源码解析及通知告警篇
大家好,这篇文章我们来聊下动态线程池开源项目(DynamicTp)的通知告警模块.目前项目提供以下通知告警功能,每一个通知项都可以独立配置是否开启.告警阈值.告警间隔时间.平台等,具体代码请看core ...
- php+gd库的源码安装
php+gd库的源码安装 PHP+GD安装 一.下载软件 gd-2.0.35.tar.gz http://www.boutell.com/gd/ jpegsrc.v6b. ...
随机推荐
- IO流入门
@ 目录 总结内容 1. IO流是什么 2. 字符流和字节流 3. File常用API(前面类型为返回类型) 4. 编码转换 5. IO流实现流程 6. 输入输出流简单实现 7. 输入输出流简单实现 ...
- vuecli中配置webpack加快打包速度
webpack4中webpack 的DllPlugin插件可以将常见的库文件作为dll文件来,每次打包的时候就不用再次打包库文件了. 但是游鱼西在vuecli中已经去除这个选项,意识到带来的打包速度提 ...
- FastAPI(七十二)实战开发《在线课程学习系统》接口开发-- 留言列表开发
之前我们分享了FastAPI(七十一)实战开发<在线课程学习系统>接口开发-- 查看留言,这次我们分享留言列表开发. 列表获取,也需要登录,根据登录用户来获取对应的留言.逻辑梳理如下. 1 ...
- Warmup小记
什么是warmup 热身,在刚刚开始训练时以很小的学习率进行训练,使得网络熟悉数据,随着训练的进行学习率慢慢变大,到了一定程度,以设置的初始学习率进行训练,接着过了一些inter后,学习率再慢慢变小: ...
- JavaWeb入门day10-JSP
JSP 什么是JSP Java Server Pages:Java服务器端页面,也和Servlet一样,用于动态Web技术 最大特点: 写JSP就像在写HTML 区别 HTML只给用户提供静态数据 J ...
- Java学习day33
线程池: 背景:经常创建和销毁.使用量特别大的资源,比如并发情况下的线程,对性能影响很大 思路:提前创建好多个线程.实现重复利用. 好处:提高响应速度,减少了创建新线程的时间:降低资源消耗,重复利用线 ...
- 生成二维码,并且保存,指定位置的view成图片,并且保存到本地相册
效果图: 保存的图片效果是: 保存到本地的,是整个视图,不只是单单的二维码的图片, 在了解的一番过程之后,我知道了, 1.首先要去获取保存图片的写入权限:(使用 https://github.com/ ...
- axios 内存泄漏
有一个项目需要post后台几万条数据,每次只能请求三五条,所以只能在每次请求成功后自调用这个请求函数. 但这样请求了成千上万次后,浏览器会崩溃并报出 out of Memory 错误,经查询,这是内存 ...
- Java语言学习day06-7月05日
今日内容介绍流程控制语句之循环语句循环高级###10for循环_1 * A: for循环_1 * a: 使用格式 for(初始化变量 ; 条件 ; 增量){ 循环体; } * b: 各模块解释 初始化 ...
- LVM从VG中删除PV及删除未知PV
当我们的硬盘发被删除掉了,我们的PV卷会变成[unknown] 一.首先我们要备份我们的文件,然后再删除lv分区 二. VG中去除PV unknown device: