日志是现代编程中必不可少的手段,除了处理基本的错误之外,通过记录日志,也可以帮助我们完成一些基本的功能,比如开发及测试期间的Debug,记录请求的上下文,排除故障原因,数据统计及分析等等。
Logrus 是一个结构化、可插拔的Go日志库,并且完全兼容官方的log库,具有很强的灵活性,有 TEXT 和 JSON 两种可选的日志输出格式,同时还提供了自定义格式的插件功能,支持 Feild 机制和可扩展的 Hook 机制。
安装Logrus
logrus 并不是Go的标准库,所以我们得通过
go get github.com/sirupsen/logrus
的形式安装到项目中。
$ go get github.com/sirupsen/logrus
go: downloading golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8
go: added github.com/sirupsen/logrus v1.9.0
go: added golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8
安装完成后,可以执行下示例:
package main
import (
"github.com/sirupsen/logrus"
func main() {
// 创建一个Logrus的实例
logger := logrus.New()
// 设置输出格式为JSON
logger.SetFormatter(&logrus.JSONFormatter{})
// 设置日志级别为debug
logger.SetLevel(logrus.DebugLevel)
// 记录日志
logger.WithFields(logrus.Fields{
"animal": "walrus",
"number": 1,
}).Info("A walrus appears")
// Output:
// {"animal":"walrus","level":"info","msg":"A walrus appears","number":1,"time":"2023-03-15T15:02:30+08:00"}
示例中,我们首先创建了一个 logrus 实例,输出格式设置为 JSON,通过 SetLevel 设置日志级别,再设置 Fields。
Logrus 支持的日志级别
相比 Go 语文的标准log库,Logrus支持多达七种的日志级别:
Panic:恐慌级别,也是最高级别的日志,会打印出错误堆栈。
Fatal:致命错误,输出日志后,执行 exit(1) 退出
Error:错误日志,必须记录与跟踪的日志
Warn:警告日志,主要记录需要提醒开发者的日志
Info:主要是提供一些必要的日志信息,在业务出现问题时,可以结合error日志快速定位问题,一般会默认使用该级别的日志。
Debug:调试信息,方便开发测试阶段的问题定位
Trace:比 debug 级别还低,一般很少用。
日志级别由 Panic 级别最高, Trace 级别最低。Logrus 默认级别为 Info,低于该级别的日志不会输出,所以默认情况下,使用Trace和Debug是不会打印出来日志的。
package main
import (
"github.com/sirupsen/logrus"
func main() {
logrus.SetLevel(logrus.TraceLevel)
logrus.Trace("Trace Level") // TRAC[0000] Trace Level
logrus.Debug("Debug Level") // DEBU[0000] Debug Level
logrus.Info("Info Level") // INFO[0000] Info Level
logrus.Warn("Warn Level") // WARN[0000] Warn Level
logrus.Error("Error Level") // ERRO[0000] Error Level
logrus.Fatal("Fatal Level") // FATA[0000] Fatal Level // 退出
logrus.Panic("Panic Level")
其结果不言而喻,唯一需要注意的是,Fatal级别后的日志不会再打印出来了。
设置日志级别
如上所述,Logrus 默认的日志级别是 InfoLevel,但是我们可以通过 logrus.SetLevel(Level)来设置我们需要的级别。
logrus.SetLevel(logrus.DebugLevel)
设置日志打印和记录的介质
Logrus 支持设置将日志输出到不同的介质:
日志打印到控制台
日志打印到文件
日志同时打印到控制台和文件中。
日志打印到控制台
通过 SetOutput设置为 os.Stdout或者 os.Stderr。
package main
import (
"github.com/sirupsen/logrus"
func main() {
// 创建一个Logrus的实例
logger := logrus.New()
logger.SetOutput(os.Stdout)
日志打印到文件
使用 logrus.SetOutput(file)来实现将日志打印到文件中。
package main
import (
"fmt"
log "github.com/sirupsen/logrus"
func main() {
logFile := "log.txt"
f, err := os.OpenFile(logFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
fmt.Println("Failed to create logfile" + logFile)
panic(err)
defer f.Close()
log.SetOutput(f)
log.SetLevel(log.DebugLevel)
log.Info("Info Level")
log.Warn("Warn Level")
log.Error("Error Level")
log.Fatal("Fatal Level")
打印到控制台及日志
通过 io.MultiWriter来实现同时打印到控制台及日志里。
package main
import (
"fmt"
"github.com/sirupsen/logrus"
func main() {
logFile := "log.txt"
f, err := os.OpenFile(logFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
fmt.Println("Failed to create logfile" + logFile)
panic(err)
defer f.Close()
log := &logrus.Logger{
Out: io.MultiWriter(f, os.Stdout),
Level: logrus.DebugLevel,
Formatter: &logrus.TextFormatter{},
log.Info("Info Level")
log.Warn("Warn Level")
log.Error("Error Level")
log.Fatal("Fatal Level")
设定输出格式
logrus 支持两种日志格式: 文本类型(TextFormatter)与 json 类型(JSONFormatter),默认是文本类型。
我们也可以通过 SetFormatter函数来设置日志格式。
设置 TextFormatter格式:
logrus.SetFormatter(&logrus.TextFormatter{
FullTimestamp: true,
TimestampFormat: "2006-01-02 15:04:05",
ForceColors: true,
FullTimestamp表示展示日期,TimestampFormat表示展示日期的格式,ForceColors表示控制台输出的日志带有颜色,其结果如下:
TextFormatter还支持其他很多属性,比如ForceQuote表示强制给使用WithFields 的值加上引号,默认logrus会输出日志等级前四个字母,使用 DisableLevelTruncation可以设置全部展示等等。
更多的你可以查看下源码:pkg.go.dev/github.com/…
JSONFormatter与 TextFormatter类似,但是不支持 ForceColors颜色。
设置日志输出文件及行号
默认 logrus 输出的日志是不带有文件及行号的,如果我们需要可以通过 logrus.SetReportCaller(true)来设置显示,但是这个会打印出文件的绝对路径。
显示效果如下:
field 机制
logrus不推荐使用冗长的消息来记录运行过程中产生的信息,它推荐使用 Fields来进行精细化、结构化的日志。
有时候,我们需要在特定场景下记录一些特定的参数,而 logrus 则可以通过使用WithField或者WithFields()实现。
WithFields接收logrus.Fields类型的参数,而 logrus.Fields的底层为map[string]interface{}。
package main
import (
"fmt"
"github.com/sirupsen/logrus"
func main() {
logger := logrus.New()
logger.SetOutput(os.Stdout)
logger.WithFields(logrus.Fields{
"request_id": "887B4F43-D330-5213-94DF-1B14FA3388C",
"ip": "101.202.112.12",
"user_id": 10022,
}).Info("Info Level")
// 或者
logger.WithField("request_id", "887B4F43-D330-5213-94DF-1B14FA3388C").WithField("ip", "101.202.112.12").WithField("user_id", 10022).Info("Info Level");
我们还可以创建一个logrus.Entry实例,为这个实例设置默认Fields,把logrus.Entry实例设置到记录器Logger,再记录日志时每次都会附带上这些默认的字段。
logger := log.WithFields(log.Fields{"request_id": "887B4F43-D330-5213-94DF-1B14FA3388C"})
logger.Info("Info Level") // 也会记录request_id
logger.Warn("Warn Levle")
上述的内容主要介绍了 logrus 的基础用法,而 logrus 还支持日志自定义输出格式以及 Hook 能力来允许我们自定义一些日志处理逻辑。