Go 高级日志记录库集成Gin框架

一、简介

Logrus是Go(golang)的结构化logger,与标准库logger完全API兼容,它有以下特点

  1. 结构化日志记录:Logrus 支持生成结构化的日志条目,这意味着日志不仅仅是文本字符串,而是包含键值对的数据结构,便于日志分析和处理。

  2. 高性能:设计上注重效率,适合高并发和高性能的应用场景,能够快速处理大量的日志输出。

  3. 灵活的输出格式:支持多种输出格式,包括文本(默认的 TextFormatter)和 JSON(JSONFormatter),用户也可以自定义格式化器(Formatter)来适配特定需求。

  4. 可插拔的钩子(Hooks)机制:允许用户自定义日志处理逻辑,比如将日志发送到远程服务器、数据库、消息队列等。钩子可以在日志事件的不同阶段触发,比如日志写入前、写入后。

  5. 丰富的日志级别:内置了多种日志级别,包括 Trace、Debug、Info、Warning、Error、Fatal 和 Panic,方便根据不同的场景选择合适的日志详细度。

  6. 兼容性:API 设计上与 Go 标准库的 log 模块兼容,使得从标准库迁移至 Logrus 相对简单,降低了学习和使用成本。

  7. 国际化和本地化:虽然原生 Logrus 不直接支持国际化,但用户可以通过自定义钩子等方式实现日志的多语言输出。

  8. 错误处理:通过 Panic 和 Fatal 级别的日志,Logrus 可以在严重错误发生时自动调用 panic 函数或 os.Exit,便于程序的错误管理。

  9. 轻量级:Logrus 本身代码量不大,且无外部依赖,易于理解和集成。

  10. 社区支持:作为 GitHub 上 Star 数量最多的 Go 日志库之一,Logrus 拥有活跃的社区支持和丰富的文档资源,许多知名项目如 Docker、Prometheus 等都在使用它。

二、日志级别

1、介绍

package mainimport ("github.com/sirupsen/logrus"
)// 创建一个新的logger实例。可以创建任意多个。
var log = logrus.New()func main() {log.Trace("一些非常低级的东西。")log.Debug("有用的调试信息。")log.Info("发生了值得注意的事情!")log.Warn("这是警告信息,需要关注。")log.Error("有些事情失败了,但我不会放弃。")// 假设发生了某个严重错误,记完日志后会调用os.Exit(1)//log.Fatal("退出。。。") // 记录日志后程序会退出// 这下面的代码不会被执行// 记完日志后会调用 panic()//log.Panic("记完日志后会调用 panic()。")
}

2、设置日志级别

package mainimport ("github.com/sirupsen/logrus"
)// 创建一个新的logger实例。可以创建任意多个。
var log = logrus.New()func main() {// 创建一个新的logrus loggerlogger := logrus.New()// 设置日志级别,这里以Info为例logger.SetLevel(logrus.InfoLevel)// 记录不同级别的日志logger.Debug("这条日志不会被输出,因为Debug级别低于Info级别")logger.Info("这条是Info级别的日志")logger.Warn("这条是Warn级别的日志")logger.Error("这条是Error级别的日志")// Fatal和Panic级别的日志会立即导致程序退出// logger.Fatal("这条是Fatal级别的日志,打印完后,程序会在这里退出")// logger.Panic("这条是Panic级别的日志,打印完后,程序会在这里退出")
}

3、字段

  • Logrus鼓励通过日志字段进行谨慎的结构化日志记录,而不是冗长的、不可解析的错误消息。

  • 例如,区别于使用log.Fatalf("Failed to send event %s to topic %s with key %d")

  • 你应该使用如下方式记录更容易发现的内容

package mainimport ("fmt"log "github.com/sirupsen/logrus"
)func main() {fmt.Println("3333")log.WithFields(log.Fields{"event": "event","topic": "topic","key":   "key",}).Info("Failed to send event")
}

4、默认字段

  • 通常,将一些字段始终附加到应用程序的全部或部分的日志语句中会很有帮助。

  • 例如,你可能希望始终在请求的上下文中记录request_iduser_ip

  • 区别于在每一行日志中写上log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})

  • 你可以向下面的示例代码一样创建一个logrus.Entry去传递这些字段。

