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. Unity 打开其他exe文件

    using UnityEngine; using System.Collections; using System.Diagnostics;///// public class FeiYuZhu : ...

  2. python实现二分法

    前言: 二分法主要是用来查找位置的id,每次能够排除掉一半的数据,查找的效率非常高,但是局限性比较大. 必须是有序序列才可以使用二分查找. 原理 首先,假设表中元素是按升序排列,将表中间位置记录的关键 ...

  3. Java 类的属性

    章节 Java 基础 Java 简介 Java 环境搭建 Java 基本语法 Java 注释 Java 变量 Java 数据类型 Java 字符串 Java 类型转换 Java 运算符 Java 字符 ...

  4. Eclipse新建Maven中创建src文件夹报The folder is already a source folder错误解决办法

    问题: 解决办法:右击项目->Build Path->Configure Build Path选择(missing)文件夹remove,然后重新New Source Folder

  5. 指令——less

    一.Liunx系统下的一般命令格式. 命令——实际上就是在Liunx终端中,在命令行中输入的内容. Liunx中一个命令的完整格式为: #指令主体(空格) [选项](空格) [操作对象] 指令主体—— ...

  6. Jrebel 远程热部署[Idea]

    服务器端 客户端-idea remote module 在服务器端,Tomcat的webapps下新建项目文件夹,如: demo/WEB-INF/classes/[jrebel.xml]

  7. 洛谷[Luogu] 普及村-简单的模拟总结

    题目列表 注明:Level值代表在本难度下的排行.(纯粹本蒟蒻主观评判)注明:Level值代表在本难度下的排行.(纯粹本蒟蒻主观评判)注明:Level值代表在本难度下的排行.(纯粹本蒟蒻主观评判) P ...

  8. 这26个为什么,让初学者理解Python更简单!

    为什么Python使用缩进来分组语句? 为什么简单的算术运算得到奇怪的结果? 为什么浮点计算不准确? 为什么Python字符串是不可变的? 为什么必须在方法定义和调用中显式使用“self”? 为什么不 ...

  9. 029-PHP取随机数

    <?php //打印从1到100中间的10个随机的数 ; $index < ; $index++) { print(rand(,) . "<BR>\n"); ...

  10. 157-PHP strrchr函数输出最后一次出现字母p的位置到字符串结尾的所有字符串

    <?php $str='PHP is a very good programming language!'; //定义一个字符串 echo strrchr($str,'o'); //输出最后一次 ...