logrus介绍

golang标准库的日志框架非常简单,仅仅提供了print,panic和fatal三个函数。对于更精细的日志级别、日志文件分割,以及日志分发等方面,并没有提供支持。在golang的世界,流行的日志框架包括logrus、zap、zerolog、seelog等。

logrus配置

1. 日志级别: logrus有7个日志级别,依次是Trace << Debug << Info << Warning << Error << Fatal << Panic

//  只输出不低于当前级别是日志数据
logrus.SetLevel(logrus.DebugLevel)

2. 日志格式: logrus内置了JSONFormatterTextFormatter两种格式,也可以通过Formatter接口定义日志格式

 // TextFormatter格式
logrus.SetFormatter(&logrus.TextFormatter{
ForceColors: true,
EnvironmentOverrideColors: true,
TimestampFormat: "2006-01-02 15:04:05", //时间格式
// FullTimestamp:true,
// DisableLevelTruncation:true,
})
 // JSONFormatter格式
logrus.SetFormatter(&logrus.JSONFormatter{
PrettyPrint: false, //格式化
TimestampFormat: "2006-01-02 15:04:05", //时间格式
})

3. 输出文件:

 logfile, _ := os.OpenFile("./app.log", os.O_CREATE|os.O_RDWR|os.O_APPEND, 0644)
logrus.SetOutput(logfile) //默认为os.stderr

