千家信息网

zap接收gin框架默认的日志并配置日志归档的方法

发表于:2025-11-07 作者:千家信息网编辑
千家信息网最后更新 2025年11月07日,这篇"zap接收gin框架默认的日志并配置日志归档的方法"文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我
千家信息网最后更新 2025年11月07日zap接收gin框架默认的日志并配置日志归档的方法

这篇"zap接收gin框架默认的日志并配置日志归档的方法"文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇"zap接收gin框架默认的日志并配置日志归档的方法"文章吧。

gin默认的中间件

首先我们来看一个最简单的gin项目:

func main() {        r := gin.Default()        r.GET("/hello", func(c *gin.Context) {                c.String("hello liwenzhou.com!")        })        r.Run(}

接下来我们看一下gin.Default()的源码:

func Default() *Engine {        debugPrintWARNINGDefault()        engine := New()        engine.Use(Logger(), Recovery())        return engine}

也就是我们在使用gin.Default()的同时是用到了gin框架内的两个默认中间件Logger()Recovery()

其中Logger()是把gin框架本身的日志输出到标准输出(我们本地开发调试时在终端输出的那些日志就是它的功劳),而Recovery()是在程序出现panic的时候恢复现场并写入500响应的。

基于zap的中间件

我们可以模仿Logger()Recovery()的实现,使用我们的日志库来接收gin框架默认输出的日志。

这里以zap为例,我们实现两个中间件如下:

// GinLogger 接收gin框架默认的日志func GinLogger(logger *zap.Logger) gin.HandlerFunc {        return func(c *gin.Context) {                start := time.Now()                path := c.Request.URL.Path                query := c.Request.URL.RawQuery                c.Next()                cost := time.Since(start)                logger.Info(path,                        zap.Int("status", c.Writer.Status()),                        zap.String("method", c.Request.Method),                        zap.String("path", path),                        zap.String("query", query),                        zap.String("ip", c.ClientIP()),                        zap.String("user-agent", c.Request.UserAgent()),                        zap.String("errors", c.Errors.ByType(gin.ErrorTypePrivate).String()),                        zap.Duration("cost", cost),                )        }}// GinRecovery recover掉项目可能出现的panicfunc GinRecovery(logger *zap.Logger, stack bool) gin.HandlerFunc {        return func(c *gin.Context) {                defer func() {                        if err := recover(); err != nil {                                // Check for a broken connection, as it is not really a                                // condition that warrants a panic stack trace.                                var brokenPipe bool                                if ne, ok := err.(*net.OpError); ok {                                        if se, ok := ne.Err.(*os.SyscallError); ok {                                                if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") {                                                        brokenPipe = true                                                }                                        }                                }                                httpRequest, _ := httputil.DumpRequest(c.Request, false)                                if brokenPipe {                                        logger.Error(c.Request.URL.Path,                                                zap.Any("error", err),                                                zap.String("request", string(httpRequest)),                                        )                                        // If the connection is dead, we can't write a status to it.                                        c.Error(err.(error)) // nolint: errcheck                                        c.Abort()                                        return                                }                                if stack {                                        logger.Error("[Recovery from panic]",                                                zap.Any("error", err),                                                zap.String("request", string(httpRequest)),                                                zap.String("stack", string(debug.Stack())),                                        )                                } else {                                        logger.Error("[Recovery from panic]",                                                zap.Any("error", err),                                                zap.String("request", string(httpRequest)),                                        )                                }                                c.AbortWithStatus(http.StatusInternalServerError)                        }                }()                c.Next()        }}

如果不想自己实现,可以使用github上有别人封装好的https://github.com/gin-contrib/zap。

这样我们就可以在gin框架中使用我们上面定义好的两个中间件来代替gin框架默认的Logger()Recovery()了。

r := gin.New()r.Use(GinLogger(), GinRecovery())

在gin项目中使用zap

最后我们再加入我们项目中常用的日志切割,完整版的logger.go代码如下:

package loggerimport (        "gin_zap_demo/config"        "net"        "net/http"        "net/http/httputil"        "os"        "runtime/debug"        "strings"        "time"        "github.com/gin-gonic/gin"        "github.com/natefinch/lumberjack"        "go.uber.org/zap"        "go.uber.org/zap/zapcore")var lg *zap.Logger// InitLogger 初始化Loggerfunc InitLogger(cfg *config.LogConfig) (err error) {        writeSyncer := getLogWriter(cfg.Filename, cfg.MaxSize, cfg.MaxBackups, cfg.MaxAge)        encoder := getEncoder()        var l = new(zapcore.Level)        err = l.UnmarshalText([]byte(cfg.Level))        if err != nil {                return        }        core := zapcore.NewCore(encoder, writeSyncer, l)        lg = zap.New(core, zap.AddCaller())        zap.ReplaceGlobals(lg) // 替换zap包中全局的logger实例,后续在其他包中只需使用zap.L()调用即可        return}func getEncoder() zapcore.Encoder {        encoderConfig := zap.NewProductionEncoderConfig()        encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder        encoderConfig.TimeKey = "time"        encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder        encoderConfig.EncodeDuration = zapcore.SecondsDurationEncoder        encoderConfig.EncodeCaller = zapcore.ShortCallerEncoder        return zapcore.NewJSONEncoder(encoderConfig)}func getLogWriter(filename string, maxSize, maxBackup, maxAge int) zapcore.WriteSyncer {        lumberJackLogger := &lumberjack.Logger{                Filename:   filename,                MaxSize:    maxSize,                MaxBackups: maxBackup,                MaxAge:     maxAge,        }        return zapcore.AddSync(lumberJackLogger)}// GinLogger 接收gin框架默认的日志func GinLogger() gin.HandlerFunc {        return func(c *gin.Context) {                start := time.Now()                path := c.Request.URL.Path                query := c.Request.URL.RawQuery                c.Next()                cost := time.Since(start)                lg.Info(path,                        zap.Int("status", c.Writer.Status()),                        zap.String("method", c.Request.Method),                        zap.String("path", path),                        zap.String("query", query),                        zap.String("ip", c.ClientIP()),                        zap.String("user-agent", c.Request.UserAgent()),                        zap.String("errors", c.Errors.ByType(gin.ErrorTypePrivate).String()),                        zap.Duration("cost", cost),                )        }}// GinRecovery recover掉项目可能出现的panic,并使用zap记录相关日志func GinRecovery(stack bool) gin.HandlerFunc {        return func(c *gin.Context) {                defer func() {                        if err := recover(); err != nil {                                // Check for a broken connection, as it is not really a                                // condition that warrants a panic stack trace.                                var brokenPipe bool                                if ne, ok := err.(*net.OpError); ok {                                        if se, ok := ne.Err.(*os.SyscallError); ok {                                                if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") {                                                        brokenPipe = true                                                }                                        }                                }                                httpRequest, _ := httputil.DumpRequest(c.Request, false)                                if brokenPipe {                                        lg.Error(c.Request.URL.Path,                                                zap.Any("error", err),                                                zap.String("request", string(httpRequest)),                                        )                                        // If the connection is dead, we can't write a status to it.                                        c.Error(err.(error)) // nolint: errcheck                                        c.Abort()                                        return                                }                                if stack {                                        lg.Error("[Recovery from panic]",                                                zap.Any("error", err),                                                zap.String("request", string(httpRequest)),                                                zap.String("stack", string(debug.Stack())),                                        )                                } else {                                        lg.Error("[Recovery from panic]",                                                zap.Any("error", err),                                                zap.String("request", string(httpRequest)),                                        )                                }                                c.AbortWithStatus(http.StatusInternalServerError)                        }                }()                c.Next()        }}

然后定义日志相关配置:

type LogConfig struct {        Level string `json:"level"`        Filename string `json:"filename"`        MaxSize int `json:"maxsize"`        MaxAge int `json:"max_age"`        MaxBackups int `json:"max_backups"`}

在项目中先从配置文件加载配置信息,再调用logger.InitLogger(config.Conf.LogConfig)即可完成logger实例的初识化。其中,通过r.Use(logger.GinLogger(), logger.GinRecovery(true))注册我们的中间件来使用zap接收gin框架自身的日志,在项目中需要的地方通过使用zap.L().Xxx()方法来记录自定义日志信息。

package mainimport (        "fmt"        "gin_zap_demo/config"        "gin_zap_demo/logger"        "net/http"        "os"        "go.uber.org/zap"        "github.com/gin-gonic/gin")func main() {        // load config from config.json        if len(os.Args) < 1 {                return        }        if err := config.Init(os.Args[1]); err != nil {                panic(err)        }        // init logger        if err := logger.InitLogger(config.Conf.LogConfig); err != nil {                fmt.Printf("init logger failed, err:%v\n", err)                return        }        gin.SetMode(config.Conf.Mode)        r := gin.Default()        // 注册zap相关中间件        r.Use(logger.GinLogger(), logger.GinRecovery(true))        r.GET("/hello", func(c *gin.Context) {                // 假设你有一些数据需要记录到日志中                var (                        name = "q1mi"                        age  = 18                )                // 记录日志并使用zap.Xxx(key, val)记录相关字段                zap.L().Debug("this is hello func", zap.String("user", name), zap.Int("age", age))                c.String(http.StatusOK, "hello liwenzhou.com!")        })        addr := fmt.Sprintf(":%v", config.Conf.Port)        r.Run(addr)}

以上就是关于"zap接收gin框架默认的日志并配置日志归档的方法"这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注行业资讯频道。

日志 框架 中间件 项目 配置 内容 方法 输出 两个 信息 实例 就是 文章 知识 篇文章 接下来 也就是 代码 价值 全局 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 数据库逻辑描述的模式有 软件开发承诺书范文 移动服务器怎么设置网络 山东流量卡网络技术有限公司 Win10家庭版不能装数据库 pubg更换服务器会有什么影响 ajax检验数据库 宜宾临港网络安全展厅 质量网络技术转让操作 红河州网络安全培训会 江苏做网络安全厂家 唐山国安网络技术有限公司 学校网络安全管理制度文本 软件数据库如何部署到阿里云 可以搭建服务器的单机游戏 公益宣传片网络安全课视频 软件开发人才外包企业培训 服务器不要带宽可以访问吗 我的世界局域网创造服务器 计算机网络技术专业论文800字 黑保利服务器 福建推广软件开发咨询热线 如何查看曙光服务器的管理地址 未转变者服务器设置 美食推荐系统数据库设计 网络安全 警用装备 软件开发需要学什么英语 英雄联盟哪些服务器 自考软件开发工具原理大纲 创建sql中数据库的代码
0