Golang | Web开发之Gin路由访问日志自定义输出实践

news/2024/10/30 23:27:24/

欢迎关注「全栈工程师修炼指南」公众号

点击 👇 下方卡片 即可关注我哟!

设为星标⭐每天带你 基础入门 到 进阶实践 再到 放弃学习

专注 企业运维实践、网络安全、系统运维、应用开发、物联网实战、全栈文章 等知识分享

  花开堪折直须折,莫待无花空折枝 


作者主页:[ https://www.weiyigeek.top ]  

博客:[ https://blog.weiyigeek.top ]

作者<开发安全运维>学习交流群,回复【学习交流群】即可加入


文章目录:

0x02 如何自定义 Gin 日志格式?

1.自定义定义路由日志的格式

2.自定义原生路由访问日志格式

3.使用 log 自定义日志并按天分隔保存到文件

0x02 如何自定义 Gin 日志格式?

1.自定义定义路由日志的格式

描述: 此处介绍如何定义路由日志的格式,而非使用默认的路由访问日志格式。
例如:默认的路由日志格式 GIN-debug] POST /foo --> main.main.func1 (3 handlers), 如果你想要以指定的格式(例如 JSON,key values 或其他格式)记录信息,则可以使用 gin.DebugPrintRouteFunc 指定格式。

package mainimport ("github.com/gin-gonic/gin""log""net/http"
)func main() {// gin 运行模式gin.SetMode(gin.DebugMode)r := gin.Default()// 关键点gin.DebugPrintRouteFunc = func(httpMethod, absolutePath, handlerName string, nuHandlers int) {log.Printf("endpoint %v %v %v %v\n", httpMethod, absolutePath, handlerName, nuHandlers)}r.POST("/foo", func(c *gin.Context) {c.JSON(http.StatusOK, "foo")})r.GET("/bar", func(c *gin.Context) {c.JSON(http.StatusOK, "bar")})r.GET("/status", func(c *gin.Context) {c.JSON(http.StatusOK, "ok")})// 监听并在 0.0.0.0:8080 上启动服务r.Run()
}

执行效果:
ad9d62e5fd58909bd9567babccda0584.png


偷偷的告诉你哟?极客全栈修炼】微信小程序已经上线了,

可直接在微信里面直接浏览博主博客了哟,后续将上线更多有趣的小工具。


2.自定义原生路由访问日志格式

描述: 此处是使用 gin.LoggerWithFormatter & gin.LogFormatterParams 实现自定义路由访问日志。

代码示例:

package mainimport ("fmt""io""os""time""github.com/gin-gonic/gin"
)func main() {// 强制日志颜色化gin.ForceConsoleColor()// 禁用控制台颜色// gin.DisableConsoleColor()// 默认为 debug 模式,设置为发布模式gin.SetMode(gin.ReleaseMode)// 将日志同时写入文件和控制台,请使用以下代码 f 表示文件,os,os.Stdout 表示终端f, _ := os.Create("gin.log")// 如果需要同时将日志写入文件和控制台,请使用以下代码。gin.DefaultWriter = io.MultiWriter(f, os.Stdout)// 生成gin实例,即 WSGI 应用程序r := gin.New()// 自定义日志格式// LoggerWithFormatter 中间件会将日志写入 gin.DefaultWriter// By default =>  gin.DefaultWriter = os.Stdoutr.Use(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.RFC1123),param.Method,param.Path,param.Request.Proto,param.StatusCode,param.Latency,param.Request.UserAgent(),param.ErrorMessage,)}))r.Use(gin.Recovery())// 声明了一个路由及对应的处理函数 (匿名函数)r.GET("/log", func(c *gin.Context) {c.JSON(200, gin.H{"code": "200", "msg": "Test gin logs", "data": "",})})r.Run()
}

执行效果:
46191b2069aceb2a187016e4ccc5a3b2.png

3.使用 log 自定义日志并按天分隔保存到文件

描述: 此处使用原生的 log 模块实现自定义路由日志,并载入到Gin的日志中间件中,实现终端与文件同时输出,输入的日志的文件按照天进行分隔,好了,废话不多说直接上代码:

日志中间件: middleware\Logger.go

package middlewareimport ("fmt""io""log""os""time""github.com/gin-gonic/gin"
)// Logger 是一个自定义的日志中间件
func Logger() gin.HandlerFunc {// 日志文件路径logFilePath := "./logs/"// 日志文件名前缀logFileName := "weiyigeek"// 日志文件后缀logFileExt := "log"// 日志文件最大大小,单位为 MBlogFileMaxSize := 1000// 日志文件切割的时间间隔,单位为天logFileSplitDays := 1// 检查日志目录是否存在,不存在则创建err := os.MkdirAll(logFilePath, os.ModePerm)if err != nil {log.Fatalf("Failed to create log directory: %v", err)}// 获取当前时间的年月日now := time.Now()year, month, day := now.Date()// 构造日志文件名logFileName = fmt.Sprintf("%s-%d-%02d-%02d", logFileName, year, month, day)// 打开日志文件logFile, err := os.OpenFile(fmt.Sprintf("%s/%s.%s", logFilePath, logFileName, logFileExt),os.O_WRONLY|os.O_APPEND|os.O_CREATE,0666,)if err != nil {log.Fatalf("Failed to open log file: %v", err)}// 设置日志输出writers := []io.Writer{logFile,os.Stdout}log.SetOutput(io.MultiWriter(writers...))log.SetFlags(log.Ldate | log.Ltime | log.LUTC)return func(c *gin.Context) {// 处理请求前记录日志// 开始时间startTime := time.Now()// 调用该请求的剩余处理程序c.Next()// 结束时间endTime := time.Now()// 执行时间latencyTime := endTime.Sub(startTime)// 请求IPclientIP := c.ClientIP()// remoteIP := c.RemoteIP()// 请求方式reqMethod := c.Request.Method// 请求路由reqUri := c.Request.RequestURI// 请求协议reqProto := c.Request.Proto// 请求来源repReferer := c.Request.Referer()// 请求UAreqUA := c.Request.UserAgent()// 请求响应内容长度resLength := c.Writer.Size()if resLength < 0 {resLength = 0}// 响应状态码statusCode := c.Writer.Status()log.Printf("%s | %3d | %s %10s | \033[44;37m%-6s\033[0m %s %s  | %10v | \"%s\" \"%s\"",colorForStatus(statusCode),statusCode,colorForStatus(0),clientIP,// remoteIP,reqMethod,reqUri,reqProto,latencyTime,reqUA,repReferer,)// 判断日志文件是否需要切割fileInfo, err := logFile.Stat()if err != nil {log.Fatalf("Failed to get log file info: %v", err)}_, _, lastDay := endTime.AddDate(0, 0, -1*logFileSplitDays).Date()if fileInfo.Size() > int64(logFileMaxSize*1024*1024) {// 关闭当前日志文件logFile.Close()// 构造新的日志文件名logFileName = fmt.Sprintf("%s-%s", logFileName, time.Now().Format("2006-01-02-15"))// 创建新的日志文件logFile, err = os.OpenFile(fmt.Sprintf("%s/%s.%s", logFilePath, logFileName, logFileExt),os.O_WRONLY|os.O_APPEND|os.O_CREATE,0666,)if err != nil {log.Fatalf("Failed to create log file: %v", err)}// 设置日志输出log.SetOutput(logFile)log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)} else if fileInfo.ModTime().Day() == lastDay {// 关闭当前日志文件logFile.Close()// 构造新的日志文件名logFileName = fmt.Sprintf("%s-%s", logFileName, endTime.Format("2006-01-02"))// 创建新的日志文件logFile, err = os.OpenFile(fmt.Sprintf("%s/%s.%s", logFilePath, logFileName, logFileExt),os.O_WRONLY|os.O_APPEND|os.O_CREATE,0666,)if err != nil {log.Fatalf("Failed to create log file: %v", err)}// 设置日志输出log.SetOutput(logFile)log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)}}
}// colorForStatus 根据 HTTP 状态码返回 ANSI 颜色代码
func colorForStatus(code int) string {switch {case code >= 200 && code < 300:return "\033[42;1;37m" // greencase code >= 300 && code < 400:return "\033[34m" // bluecase code >= 400 && code < 500:return "\033[33m" // yellowcase code == 0:return "\033[0m" // canceldefault:return "\033[31m" // red}
}

亲,文章就要看完了,不关注一下【全栈工程师修炼指南】吗?

460a49746716310aa47684db73dcf3ec.jpeg

入口文件: main.go

package mainimport ("devopsapi/middleware"router "devopsapi/routers""fmt""log""net/http""time""github.com/gin-gonic/gin""golang.org/x/sync/errgroup"
)// 处理属于同一总体任务的子任务的goroutine的集合
var (g errgroup.Group
)func main() {// 指定 gin 运行模式gin.SetMode(global.App.Mode)// 返回一个新的空白Engine实例r := gin.New()// 设置日志中间件r.Use(middleware.Logger())// 加载自定义路由router.Load(r)// Linux、Mac 环境下使用 fvbock/endless 艰辛平滑重启// err := endless.ListenAndServe(fmt.Sprintf("%s:%d", global.App.Host, global.App.Port), r)// if err != nil || err != http.ErrServerClosed {// 	log.Println("err:", err)// }// W通用:开放监听运行Gin服务server := &http.Server{// Gin运行的监听端口Addr: ":8080",// 要调用的处理程序,http.DefaultServeMux如果为nilHandler: r,// ReadTimeout是读取整个请求(包括正文)的最长持续时间。ReadTimeout: 5 * time.Second,// WriteTimeout是超时写入响应之前的最长持续时间WriteTimeout: 10 * time.Second,// MaxHeaderBytes控制服务器解析请求标头的键和值(包括请求行)时读取的最大字节数 (通常情况下不进行设置)MaxHeaderBytes: 1 << 20,}// 创建 goroutine 中调用给定的函数g.Go(func() error {return server.ListenAndServe()})// goroutine 所有函数调用都返回,然后从中返回第一个非零错误(如果有的话)。if err := g.Wait(); err != nil {log.Fatal(err)}
}

执行结果:
日志实现格式: 2023/06/09 09:59:04 [42;1;37m | 200 | [0m 10.20.172.103 | [44;37mGET [0m /app/version HTTP/1.1 | 144.4µs | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.57" ""
5c1339cc387a4d6ed48f95dfbe1fdbdc.png

本文至此完毕,更多技术文章,尽情等待下篇好文!

原文地址: https://blog.weiyigeek.top/2023/6-2-745.html

如果此篇文章对你有帮助,请你将它分享给更多的人! 

06c5016b3c7abe2f68e09f0e1c10e523.gif

b170e278a18bbef9ffc999df98b935ca.png 学习书籍推荐 往期发布文章 b7f0ff7b0cd2bda1dc6c7c0cb1dbdedf.png

公众号回复【0008】获取【Ubuntu22.04安装与加固脚本】

公众号回复【10001】获取【WinServer安全加固脚本】

公众号回复【10002】获取【KylinOS银河麒麟安全加固脚本】

公众号回复【0011】获取【k8S二进制安装部署教程】

公众号回复【0014】获取【Nginx学习之路汇总】

公众号回复【0015】获取【Jenkins学习之路汇总】

公众号回复【10005】获取【adb工具刷抖音赚米】

 热文推荐  

  • Golang | Web开发之Gin框架快速入门基础实践

  • Go开发学习 | 如何快速读取json/yaml/ini等格式的配置文件使用示例

  • Go开发学习 | 如何使用Gomail.v2模块包发送邮箱验证码消息及附件学习记录

  • Go开发学习 | 如何使用日志记录模块包针对日志按天数、按大小分隔文件示例

  • 开发基础 | Golang语言的RESTfulAPI接口设计规范快速入门

欢迎长按(扫描)二维码 取更多渠道哟!

79e45baccb4ad8627618b14f43de35a7.gif

欢迎关注 【全栈工程师修炼指南】(^U^)ノ~YO

添加作者微信【weiyigeeker 】 一起学习交流吧!

关注回复【学习交流群】即可加入【安全运维沟通交流小群

温馨提示: 由于作者水平有限,本章错漏缺点在所难免,希望读者批评指正,若有问题或建议请在文章末尾留下您宝贵的经验知识,或联系邮箱地址

master@weiyigeek.top 或 关注公众号 [全栈工程师修炼指南] 留言。

点个【赞 + 在看】吧!

点击【"阅读原文"】获取更多有趣的知识!   


http://www.ppmy.cn/news/359613.html

相关文章

一公司禁止婚外情和出轨,称如果员工出现此类情况,将予以辞退处理

大家好&#xff01;我是老洪。 刚看到一则有意思的资讯。 一家公司发布了禁止婚外情和出轨的通知&#xff0c;称如果员工出现此类情况&#xff0c;将予以辞退处理。 这份通知称&#xff0c;公司已婚员工如有婚外情、出轨、包养小三等不良情况&#xff0c;将辞退处理。 公司竟然…

开关电源-FPC入门知识

01功率因数补偿和功率因数校正 功率因数补偿&#xff1a;在上世纪五十年代&#xff0c;已经针对具有感性负载的交流用电器具的电压和电流不同相&#xff08;图1&#xff09;从而引起的供电效率低下提出了改进方法&#xff08;由于感性负载的电流滞后所加电压&#xff0c;由于电…

【实用教程】大富增加系统彩教程/超详细的教程文档,菜鸡根据教程都可以百分百可以上手

我整理成了一个Word文档&#xff0c;每一步都写出来了&#xff0c;知识付费&#xff0c;经营不易&#xff0c;多多支持&#xff01; 只要会这个技术&#xff0c;完全可以去接单&#xff0c;因为需求是有的&#xff0c;就看你会不会&#xff0c;不会的话这个单子和你没有关系&a…

从Kotlin中return@forEach了个寂寞

点击上方蓝字关注我&#xff0c;知识会给你力量 今天在Review&#xff08;copy&#xff09;同事代码的时候&#xff0c;发现了一个问题&#xff0c;想到很久之前&#xff0c;自己也遇到过这个问题&#xff0c;那么就来看下吧。首先&#xff0c;我们抽取最小复现代码。 (1..7).f…

钓鱼网站新花招 福彩赌球成噱头

因为博彩活动越来越引人注目&#xff0c;一些钓鱼网站的制作者&#xff0c;又将博彩当成了一种引人耳目的心噱头&#xff0c;实施网络诈骗。甚至一些不法网站竟然公开制作并销售钓鱼网站模版&#xff0c;对网络安全造成了巨大的危害。 博彩成为一种新的娱乐方式&#xff0c;当然…

全球及中国高纯二氧化硅行业趋势分析及投资调研评估报告2022年版

全球及中国高纯二氧化硅行业趋势分析及投资调研评估报告2022年版 【报告编号】: 414674 【出版时间】: 2022年3月 【出版单位】: 中商经济研究网 1 高纯二氧化硅市场概述 1.1 高纯二氧化硅行业概述及统计范围 1.2 按照不同产品类型&#xff0c;高纯二氧化硅主要可以分为…

转载:一个老IT人的自白:看十年硬件品牌兴亡史

一个老IT人的自白&#xff1a;看十年硬件品牌兴亡史 1 华硕   我用的第一台电脑就是华硕&#xff0c;型号是P5什么的&#xff0c;忘记了&#xff0c;配P133的CPU,这台机器现在仍在当一个打字机服役&#xff0c;十年来死机0次。这就是磐石的根基所在&#xff0c;像一颗百年老树…

近十年硬件品牌兴亡史,一个老IT人的自白

1 华硕 我用的第一台电脑就是华硕&#xff0c;型号是P5什么的&#xff0c;忘记了&#xff0c;配P133的CPU,这台机器现在仍在当一个打字机服役&#xff0c;十年来死机0次。这就是磐石的根基所在&#xff0c;像一颗百年老树&#xff0c;表面上看起来枝繁叶茂&#xff0c;一派繁荣…