我们自己写个log日志包,把zap和sentry封装到一起。
下面直接贴上主要部分代码(两个模块初始化部分的代码请自行查阅官方文档):
- logger.go
package log
import (
"github.com/getsentry/sentry-go"
"go.uber.org/zap"
)
type Logger struct {
*zap.Logger
}
// Debug logs a message at DebugLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func (log *Logger) Debug(msg string, fields ...zap.Field) {
log.Logger.Debug(msg, fields...)
NewMessage(sentry.LevelDebug, msg, fields)
}
// Info logs a message at InfoLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func (log *Logger) Info(msg string, fields ...zap.Field) {
log.Logger.Info(msg, fields...)
NewMessage(sentry.LevelInfo, msg, fields)
}
// Warn logs a message at WarnLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func (log *Logger) Warn(msg string, fields ...zap.Field) {
log.Logger.Warn(msg, fields...)
NewMessage(sentry.LevelWarning, msg, fields)
}
// Error logs a message at ErrorLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func (log *Logger) Error(msg string, fields ...zap.Field) {
log.Logger.Error(msg, fields...)
NewMessage(sentry.LevelError, msg, fields)
}
// Fatal logs a message at FatalLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
//
// The logger then calls os.Exit(1), even if logging at FatalLevel is
// disabled.
func (log *Logger) Fatal(msg string, fields ...zap.Field) {
log.Logger.Fatal(msg, fields...)
NewMessage(sentry.LevelFatal, msg, fields)
}
- sentry.go
package log
import (
"fmt"
"utils/stime"
"github.com/getsentry/sentry-go"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"math"
"runtime"
"time"
)
type CustomError struct {
msg string
stackTrace []uintptr
}
func (e *CustomError) Error() string {
return e.msg
}
func (e *CustomError) StackTrace() []uintptr {
return e.stackTrace
}
func NewMessage(level sentry.Level, msg string, fields []zap.Field) {
if sentryUsable {
sentry.WithScope(func(scope *sentry.Scope) {
scope.SetLevel(level)
scope.SetExtra("msg", msg)
if len(fields) > 0 {
for _, field := range fields {
switch field.Type {
case zapcore.StringType:
scope.SetExtra(field.Key, field.String)
case zapcore.ErrorType:
scope.SetExtra(field.Key, field.Interface.(error).Error())
case zapcore.StringerType:
scope.SetExtra(field.Key, field.Interface.(fmt.Stringer).String())
case zapcore.Int8Type, zapcore.Int16Type, zapcore.Int32Type, zapcore.Int64Type, zapcore.Uint8Type, zapcore.Uint16Type, zapcore.Uint32Type, zapcore.Uint64Type:
scope.SetExtra(field.Key, field.Integer)
case zapcore.Float32Type, zapcore.Float64Type:
floatVal := math.Float32frombits(uint32(field.Integer))
scope.SetExtra(field.Key, floatVal)
case zapcore.BoolType:
scope.SetExtra(field.Key, field.Integer == 1)
case zapcore.TimeFullType:
if ts, ok := field.Interface.(time.Time); ok {
scope.SetExtra(field.Key, ts.Format(stime.Format_Normal_YMDhms))
}
case zapcore.TimeType:
scope.SetExtra(field.Key, time.Unix(0, field.Integer).UTC())
default:
scope.SetExtra(field.Key, fmt.Sprintf("%+v", field.Interface))
}
}
}
scope.SetFingerprint([]string{msg})
if level == sentry.LevelError {
stackTrace := make([]uintptr, 20)
runtime.Callers(6, stackTrace)
err := &CustomError{
msg: msg,
stackTrace: stackTrace,
}
sentry.CaptureException(err)
} else {
sentry.CaptureMessage(msg)
}
})
}
}
效果展示:
错误消息会展示错误类型,其它的debug、info等会直接展示消息名称
错误消息详情:
- 详情中包含错误位置和调用方法,我就不单独写调用示例了。
- 消息详情中可已看到zap.Field中携带的消息内容