前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Gin框架 - 日志记录

Gin框架 - 日志记录

作者头像
新亮
修改2019-07-23 10:09:26
3.3K0
修改2019-07-23 10:09:26
举报
文章被收录于专栏:新亮笔记

概述

上篇文章分享了 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 文件新增:

代码语言:javascript
复制
[[constraint]]
  name = "github.com/sirupsen/logrus"
  version = "1.4.2"

在项目中导入:

代码语言:javascript
复制
import"github.com/sirupsen/logrus"

在项目命令行执行:

代码语言:javascript
复制
dep ensure

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

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

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

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

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

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

...

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

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

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

代码语言:javascript
复制
package middleware
import (
 "fmt"
 "ginDemo/config"
 "github.com/gin-gonic/gin"
 "github.com/sirupsen/logrus"
 "os"
 "path"
 "time"
)
// 日志记录到文件
func LoggerToFile() gin.HandlerFunc {
    logFilePath := config.Log_FILE_PATH
    logFileName := 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()
 // 请求IP
        clientIP := c.ClientIP()
 // 日志格式
        logger.Infof("| %3d | %13v | %15s | %s | %s |",
            statusCode,
            latencyTime,
            clientIP,
            reqMethod,
            reqUri,
        )
    }
}
// 日志记录到 MongoDB
func LoggerToMongo() gin.HandlerFunc {
 return func(c *gin.Context) {
    }
}
// 日志记录到 ES
func LoggerToES() gin.HandlerFunc {
 return func(c *gin.Context) {
    }
}
// 日志记录到 MQ
func LoggerToMQ() gin.HandlerFunc {
 return func(c *gin.Context) {
    }
}

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

只需在 main.go 中新增:

代码语言:javascript
复制
engine := gin.Default() //在这行后新增
engine.Use(middleware.LoggerToFile())

执行一下,看看日志:

代码语言:javascript
复制
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

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

执行一下,再看日志:

代码语言:javascript
复制
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 格式,怎么办?

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

执行一下,再看日志:

代码语言:javascript
复制
{"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 信息太多,不方便看,怎么办?

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

执行一下,再看日志:

代码语言:javascript
复制
{"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、可以利用 Linuxlogrotate,统一由运维进行处理。

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

需要导入包:

github.com/lestrrat-go/file-rotatelogs

github.com/rifflock/lfshook

奉上完整代码:

代码语言:javascript
复制
package middleware
import (
 "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_PATH
    logFileName := 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)
 // 设置 rotatelogs
    logWriter, 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",
    })
 // 新增 Hook
    logger.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()
 // 请求IP
        clientIP := c.ClientIP()
 // 日志格式
        logger.WithFields(logrus.Fields{
 "status_code"  : statusCode,
 "latency_time" : latencyTime,
 "client_ip"    : clientIP,
 "req_method"   : reqMethod,
 "req_uri"      : reqUri,
        }).Info()
    }
}
// 日志记录到 MongoDB
func LoggerToMongo() gin.HandlerFunc {
 return func(c *gin.Context) {
    }
}
// 日志记录到 ES
func LoggerToES() gin.HandlerFunc {
 return func(c *gin.Context) {
    }
}
// 日志记录到 MQ
func LoggerToMQ() gin.HandlerFunc {
 return func(c *gin.Context) {
    }
}

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

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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-07-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 新亮笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概述
  • 日志格式
  • Logrus 使用
相关产品与服务
日志服务
日志服务(Cloud Log Service,CLS)是腾讯云提供的一站式日志服务平台,提供了从日志采集、日志存储到日志检索,图表分析、监控告警、日志投递等多项服务,协助用户通过日志来解决业务运维、服务监控、日志审计等场景问题。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档