📦 Go1.22.5
、Gin1.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提供了三种模式:
- DebugMode: 这是 Gin 的默认模式。在此模式下,框架会提供详细的错误信息,包括堆栈跟踪,这对于开发阶段非常有用,因为它可以帮助开发者快速定位问题。但这也意味着错误信息可能包含敏感数据,不应在生产环境中暴露。
- ReleaseMode: 当设置为 ReleaseMode 时,Gin 会禁用调试日志,并优化一些性能设置,比如禁用日志颜色输出,减少内存分配等。这有助于提高应用在生产环境中的运行效率和安全性,因为错误页面不会显示详细的错误信息,从而保护应用免受攻击。
- 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️⃣ 测试
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")
}