Golang logrus的高级配置(hook, logrotate)

·  阅读 10277
原文链接: xiaorui.cc

前言:

        这次聊下最近使用logrus的心得,没有高深的源码,只是一些相对高级的配置吧。golang默认的log模块略显简陋,连基本的info, warn, error 打印方法都没有,不是太适用。 在使用logrus模块之前,我先前都在使用自己封装的log模块,虽然比不上logrus那么多功能,够用是没问题的。 

      话说,golang社区里排名最高的日志模块就那么几个,logrus,log4j … 单看github的活跃度logrus显得更显一筹了。国内外比较出名的golang开源项目,大多都是自己实现的日志磨矿。

     该文章后续会有更新, 原文地址    xiaorui.cc/?p=4963

     

logrus日志切分功能 ?

      对的,logrus默认是没有像logrotate那样的日志切割功能,我曾经在issue里问过sirupsen, 为毛没有日志基本的logrotate ? 他的回复说,不需要切分,首先该功能不是核心功能,最重要的是 作者建议大家把日志输出到其他的日志server里,比如 filebeat, logstash, syslog, rsyslog, Fluentd 等等。 logrus官方支持的日志服务列表有很多,只要我们能想到的基本都有。

     那么,如果我现在logrus实现日志切分,该如何操作?两种方法.  


第一种,借助于 linux logrotate命令 。

/devops/app/go/src/task_dispatcher/logs/*.log
{
    daily
    sharedscripts
    dateext
    nocompress
    size 1G
    missingok
    notifempty
    copytruncate
    rotate 3复制代码

第二种方法,  使用logrus的hook来加载 github.com/lestrrat/go-file-rotatelogs 模块. 每次当我们写入日志的时候,logrus都会调用 go-file-rotatelogs 来判断日志是否要进行切分…   go-file-rotatelogs  可以实现linux logratate的大多数功能。

package context

import (
    "github.com/lestrrat/go-file-rotatelogs"
    "github.com/rifflock/lfshook"
    log "github.com/sirupsen/logrus"
    "github.com/pkg/errors"
    "path"
    "time"
    "os"
    "fmt"
    "bufio"
)

func InitLogger() {
    baseLogPath := path.Join(GlobalConfig.LogConf.Logdir,
        GlobalConfig.LogConf.Filename)
    writer, err := rotatelogs.New(
        baseLogPath+".%Y%m%d%H%M",
        rotatelogs.WithLinkName(baseLogPath),      // 生成软链,指向最新日志文件
        rotatelogs.WithMaxAge(7*24*time.Hour),     // 文件最大保存时间
        rotatelogs.WithRotationTime(24*time.Hour), // 日志切割时间间隔
    )
    if err != nil {
        log.Errorf("config local file system logger error. %v", errors.WithStack(err))
    }

    //log.SetFormatter(&log.TextFormatter{})
    switch level := GlobalConfig.LogConf.LogLevel; level {
    /*
    如果日志级别不是debug就不要打印日志到控制台了
     */
    case "debug":
        log.SetLevel(log.DebugLevel)
        log.SetOutput(os.Stderr)
    case "info":
        setNull()
        log.SetLevel(log.InfoLevel)
    case "warn":
        setNull()
        log.SetLevel(log.WarnLevel)
    case "error":
        setNull()
        log.SetLevel(log.ErrorLevel)
    default:
        setNull()
        log.SetLevel(log.InfoLevel)
    }

    lfHook := lfshook.NewHook(lfshook.WriterMap{
        log.DebugLevel: writer, // 为不同级别设置不同的输出目的
        log.InfoLevel:  writer,
        log.WarnLevel:  writer,
        log.ErrorLevel: writer,
        log.FatalLevel: writer,
        log.PanicLevel: writer,
    })
    log.AddHook(lfHook)
}

func setNull() {
    src, err := os.OpenFile(os.DevNull, os.O_APPEND|os.O_WRONLY, os.ModeAppend)
    if err!= nil{
        fmt.Println("err", err)
    }
    writer := bufio.NewWriter(src)
    log.SetOutput(writer)
}复制代码

既然作者这么推荐大家使用logrus hook的方式来扩展日志功能,那么怎么自己写一个hook模块?  其实很简单,只需要实现这几个方法就可以了,主要看 Fire 函数…  当我们调用logrus.addHook把自定义的hook加载后,每次我们写日志的时候,都会调用Fire方法。 

logrus hook 是一个值得深入学习的设计,你可以轻易适用hook来实现多文件写入。 比如,error级别的日志独立输出到error.log文件里,其他都放在一起。

package syslog

import (
    "fmt"
    "log/syslog"
    "os"

    "github.com/sirupsen/logrus"
)


type SyslogHook struct {
    Writer        *syslog.Writer
    SyslogNetwork string
    SyslogRaddr   string
}

func NewSyslogHook(network, raddr string, priority syslog.Priority, tag string) (*SyslogHook, error) {
    w, err := syslog.Dial(network, raddr, priority, tag)
    return &SyslogHook{w, network, raddr}, err
}

func (hook *SyslogHook) Fire(entry *logrus.Entry) error {
    line, err := entry.String()
    if err != nil {
        fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err)
        return err
    }

    switch entry.Level {
    case logrus.PanicLevel:
        return hook.Writer.Crit(line)
    case logrus.FatalLevel:
        return hook.Writer.Crit(line)
    case logrus.ErrorLevel:
        return hook.Writer.Err(line)
    case logrus.WarnLevel:
        return hook.Writer.Warning(line)
    case logrus.InfoLevel:
        return hook.Writer.Info(line)
    case logrus.DebugLevel:
        return hook.Writer.Debug(line)
    default:
        return nil
    }
}

func (hook *SyslogHook) Levels() []logrus.Level {
    return logrus.AllLevels
}复制代码

总结,个人对logrus的功能不是太满意,压根用不到的功能贼多,真正会用到的功能不够简单干练。  针对logrus日志切割的问题,我给作者提过两次了,作者忽忽悠悠把issue给关了。

END. 

分类:
后端
收藏成功!
已添加到「」, 点击更改