我偶尔会看到截断的json对象通过我的自定义日志中间件写入loggly。我已经确认,在我的代码中,传出的记录实际上被截断了。
日志是用zerolog格式化的,然后在stdout和loggly之间输出。
我使用的loggly包很旧,但似乎只是实现了一个带有缓冲区的io.Writer
https://github.com/segmentio/go-loggly.
我担心的是,gin是在日志写入缓冲区之前终止上下文,还是缩短了写入?但在杜松子酒医生提供的例子中,我没有看到任何明显的不同。我已经删除了同样多的仍然存在问题的无关代码。
写入STDOUT的日志是完整的,但通过loggly包发送的日志被截断。
package main
import (
"io"
"os"
"github.com/gin-gonic/gin"
"github.com/rs/zerolog"
"github.com/segmentio/go-loggly"
)
var logglyClient *loggly.Client
func init() {
logglyToken := "potato"
logglyClient = loggly.New(logglyToken)
}
func NewLogger() zerolog.Logger {
writers := []io.Writer{zerolog.ConsoleWriter{Out: os.Stdout}}
writers = append(writers, logglyClient)
multiWriter := zerolog.MultiLevelWriter(writers...)
logger := zerolog.New(multiWriter).With().Timestamp().Logger()
return logger
}
func GinMiddleware() gin.HandlerFunc {
return func(gctx *gin.Context) {
logger := NewLogger()
logger.Info().Msg("API request")
gctx.Next()
}
}
func main() {
router := gin.New()
router.Use(GinMiddleware())
logger := NewLogger()
router.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
logger.Info().Msg("Server Listening!")
router.Run(":8080")
}
使用的软件包如下
github.com/gin-gonic/gin v1.7.7
github.com/rs/zerolog v1.26.0
github.com/segmentio/go-loggly v0.5.0
在退出程序之前刷新loggly客户端就可以了。
https://github.com/segmentio/go-loggly/blob/7a70408c3650c37ba8e58a934f686d0c44cb9b58/loggly.go#L216
func main() {
defer logglyClient.Flush()
router := gin.New()
router.Use(GinMiddleware())
logger := NewLogger()
router.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
logger.Info().Msg("Server Listening!")
router.Run(":8080")
}
最重要的是,您必须实现服务器的优雅关闭,以防止程序突然退出。
Gin文档中有一个的例子
https://chenyitian.gitbooks.io/gin-web-framework/content/docs/38.html
func main() {
router := gin.Default()
router.GET("/", func(c *gin.Context) {
time.Sleep(5 * time.Second)
c.String(http.StatusOK, "Welcome Gin Server")
})
srv := &http.Server{
Addr: ":8080",
Handler: router,
}
go func() {
// service connections
if err := srv.ListenAndServe(); err != nil {
log.Printf("listen: %sn", err)
}
}()
// Wait for interrupt signal to gracefully shutdown the server with
// a timeout of 5 seconds.
quit := make(chan os.Signal)
signal.Notify(quit, os.Interrupt)
<-quit
log.Println("Shutdown Server ...")
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
log.Fatal("Server Shutdown:", err)
}
log.Println("Server exiting")
}