0%

Go每周一库之Logrus

golang开发者常用的日志三方库Logrus;具备兼容性、扩展性等多种优点;本篇博客结合源码来分析它的设计思路和更高级的使用方法;

基础介绍

官方给到的介绍 Logrus 是 Go (golang) 的结构化记录器,与标准库记录器完全 API 兼容。

包含三大组成部分:日志等级、打印信息、输出样式;

日志等级

日志等级从低到高(Panic、、ErrorWarnInfoDebugTrace

exported.go中实现了一个标准logger对象std;其默认的日志记录等级是Info,只有当打印等级低于日志记录等级才会进行输出(祥见export.goIsLevelEnabled方法);

1
2
3
4
var (
// std is the name of the standard logger in stdlib `log`
std = New()
)
1
2
3
4
5
6
7
8
9
10
11
// It's recommended to make this a global instance called `log`.
func New() *Logger {
return &Logger{
Out: os.Stderr,
Formatter: new(TextFormatter),
Hooks: make(LevelHooks),
Level: InfoLevel,
ExitFunc: os.Exit,
ReportCaller: false,
}
}
1
2
3
4
// IsLevelEnabled checks if the log level of the logger is greater than the level param
func (logger *Logger) IsLevelEnabled(level Level) bool {
return logger.level() >= level
}

Entry和Logger两者的关系

EntryLogger是整个Logrus库中最重要的两个数据结构;了解了这两者的关系你就能更清楚的知道Logrus的整个设计思路;

  • Logger是一个全局日志工具,所有记录日志的上层操作接口是由Logger提供,Entry属于单条日志记录的实体,Logger每打印一条日志,都对应创建一个Entry对象,并最后交由它处理;
  • Entry是每条日志记录的实体,每记录一条日志,都会创建一个Entry对象,里面包含具体日志记录的数据字段和方法集;

exported中常用方法

exported.go中实现了一个标准的logger对象,并提供基础方法;

SetReportCaller

SetReportCaller(true)方法其功能就是输出日志中添加文件名和方法信息;logger对象中有ReportCaller字段,用于是否记录调用者信息的标志,默认为false;Entry对象会根据这个标志创建Caller,Caller是runtime.Frame类型,可以检索第一个非 Logrus 调用函数的名称和包名;

SetOutput

SetOutput()方法可重定向日志输出到文件等;

1
2
3
4
// SetOutput sets the standard logger output.
func SetOutput(out io.Writer) {
std.SetOutput(out)
}

SetFormatter

SetFormatter()可通过实现Formatter接口重新定义日志输出格式;Logrus已经实现了JSONFormatterTextFormatter两种输出样式;也可以自己实现接口自定义输出样式;

1
2
3
type Formatter interface {
Format(*Entry) ([]byte, error)
}
1
2
3
4
// SetFormatter sets the standard logger formatter.
func SetFormatter(formatter Formatter) {
std.SetFormatter(formatter)
}

AddHook

Logrus可以通过添加钩子的方式来实现每条日志输出前都会执行钩子的特定方法;

1
2
3
4
// AddHook adds a hook to the standard logger hooks.
func AddHook(hook Hook) {
std.AddHook(hook)
}

通过实现Hook接口创建钩子,添加钩子对象会在entry的log方法中执行钩子方法fire();从注释可以知道钩子方法的执行和日志等级应该,同时钩子方法并不会开辟goroutine进行执行;

1
2
3
4
5
6
//A hook to be fired when logging on the logging levels returned from
//`Levels()` on your implementation of the interface. Note that this is //not fired in a goroutine or a channel with workers, you should handle //such functionality yourself if your call is non-blocking and you //don't wish for the logging calls for levels returned from `Levels()` //to block.
type Hook interface {
Levels() []Level
Fire(*Entry) error
}

第三方Hook

将日志发送到 缓冲或队列 等中间件中:

最后

Logger是可以高度定制的,使用Hook钩子机制,Formatter定义日志格式,可以做到多级别输出、格式化输出、多样化输出。你学费了吗?