Logrus - 基于Golang的结构化日志记录器

AI 摘要: Logrus是Go的结构化记录器,与标准库记录器log API完全兼容,支持多种功能和特性,包括与标准日志格式兼容,日志等级设置,自定义格式化输出等

Logrus是Go(golang)的结构化记录器,与标准库记录器log API完全兼容。

更多了解:https://github.com/sirupsen/logrus

1. 主要功能

  • 与标准库log API兼容
  • 支持标准日志格式等级:Trace、Debug、Info、Warn、Error、Fatal、Panic
  • 支持基于环境变量,设置不同的日志格式类型、日志记录输出方式、日志等级
  • 日志记录中的Fields项格式是type Fields map[string]interface{},支持多种值类型
  • 支持公共信息记录,诸如IP来源、URL类型的信息
  • 将日志记录器用作io.Writer,用于http serverErrorLog日志记录
  • 支持钩子操作(在日志等级高于某个级别,比如错误级别以上,触发邮件或者短信通知)
  • 支持自定义格式化(logrus.TextFormatterlogrus.JSONFormatter)以及第三方格式化输出,比如logstash
  • Fatal处理器(在os.Exit(1)退出应用之前,可以做出相关做的操作
  • 并发安全,基于mutex互斥写操作,可以基于logger.SetNoLock()取消

2. 功能介绍

2.1. 日志等级

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
func DefaultLogging() {
    dfLogger := logrus.WithFields(logrus.Fields{
        "uid":      100,
        "nickname": "clark",
        "new":      false,
    })

    dfLogger.Trace("---------trace level msg")
    dfLogger.Debug("---------debug level msg")
    dfLogger.Info("---------info level msg")
    dfLogger.Warn("---------warn level msg")
    dfLogger.Error("---------error level msg")
    //dfLogger.Fatal("user join activity !")
    //dfLogger.Panic("panic level msg @")
}

2.2. 文件记录

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
func FileLogging() {
    fileLogger := logrus.New()
    logFile := os.TempDir() + "logrus.log"

    //You could set this to any `io.Writer` such as a file
    file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
    if err == nil {
        fileLogger.SetOutput(file)
    } else {
        logrus.Info("Failed to log to file, using default stderr")
    }

    fileLogger.WithFields(logrus.Fields{
        "animal": "walrus",
        "size":   10,
    }).Warn("A group of walrus emerges from the ocean")

    // log output os.Stdout
    logrus.WithFields(logrus.Fields{
        "logFile": logFile,
    }).Info("logrus to file...")
}

2.3. 记录上下文

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
func CommonLogging() {
    hostname, _ := os.Hostname()

    // A common pattern is to re-use fields between logging statements by re-using
    // the logrus.Entry returned from WithFields()
    contextLogger := logrus.WithFields(logrus.Fields{
        "hostname": hostname,
        "pid":      os.Getpid(),
    })
    contextLogger.Info("I'll be logged with common and other field")
    contextLogger.Info("Me too")
}

2.4. Logger作为io.Writer

1
2
3
4
5
6
func ServerLogging()  {
    w := logrus.StandardLogger().Writer()
    _ = &http.Server{
        ErrorLog: log.New(w, "", 0),
    }
}

2.5. 基于环境配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var Environment = "dev"

func init() {
    logrus.SetFormatter(&logrus.JSONFormatter{
        DisableTimestamp: false,
    })
    logrus.SetLevel(logrus.TraceLevel)
    switch Environment {
    case "dev", "test":
        logrus.SetFormatter(&logrus.TextFormatter{
            DisableTimestamp: false,
            ForceColors: true,
        })
        logrus.SetOutput(colorable.NewColorableStdout())
    case "stage":
        logrus.SetOutput(os.Stdout)
    case "prod":
        logrus.SetLevel(logrus.InfoLevel)
        logFile := os.TempDir() + "logrus.log"
        file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
        if err != nil {
            logrus.Fatal(err)
        }
        logrus.SetOutput(file)
    }
}

2.6. Hook使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
log := logrus.New()
conn, err := net.Dial("tcp", "logstash.mycompany.net:8911")
if err != nil {
        log.Fatal(err)
}
hook := logrustash.New(conn, logrustash.DefaultFormatter(logrus.Fields{"type": "myappName"}))

log.Hooks.Add(hook)
ctx := log.WithFields(logrus.Fields{
        "method": "main",
})
ctx.Info("Hello World!")

2.7. 输出示例

dev

stage

1
2
3
4
5
6
7
8
{"level":"info","logFile":"/var/folders/pk/2mwxkhlx5g7ckfwyks8vn3n40000gn/T/logrus.log","msg":"logrus to file...","time":"2019-07-05T00:31:39+08:00","version":"v1.0.1"}
{"level":"trace","msg":"---------trace level msg","new":false,"nickname":"clark","time":"2019-07-05T00:31:39+08:00","uid":100}
{"level":"debug","msg":"---------debug level msg","new":false,"nickname":"clark","time":"2019-07-05T00:31:39+08:00","uid":100}
{"level":"info","msg":"---------info level msg","new":false,"nickname":"clark","time":"2019-07-05T00:31:39+08:00","uid":100}
{"level":"warning","msg":"---------warn level msg","new":false,"nickname":"clark","time":"2019-07-05T00:31:39+08:00","uid":100}
{"level":"error","msg":"---------error level msg","new":false,"nickname":"clark","time":"2019-07-05T00:31:39+08:00","uid":100}
{"hostname":"home-mac","level":"info","msg":"I'll be logged with common and other field","pid":26442,"time":"2019-07-05T00:31:39+08:00"}
{"hostname":"home-mac","level":"info","msg":"Me too","pid":26442,"time":"2019-07-05T00:31:39+08:00"}