package ginzap import ( "net" "net/http" "os" "runtime/debug" "strings" "time" "91porn-server/common/hevcpull" "91porn-server/common/log" "github.com/gin-gonic/gin" ) func Logger(ctxKeys []string) gin.HandlerFunc { return func(c *gin.Context) { start := time.Now() path := c.Request.URL.Path query := hevcpull.RedactText(c.Request.URL.RawQuery) c.Next() end := time.Now() latency := end.Sub(start) if len(c.Errors) > 0 { for _, e := range c.Errors.Errors() { log.Error(e, log.R(c)) } } else { l := []log.Field{ log.R(c), log.Any("status", c.Writer.Status()), log.Any("method", c.Request.Method), log.Any("path", path), log.Any("query", query), log.Any("user-agent", c.Request.UserAgent()), log.Any("time", end.Format("2006-01-02 15:04:05")), log.Any("latency", latency), } for _, k := range ctxKeys { v, e := c.Get(k) if e { l = append(l, log.Any(k, v)) } } log.Info(path, l...) } } } // RecoveryWithZap returns a gin.HandlerFunc (middleware) // that recovers from any panics and logs requests using uber-go/zap. // All errors are logged using zap.Error(). // stack means whether output the stack info. // The stack info is easy to find where the error occurs but the stack info is too large. func Recovery(stack bool, do func(err interface{})) gin.HandlerFunc { return func(c *gin.Context) { defer func() { if err := recover(); err != nil { if do != nil { do(err) } // 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 } } } // Record request identity without exposing authentication headers or body. requestFields := []log.Field{ log.R(c), log.Any("method", c.Request.Method), log.Any("path", c.Request.URL.Path), log.Any("panic", err), } if brokenPipe { log.Error(c.Request.URL.Path, requestFields...) // If the connection is dead, we can't write a status to it. c.Error(err.(error)) // nolint: errcheck c.Abort() return } if stack { requestFields = append(requestFields, log.Any("stack", string(debug.Stack()))) } log.Error("[Recovery from panic]", requestFields...) c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{ "result": false, "error": http.StatusText(http.StatusInternalServerError), }) } }() c.Next() } }