4. 日志定位: 定位行号(如:func=main.main file="./xxx.go:38"

logrus.SetReportCaller(true)

示例:

func init() {
logrus.SetLevel(logrus.DebugLevel) logrus.SetFormatter(&logrus.JSONFormatter{
TimestampFormat: "2006-01-02 15:04:05",
}) logfile, _ := os.OpenFile("./app.log", os.O_CREATE|os.O_RDWR|os.O_APPEND, 0644)
logrus.SetOutput(logfile) //默认为os.stderr
} //方式一:logrus函数(最终调用的是logrus.StandardLogger默认实例方法)
func main() {
logrus.Infoln("测试数据")
}

日志打印

FieldLogger接口: FieldLogger定义了所有日志打印的方法

type FieldLogger interface {
WithField(key string, value interface{}) *Entry
WithFields(fields Fields) *Entry
WithError(err error) *Entry Debugf(format string, args ...interface{})
Infof(format string, args ...interface{})
Printf(format string, args ...interface{})
Warnf(format string, args ...interface{})
Warningf(format string, args ...interface{})
Errorf(format string, args ...interface{})
Fatalf(format string, args ...interface{})
Panicf(format string, args ...interface{}) Debug(args ...interface{})
Info(args ...interface{})
Print(args ...interface{})
Warn(args ...interface{})
Warning(args ...interface{})
Error(args ...interface{})
Fatal(args ...interface{})
Panic(args ...interface{}) Debugln(args ...interface{})
Infoln(args ...interface{})
Println(args ...interface{})
Warnln(args ...interface{})
Warningln(args ...interface{})
Errorln(args ...interface{})
Fatalln(args ...interface{})
Panicln(args ...interface{})
}

日志打印1: 默认实例 (函数),即通过logrus包提供的函数(覆盖了FieldLogger接口的所有方法),直接打印日志。但其实logrus包函数是调用了logrus.Loger默认实例。

// 直接调用包函数
func main() {
logrus.Infoln("...")
logrus.Errorln("...")
// ...
}

日志打印2:Logger实例(对象),它实现了FieldLogger接口。

func main() {
//var loger = logrus.StandardLogger()
var loger = logrus.New()
loger.Formatter = &logrus.JSONFormatter{TimestampFormat: "2006-01-02 15:04:05"}
loger.Infoln("可以创建任意数量的logrus实例")
}

日志打印3:Entry示例(对象),它也实现了FieldLogger接口,是最终是日志打印入口。

  • 这里用到了Field机制,logrus鼓励通过Field机制进行精细化的、结构化的日志记录,而不是通过冗长的消息来记录日志。
func main() {
logrus.SetFormatter(&logrus.JSONFormatter{TimestampFormat: "2006-01-02 15:04:05"}) // Entry实例
entry := logrus.WithFields(logrus.Fields{
"global": "全局字段",
}) entry.WithFields(logrus.Fields{"module": "用户模块"}).
Info("测试ok")
}

HOOK机制

  • hook即钩子,拦截器。它为logrus提供了强大的功能扩展,如将日志分发到任意地方,如本地文件系统、logstashes等,或者切割日志、定义日志内容和格式等。hook接口原型如下:
type Hook interface {
Levels() []Level //日志级别
Fire(*Entry) error //打印入口(Entry对象)
}

Hook - 日志切割:

import (
"github.com/lestrrat-go/file-rotatelogs"
"github.com/rifflock/lfshook"
"github.com/sirupsen/logrus"
"time"
) // 说明:按时间切割日志文件(2秒创建一个日志文件)
func main() {
hook := NewLfsHook("app_hook", time.Second*2, 5)
logrus.AddHook(hook) logrus.Infoln("测试开始")
log := logrus.WithFields(logrus.Fields{"module": "用户模块"}) for i := 0; i < 10; i++ {
log.Infoln("成功", i)
time.Sleep(time.Second)
}
} // 日志钩子(日志拦截,并重定向)
func NewLfsHook(logName string, rotationTime time.Duration, leastDay uint) logrus.Hook {
writer, err := rotatelogs.New(
// 日志文件
logName+".%Y%m%d%H%M%S", // 日志周期(默认每86400秒/一天旋转一次)
rotatelogs.WithRotationTime(rotationTime), // 清除历史 (WithMaxAge和WithRotationCount只能选其一)
//rotatelogs.WithMaxAge(time.Hour*24*7), //默认每7天清除下日志文件
rotatelogs.WithRotationCount(leastDay), //只保留最近的N个日志文件
)
if err != nil {
panic(err)
} // 可设置按不同level创建不同的文件名
lfsHook := lfshook.NewHook(lfshook.WriterMap{
logrus.DebugLevel: writer,
logrus.InfoLevel: writer,
logrus.WarnLevel: writer,
logrus.ErrorLevel: writer,
logrus.FatalLevel: writer,
logrus.PanicLevel: writer,
}, &logrus.JSONFormatter{TimestampFormat: "2006-01-02 15:04:05"}) return lfsHook
}

Hook - Redis重定向: 即将日志输出到redis

import (
logredis "github.com/rogierlommers/logrus-redis-hook"
"io/ioutil"
"github.com/sirupsen/logrus"
) func init() {
hookConfig := logredis.HookConfig{
Host: "localhost",
Key: "test",
Format: "v1",
App: "my_app_name",
Port: 6379,
Hostname: "my_app_hostname",
DB: 0, // optional
TTL: 3600,
} hook, err := logredis.NewHook(hookConfig)
if err == nil {
logrus.AddHook(hook)
} else {
logrus.Errorf("logredis error: %q", err)
}
} func main() {
logrus.WithFields(logrus.Fields{
"module": "user"}).
Info("user login") // If you want to disable writing to stdout, use setOutput
logrus.SetOutput(ioutil.Discard)
logrus.Info("log to Redis")
} // 测试:
// 1.启动redis服务: redis-server
// 2.监控redis数据: redis-cli monitor

其他Hook:

Gin日志

  • 将gin框架的日志定向到logrus日志文件
func init() {
// 输出格式
logrus.SetFormatter(&logrus.JSONFormatter{TimestampFormat: "2006-01-02 15:04:05"}) // 输出路径
logfile, _ := os.OpenFile("./app.log", os.O_CREATE|os.O_RDWR|os.O_APPEND, 0644)
logrus.SetOutput(logfile) // Gin日志重定向
gin.DisableConsoleColor() //不需要颜色
gin.DefaultWriter = io.MultiWriter(os.Stdout, logfile) //os.Stdout
} //测试:curl 0.0.0.0:8080/index
func main() {
log := logrus.WithFields(logrus.Fields{
"module": "用户模块",
}) r := gin.Default()
r.GET("/index", func(c *gin.Context) {
log.Warnln("gin日志数据")
c.String(200, "ok")
})
_ = r.Run()
}

Fatal处理

  • logrus的Fatal输出,会执行os.Exit(1)。logrus提供RegisterExitHandler方法,可以在系统异常时调用一些资源释放api等,让应用正确地关闭。
func main() {
logrus.RegisterExitHandler(func() {
fmt.Println("发生了fatal异常,执行关闭文件等工作")
}) logrus.Warnln("warn测试")
logrus.Fatalln("fatal测试")
logrus.Infoln("info测试") //不会执行
}

线程安全

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

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

参考

https://blog.csdn.net/wslyk606/article/details/81670713

logrus日志框架的更多相关文章

  1. golang日志框架--logrus学习笔记

    golang日志框架--logrus学习笔记 golang标准库的日志框架非常简单,仅仅提供了print,panic和fatal三个函数,对于更精细的日志级别.日志文件分割以及日志分发等方面并没有提供 ...

  2. logrus日志使用详解

    1.logrus特点 golang标准库的日志框架很简单,logrus框架的特点: 1)完全兼容标准日志库 六种日志级别:debug, info, warn, error, fatal, panic ...

  3. 解读ASP.NET 5 & MVC6系列(9):日志框架

    框架介绍 在之前的.NET中,微软还没有提供过像样的日志框架,目前能用的一些框架比如Log4Net.NLog.CommonLogging使用起来多多少少都有些费劲,和java的SLF4J根本无法相比. ...

  4. Java日志框架:SLF4J,Common-Logging,Log4J,Logback说明

    Log4j  Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台.文件.GUI组件.甚至是套接口服务 器.NT的事件记录器.UNIX Syslog守护进程等 ...

  5. java日志框架slf4j与log4j

    日志记录自然是非常重要的,但恐怕能记住slf4j与log4j等日志框架配置的人就很少了,这个东西不难,只是配置好后很少会去动它,开发新项目一般也是从其他项目拷贝,或者参照文档 废话不多说,先说log4 ...

  6. Moon转告给你一个比Log4net更好日志框架--TracerX Logger 及其对应的日志查看器

    一.介绍 TracerX logger是一个易于上手,且拥有众多高级特性的.NET日志框架. 它能够发送输出结果到多目的地(循环文件.事件日志等....).它也能生成文本和二进制文件.它拥有一个强大的 ...

  7. lombok+slf4j+logback SLF4J和Logback日志框架详解

    maven 包依赖 <dependency> <groupId>org.projectlombok</groupId> <artifactId>lomb ...

  8. log4net 日志框架的配置

    log4net 日志框架的配置——静态文件(一) 添加对log4net程序集的引用 选择程序集文件添加引用即可,需要注意的是需要添加相应程序版本的程序集,如果你的应用是基于.netFramework2 ...

  9. 日志框架对比 NLog VS Log4net

    Log4net 先说Log4net,它是.net平台上一个老牌的日志框架,我接触的时间也不长(因为公司有自己的日志库),但是看着各开源库都在用这个于是前段时间也尝试去了解了一下. 首先让我认识到Log ...

