Go Gin框架登录JSON

And*_*alu 10 go go-gin

我正在使用 Go Gin 设置一个小型 API,但是我无法说服记录器输出 JSON。默认情况下它是一个键/值字符串,但我需要它作为 json。

我怎样才能做到这一点?我觉得它应该很容易支持,但我一直在努力使用自定义格式化功能,我需要自己考虑各种参数。

或者,我也使用 uber/zap 记录器手动记录,但我还没有找到用我的记录器替换 gin 记录器的方法。

任何指点都将不胜感激,因为 gin 的 github 上的文档并没有太大帮助。

谢谢!

编辑:澄清一下,添加中间件有助于记录请求,但我正在寻找为 Gin 设置 JSON 日志记录的单点(例如:包括与请求无关的日志,例如框架内部的调试/信息日志)

eud*_*ore 14

访问记录器

https://github.com/sbecker/gin-api-demo/blob/master/middleware/json_logger.go


// JSONLogMiddleware logs a gin HTTP request in JSON format, with some additional custom key/values
func JSONLogMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // Start timer
        start := time.Now()

        // Process Request
        c.Next()

        // Stop timer
        duration := util.GetDurationInMillseconds(start)

        entry := log.WithFields(log.Fields{
            "client_ip":  util.GetClientIP(c),
            "duration":   duration,
            "method":     c.Request.Method,
            "path":       c.Request.RequestURI,
            "status":     c.Writer.Status(),
            "user_id":    util.GetUserID(c),
            "referrer":   c.Request.Referer(),
            "request_id": c.Writer.Header().Get("Request-Id"),
            // "api_version": util.ApiVersion,
        })

        if c.Writer.Status() >= 500 {
            entry.Error(c.Errors.String())
        } else {
            entry.Info("")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

调试记录器

查看gin源码,发现debug日志输出到了一个io.Writer中。重写该对象会将输出重定向为json,类似于处理http.Server.Errorlog的输出的方法。

func debugPrint(format string, values ...interface{}) {
    if IsDebugging() {
        if !strings.HasSuffix(format, "\n") {
            format += "\n"
        }
        fmt.Fprintf(DefaultWriter, "[GIN-debug] "+format, values...)
    }
}
Run Code Online (Sandbox Code Playgroud)

设置debug写入,这段代码没有测试。

// WriteFunc convert func to io.Writer.
type WriteFunc func([]byte) (int, error)
func (fn WriteFunc) Write(data []byte) (int, error) {
    return fn(data)
}

func NewLogrusWrite() io.Writer {
    return WriteFunc(func(data []byte) (int, error) {
        logrus.Debugf("%s", data)
        return 0, nil
    })
}
// set gin write to logrus debug.
gin.DefaultWriter = NewLogrusWrite()
Run Code Online (Sandbox Code Playgroud)

获取所有 http.Server 错误日志。

htt.服务器

htt.Server将日志输出到一个log.Logger,并通过指定的io.Writer创建一个log.Logger输出,用于接收来自http.Sever的Error日志。目前没有详细的编写gin使用自定义Sever代码,请查看gin文档。

srv := &http.Server{
    // log level is bebug, please create a error level io.Writer
    ErrorLog: log.New(NewLogrusWrite(), "", 0),
} 

Run Code Online (Sandbox Code Playgroud)


Meh*_*alp 7

除了@audore的回答;他的方法将更改默认输出,默认为 stdout。我们仍然想使用标准输出,但如果我们想更改整个输出,我们应该执行这些步骤。

1-更改杜松子酒初始化

r := gin.Default()
Run Code Online (Sandbox Code Playgroud)

r := gin.New()
r.Use(gin.Recovery()) // to recover gin automatically
r.Use(jsonLoggerMiddleware()) // we'll define it later
Run Code Online (Sandbox Code Playgroud)

因为 gin.Default() 使用默认的 Logger() 中间件。如果我们继续使用它,gin 会输出两次

2-将中间件添加到您的应用程序中

func jsonLoggerMiddleware() gin.HandlerFunc {
    return gin.LoggerWithFormatter(
        func(params gin.LogFormatterParams) string {
            log := make(map[string]interface{})

            log["status_code"] = params.StatusCode
            log["path"] = params.Path
            log["method"] = params.Method
            log["start_time"] = params.TimeStamp.Format("2006/01/02 - 15:04:05")
            log["remote_addr"] = params.ClientIP
            log["response_time"] = params.Latency.String()

            s, _ := json.Marshal(log)
            return string(s) + "\n"
        },
    )
}
Run Code Online (Sandbox Code Playgroud)

你的输出将是:

{"method":"GET","path":"/v1/somepath","remote_addr":"::1","response_time":"5.719ms","start_time":"2022/10/03 - 17:26:11","status_code":200}
Run Code Online (Sandbox Code Playgroud)

从像 Loki+Grafana 这样的日志监听器中解析起来太容易了