101 lines
2.7 KiB
Go
101 lines
2.7 KiB
Go
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()
|
|
}
|
|
}
|