logrus日志使用详解

1.logrus特色
golang标准库的日志框架很简单,logrus框架的特色:
1)彻底兼容标准日志库
六种日志级别:debug, info, warn, error, fatal, panic
2)可扩展的Hook机制
容许使用者经过Hook的方式将日志分发到任意地方,如本地文件系统,logstash,elasticsearch或者mq等,或者经过Hook定义日志内容和格式等
3)可选的日志输出格式
内置了两种日志格式JSONFormater和TextFormatter,还能够自定义日志格式
4)Field机制
经过Filed机制进行结构化的日志记录
5)线程安全git

logrus不提供的功能以下:
1)没有提供行号和文件名的支持
2)输出到本地文件系统没有提供日志分割功能
3)没有提供输出到ELK等日志处理中心的功能
这些功能均可以经过自定义hook来实现github

2.使用示例golang

package main

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

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

运行结果:redis

time="2019-01-24T18:43:57+08:00" level=info msg="a walrus appears" animal=walrus

3.设置log的参数api

func init(){
    log.SetFormatter(&log.JSONFormatter{})
    log.SetOutput(os.Stdout)
    log.SetLevel(log.InfoLevel)
}

运行结果:安全

{"animal":"walrus","level":"info","msg":"a walrus appears","time":"2019-01-24T18:51:00+08:00"}

4.建立Logger实例
logrus有一个默认的Logger
当一个应用中,须要向多个地方输出时,须要不一样的Logger实例app

var log = logrus.New()

可使用以上语句,建立Logger实例框架

package main

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

var log = logrus.New()

func main() {
    file ,err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666)
    if err == nil{
        log.Out = file
    }else{
        log.Info("Failed to log to file")
    }

    log.WithFields(logrus.Fields{
        "filename": "123.txt",
    }).Info("打开文件失败")
}

运行结果:
logrus.log文件elasticsearch

time="2019-01-24T19:02:21+08:00" level=info msg="打开文件失败" filename=123.txt

5.Fields
1)做用
结构化信息记录,传统的记录方式如:函数

log.Fatalf("Failed to send event %s to topic %s with key %d", event, topic, key)

在logrus中不提倡这样写,鼓励使用Fields结构化日志内容,如:

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

2)固定Fields
能够固定Fields不用每次都写

package main

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

var log = logrus.New()

func main() {
    entry := logrus.WithFields(logrus.Fields{
        "name": "test",
    })
    entry.Info("message1")
    entry.Info("message2")
}

运行结果:

time="2019-01-24T19:04:51+08:00" level=info msg=message1 name=test
time="2019-01-24T19:04:51+08:00" level=info msg=message2 name=test

6.hook
hook的原理是,在logrus写入日志时拦截,修改logrus.Entry

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

使用示例:
自定义一个hook DefaultFieldHook,在全部级别的日志消息中加入默认字段appName="myAppName"

type DefaultFieldHook struct {
}

func (hook *DefaultFieldHook) Fire(entry *log.Entry) error {
    entry.Data["appName"] = "MyAppName"
    return nil
}

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

在初始化时,调用logrus.AddHook(hook)添加响应的hook便可

7.记录文件名和行号

8.日志文件本地分割
经过hook插件file-rotatelogs进行日志本地文件分割

import (
    "github.com/lestrrat-go/file-rotatelogs"
    "github.com/rifflock/lfshook"
    log "github.com/sirupsen/logrus"
    "time"
)

func newLfsHook(logLevel *string, maxRemainCnt uint) log.Hook {
    writer, err := rotatelogs.New(
        logName+".%Y%m%d%H",
        // WithLinkName为最新的日志创建软链接,以方便随着找到当前日志文件
        rotatelogs.WithLinkName(logName),

        // WithRotationTime设置日志分割的时间,这里设置为一小时分割一次
        rotatelogs.WithRotationTime(time.Hour),

        // WithMaxAge和WithRotationCount两者只能设置一个,
        // WithMaxAge设置文件清理前的最长保存时间,
        // WithRotationCount设置文件清理前最多保存的个数。
        //rotatelogs.WithMaxAge(time.Hour*24),
        rotatelogs.WithRotationCount(maxRemainCnt),
    )

    if err != nil {
        log.Errorf("config local file system for logger error: %v", err)
    }

    level, ok := logLevels[*logLevel]

    if ok {
        log.SetLevel(level)
    } else {
        log.SetLevel(log.WarnLevel)
    }

    lfsHook := lfshook.NewHook(lfshook.WriterMap{
        log.DebugLevel: writer,
        log.InfoLevel:  writer,
        log.WarnLevel:  writer,
        log.ErrorLevel: writer,
        log.FatalLevel: writer,
        log.PanicLevel: writer,
    }, &log.TextFormatter{DisableColors: true})

    return lfsHook
}

9.日志文件发送到elasticsearch
将logrus日志发送到elasticsearch的原理是在hook的每次fire调用时,使用golang的es客户端将日志信息写入elasticsearch

import (
    "github.com/olivere/elastic"
    "gopkg.in/sohlich/elogrus"
)

func initLog() {
    client, err := elastic.NewClient(elastic.SetURL("http://localhost:9200"))
    if err != nil {
        log.Panic(err)
    }
    hook, err := elogrus.NewElasticHook(client, "localhost", log.DebugLevel, "mylog")
    if err != nil {
        log.Panic(err)
    }
    log.AddHook(hook)
}

10.将日志发送到其余位置

logrus_amqp:Logrus hook for Activemq。
logrus-logstash-hook:Logstash hook for logrus。
mgorus:Mongodb Hooks for Logrus。
logrus_influxdb:InfluxDB Hook for Logrus。
logrus-redis-hook:Hook for Logrus which enables logging to RELK stack (Redis, Elasticsearch, Logstash and Kibana)。

11.Fatal处理 和不少日志框架同样,logrus的Fatal系列函数会执行os.Exit(1)。可是logrus提供能够注册一个或多个fatal handler函数的接口logrus.RegisterExitHandler(handler func() {} ),让logrus在执行os.Exit(1)以前进行相应的处理。fatal handler能够在系统异常时调用一些资源释放api等,让应用正确的关闭。

相关文章
相关标签/搜索