📦 Go1.22.5Gin1.10.0

🌟 Gin的日志

🍅 在启动 Gin时在 ide终端下会显示一些日志代码,这些日志代码时可以自定义的

⭐️ 自定义日志

🍵 DebugPrintRouteFunc调试路由日志格式

1️⃣ 先来看看默认的日志格式,表示分别表示日志类型,请求类型,路由,处理器

[GIN-debug] POST   /foo                      --> main.main.func1 (3 handlers)
[GIN-debug] GET    /bar                      --> main.main.func2 (3 handlers)
[GIN-debug] GET    /status                   --> main.main.func3 (3 handlers)

2️⃣ 使用 DebugPrintRouteFunc修改调试路由日志,它接收四个参数分别是:请求方法、请求类型,路由,处理器名,和处理器格式

package main

import (
	"github.com/gin-gonic/gin"
	"log"
)

func main() {

	ginServer := gin.New()

	ginServer.Use(gin.Logger(), gin.Recovery())

	//调试路由日志
	gin.DebugPrintRouteFunc = func(httpMethod, absolutePath, handlerName string, nuHandlers int) {
		// 输出日志
		log.Printf("[Tanc] 请求方法: %v | 路由名: %v |处理器名:  %v(有%v个handler)\n", httpMethod, absolutePath, handlerName, nuHandlers)
	}

	ginServer.GET("/home", func(context *gin.Context) {
		context.String(200, "Hello!!")
	})

	ginServer.Run(":8081")

}

3️⃣ 修改后的路由格式

2024/06/22 21:47:26 [Tanc] 请求方法: GET | 路由名: /home |处理器名:  main.main.func2(有3个handler)

2️⃣ 有个更加简单的办法那就是直接打印路由

router.Routes()  // 它会返回已注册的路由列表

🍵 DebugPrintFunc调试日志

	//调试日志
	gin.DebugPrintFunc = func(format string, values ...interface{}) {
		log.Printf(format, values...)
	}

🍵 关闭调试日志

设置为 releaseMode就不会显示调试日志,Gin提供了三种模式:

  1. DebugMode: 这是 Gin 的默认模式。在此模式下,框架会提供详细的错误信息,包括堆栈跟踪,这对于开发阶段非常有用,因为它可以帮助开发者快速定位问题。但这也意味着错误信息可能包含敏感数据,不应在生产环境中暴露。
  2. ReleaseMode: 当设置为 ReleaseMode 时,Gin 会禁用调试日志,并优化一些性能设置,比如禁用日志颜色输出,减少内存分配等。这有助于提高应用在生产环境中的运行效率和安全性,因为错误页面不会显示详细的错误信息,从而保护应用免受攻击。
  3. TestMode: 此模式通常在进行单元测试或集成测试时使用,它会提供一种适合测试环境的配置,比如可能会关闭日志输出,以便更专注于测试结果,而不是日志信息
	//设置为ReleaseMode模式
	gin.SetMode(gin.ReleaseMode)

	ginServer := gin.New()

	ginServer.Use(gin.Logger(), gin.Recovery())

🍵 自定义日志格式

🍅 Gin提供了一种自定义日志格式的方法,前面提到过中间件 Logger就是提供日志功能,那么自定义日志格式,就可以使用自定义中间件的方法

1️⃣ 在 Gin中提供了两种自定义 log的方法 gin.LoggerWithConfig()gin.LoggerWithFormatter(),它们两个的区别在于前者配置更加全面,使用结构体来配置,后者配置相对来说比较简单,先试一下简单的

首先看一下源代码,它接收一个 LogFormatter,然后也是调用的 LoggerWithConfig来配置😂 ,其实也可以理解为是它的封装

// LoggerWithFormatter instance a Logger middleware with the specified log format function.
func LoggerWithFormatter(f LogFormatter) HandlerFunc {
	return LoggerWithConfig(LoggerConfig{
		Formatter: f,
	})
}