package mainimport log "github.com/sirupsen/logrus"func main() {requestLogger := log.WithFields(log.Fields{"request_id": "请求id", "user_ip": "用户id"})requestLogger.Info("应要求发生了一些事情")  // 将记录request_id和user_iprequestLogger.Warn("发生了一些不太好的事情") // 将记录request_id和user_ip
}/*
time="2024-05-23T17:30:13+08:00" level=info msg="应要求发生了一些事情" request_id2="请求id" user_ip="用户id"
time="2024-05-23T17:30:13+08:00" level=warning msg="发生了一些不太好的事情" request_id2="请求id" user_ip="用户id"
*/

 5、格式化

package mainimport ("github.com/sirupsen/logrus"
)var log = logrus.New()func main() {log.Formatter = &logrus.JSONFormatter{}log.SetReportCaller(true) // 可以开启记录函数名,但是会消耗性能log.WithFields(logrus.Fields{"event": "xxx事件","topic": "xxx内容","key":   "xxx_key",}).Info("发送事件失败")
}/*
{"event": "xxx事件","key": "xxx_key","level": "info","msg": "发送事件失败","time": "2024-05-23T17:42:31+08:00","topic": "xxx内容"
}
// 开启记录函数名
{"event": "xxx事件","file": "D:/GoCode/src/gin-mall/main.go:16","func": "main.main","key": "xxx_key","level": "info","msg": "发送事件失败","time": "2024-05-23T17:43:20+08:00","topic": "xxx内容"
}
*/

6、Hooks

logrus 中,钩子(Hooks)是一种在记录特定级别日志时执行自定义逻辑的方法。钩子可以用来发送日志到第三方服务,如 Sentry、BugSnag、Logstash 等,或者执行其他任何你想要在日志事件发生时进行的操作。

1. 实现钩子接口

钩子需要实现 logrus.Hook 接口,该接口有两个方法:Levels()Fire()

  • Levels() 返回一个包含钩子关心的日志级别的切片。
  • Fire() 接收一个 logrus.Entry,包含了日志的详细信息,当日志触发时执行。
package mainimport ("fmt""github.com/sirupsen/logrus"
)// MyHook 是一个自定义钩子,实现了logrus.Hook接口
type MyHook struct{}// Levels 方法返回这个钩子关心的日志级别
func (hook *MyHook) Levels() []logrus.Level {return []logrus.Level{logrus.ErrorLevel,logrus.FatalLevel,logrus.PanicLevel,}
}// Fire 方法在记录日志时触发,entry 包含了日志的详细信息
func (hook *MyHook) Fire(entry *logrus.Entry) error {// 这里可以执行自定义逻辑,例如发送日志到监控系统// 以下是简单的打印到标准输出的示例fmt.Printf("Error: %s\n", entry.Message)// 始终返回nil,表示没有错误return nil
}

2. 添加钩子到 logger

在 Logrus 中,钩子(Hooks)是一种强大的特性,允许你在日志事件处理流程中的特定点插入自定义的行为,而无需修改日志记录的核心逻辑。这对于实现如日志的额外存储(例如保存到文件、数据库、或者发送到远程服务器)非常有用。

自定义钩子示例

将错误日志同时输出到文件

首先,你需要定义一个实现了 logrus.Hook 接口的结构体。这个接口要求实现三个方法:Levels(), Fire(*logrus.Entry) error, 和可选的 SetFormatter(formatter logrus.Formatter)

package mainimport (log "github.com/sirupsen/logrus""os"
)// FileHook 将错误日志写入文件
type FileHook struct {file *os.File
}// NewFileHook 创建一个新的 FileHook 实例
func NewFileHook(filename string) (*FileHook, error) {file, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)if err != nil {return nil, err}return &FileHook{file: file}, nil
}// Levels 钩子关心的日志级别
func (hook *FileHook) Levels() []log.Level {return []log.Level{log.PanicLevel, log.FatalLevel, log.ErrorLevel}
}// Fire 当日志事件触发时被调用
func (hook *FileHook) Fire(entry *log.Entry) error {_, err := hook.file.WriteString(entry.Message + "\n")if err != nil {return err}return nil
}func main() {// 初始化日志logger := log.New()logger.SetLevel(log.DebugLevel)// 创建并添加 FileHookhook, err := NewFileHook("errors.log")if err == nil {logger.AddHook(hook)} else {logger.Fatal("无法创建文件挂钩", err)}// 记录一些日志logger.Info("这是一条Info级别消息")logger.Warn("这是一条Warn级别消息")logger.Error("这是一条Error级别消息")//logger.Fatal("这是一条Fatal级别消息")//打印完日志后退出//logger.Panic("这是一条Panic级别消息")//打印完日志后退出
}

 三、gin中使用logrus

