当前位置: 首页 > news >正文

gin: 用zap记录访问日志

一,zap库安装

$ go get -u go.uber.org/zap
go: added go.uber.org/multierr v1.11.0
go: added go.uber.org/zap v1.27.0

二,代码

accesslog

package middlewareimport ("bytes""fmt""github.com/gin-gonic/gin""go.uber.org/zap""io""mediabank/global""os""time"
)type responseWriter struct {gin.ResponseWriterb *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) {//请求 headerrequestHeader := c.Request.HeaderrequestHeaderStr:=fmt.Sprintf("%v",requestHeader)fmt.Println("请求头:",requestHeaderStr)//请求体 bodyrequestBody := ""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 = writerbeginTime := time.Now().UnixNano()c.Next()endTime := time.Now().UnixNano()duration:=endTime-beginTime//判断当前日志目录是否存在var curDir = "./logs"if global.IsDirExists(curDir) == false {// 创建多级目录err := os.MkdirAll(curDir, 0755)if err != nil {fmt.Println(err)}}//得到当前日期var curDate = global.FormattedNow("20060102")cfg := zap.NewProductionConfig()cfg.OutputPaths = []string{"./logs/access_"+curDate+".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()//响应 headerresponseHeader := c.Writer.Header()responseHeaderStr := fmt.Sprintf("%v",responseHeader)//响应体大小responseBodySize := c.Writer.Size()//响应体 bodyresponseBody := 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),)}
}

global/functions.go

package globalimport ("github.com/gin-gonic/gin""os""strings""time"
)//格式化当前时间
func FormattedNow(format string) string {// 获取当前时间now := time.Now()// 格式化时间formatted := now.Format(format)return formatted
}//判断目录是否存在
func IsDirExists(path string) bool {_, err := os.Stat(path)if err != nil {if os.IsNotExist(err) {return false}}return true
}//得到所有get参数
func GetAllGetParams(c *gin.Context) (string) {params := c.Request.URL.Query()resStr := ""// 遍历并打印所有参数及其值for key, values := range params {for _, value := range values {resStr = resStr+"key:"+key+",value:"+value+"\n"}}return resStr
}//得到所有post参数
func GetAllPostParams(c *gin.Context) (string) {c.Request.ParseMultipartForm(32 << 20)resStr := ""for k, v := range c.Request.PostForm {resStr = resStr+"key:"+k+",value:"+strings.Join(v, ",")+"\n"}return resStr
}

routes.go 启用日志中间件

package routesimport ("embed""fmt""github.com/gin-gonic/gin""html/template""io/fs""mediabank/controller""mediabank/global""mediabank/middleware""net/http""runtime/debug""time"
)func Routes(embedFs embed.FS) *gin.Engine {router := gin.Default()//全局使用访问日志//router.Use(middleware.AccessLog())//处理找不到路由router.NoRoute(HandleNotFound)router.NoMethod(HandleNotFound)//处理发生异常router.Use(Recover)//1, 加载模板文件tmpl := template.Must(template.New("").ParseFS(embedFs, "templates/**/*.html"))router.SetHTMLTemplate(tmpl)//2, 加载静态文件fp, _ := fs.Sub(embedFs, "static")router.StaticFS("/static", http.FS(fp))//3,加载favicon//static是存放favicon.ico的目录faviconHandler := http.FileServer(http.FS(fp))router.GET("/favicon.ico", func(c *gin.Context) {faviconHandler.ServeHTTP(c.Writer, c.Request)})//media,使用自定义的访问日志中间件media := controller.NewMediaController()mediaGroup := router.Group("/media").Use(middleware.AccessLog()){mediaGroup.GET("/detail", media.Detail)mediaGroup.GET("/list", media.List)mediaGroup.GET("/user", media.User)}return router
}

三,测试效果

{"level":"info","ts":1757388627.6531723,"caller":"middleware/accesslog.go:98","msg":"记录一条日志","time":"2025-09-09 11:30:27","ip":"192.168.219.1","proto":"HTTP/1.1","method":"GET","host":"192.168.219.3:8080","url":"/media/detail","get_params":"","post_params":"","UserAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.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/139.0.0.0 Safari/537.36]]","requestBody":"","responseStatus":200,"responseHeader":"map[Content-Type:[text/html; charset=utf-8]]","responseBodySize":1224,"responseBody":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Gin 模板示例</title>\n    <link rel=\"stylesheet\" href=\"/static/css/global.css\">\n    <script src=\"/static/js/jquery-3.7.1.min.js\"></script>\n</head>\n<body>\n<h1>欢迎来到 Gin 的世界!</h1>\n<button onclick=\"getName()\">获取当前用户名字</button>\n<script>\n    function getName() {\n        var paramsData = {\n            a:1,\n            b:2\n        }\n        var url = \"/media/user\";\n        $.ajax({\n            type: 'GET',\n            url: url,\n            data: paramsData,\n            dataType: 'json',\n            success: function(data) {\n\n                console.log(\"成功\");\n                console.log(data);\n                if (data.hasOwnProperty('name')) {\n                    alert('name:'+data.name)\n                } else {\n                    alert('数据获取失败')\n                }\n            },\n            error: function(jqXHR, textStatus, errorThrown) {\n                console.log(\"失败\");\n\n                console.error('Error: ' + textStatus + ' - ' + errorThrown);\n            }\n        });\n    }\n\n</script>\n</body>\n</html>","duration":257}

 

http://www.hskmm.com/?act=detail&tid=10420

相关文章:

  • gin: 打包模板文件、静态文件到二进制文件中
  • gin: 判断是否ajax请求
  • gin: 静态文件
  • 详细介绍:【论文精读】基于YOLOv3算法的高速公路火灾检测
  • MacOS 下fuzz学习踩坑点
  • An Empirical Study on Commit Message Generation using LLMs via In-Context Learning 论文笔记
  • 实用指南:人工智能学习:Transformer结构中的编码器层(Encoder Layer)
  • vcpkg 安装依赖
  • Java03课前问题列表
  • JavaScript错误处理完全指南:从基础到自定义错误实战
  • 1、论文准备
  • PION 游击
  • Web3 开发者修炼全图谱:从 Web2 走向 Web3 的实用的系统性学习指南
  • 实用指南:医院高值耗材智能化管理路径分析(下)
  • Flutter应用自动更新系统:生产环境的挑战与解决方案
  • .NET Core中使用SignalR
  • 实用指南:修复Conda连接异常:CondaHTTPError HTTP 000 CONNECTION FAILED故障排除指南
  • 高级数据结构手册
  • Tarjan 学习笔记
  • 使用JavaScript和CSS创建动态高亮导航栏
  • Gridspech 全通关
  • 1967
  • 20253320蒋丰任
  • .
  • 又有两位智驾大牛联手入局具身智能机器人赛道创业,已完成数亿元融资!
  • 纯国产GPU性能对比,谁才是国产算力之王?
  • 地平线明年发布并争取量产舱驾一体芯片;比亚迪补强智舱团队,斑马智行原 CTO 加入
  • 英伟达入股英特尔,当竞争对手便成协作者,真正受益的......
  • ODT/珂朵莉树 入门
  • 在AI技术快速实现功能的时代,挖掘新需求成为关键突破点——某知名游戏资源分析工具需求洞察