在来查看一下这个 LogFormatter是个什么类型,它是一个方法的别名,这个方法内部有一个 LogFormatterParams

以下是您提供的代码注释的中文翻译:

// LogFormatter 是一个函数,用于定义日志的格式。当需要记录日志时,这个函数会被调用。
type LogFormatter func(params LogFormatterParams) string

// LogFormatterParams 是一个结构体,当需要记录日志时,任何格式化器都会接收到这个结构体。
type LogFormatterParams struct {
	Request *http.Request

	// TimeStamp 显示服务器返回响应后的时间。
	TimeStamp time.Time
	// StatusCode 是HTTP响应码。
	StatusCode int
	// Latency 是服务器处理某个请求所花费的时间。
	Latency time.Duration
	// ClientIP 等于 Context 的 ClientIP 方法的返回值。
	ClientIP string
	// Method 是请求所使用的HTTP方法。
	Method string
	// Path 是客户端请求的路径。
	Path string
	// ErrorMessage 会在处理请求过程中发生错误时设置。
	ErrorMessage string
	// isTerm 显示 gin 的输出描述符是否指向一个终端。
	isTerm bool
	// BodySize 是响应体的大小。
	BodySize int
	// Keys 是在请求的上下文中设置的键。
	Keys map[string]any
}

2️⃣ 开始使用

ginServer.Use(gin.Recovery(), gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
		return fmt.Sprintf("%s - [%s] \"%s %s %s %d %s \"%s\" %s\"\n",
			param.ClientIP,
			param.TimeStamp.Format(time.DateTime),
			param.Method,
			param.Path,
			param.Request.Proto,
			param.StatusCode,
			param.Latency,
			param.Request.UserAgent(),
			param.ErrorMessage,
		)
	}))

2️⃣ 测试

image-20240623105223230

2️⃣ 在来试一下 LoggerWithConfig的源代码

// LoggerConfig 定义了 Logger 中间件的配置。
type LoggerConfig struct {
	// 可选。默认值是 gin.defaultLogFormatter。
	// Formatter 是一个 LogFormatter 类型的变量,用于定义日志的格式。
	Formatter LogFormatter

	// Output 是一个 writer,日志将被写入到这个 writer 中。
	// 可选。默认值是 gin.DefaultWriter。
	Output io.Writer

	// SkipPaths 是一个 URL 路径数组,这些路径的日志将不会被写入。
	// 可选。
	SkipPaths []string

	// Skip 是一个 Skipper 类型的变量,它指示哪些日志不应该被写入。
	// 可选。
	Skip Skipper
}

3️⃣ 使用方法也都差不多了

logConfig := gin.LoggerConfig{
		Formatter: func(param gin.LogFormatterParams) string {
			// 自定义日志格式
			return fmt.Sprintf("%s - [%s] \"%s %s %s\" %d %s %s\n",
				param.ClientIP,
				param.TimeStamp.Format(time.DateTime),
				param.Method,
				param.Path,
				param.Request.Proto,
				param.StatusCode,
				param.Latency,
				param.ErrorMessage,
			)
		},
		Output: ioutil.Discard, // 日志输出目的地,这里使用 ioutil.Discard 表示不输出日志
		// 其他配置...
	}

ginServer.Use(logConfig)

🍵 将日志保存到文件

func main() {
    // 禁用控制台颜色,将日志写入文件时不需要控制台颜色。
    gin.DisableConsoleColor()

    // 记录到文件。
    f, _ := os.Create("gin.log")
    gin.DefaultWriter = io.MultiWriter(f)

    // 如果需要同时将日志写入文件和控制台,请使用以下代码。
    // gin.DefaultWriter = io.MultiWriter(f, os.Stdout)

    router := gin.Default()
    router.GET("/ping", func(c *gin.Context) {
        c.String(200, "pong")
    })

    router.Run(":8080")
}