当前位置: 首页 > 工具软件 > Logrus > 使用案例 >

golang日志框架之logrus详细说明

终祯
2023-12-01

前面的话

下面示例代码中的一些import我没做校验,我只是从我的一个测试代码里抠出来的,出现一些错误自己简单处理下就可以用。

logrus简介

logrus是一个可插拔的、结构化的日志框架。
logrus拥有六种日志级别:debug、info、warn、error、fatal和panic
可扩展的Hook机制:
允许使用者通过hook的方式将日志分发到任意地方,如本地文件系统、标准输出、logstash、elasticsearch或者mq等,或者通过hook定义日志内容和格式等。
logrus内置了两种日志格式,JSONFormatter和TextFormatter,如果这两个格式不满足需求,可以自己动手实现接口Formatter,来定义自己的日志格式。
logrus鼓励通过Field机制进行精细化的、结构化的日志记录,而不是通过冗长的消息来记录日志。

写一个简单的例子

package main

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

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

高级用法

logger是一种相对高级的用法, 对于一个大型项目, 往往需要一个全局的logrus实例,即logger对象来记录项目所有的日志。

一些默认的初始化

package main

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

func main() {
	var log = logrus.New()
	// 设置日志级别为xx以及以上
	 log.SetLevel(logrus.InfoLevel)
	 //JSON在生产中通常只在使用Splunk或Logstash等工具进行日志聚合时才有用。
	 // 设置日志格式为json格式
	// log.SetFormatter(&logrus.JSONFormatter{
	// 	// PrettyPrint: true,//格式化json
	// 	TimestampFormat: "2006-01-02 15:04:05",//时间格式化
	// })
	log.SetFormatter(&logrus.TextFormatter{
		TimestampFormat: "2006-01-02 15:04:05",//时间格式化
	})
	// 设置将日志输出到标准输出(默认的输出为stderr,标准错误)
	// 日志消息输出可以是任意的io.writer类型
	log.SetOutput(os.Stdout)
    // 初始化一些公共参数
	loginit:=log.WithFields(logrus.Fields{
		"animal": "walrus",
	})
	//输出日志
	log.Info("A walrus appears")
}

在日志中打印文件行号等信息

log.SetReportCaller(true)可以打印行号

package main

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

func main() {
// logger是一种相对高级的用法, 对于一个大型项目, 往往需要一个全局的logrus实例,即logger对象来记录项目所有的日志。
	var log = logrus.New()
	log.SetReportCaller(true) // 显示行号等信息
	 // 设置日志级别为xx以及以上
	 log.SetLevel(logrus.InfoLevel)
	log.SetFormatter(&logrus.TextFormatter{
		TimestampFormat: "2006-01-02 15:04:05",//时间格式化
	})
	// 设置将日志输出到标准输出(默认的输出为stderr,标准错误)
	// 日志消息输出可以是任意的io.writer类型
	log.SetOutput(os.Stdout)
	// 初始化一些公共参数
	loginit:=log.WithFields(logrus.Fields{
		"animal": "walrus",
	})
	log.Info("A walrus appears")
}

hook使用

使用的是AddHook()方法

package main

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

func main() {
// logger是一种相对高级的用法, 对于一个大型项目, 往往需要一个全局的logrus实例,即logger对象来记录项目所有的日志。
	var log = logrus.New()
	log.SetReportCaller(true)
	 // 设置日志级别为xx以及以上
	 log.SetLevel(logrus.InfoLevel)
	log.AddHook(&DefaultFieldHook{})

	log.SetFormatter(&logrus.TextFormatter{
		TimestampFormat: "2006-01-02 15:04:05",//时间格式化

	})
	// 设置将日志输出到标准输出(默认的输出为stderr,标准错误)
	// 日志消息输出可以是任意的io.writer类型
	log.SetOutput(os.Stdout)

	// 初始化一些公共参数
	loginit:=log.WithFields(logrus.Fields{
		"animal": "walrus",
	})

	log.Info("A walrus appears")
	
	}
}
type DefaultFieldHook struct {
}

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

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

日志分割

Logrus不提供该功能,需要借助file-rotatelogs进行日志本地文件分割。

一些说明

WithLinkName()为最新的日志建立软连接,以方便随着找到当前日志文件
WithRotationTime()设置文件分割之间的间隔。默认情况下,日志每86400秒即1天分割一次。
WithMaxAge和WithRotationCount二者只能设置一个,
WithMaxAge()设置文件清理前的最长保存时间,就是说只保留最近指定时间内的日志,之前的日志都被清除。默认每7天清除下日志文件,需要设置为rotatelogs.WithMaxAge(-1)手动禁止
WithRotationCount()清除除最新n个文件之外的日志,默认禁用。

