写在前面:
Logrus版本: v1.4.2
logrus相当于标准库log包的加强版,是目前最流行的日志库.它在完全兼容原生方法的基础上,增加了格式化日志的能力,简单易用,使得日志更为工整.其源码代码量并不大,通读一下便于后续理解使用.
time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8
time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10
time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true
time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4
time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009
一. Logrus官网-并没有
Logrus的特点就是使用简单,并不需要特别搭个网站说明,文档就是项目的readme.
sirupsen/logrus: Structured, pluggable logging for Go. - GitHub
中文版的简单介绍:
Logrus日志框架
二. 使用+说明:
logrus日志使用详解
Go进阶10:logrus日志使用教程
源码中 example_**.go, 和readme中说明的一样的,只是更加完整.
三. Logrus源码(v1.4.2)
1. exported.go
这是包的入口,在这里定义了包级变量std(实际是logger)作为标准库log替代,并声明了包方法WithField(),Debug()等供外部调用.实际就是调用logger结构的方法.
2. logrus.go和logger.go
logrus.go是包的类型说明文件,定义了Fields是map[string]interface{}类型;Level的枚举;StdLogger和FieldLogger两个接口.
logger.go是整个包的核心,当我们调用日志方法时候,就是它在工作.当然它作为包级变量也不是自己去实干,而是根据参数newEntry出来,让Entry实际完成写日志的动作.
3. entry.go
Entry结构是真正干活的,它保持需要记录日志的要素,包括通用(Time,Level)和自定义(Data)
type Entry struct {
Logger *Logger
// Contains all the fields set by the user.
Data Fields
// Time at which the log entry was created
Time time.Time
// Level the log entry was logged at: Trace, Debug, Info, Warn, Error, Fatal or Panic
// This field will be set on entry firing and the value will be equal to the one in Logger struct field.
Level Level
// Calling method, with package name
Caller *runtime.Frame
// Message passed to Trace, Debug, Info, Warn, Error, Fatal or Panic
Message string
// When formatter is called in entry.log(), a Buffer may be set to entry
Buffer *bytes.Buffer
// Contains the context set by the user. Useful for hook processing etc.
Context context.Context
// err may contain a field formatting error
err string
}
其核心方法是log(),里面把打印的内容放入buffer,然后调用entry.write(),写入Logger.Out.(由于Logger.Out(通常是日志文件)可能会并冲突,因而write()方法是有进行加锁的.)
P.S.1. 从log()方法可以看出,entry至少有Time,Level,Message三部分,这样就能格式化出基本的格式.
P.S.2. GO并没有java的Trace()机制,要实现打印调用栈就要用到runtime.Frame,Logrus使用getCaller()方法跟踪函数的调用情况,从而实现调用栈的打印.
4. formatter.go以及son_formatter.go和text_formatter.go实现
formatter是logrus扩展处,它从Entry构造出需要打印的data(实际就是Map)结构,再转换为实际输出的[]byte
Logrus提供了两种标准实现:
- JSON主要就是用Encoder完成Json的序列化
- Text复杂点,特别如果设置corlored,还要调用printColored()实现彩色字体.(这个真没细看...)
5. hooks.go和hooks目录
logrus实现了Hook机制,在entry的log()方法的write方法前,会调用entry.fireHooks()执行钩子函数.这个时候会把entry传递给Hook,让钩子进行自定义操作.
hooks.go定义了包变量LevelHooks(根据日志级别登记所有Hooks),和Hook接口:
type Hook interface {
Levels() []Level
Fire(*Entry) error
}
hooks目录定义了一个系统钩子,其writer为*syslog.Writer,这样使用这个Hook,就会在各种日志级别也写一份日志到这个Writer中.Logrus官方整理了各种Hook:
https://github.com/sirupsen/logrus/wiki/Hooks
例如KafkaLogrus可以同步Log到kafaka,Logstash可以同步Log到ELK
6. 其他
- terminal_check_*.go: 检测各种操作系统是否有控制台.
- writter.go: 对io.Writer的实现,使得Logrus能够传给其他Lib用,如http.Server或者替换系统的标准输出:
log.SetOutput(logger.Writer())
四.其他推荐阅读文章
Logrus -- Go 的结构化 logger
Golang logrus的高级配置(hook, logrotate)
Logrus源码阅读(1)--基本用法
Logrus源码阅读(2)--logrus生命周期