From 3327d648336cabd4a18eb3dde886f09ebeb120c6 Mon Sep 17 00:00:00 2001 From: icey-yu <1186114839@qq.com> Date: Wed, 11 Dec 2024 18:19:26 +0800 Subject: [PATCH] feat: log.ZPanic --- errs/stack.go | 48 ++++++++++++++++++++++++++++++++++++ log/logger.go | 2 +- log/zap.go | 15 ++++++++--- mw/errstack.go | 33 ------------------------- mw/gin.go | 7 +++--- mw/rpc_client_interceptor.go | 2 +- 6 files changed, 65 insertions(+), 42 deletions(-) create mode 100644 errs/stack.go diff --git a/errs/stack.go b/errs/stack.go new file mode 100644 index 00000000..ab92574a --- /dev/null +++ b/errs/stack.go @@ -0,0 +1,48 @@ +package errs + +import ( + "fmt" + "runtime" + "strings" +) + +func GetPanicStack() string { + var pcs [32]uintptr + n := runtime.Callers(0, pcs[:]) + frames := runtime.CallersFrames(pcs[:n]) + + var ( + sb strings.Builder + frame runtime.Frame + beginPanicStack = false + more = true + begin = true + ) + + for { + if !more { + break + } + frame, more = frames.Next() + if !beginPanicStack && !strings.Contains(frame.Function, "gopanic") { + + continue + } else { + beginPanicStack = true + } + + if strings.HasPrefix(frame.Function, "runtime.") { + continue + } + + if begin { + begin = false + } else { + sb.WriteString(" -> ") + } + funcNameParts := strings.Split(frame.Function, ".") + s := fmt.Sprintf("%s (%s:%d)", funcNameParts[len(funcNameParts)-1], frame.File, frame.Line) + sb.WriteString(s) + } + return sb.String() +} diff --git a/log/logger.go b/log/logger.go index fc53512c..b4611133 100644 --- a/log/logger.go +++ b/log/logger.go @@ -35,7 +35,7 @@ type Logger interface { // Panic logs a message at the panic level, indicating a critical error like nil pointer exception that requires immediate attention. // It includes an error object and any supplementary key-value pairs. - Panic(ctx context.Context, msg string, err error, keysAndValues ...any) + Panic(ctx context.Context, msg string, r interface{}, keysAndValues ...any) // WithValues returns a new Logger instance that will include the specified key-value pairs // in all subsequent log messages. Useful for adding consistent context to a series of logs. diff --git a/log/zap.go b/log/zap.go index b7c56487..14e50f25 100644 --- a/log/zap.go +++ b/log/zap.go @@ -7,6 +7,7 @@ import ( "path/filepath" "time" + "github.com/openimsdk/tools/errs" rotatelogs "github.com/openimsdk/tools/log/file-rotatelogs" "github.com/openimsdk/tools/utils/stringutil" @@ -129,7 +130,7 @@ func ZError(ctx context.Context, msg string, err error, keysAndValues ...any) { pkgLogger.Error(ctx, msg, err, keysAndValues...) } -func ZPanic(ctx context.Context, msg string, err error, keysAndValues ...any) { +func ZPanic(ctx context.Context, msg string, err interface{}, keysAndValues ...any) { pkgLogger.Panic(ctx, msg, err, keysAndValues...) } @@ -420,13 +421,19 @@ func (l *ZapLogger) Error(ctx context.Context, msg string, err error, keysAndVal l.zap.Errorw(msg, keysAndValues...) } -func (l *ZapLogger) Panic(ctx context.Context, msg string, err error, keysAndValues ...any) { +func (l *ZapLogger) Panic(ctx context.Context, msg string, r interface{}, keysAndValues ...any) { if l.level > zapcore.PanicLevel { return } - if err != nil { - keysAndValues = append(keysAndValues, "error", err.Error()) + + panicStack := errs.GetPanicStack() + if e, ok := r.(error); ok { + keysAndValues = append(keysAndValues, "error", e.Error()) + } else { + keysAndValues = append(keysAndValues, "recover", r) } + keysAndValues = append(keysAndValues, "stacktrace", panicStack) + keysAndValues = l.kvAppend(ctx, keysAndValues) l.zap.Errorw(msg, keysAndValues...) } diff --git a/mw/errstack.go b/mw/errstack.go index 0f69cb02..74ba703a 100644 --- a/mw/errstack.go +++ b/mw/errstack.go @@ -1,11 +1,8 @@ package mw import ( - "context" "fmt" - "github.com/openimsdk/tools/log" "runtime" - "strconv" "strings" "github.com/pkg/errors" @@ -55,33 +52,3 @@ func simplifyFuncName(fullFuncName string) string { } return lastPart } - -func getPanicStack(skip int) string { - var pcs [32]uintptr - n := runtime.Callers(skip, pcs[:]) - frames := runtime.CallersFrames(pcs[:n]) - - var sb strings.Builder - for { - frame, more := frames.Next() - //sb.WriteString(frame.File) - //sb.WriteString(":") - sb.WriteString(frame.Function) - sb.WriteString(":") - sb.WriteString(strconv.Itoa(frame.Line)) - if !more { - break - } - sb.WriteString(" -> ") - } - return sb.String() -} - -func PanicStackToLog(ctx context.Context, err any) { - panicStack := getPanicStack(0) - if e, ok := err.(error); ok { - log.ZError(ctx, "recovered from panic", e, "stack", panicStack) - } else { - log.ZError(ctx, "recovered from panic with non-error type", e, "stack", panicStack) - } -} diff --git a/mw/gin.go b/mw/gin.go index 485a8715..3e5eae3a 100644 --- a/mw/gin.go +++ b/mw/gin.go @@ -15,11 +15,12 @@ package mw import ( + "net/http" + "strings" + "github.com/golang-jwt/jwt/v4" "github.com/openimsdk/tools/log" "github.com/openimsdk/tools/tokenverify" - "net/http" - "strings" "github.com/gin-gonic/gin" "github.com/openimsdk/protocol/constant" @@ -119,6 +120,6 @@ func CreateToken(userID string, accessSecret string, accessExpire int64, platfor } func GinPanicErr(c *gin.Context, err any) { - PanicStackToLog(c, err) + log.ZPanic(c, "GinPanicErr panic", err) c.AbortWithStatus(http.StatusInternalServerError) } diff --git a/mw/rpc_client_interceptor.go b/mw/rpc_client_interceptor.go index bd5216c2..e4a95b6c 100644 --- a/mw/rpc_client_interceptor.go +++ b/mw/rpc_client_interceptor.go @@ -45,7 +45,7 @@ func RpcClientInterceptor(ctx context.Context, method string, req, resp any, cc log.ZDebug(ctx, fmt.Sprintf("RPC Client Request - %s", extractFunctionName(method)), "funcName", method, "req", req, "conn target", cc.Target()) defer func() { if r := recover(); r != nil { - PanicStackToLog(ctx, r) + log.ZPanic(ctx, "RpcClientInterceptor panic", r) } }() err = invoker(ctx, method, req, resp, cc, opts...)