golang zap日志模块封装sentry

我们自己写个log日志包,把zap和sentry封装到一起。

下面直接贴上主要部分代码(两个模块初始化部分的代码请自行查阅官方文档):

  • logger.go
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
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中携带的消息内容
相关推荐
福大大架构师每日一题5 小时前
ollama v0.30.7 正式发布:Hermes 桌面端落地,接口、文档、底层依赖全方位优化
golang·log4j
不爱编程的小陈7 小时前
深入解析 Go 网络 I/O 的底层引擎:从 epoll 到 netpoll
服务器·网络·golang
何以解忧,唯有..10 小时前
Go 语言数据类型详解:从基础到复合类型
开发语言·golang·mfc
踏着七彩祥云的小丑11 小时前
Go学习第7天:Map集合 + 递归函数 + 类型转换
开发语言·学习·golang·go
何以解忧,唯有..11 小时前
Go语言变量的声明方式详解
开发语言·后端·golang
寂夜了无痕11 小时前
Go 多版本管理工具G 保姆级安装配置教程
golang·go多版本管理
张忠琳12 小时前
【Go 1.26.4】Golang Slice 深度解析
开发语言·后端·golang
张忠琳1 天前
【Go 1.26.4】Golang Channel 深度解析
开发语言·后端·golang
张忠琳1 天前
【Go 1.26.4】Golang Map 深度解析
开发语言·后端·golang
何以解忧,唯有..1 天前
Go 语言安装与环境配置完整指南
开发语言·后端·golang