随机推荐

  1. redis数据导入与导出以及配置使用

    最近在研究redis 遇到redis requires Ruby version >= 2.2.2问题 解决办法是 先安装rvm,再把ruby版本提升至2.3.3 1.安装curl sudo y ...

  2. Redis混合存储-冷热数据识别与交换

    Redis混合存储产品是阿里云自主研发的完全兼容Redis协议和特性的混合存储产品. 通过将部分冷数据存储到磁盘,在保证绝大部分访问性能不下降的基础上,大大降低了用户成本并突破了内存对Redis单实例 ...

  3. 08 SSM整合案例(企业权限管理系统):05.SSM整合案例的基本介绍

    04.AdminLTE的基本介绍 05.SSM整合案例的基本介绍 06.产品操作 07.订单操作 08.权限控制 09.用户和角色操作 10.权限关联 11.AOP日志 05.SSM整合案例的基本介绍 ...

  4. Codeforces Round #611 (Div. 3)

    原题面:https://codeforces.com/contest/1283 A.Minutes Before the New Year 题目大意:给定时间,问距离零点零分还有多久? 分析:注意一下 ...

  5. Golang的单目(一元)运算符-地址操作符和接收操作符

    Golang的单目(一元)运算符-地址操作符和接收操作符 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Golang的单目(一元)运算符概述 常见的地址操作符: &: ...

  6. Kafka--初识Kafka

    前言 数据为企业的发展提供动力.我们从数据中获取信息,对他们进行分析处理,然后生成更多的数据.每个应用程序都会产生数据,包括日志消息,度量指标,用户活动记录,响应消息等.数据的点点滴滴都在暗示一些重要 ...

  7. netty权威指南学习笔记六——编解码技术之MessagePack

    编解码技术主要应用在网络传输中,将对象比如BOJO进行编解码以利于网络中进行传输.平常我们也会将编解码说成是序列化/反序列化 定义:当进行远程跨进程服务调用时,需要把被传输的java对象编码为字节数组 ...

  8. IPsec_crypto[6]次配置

    IPsec_crypto[6]次配置: ①.①:crypto isakmp enbale——启用ISAKMP ②.②:crypto isakmp policy 10——创建一个策略组 ③:encryp ...

  9. 个人vim简单配置

    精简.vimrc配置,简约不简单 该配置没有花里胡哨的插件,只是用ctags和cscope然后配合vim提供的基础功能就可以完成常见的代码编辑,浏览,查找等工作. "************ ...

  10. POJ-3984 迷宫问题(BFS找最短路径并保存)

    问题: 定义一个二维数组:  int maze[5][5] = { 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, ...