字节开源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. ...
随机推荐
- 【每日日报】第四十七天---<div>
1 学习HTML HTML <div> 元素是块级元素,它可用于组合其他 HTML 元素的容器. <div> 元素没有特定的含义.除此之外,由于它属于块级元素,浏览器会在其前后 ...
- maven安装和配置阿里云镜像(各种详细配置)
maven安装和详细配置 提示:下面是maven3.6.3版本百度云链接,记住maven3.3以上版本必须安装jdk1.7及以上版本,否则会出错. 链接:https://pan.baidu.com/s ...
- Spring原始注解开发-02
使用@Repository.@Service.@Controller注解配置,使其更加清晰属于哪一层,因为我是模拟的web层,所有没有使用@Controller注解,后面结合web开发会使用到 1.创 ...
- Fabric2.2中的Raft共识模块源码分析
引言 Hyperledger Fabric是当前比较流行的一种联盟链系统,它隶属于Linux基金会在2015年创建的超级账本项目且是这个项目最重要的一个子项目.目前,与Hyperledger的另外几个 ...
- 不借助 Javascript,利用 SVG 快速构建马赛克效果
之前在公众号转发了好友 Vajoy 的一篇文章 -- 巧用 CSS 把图片马赛克风格化. 核心是利用了 CSS 中一个很有意思的属性 -- image-rendering,它可以用于设置图像缩放算法. ...
- ElasticSearch 设置某个字段不分词
先说结论:字段类型更改为 'keyword' elasticSearch官方文档中创建index代码如下 PUT /my_store { "mappings" : { " ...
- 苞米面 C++ 模板库 介绍
苞米面 C++ 模板库 简介 苞米面 C++ 模板库,无需编译,直接包含头文件就可以. 所有模板类和算法都包含在 bmm 名字空间里,例如: bmm::recent. 需要 C++ 编译器,支持 C+ ...
- come on! 基于LinkedHashMap实现LRU缓存
/** * @Description 基于LinkedHashMap实现一个基于'LRU最近最少使用'算法的缓存,并且最多存MAX个值 * @Author afei * @date:2021/4/25 ...
- 看看JDK1.7与1.8的内存模型差异
JDK1.7与1.8的区别的内存模型差异? jsk1.7的内存模型: 堆分为初生代和老年代,大小比例为1:2,初生代又分为eden.from.to三个区域,大小比例为8:1:1 方法区:有代码区.常量 ...
- [AcWing 768] 忽略大小写比较字符串大小
点击查看代码 #include<iostream> using namespace std; string a, b; int main() { getline(cin, a); getl ...