Go编程快闪之 logrus日志库
阅读原文时间:2023年08月09日阅读:3

战术卧倒

golang中常见的日志包是logrus, 根据logrus的胚子和我们的生产要求,给出一个生产可用的logrus实践姿势。

主谓宾定状补

logrus是一个结构化的、可插拔的、兼容golang标准log api的日志库。

快速过一下能力

  • 支持对output=TTY增加关键字颜色

  • 内置JSONFormatter和TextFormatter(默认)两种Formatter

  • 支持输出logger所在的函数行位置 log.SetReportCaller(true)

  • 可以兼容golang内置的标准log库, 建议无脑替换

  • 鼓励输出可解析的日志字段,而不是大段的无法结构化的文本日志

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

基于现状,凑了6个钱包上生产,下面给出一些自己的生产实践。

添砖加瓦

1. logrus不支持滚动日志

好马配好鞍 https://github.com/lestrrat-go/file-rotatelogs 让你下雨天不再哭泣。

它会根据配置自动按照时间切分日志,并滚动清理日志(不用配磁盘报警,不用担心磁盘满故障)。

    logf, err := rotatelogs.New(
      cfg.Log.LogDir+logName+".%Y%m%d%H%M",
      rotatelogs.WithLinkName(cfg.Log.LogDir+logName),
      rotatelogs.WithMaxAge(24*time.Hour),
      rotatelogs.WithRotationTime(time.Hour),
  )
  if err != nil {
      stdLog.Printf("failed to create rotatelogs: %s", err)
      return
  }

2. 日志格式化

java生态默认日志输出格式:

11:44:44.827 WARN [93ef3E0120160803114444] [main] [ClassPathXmlApplicationContext] Exception encountered during context initialization - cancelling refresh attempt

在公司中javaer占据主流,故java的默认格式就成了公司集中式日志的"标准"格式。

很明显,logrus默认的两种Formatter都不匹配。

github.com/antonfisher/nested-logrus-formatter 让你柳暗花明。

log.SetFormatter(&nested.Formatter{ // 嵌套日志兼容skynet日志格式
        HideKeys:        true,
        FieldsOrder:     []string{"region", "node", "topic"},
        TimestampFormat: "2006-01-02 15:04:05.000", // 显示ms
    })

3. 自定义Hook用法:输出默认字段

写本文的时候,发现logrus官方本身支持输出默认日志字段。

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

Hook: 通常 钩子函数用于在触发某种事件时附带一些动作。

logrus的Hook定义:logEntry满足指定的logLevel日志时, 你想要做的动作(你甚至可以不设置output直接在hook输出日志, 这就是内置write hook的实现)。

type Hook interface {
    Levels() []Level
    Fire(*Entry) error
}

示例代码为logLevel>=info的logEntry,固定了2个日志字段。

type FixedFieldHook struct {
    LogLevels  []logrus.Level
    FixedField map[string]string
}

// Fire will be called when some logging function is called with current hook
// It will format log entry to string and write it to appropriate writer
func (hook *FixedFieldHook) Fire(entry *logrus.Entry) error {
    for k, v := range hook.FixedField {
        entry.Data[k] = v
    }
    return nil
}

log.AddHook(&FixedFieldHook{ // Set fixed field
        FixedField: map[string]string{"region": cfg.LocalRegion, "node": ip},
        LogLevels: []logrus.Level{
            logrus.InfoLevel,
            logrus.ErrorLevel,
            logrus.WarnLevel,
            logrus.FatalLevel,
        },
    })

抛砖引玉,战术卧倒。

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章