Go Gin 通过中间件实现日志记录

Go Gin 通过中间件实现日志记录

Go Gin 通过中间件实现日志记录_第1张图片

文章目录

  • Go Gin 通过中间件实现日志记录
  • 一、日志文件夹的创建
  • 二、创建打开日志文件?
  • 三、创建 ``logrus.Logger``对象,并可修改写入的文件对象
  • 四.实现消息中间件
  • 五、完整代码
  • 参考


一、日志文件夹的创建

在当前文件目录下创建logs文件夹专门存放日志文件

// 检查并且创建日志文件夹
func createFolder(logFilePath string) {
	if err := os.MkdirAll(logFilePath, 0777); err != nil {
		fmt.Println("文件夹创建失败")
		panic(err)
	}
}

提示:os.MkdirAll可以用于文件夹的创建,当有同名文件夹存在将不进行操作。

例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


二、创建打开日志文件?

// |创建| 打开 日志文件
func createLogFile(logFilePath, filenameFormat string) *os.File {
	logFileName := filenameFormat + ".log"
	fileName := path.Join(logFilePath, logFileName)

	// 检查是否能够成功创建日志文件
	checkFile := func(filename string) {
		// 以时间去命名日志文件
		// 先去判断文件名字是否合法
		if _, err := os.Stat(filename); err != nil {
			if _, err := os.Create(filename); err != nil {
				fmt.Println("打开文件失败")
				panic(err)
			}
		}
	}
	checkFile(fileName)
	src, err := os.OpenFile(fileName, os.O_APPEND|os.O_WRONLY, os.ModeAppend)
	if err != nil {
		panic(err)
	}
	return src
}

三、创建 logrus.Logger对象,并可修改写入的文件对象

// 获取日志写入的 logger
func getLogger() (*logrus.Logger, func()) {
	logFilePath := ""
	if dir, err := os.Getwd(); err == nil {
		logFilePath = dir + "/logs/"
	}
	// 创建日志文件夹
	createFolder(logFilePath)
	filenameFormat := time.Now().Format("2006-01-02")
	src := createLogFile(logFilePath, filenameFormat)

	logger := logrus.New()
	logger.Out = src
	logger.SetLevel(logrus.DebugLevel)

	logger.SetFormatter(&logrus.TextFormatter{
		TimestampFormat: "2006-01-02 15:04:05",
	})

	// 检查更新当前的时间
	// 还存在个BUG 实现了日志文件的切换 但是文件流不能被关闭,
	return logger, func() {
		newFileNameFormat := time.Now().Format("2006-01-02") // + strconv.Itoa(rand.Int(4))  // 用来测试是否能切换日志的写入文件
		if newFileNameFormat != filenameFormat {
			filenameFormat = newFileNameFormat
			src.Close()
			newSrc := createLogFile(logFilePath, filenameFormat)
			logger.Out = newSrc
		}
	}
}

通过这个函数创建了logger实体,主要设置了日志写入的文件,日志记录的等级,日志的写入格式。
返回了一个可修改logger的函数, 主要用于切换日志的写入文件。
注意:现在存在的bug 是当切换日志文件后,切换前的文件流好像没有被关闭成功

四.实现消息中间件

// 日志的中间件
func LoogerToFile() gin.HandlerFunc {
	logger, changeSrc := getLogger()
	fmt.Println("使用middle ware")
	return func(c *gin.Context) {
		fmt.Println("收到请求")

		// 检查日期判断是否切换写入的日志文件
		changeSrc()

		// 开始的时间
		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 | %s |",
			statusCode,
			latencyTime,
			clientIp,
			reqMethod,
			reqUri,
			clientIp,
		)
	}

通过消息的中间件可以记录请求的携带的比如请求方法、请求Ip、请求处理的时间……

日志记录的样式在这里插入图片描述


五、完整代码

package main

import (
	"fmt"
	"net/http"
	"os"
	"path"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"
)

// 检查并且创建日志文件夹
func createFolder(logFilePath string) {
	if err := os.MkdirAll(logFilePath, 0777); err != nil {
		fmt.Println("文件夹创建失败")
		panic(err)
	}
}

// |创建| 打开 日志文件
func createLogFile(logFilePath, filenameFormat string) *os.File {
	logFileName := filenameFormat + ".log"
	fileName := path.Join(logFilePath, logFileName)

	// 检查是否能够成功创建日志文件
	checkFile := func(filename string) {
		// 以时间去命名日志文件
		// 先去判断文件名字是否合法
		if _, err := os.Stat(filename); err != nil {
			if _, err := os.Create(filename); err != nil {
				fmt.Println("打开文件失败")
				panic(err)
			}
		}
	}
	checkFile(fileName)
	src, err := os.OpenFile(fileName, os.O_APPEND|os.O_WRONLY, os.ModeAppend)
	if err != nil {
		panic(err)
	}
	return src
}

// 获取日志写入的 logger
func getLogger() (*logrus.Logger, func()) {
	logFilePath := ""
	if dir, err := os.Getwd(); err == nil {
		logFilePath = dir + "/logs/"
	}
	// 创建日志文件夹
	createFolder(logFilePath)
	filenameFormat := time.Now().Format("2006-01-02")
	src := createLogFile(logFilePath, filenameFormat)

	logger := logrus.New()
	logger.Out = src
	logger.SetLevel(logrus.DebugLevel)

	logger.SetFormatter(&logrus.TextFormatter{
		TimestampFormat: "2006-01-02 15:04:05",
	})

	// 检查更新当前的时间
	// 还存在个BUG 实现了日志文件的切换 但是文件流不能被关闭,
	return logger, func() {
		newFileNameFormat := time.Now().Format("2006-01-02")
		if newFileNameFormat != filenameFormat {
			filenameFormat = newFileNameFormat
			src.Close()
			newSrc := createLogFile(logFilePath, filenameFormat)
			logger.Out = newSrc
		}
	}
}

// 日志的中间件
func LoogerToFile() gin.HandlerFunc {
	logger, changeSrc := getLogger()
	fmt.Println("使用middle ware")
	return func(c *gin.Context) {
		fmt.Println("收到请求")

		// 检查日期判断是否切换写入的日志文件
		changeSrc()

		// 开始的时间
		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 | %s |",
			statusCode,
			latencyTime,
			clientIp,
			reqMethod,
			reqUri,
			clientIp,
		)
	}
}

func main() {
	router := gin.Default()
	router.Use(LoogerToFile())
	router.GET("/", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"msg": "你好",
		})
	})
	router.Run(":8081")
}

参考

  • 有更多关于中间件的,比如分组中间件 :https://geektutu.com/post/quick-go-gin.html
  • 本章代码主要参考:https://studygolang.com/articles/27098

你可能感兴趣的:(Go,golang,中间件)