如果不想清除日志,WithRotationCount因为默认是禁止的所有不设置,WithMaxAge需要设置参数为-1。这样才不会清除日志。

日志分割规则:
rotatelogs.New()的第一个参数是日志名称规则:如 logName+“.%Y%m%d%H%M%S”,这里精度是年月日时分秒;
WithRotationTime默认是每天分割一次日志文件,如果你要测试,比如设置为每3s分割一次日志文件:rotatelogs.WithRotationTime(time.Second*3),这样可以方便你快速测试代码正确与否

下面的代码中我起了一万个协程来并发记录日志,为的是测试hook和其他的并发安全,不是必须这么写。

package main

import (
  "github.com/sirupsen/logrus"
  "os"
  "runtime"
	//   "fmt"
	//   "strings"
	"github.com/lestrrat-go/file-rotatelogs"
	"github.com/rifflock/lfshook"
	"time"
)

func main() {
// logger是一种相对高级的用法, 对于一个大型项目, 往往需要一个全局的logrus实例,即logger对象来记录项目所有的日志。
	var log = logrus.New()
	log.SetReportCaller(true)
	 // 设置日志级别为xx以及以上
	 log.SetLevel(logrus.InfoLevel)
	 log.AddHook(&DefaultFieldHook{})
	// 设置日志格式为json格式
	// log.SetFormatter(&logrus.JSONFormatter{
	// 	// PrettyPrint: true,//格式化json
	// 	TimestampFormat: "2006-01-02 15:04:05",//时间格式化
	// })
	log.SetFormatter(&logrus.TextFormatter{
		ForceColors:true,
		EnvironmentOverrideColors:true,
		// FullTimestamp:true,
		TimestampFormat: "2006-01-02 15:04:05",//时间格式化
		// DisableLevelTruncation:true,
	})
	// 设置将日志输出到标准输出(默认的输出为stderr,标准错误)
	// 日志消息输出可以是任意的io.writer类型
	log.SetOutput(os.Stdout)
	//这是我在window上的测试代码,文件名自己修改
	logName:=`G:\gopath\src\github.com\gonote\27tools\日志\aaa`
	writer, err := rotatelogs.New(
	 	//这是分割代码的命名规则,要和下面WithRotationTime时间精度一致。要是分钟都是分钟
        logName+".%Y%m%d%H%M%S",
        // WithLinkName为最新的日志建立软连接,以方便随着找到当前日志文件。windows报错没权限
        // rotatelogs.WithLinkName(logName),

       //文件切割之间的间隔。默认情况下,日志每86400秒/一天旋转一次。注意:记住要利用时间。持续时间值。
        // rotatelogs.WithRotationTime(time.Second*3),
        // WithMaxAge和WithRotationCount二者只能设置一个,
        // WithMaxAge设置文件清理前的最长保存时间,
        // WithRotationCount设置文件清理前最多保存的个数。 默认情况下,此选项是禁用的。
		// rotatelogs.WithMaxAge(time.Second*30),//默认每7天清除下日志文件
		rotatelogs.WithMaxAge(-1), //需要手动禁用禁用  默认情况下不清除日志,
        rotatelogs.WithRotationCount(2),//清除除最新2个文件之外的日志,默认禁用
    )
    if err != nil {
        log.Errorf("config local file system for logger error: %v", err)
    }

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

	log.AddHook(lfsHook)



	// 初始化一些公共参数
	loginit:=log.WithFields(logrus.Fields{
		"animal": "walrus",
	})

	for i:=0;i<10000;i++{
		go func(log *logrus.Entry){
			for {
				time.Sleep(time.Second*1)
				log.Info("A walrus appears")
			}
		}(loginit)
	
	}

	select{}
}

线程安全

线程安全
默认情况下,logrus的api都是线程安全的,其内部通过互斥锁来保护并发写。互斥锁工作于调用hooks或者写日志的时候。如果不需要锁,可以调用logger.SetNoLock()来关闭之。可以关闭logrus互斥锁的情形包括:

没有设置hook,或者所有的hook都是线程安全的实现。
写日志到logger.Out已经是线程安全的了。例如,logger.Out已经被锁保护,或者写文件时,文件是以O_APPEND方式打开的,并且每次写操作都小于4k。

Fatal处理

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

后记

logrus基本能满足大多数日志需求,一些其他的特性,基本去github看下文档或者百度下就能出来

 类似资料: