golang结构化日志记录插件库logrus的使用

Golang 结构化日志记录插件库 logrus 的使用

Logrus 是 Go 语言的一个结构化日志记录库,完全兼容标准库 logger 的 API。

基础使用

简单示例

package main

import (
  log "github.com/sirupsen/logrus"
)

func main() {
  log.WithFields(log.Fields{
    "animal": "walrus",
  }).Info("A walrus appears")
}

配置示例

package main

import (
  "os"
  log "github.com/sirupsen/logrus"
)

func init() {
  // 使用 JSON 格式而不是默认的 ASCII 格式
  log.SetFormatter(&log.JSONFormatter{})

  // 输出到 stdout 而不是默认的 stderr
  log.SetOutput(os.Stdout)

  // 只记录 warning 级别及以上的日志
  log.SetLevel(log.WarnLevel)
}

func main() {
  log.WithFields(log.Fields{
    "animal": "walrus",
    "size":   10,
  }).Info("A group of walrus emerges from the ocean")

  log.WithFields(log.Fields{
    "omg":    true,
    "number": 122,
  }).Warn("The group's number increased tremendously!")

  log.WithFields(log.Fields{
    "omg":    true,
    "number": 100,
  }).Fatal("The ice breaks!")
}

日志级别

Logrus 有七个日志级别:Trace, Debug, Info, Warning, Error, Fatal 和 Panic。

log.Trace("Something very low level.")
log.Debug("Useful debugging information.")
log.Info("Something noteworthy happened!")
log.Warn("You should probably take a look at this.")
log.Error("Something failed but I'm not quitting.")
log.Fatal("Bye.") // 调用 os.Exit(1)
log.Panic("I'm bailing.") // 调用 panic()

字段

Logrus 鼓励使用字段进行结构化日志记录:

log.WithFields(log.Fields{
  "event": event,
  "topic": topic,
  "key":   key,
}).Fatal("Failed to send event")

默认字段

可以为日志条目设置默认字段:

requestLogger := log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})
requestLogger.Info("something happened on that request")
requestLogger.Warn("something not great happened")

日志格式

TextFormatter (默认)

log.SetFormatter(&log.TextFormatter{
  DisableColors: true,
  FullTimestamp: true,
})

JSONFormatter

log.SetFormatter(&log.JSONFormatter{})

自定义格式

可以实现 Formatter 接口来自定义格式:

type MyJSONFormatter struct {
}

log.SetFormatter(new(MyJSONFormatter))

func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) {
  serialized, err := json.Marshal(entry.Data)
  if err != nil {
    return nil, fmt.Errorf("Failed to marshal fields to JSON, %w", err)
  }
  return append(serialized, '\n'), nil
}

钩子(Hooks)

可以添加钩子来处理特定级别的日志:

import (
  log "github.com/sirupsen/logrus"
  "gopkg.in/gemnasium/logrus-airbrake-hook.v2"
  logrus_syslog "github.com/sirupsen/logrus/hooks/syslog"
  "log/syslog"
)

func init() {
  log.AddHook(airbrake.NewHook(123, "xyz", "production"))

  hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
  if err != nil {
    log.Error("Unable to connect to local syslog daemon")
  } else {
    log.AddHook(hook)
  }
}

测试

Logrus 提供了测试工具:

import(
  "github.com/sirupsen/logrus"
  "github.com/sirupsen/logrus/hooks/test"
  "github.com/stretchr/testify/assert"
  "testing"
)

func TestSomething(t *testing.T){
  logger, hook := test.NewNullLogger()
  logger.Error("Helloerror")

  assert.Equal(t, 1, len(hook.Entries))
  assert.Equal(t, logrus.ErrorLevel, hook.LastEntry().Level)
  assert.Equal(t, "Helloerror", hook.LastEntry().Message)

  hook.Reset()
  assert.Nil(t, hook.LastEntry())
}

完整示例

package main

import (
  "os"
  log "github.com/sirupsen/logrus"
)

func init() {
  // 设置日志格式为 JSON
  log.SetFormatter(&log.JSONFormatter{})
  
  // 设置输出到标准输出
  log.SetOutput(os.Stdout)
  
  // 设置日志级别
  log.SetLevel(log.InfoLevel)
  
  // 启用调用者信息
  log.SetReportCaller(true)
}

func main() {
  // 基础日志
  log.Info("Starting application")
  
  // 带字段的日志
  log.WithFields(log.Fields{
    "component": "user",
    "action":    "login",
    "user_id":   12345,
  }).Info("User logged in")
  
  // 错误日志
  log.WithFields(log.Fields{
    "error":     "connection timeout",
    "attempts":  3,
    "service":   "database",
  }).Error("Failed to connect to database")
  
  // 创建带默认字段的记录器
  contextLogger := log.WithFields(log.Fields{
    "request_id": "abc123",
    "ip":        "192.168.1.1",
  })
  
  contextLogger.Info("Request started")
  contextLogger.Warn("Request taking longer than expected")
  
  // 致命错误
  log.WithFields(log.Fields{
    "error": "disk full",
  }).Fatal("Cannot continue execution")
}

Logrus 是一个功能强大且灵活的结构化日志记录库,适合在各种规模的 Go 项目中使用。


更多关于golang结构化日志记录插件库logrus的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang结构化日志记录插件库logrus的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


logrus - Go语言结构化日志记录库

logrus是Go语言中最流行的结构化日志记录库之一,它提供了丰富的日志功能和灵活的配置选项。下面我将详细介绍logrus的使用方法。

基本安装与导入

首先安装logrus:

go get github.com/sirupsen/logrus

然后导入:

import (
  log "github.com/sirupsen/logrus"
)

基本用法

package main

import (
  log "github.com/sirupsen/logrus"
)

func main() {
  // 基本日志输出
  log.Info("This is an info message")
  log.Warn("This is a warning message")
  log.Error("This is an error message")
  
  // 带字段的日志
  log.WithFields(log.Fields{
    "animal": "walrus",
    "size":   10,
  }).Info("A group of walrus emerges from the ocean")
}

日志级别

logrus支持7个日志级别:

log.Trace("Very low level debug information")
log.Debug("Debug information")
log.Info("General operational entries")
log.Warn("Non-critical issues")
log.Error("Errors that should definitely be noted")
log.Fatal("Critical errors - calls os.Exit(1)")
log.Panic("Highest level of severity - calls panic()")

设置日志级别:

func main() {
  // 只记录警告及以上级别的日志
  log.SetLevel(log.WarnLevel)
  
  log.Info("This won't be logged") // 不会输出
  log.Warn("This will be logged") // 会输出
}

日志格式

logrus支持多种日志格式:

func main() {
  // 文本格式(默认)
  log.SetFormatter(&log.TextFormatter{
    FullTimestamp: true,
  })
  
  // JSON格式
  log.SetFormatter(&log.JSONFormatter{})
  
  log.WithFields(log.Fields{
    "event": "purchase",
    "amount": 123.45,
  }).Info("Order processed")
}

钩子(Hooks)

logrus支持钩子,可以在日志记录前后执行自定义操作:

type MyHook struct{}

func (hook *MyHook) Levels() []log.Level {
  return log.AllLevels
}

func (hook *MyHook) Fire(entry *log.Entry) error {
  // 在这里可以添加自定义逻辑,如发送日志到远程服务器
  entry.Data["custom_field"] = "custom_value"
  return nil
}

func main() {
  log.AddHook(&MyHook{})
  log.Info("This log will have a custom field")
}

文件输出

将日志输出到文件:

import (
  "os"
  log "github.com/sirupsen/logrus"
)

func main() {
  file, err := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
  if err == nil {
    log.SetOutput(file)
  } else {
    log.Info("Failed to log to file, using default stderr")
  }
  
  log.Info("This will be written to the log file")
}

上下文日志

可以创建带有预设字段的日志实例:

func main() {
  logger := log.WithFields(log.Fields{
    "app": "myapp",
    "env": "production",
  })
  
  logger.Info("Starting application")
  logger.WithField("user", "john").Info("User logged in")
}

性能优化

对于高性能场景,可以使用Entry的日志方法:

func main() {
  logger := log.WithFields(log.Fields{
    "component": "user",
  })
  
  // 更高效的方式
  entry := logger.WithField("method", "login")
  entry.Info("User login attempt")
  entry.WithField("ip", "192.168.1.1").Info("User login from IP")
}

实际应用示例

package main

import (
  "os"
  log "github.com/sirupsen/logrus"
)

func initLogger() {
  // 设置JSON格式
  log.SetFormatter(&log.JSONFormatter{})
  
  // 设置输出到标准输出和文件
  file, err := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
  if err == nil {
    log.SetOutput(file)
  } else {
    log.Info("Failed to log to file, using default stderr")
  }
  
  // 设置日志级别
  log.SetLevel(log.InfoLevel)
}

func main() {
  initLogger()
  
  // 创建带有应用信息的日志实例
  appLogger := log.WithFields(log.Fields{
    "app": "my-application",
    "version": "1.0.0",
  })
  
  appLogger.Info("Application starting")
  
  // 处理请求示例
  processRequest(appLogger, "user123", "/api/data")
  
  appLogger.Info("Application shutting down")
}

func processRequest(logger *log.Entry, userID, path string) {
  requestLogger := logger.WithFields(log.Fields{
    "user": userID,
    "path": path,
  })
  
  requestLogger.Info("Processing request")
  
  // 模拟业务逻辑
  if path == "/api/data" {
    requestLogger.WithField("data", "sensitive").Warn("Accessing sensitive data")
  }
  
  requestLogger.Info("Request processed")
}

logrus提供了强大而灵活的日志记录功能,特别适合需要结构化日志的应用程序。通过合理配置,可以满足从开发调试到生产环境的各种日志需求。

回到顶部