项目开发-日志篇 | Go

Logrus 是 Go 的结构化日志记录库,与标准库中的日志模块完全兼容。

logrus安装

go install github.com/sirupsen/logrus@latest

logrus使用

在使用 logrus 时,鼓励用 log.WithFields(log.Fields{}).Fatal() 这种方式替代 log.Fatalf("Failed to send event %s to topic %s with key %d"), 以结构化日志输出。

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

若想让重复出现的字段始终附加日志语中,可以将其设置为默认字段,通过创建一个 logrus.Entry来实现

requestLogger := log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})
requestLogger.Info("something happened on that request") # will log request_id and user_ip
requestLogger.Warn("something not great happened")
  • 日志输出级别

Logrus日志级别共有7类,警告级别从低到高低依次为:Trace, Debug, Info, Warning, Error, Fatal and 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.")
// Calls os.Exit(1) after logging
log.Fatal("Bye.")
// Calls panic() after logging
log.Panic("I'm bailing.")

设置日志输出警告级别

log.SetLevel(log.WarnLevel) 
  • 日志输出格式

Logrus内置了JSONFormatter 和 TextFormatter,来定义输出的日志格式。实际开发中,也可以自定义输出格式。

设置内置日志输出格式

log.SetFormatter(&log.JSONFormatter{
    TimestampFormat: "2006-01-02 15:04:05", 
})
//Log as JSON instead of the default ASCII formatter.
log.SetFormatter(&log.JSONFormatter{})


log.SetFormatter(&log.TextFormatter{
    TimestampFormat: "2006-01-02 15:04:05", 
    DisableColors: true,
    FullTimestamp: true,
})
//Log as Text instead of the default ASCII formatter.
log.SetFormatter(&log.TextFormatter{})

自定义日志格式

如下所示,可以参考SetFormatter方法中的参数Formatter, 使用该接口自定义日志格式,其包含 Format 方法,方法内有一个struct类型数据 *Entry, Entry.Data 是所有字段集合,Fields 类型为 map[string]interface{}

// SetFormatter sets the logger formatter.
func (logger *Logger) SetFormatter(formatter Formatter) {
    logger.mu.Lock()
    defer logger.mu.Unlock()
    logger.Formatter = formatter
}

type Formatter interface {
    Format(*Entry) ([]byte, error)
}

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
}

自定义日志格式例子

type MyJSONFormatter struct {
}

log.SetFormatter(new(MyJSONFormatter))

func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) {
  // Note this doesn't include Time, Level and Message which are available on
  // the Entry. Consult `godoc` on information about those fields or read the
  // source of the official loggers.
  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
}
  • 日志输出方式

设置日志输出方式

// Output to stdout instead of the default stderr
log.SetOutput(os.Stdout)

// Can be any io.Writer, see below for File example
logfile, err := os.OpenFile("./logrus.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND,0644)
if err == nil {
    log.SetOutput(logfile) 
} else {
    log.Info("Failed to log to file, using default stderr")
}
  • 日志输出内容

如果希望将调用方法添加为字段,可以设置

log.SetReportCaller(true)

日志输出

{"animal":"penguin","level":"fatal","method":"github.com/sirupsen/arcticcreatures.migrate","msg":"a penguin swims by",
"time":"2014-03-10 19:57:38.562543129 -0400 EDT"}

版权声明:本博客所有文章除特别声明外,均采用 CC BY 4.0许可协议,转载请注明出处
本文链接:https://blog.redamancy.tech/technique/21