package mainimport ("github.com/gin-gonic/gin""github.com/sirupsen/logrus""os"
)var log = logrus.New()
var logFile *os.Filefunc init() {// 以JSON格式而不是默认的ASCII格式器进行日志记录。log.Formatter = &logrus.JSONFormatter{}//输出到stdout而不是默认的stderr//可以是任何io.Writer,请参阅下面的文件示例//logFile, _ := os.Create("./gin.log")//使用os.Create函数创建文件时,默认情况下新创建的文件是空的,任何写入都会追加到文件末尾// 使用os.OpenFile而不是os.Create// flag参数设置为os.O_CREATE和os.O_APPEND,这意味着文件将被创建(如果它不存在)并且写入将追加到文件末尾// perm参数设置文件的权限(例如0644),这是一个常用的选项,表示文件对所有用户可读写,但只对拥有者可执行logFile, err := os.OpenFile("./gin.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)if err != nil {log.Fatal(err)}//defer f.Close()log.Out = logFilegin.SetMode(gin.ReleaseMode)gin.DefaultWriter = log.Out// 仅记录警告严重性或更高级别输出log.Level = logrus.InfoLevel
}func main() {// 创建一个默认的路由引擎r := gin.Default()defer logFile.Close()// GET:请求方式;/hello:请求的路径// 当客户端以GET方法请求/hello路径时,会执行后面的匿名函数r.GET("/hello", func(c *gin.Context) {log.WithFields(logrus.Fields{"animal": "狼","size":   10,}).Warn("一群狼在丛林中出现")// c.JSON:返回JSON格式的数据c.JSON(200, gin.H{"message": "Hello 狼!",})})r.Run(":8080")
}

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/18285.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ceph 高级部署

一、基础环境配置 1.1 网络配置 ubuntu: network: ethernets:eno1:dhcp4: trueeno2:dhcp4: trueeno3:dhcp4: trueeno4:dhcp4: truebonds:bond0:addresses:- 100.64.0.12/22routes:- to: defaultvia: 100.64.0.1nameservers:addresses:- 114.114.114.114interfaces:- eno1- …

TTime:截图翻译/OCR

日常网页翻译Translate Web Pages完全足够,TTime最重要的功能,还是截图翻译,还有个厉害的功能,就是静默OCR,相比之前的分享的识字精灵效率更高。 软件使用 打开软件,点击翻译源设置,建议勾选一…

强化学习学习笔记-李宏毅

Policy Gradient actorenvreward function,env和reward是不能控制的,唯一可以变的是actor,Policy π \pi π是一个网络,参数为 θ \theta θ,输入是当前的观察,输出是采取的行为,例如游戏中输…

C++可变参技巧揭秘:从函数到模板,一网打尽

最近在用C开发项目过程中,遇到了场景需要用可变参(...)的情况,发现开发业务相关同事,对这块理解不是很清晰,遂对此进行梳理总结,以便业务相关同事学习,以及后续遇到时的参考。 对此不…

第十三期Big Demo Day亮点项目:CCarbon重塑碳交易生态,助力全球绿色发展

第十三期Big Demo Day活动即将于2024年5月28日在香港数码港的CyberArena隆重举行。我们荣幸地宣布,利用区块链技术优化全球碳交易CCarbon项目将亮相,参与精彩的项目路演。本次活动由ZeeprLabs、BiKing Exchange、Gather冠名赞助,Central Rese…

DOS学习-目录与文件应用操作经典案例-ren

新书上架~👇全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~ 目录 一.前言 二.使用 三.案例 案例 1:重命名当前目录下的文件 案例 2&#xff1a…

自定义函数与结构体

定义一个结构体 Point,其中包含两个 double 类型的成员 x 和 y,用来表示一个二维坐标点。接着定义一个函数 dist,用来计算两个点之间的欧几里德距离。 在函数中,通过调用 hypot 函数来计算两点之间的距离,C 中的hypot…

超清高帧,成像升级 | SWIR短波红外相机500万像素992芯片

