下面示例代码中的一些import我没做校验,我只是从我的一个测试代码里抠出来的,出现一些错误自己简单处理下就可以用。
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")
}
使用的是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。
和很多日志框架一样,logrus的Fatal系列函数会执行os.Exit(1)。但是,logrus提供“可以注册一个或多个fatal handler函数”的接口logrus.RegisterExitHandler(handler func(){}),让logrus在执行os.Exit(1)之前进行相应的处理。fatal handler可以在系统异常时调用一些资源释放api等,让应用正确地关闭。
logrus基本能满足大多数日志需求,一些其他的特性,基本去github看下文档或者百度下就能出来