Movatterモバイル変換


[0]ホーム

URL:


返回主页

程序员新亮

GitHub 9K+ Star,其中适合 Go 新手的开箱即用项目 go-gin-api 5.2K Star:https://github.com/xinliangnote/go-gin-api,联系我:wx-xinliang

[系列] Gin 框架 - 使用 logrus 进行日志记录

概述

上篇文章分享了 Gin 框架的路由配置,这篇文章分享日志记录。

查了很多资料,Go 的日志记录用的最多的还是github.com/sirupsen/logrus

Logrus is a structured logger for Go (golang), completely API compatible with the standard library logger.

Gin 框架的日志默认只会在控制台输出,咱们利用Logrus 封装一个中间件,将日志记录到文件中。

这篇文章就是学习和使用Logrus

日志格式

比如,我们约定日志格式为 Text,包含字段如下:

请求时间日志级别状态码执行时间请求IP请求方式请求路由

接下来,咱们利用Logrus 实现它。

Logrus 使用

dep 方式进行安装。

Gopkg.toml 文件新增:

[[constraint]]  name = "github.com/sirupsen/logrus"  version = "1.4.2"

在项目中导入:

import "github.com/sirupsen/logrus"

在项目命令行执行:

dep ensure

这时,在vendor/github.com/ 目录中就会看到sirupsen 目录。

准备上手用了,上手之前咱们先规划一下,将这个功能设置成一个中间件,比如:logger.go

日志可以记录到 File 中,定义一个LoggerToFile 方法。

日志可以记录到 MongoDB 中,定义一个LoggerToMongo 方法。

日志可以记录到 ES 中,定义一个LoggerToES 方法。

日志可以记录到 MQ 中,定义一个LoggerToMQ 方法。

...

这次咱们先实现记录到文件, 实现LoggerToFile 方法,其他的可以根据自己的需求进行实现。

这个logger 中间件,创建好了,可以任意在其他项目中进行迁移使用。

废话不多说,直接看代码。

package middlewareimport ("fmt""ginDemo/config""github.com/gin-gonic/gin""github.com/sirupsen/logrus""os""path""time")// 日志记录到文件func LoggerToFile() gin.HandlerFunc {logFilePath := config.Log_FILE_PATHlogFileName := config.LOG_FILE_NAME//日志文件fileName := path.Join(logFilePath, logFileName)//写入文件src, err := os.OpenFile(fileName, os.O_APPEND|os.O_WRONLY, os.ModeAppend)if err != nil {fmt.Println("err", err)}//实例化logger := logrus.New()//设置输出logger.Out = src//设置日志级别logger.SetLevel(logrus.DebugLevel)//设置日志格式logger.SetFormatter(&logrus.TextFormatter{})return func(c *gin.Context) {// 开始时间startTime := time.Now()// 处理请求c.Next()// 结束时间endTime := time.Now()// 执行时间latencyTime := endTime.Sub(startTime)// 请求方式reqMethod := c.Request.Method// 请求路由reqUri := c.Request.RequestURI// 状态码statusCode := c.Writer.Status()// 请求IPclientIP := c.ClientIP()// 日志格式logger.Infof("| %3d | %13v | %15s | %s | %s |",statusCode,latencyTime,clientIP,reqMethod,reqUri,)}}// 日志记录到 MongoDBfunc LoggerToMongo() gin.HandlerFunc {return func(c *gin.Context) {}}// 日志记录到 ESfunc LoggerToES() gin.HandlerFunc {return func(c *gin.Context) {}}// 日志记录到 MQfunc LoggerToMQ() gin.HandlerFunc {return func(c *gin.Context) {}}

日志中间件写好了,怎么调用呢?

只需在 main.go 中新增:

engine := gin.Default() //在这行后新增engine.Use(middleware.LoggerToFile())

运行一下,看看日志:

time="2019-07-17T22:10:45+08:00" level=info msg="| 200 |      27.698µs |             ::1 | GET | /v1/product/add?name=a&price=10 |"time="2019-07-17T22:10:46+08:00" level=info msg="| 200 |      27.239µs |             ::1 | GET | /v1/product/add?name=a&price=10 |"

这个time="2019-07-17T22:10:45+08:00" ,这个时间格式不是咱们想要的,怎么办?

时间需要格式化一下,修改logger.SetFormatter

//设置日志格式logger.SetFormatter(&logrus.TextFormatter{TimestampFormat:"2006-01-02 15:04:05",})

执行以下,再看日志:

time="2019-07-17 22:15:57" level=info msg="| 200 |     185.027µs |             ::1 | GET | /v1/product/add?name=a&price=10 |"time="2019-07-17 22:15:58" level=info msg="| 200 |      56.989µs |             ::1 | GET | /v1/product/add?name=a&price=10 |"

时间变得正常了。

我不喜欢文本格式,喜欢 JSON 格式,怎么办?

//设置日志格式logger.SetFormatter(&logrus.JSONFormatter{TimestampFormat:"2006-01-02 15:04:05",})

执行以下,再看日志:

