zoukankan      html  css  js  c++  java
  • 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)线程安全

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

    2.使用示例

    package main
    
    import (
    	log "github.com/sirupsen/logrus"
    )
    
    func main() {
    	log.WithFields(log.Fields{
    		"animal": "walrus",
    	}).Info("a walrus appears")
    }
    

    运行结果:

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

    3.设置log的参数

    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实例

    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文件

    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等,让应用正确的关闭。

  • 相关阅读:
    RestKit ,一个用于更好支持RESTful风格服务器接口的iOS库
    Pop–实现任意iOS对象的任意属性的动态变化
    界面传值失败
    UIImagePickerController
    NSURLSession
    iOS图标尺寸
    cocoapods
    duplicate symbol _OBJC_IVAR
    MAC升级openssl
    Mac
  • 原文地址:https://www.cnblogs.com/shijingjing07/p/10316444.html
Copyright © 2011-2022 走看看