博图光电5MP短波红外相机,搭载了索尼IMX992 SenSWIR传感器,支持5.2MP分辨率,适合探测波长在400nm-1700nm波段的可见光和短波红外光,有效面积和透光率得到提升,内置TEC制冷片,实现了像素尺寸和图像均匀性方面…

OSPF不规则区域

一、OSPF不规则区域 1、远离了骨干的非骨干 2、不连续骨干 解决目的--全网可达 解决方案: 1、tunnel-- 在合法与非法 ABR 间使用 tunnel建立一个新的网段(类似连接一条独立的网线);然后将该网段宣告到ospf协议中; 缺点: 1)选路不佳 2)周期和触发信息对中间穿越区域造成影响…

网络实时安全:构筑数字时代的铜墙铁壁

什么是网络实时安全? 网络实时安全,简而言之,是一种能够在威胁发生的瞬间即刻识别、响应并有效抵御的安全机制。它强调的是速度与效率,确保网络环境能够持续处于安全状态。这背后,离不开高科技的支撑——扩展检测系统…

Linux源码编译安装MySQL + Qt连接MySQL

一、准备工作 1. 编译环境: 银河麒麟V10 飞腾D2000 CPU 2. 下载MySQL源码 这里编译的是5.7.44版本,带Boost库,这是官网的下载地址:MySQL :: Download MySQL Community Server (Archived Versions) 3. 解压压缩包 tar -zxvf mys…

Python内置方法串讲:类型转化与实用技巧

新书上架~👇全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~ 目录 一、类型转化:从A到B的魔法 二、实用技巧:避免类型错误 三、总结 一…

Datawhale团队第十一期录取名单!

Datawhale团队 公示:Datawhale团队成员 Datawhale成立五年了,从一开始的12个人,学习互助,到提议成立开源组织,做更多开源的事情,帮助更多学习者,也促使我们更好地成长。于是有了我们的使命&…

一年前的Java作业,模拟游戏玩家战斗

说明:一年前写的作业,感觉挺有意思的,将源码分享给大家。 刚开始看题也觉得很难,不过写着写着思路更加清晰,发现也没有想象中的那么难。 一、作业题目描述: 题目:模拟游戏玩家战斗 1.1 基础功…

清华大学 | 机器人实验室 | 机械结构 | 招聘

招聘实习生、正式工程师,请发送简历,具体工作内容、福利待遇详细沟通 基本要求 1. 熟练使用3D建模软件(如SolidWorks、CATIA、CAD等) 2. 有过机器人项目经验,参加过机器人相关比赛者优先 3. 具备静力学仿真经验,熟悉有限元分析…

假象和谎言

原创 | 刘教链 隔夜BTC(比特币)徘徊在69k一线。5.25教链内参报告,《BTC ETF持仓即将超越中本聪》。ETH ETF的尘嚣逐渐散去,复归于平静。戏刚唱了个开头,结尾还留着悬念。4000刀之于ETH看来是个关键阻力位,最…

element ui 的密码输入框点击显示隐藏密码时,图标随之改变

场景图&#xff1a; 原理&#xff1a; 通过修改el-input框的type属性&#xff0c;来设置显示或者隐藏。从而改变图标地址。 <el-input class"passwordinput" :type"pwdObj.pwdType" ref"pwdInput" placeholder"密码"v-model"…

Vue热更新出现内存溢出

Vue热更新出现内存溢出 vue-cli2遇到此问题的解决办法&#xff1a;vue-cli3遇到此问题的解决办法&#xff1a;方法一&#xff08;已测试ok&#xff09;方法二&#xff08;未尝试&#xff09; 开发项目有一段时间了&#xff0c;随着项目越来越大&#xff0c;打包的时间也相应的变…

若依微服务实现分布式事务

一、基本介绍 1、什么是分布式事务 指一次大的操作由不同的小操作组成的&#xff0c;这些小的操作分布在不同的服务器上&#xff0c;分布式事务需要保证这些小操作要么全部成功&#xff0c;要么全部失败。从本质上来说&#xff0c;分布式事务就是为了保证不同数据库的数据一致…

ssm137基于SSM框架的微博系统+vue

微博系统网站的设计与实现 摘 要 网络技术和计算机技术发展至今&#xff0c;已经拥有了深厚的理论基础&#xff0c;并在现实中进行了充分运用&#xff0c;尤其是基于计算机运行的软件更是受到各界的关注。加上现在人们已经步入信息时代&#xff0c;所以对于信息的宣传和管理就…