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中携带的消息内容
相关推荐
apocelipes7 小时前
下划线字段在golang结构体中的应用
golang
Python私教18 小时前
从“Hello World”到“高并发中间件”:Go 语言 2025 系统学习路线图
学习·中间件·golang
光爷不秃2 天前
Go语言中安全停止Goroutine的三种方法及设计哲学
开发语言·安全·golang
博哥爱吃肉2 天前
第2篇_Go语言基础语法_变量常量与数据类型
开发语言·算法·golang
chillxiaohan2 天前
GO学习记录五——数据库表的增删改查
数据库·学习·golang
-睡到自然醒~3 天前
[go] 命令模式
java·开发语言·javascript·后端·golang·命令模式
q567315233 天前
使用reqwest+select实现简单网页爬虫
开发语言·爬虫·golang·kotlin
Flobby5294 天前
Go 语言中的结构体、切片与映射:构建高效数据模型的基石
开发语言·后端·golang