gin: 用zap记录访问日志
一,安装zap
$ go get -u go.uber.org/zap
go: downloading go.uber.org/zap v1.27.0
go: downloading go.uber.org/multierr v1.10.0
go: downloading go.uber.org/multierr v1.11.0
go: added go.uber.org/multierr v1.11.0
go: added go.uber.org/zap v1.27.0
二,测试一个例子:
//得到列表
func (ic *ImageController) List(c *gin.Context) {
//logger := zap.NewExample()
cfg := zap.NewProductionConfig()
cfg.OutputPaths = []string{
"/data/gologs/logs/access.log",
//"stderr",
"stdout",
}
logger,err := cfg.Build()
if err!=nil {
fmt.Println("日志启动出错:",err.Error())
return
}
defer logger.Sync()
timeStr := time.Now().Format("2006-01-02 15:04:05")
logger.Info("记录一条日志",
zap.String("time", timeStr),
zap.String("url", c.Request.URL.String()),
)
c.JSON(http.StatusOK, gin.H{
"message": "image list",
})
}
输出例子:
{"level":"info","ts":1738244531.3267372,"caller":"controller/ImageController.go:54","msg":"记录一条日志","time":"2025-01-30 21:42:11","url":"/image/list?a=1&bc=2"}
三,记录访问日志
middleware/accesslog.go
package middleware
import (
"bytes"
"fmt"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
"imagebank/global"
"io"
"time"
)
type responseWriter struct {
gin.ResponseWriter
b *bytes.Buffer
}
//重写 Write([]byte) (int, error) 方法
func(w responseWriter)Write(b []byte)(int, error) {
//向一个bytes.buffer中写一份数据来为获取body使用
w.b.Write(b)
//完成gin.Context.Writer.Write()原有功能
return w.ResponseWriter.Write(b)
}
func AccessLog() gin.HandlerFunc {
return func(c *gin.Context) {
//请求 header
requestHeader := c.Request.Header
requestHeaderStr:=fmt.Sprintf("%v",requestHeader)
fmt.Println("请求头:",requestHeaderStr)
//请求体 body
requestBody := ""
b, err := c.GetRawData()
if err != nil {
requestBody = "failed to get request body"
} else {
requestBody = string(b)
}
c.Request.Body = io.NopCloser(bytes.NewBuffer(b))
fmt.Println("请求体:",requestBody)
writer := responseWriter{
c.Writer,
bytes.NewBuffer([]byte{}),
}
c.Writer = writer
beginTime := time.Now().UnixNano()
c.Next()
endTime := time.Now().UnixNano()
duration:=endTime-beginTime
cfg := zap.NewProductionConfig()
cfg.OutputPaths = []string{
"/data/gologs/logs/access.log",
//"stderr",
"stdout",
}
logger,err := cfg.Build()
if err!=nil {
fmt.Println("日志启动出错:",err.Error())
return
}
defer logger.Sync()
timeStr := time.Now().Format("2006-01-02 15:04:05")
//响应状态码
responseStatus := c.Writer.Status()
//响应 header
responseHeader := c.Writer.Header()
responseHeaderStr := fmt.Sprintf("%v",responseHeader)
//响应体大小
responseBodySize := c.Writer.Size()
//响应体 body
responseBody := writer.b.String()
logger.Info("记录一条日志",
zap.String("time", timeStr),
zap.String("ip", c.ClientIP()),
zap.String("proto", c.Request.Proto),
zap.String("method", c.Request.Method),
zap.String("host", c.Request.Host),
zap.String("url", c.Request.URL.String()),
zap.String("get_params", global.GetAllGetParams(c)),
zap.String("post_params", global.GetAllPostParams(c)),
zap.String("UserAgent", c.Request.UserAgent()),
//请求头,请求体
zap.String("requestHeader", requestHeaderStr),
zap.String("requestBody", requestBody),
//响应头、响应体
zap.Int("responseStatus", responseStatus),
zap.String("responseHeader", responseHeaderStr),
zap.Int("responseBodySize", responseBodySize),
zap.String("responseBody", responseBody),
//时长,微秒
zap.Int64("duration", duration/1000),
)
}
}
routes/routes.go
package routes
import (
"fmt"
"github.com/gin-gonic/gin"
"imagebank/controller"
"imagebank/global"
"imagebank/middleware"
"runtime/debug"
"time"
)
func Routes() *gin.Engine {
router := gin.Default()
//router.Use(middleware.AccessLog())
//处理找不到路由
router.NoRoute(HandleNotFound)
router.NoMethod(HandleNotFound)
//处理发生异常
router.Use(Recover)
//image
image := controller.NewImageController()
imageGroup := router.Group("/image").Use(middleware.AccessLog())
{
imageGroup.GET("/detail", image.Detail)
imageGroup.GET("/list", image.List)
imageGroup.POST("/add", image.Add)
}
//访问根目录
router.GET("/", image.List)
//访问根目录
router.GET("/favicon.ico", func(c *gin.Context) {
c.String(404, "not exist")
})
return router
}
可以应用到全局,
也可以应用到组
四,测试效果:
{"level":"info","ts":1738288864.7150245,
"caller":"middleware/accesslog.go:122",
"msg":"记录一条日志","time":"2025-01-31 10:01:04",
"ip":"192.168.219.1","proto":"HTTP/1.1",
"method":"GET","host":"192.168.219.3:8080",
"url":"/image/list?a=1&bc=2","get_params":"key:a,value:1\nkey:bc,value:2\n",
"post_params":"",
"UserAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36",
"requestHeader":"map[Accept:[text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7] Accept-Encoding:[gzip, deflate] Accept-Language:[zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,ja;q=0.6] Cache-Control:[max-age=0] Connection:[keep-alive] Cookie:[PHPSID=e239cbb4d5ddd941f501d2d3a9cca3d5] Upgrade-Insecure-Requests:[1] User-Agent:[Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36]]",
"requestBody":"","responseStatus":200,
"responseHeader":"map[Content-Type:[application/json; charset=utf-8]]",
"responseBodySize":24,"responseBody":"{\"message\":\"image list\"}","duration":42}
浙公网安备 33010602011771号