{"level":"info","msg":"| 200 |       24.78µs |             ::1 | GET | /v1/product/add?name=a\u0026price=10 |","time":"2019-07-17 22:23:55"}{"level":"info","msg":"| 200 |      26.946µs |             ::1 | GET | /v1/product/add?name=a\u0026price=10 |","time":"2019-07-17 22:23:56"}

msg 信息太多,不方便看,怎么办?

// 日志格式logger.WithFields(logrus.Fields{"status_code"  : statusCode,"latency_time" : latencyTime,"client_ip"    : clientIP,"req_method"   : reqMethod,"req_uri"      : reqUri,}).Info()

执行以下,再看日志:

{"client_ip":"::1","latency_time":26681,"level":"info","msg":"","req_method":"GET","req_uri":"/v1/product/add?name=a\u0026price=10","status_code":200,"time":"2019-07-17 22:37:54"}{"client_ip":"::1","latency_time":24315,"level":"info","msg":"","req_method":"GET","req_uri":"/v1/product/add?name=a\u0026price=10","status_code":200,"time":"2019-07-17 22:37:55"}

说明一下:timemsglevel 这些参数是 logrus 自动加上的。

logrus 支持输出文件名和行号吗?

不支持,作者的回复是太耗性能。

不过网上也有人通过 Hook 的方式实现了,选择在生产环境使用的时候,记得做性能测试。

logrus 支持日志分割吗?

不支持,但有办法实现它。

1、可以利用Linux logrotate,统一由运维进行处理。

2、可以利用file-rotatelogs 实现。

需要导入包:

github.com/lestrrat-go/file-rotatelogs

github.com/rifflock/lfshook

奉上完整代码:

package middlewareimport ("fmt""ginDemo/config""github.com/gin-gonic/gin"rotatelogs "github.com/lestrrat-go/file-rotatelogs""github.com/rifflock/lfshook""github.com/sirupsen/logrus""os""path""time")// 日志记录到文件func LoggerToFile() gin.HandlerFunc {logFilePath := config.Log_FILE_PATHlogFileName := config.LOG_FILE_NAME// 日志文件fileName := path.Join(logFilePath, logFileName)// 写入文件src, err := os.OpenFile(fileName, os.O_APPEND|os.O_WRONLY, os.ModeAppend)if err != nil {fmt.Println("err", err)}// 实例化logger := logrus.New()// 设置输出logger.Out = src// 设置日志级别logger.SetLevel(logrus.DebugLevel)// 设置 rotatelogslogWriter, err := rotatelogs.New(// 分割后的文件名称fileName + ".%Y%m%d.log",// 生成软链,指向最新日志文件rotatelogs.WithLinkName(fileName),// 设置最大保存时间(7天)rotatelogs.WithMaxAge(7*24*time.Hour),// 设置日志切割时间间隔(1天)rotatelogs.WithRotationTime(24*time.Hour),)writeMap := lfshook.WriterMap{logrus.InfoLevel:  logWriter,logrus.FatalLevel: logWriter,logrus.DebugLevel: logWriter,logrus.WarnLevel:  logWriter,logrus.ErrorLevel: logWriter,logrus.PanicLevel: logWriter,}lfHook := lfshook.NewHook(writeMap, &logrus.JSONFormatter{TimestampFormat:"2006-01-02 15:04:05",})// 新增 Hooklogger.AddHook(lfHook)return func(c *gin.Context) {// 开始时间startTime := time.Now()// 处理请求c.Next()// 结束时间endTime := time.Now()// 执行时间latencyTime := endTime.Sub(startTime)// 请求方式reqMethod := c.Request.Method// 请求路由reqUri := c.Request.RequestURI// 状态码statusCode := c.Writer.Status()// 请求IPclientIP := c.ClientIP()// 日志格式logger.WithFields(logrus.Fields{"status_code"  : statusCode,"latency_time" : latencyTime,"client_ip"    : clientIP,"req_method"   : reqMethod,"req_uri"      : reqUri,}).Info()}}// 日志记录到 MongoDBfunc LoggerToMongo() gin.HandlerFunc {return func(c *gin.Context) {}}// 日志记录到 ESfunc LoggerToES() gin.HandlerFunc {return func(c *gin.Context) {}}// 日志记录到 MQfunc LoggerToMQ() gin.HandlerFunc {return func(c *gin.Context) {}}

这时会新生成一个文件system.log.20190717.log,日志内容与上面的格式一致。

最后,logrus 可扩展的 Hook 很多,大家可以去网上查找。

有些读者建议,手机上看代码不方便,建议更新到 GitHub 上。

现已更新,地址如下:

https://github.com/xinliangnote/Go

推荐阅读

Gin 框架

基础篇

本文欢迎转发,转发请注明作者和出处,谢谢!

作者:新亮笔记(关注公众号,可申请添加微信好友)
出处:https://www.cnblogs.com/xinliangcoder
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

posted @2019-07-19 12:42 程序员新亮 阅读(27888) 评论(0)  收藏 举报

公告

博客园  ©  2004-2025
浙公网安备 33010602011771号浙ICP备2021040463号-3

[8]ページ先頭

©2009-2025 Movatter.jp