Files
tyapi-server/internal/shared/tracing/service_wrapper.go

190 lines
4.7 KiB
Go
Raw Normal View History

2025-07-02 16:17:59 +08:00
package tracing
import (
"context"
"fmt"
"time"
"go.opentelemetry.io/otel/attribute"
"go.uber.org/zap"
2025-07-13 16:36:20 +08:00
"tyapi-server/internal/application/user/dto/commands"
2025-07-02 16:17:59 +08:00
"tyapi-server/internal/domains/user/entities"
"tyapi-server/internal/shared/interfaces"
)
// ServiceWrapper 服务包装器,提供自动追踪能力
type ServiceWrapper struct {
tracer *Tracer
logger *zap.Logger
}
// NewServiceWrapper 创建服务包装器
func NewServiceWrapper(tracer *Tracer, logger *zap.Logger) *ServiceWrapper {
return &ServiceWrapper{
tracer: tracer,
logger: logger,
}
}
// TraceServiceCall 追踪服务调用的通用方法
func (w *ServiceWrapper) TraceServiceCall(
ctx context.Context,
serviceName, methodName string,
fn func(context.Context) error,
) error {
// 创建span名称
spanName := fmt.Sprintf("%s.%s", serviceName, methodName)
// 开始追踪
ctx, span := w.tracer.StartSpan(ctx, spanName)
defer span.End()
// 添加基础属性
w.tracer.AddSpanAttributes(span,
attribute.String("service.name", serviceName),
attribute.String("service.method", methodName),
attribute.String("service.type", "business"),
)
// 记录开始时间
startTime := time.Now()
// 执行原始方法
err := fn(ctx)
// 计算执行时间
duration := time.Since(startTime)
w.tracer.AddSpanAttributes(span,
attribute.Int64("service.duration_ms", duration.Milliseconds()),
)
// 标记慢方法
if duration > 100*time.Millisecond {
w.tracer.AddSpanAttributes(span,
attribute.Bool("service.slow_method", true),
)
w.logger.Warn("慢方法检测",
zap.String("service", serviceName),
zap.String("method", methodName),
zap.Duration("duration", duration),
zap.String("trace_id", w.tracer.GetTraceID(ctx)),
)
}
// 处理错误
if err != nil {
w.tracer.SetSpanError(span, err)
w.logger.Error("服务方法执行失败",
zap.String("service", serviceName),
zap.String("method", methodName),
zap.Error(err),
zap.String("trace_id", w.tracer.GetTraceID(ctx)),
)
} else {
w.tracer.SetSpanSuccess(span)
}
return err
}
// TracedUserService 自动追踪的用户服务包装器
type TracedUserService struct {
service interfaces.UserService
wrapper *ServiceWrapper
}
// NewTracedUserService 创建带追踪的用户服务
func NewTracedUserService(service interfaces.UserService, wrapper *ServiceWrapper) interfaces.UserService {
return &TracedUserService{
service: service,
wrapper: wrapper,
}
}
func (t *TracedUserService) Name() string {
return "user-service"
}
func (t *TracedUserService) Initialize(ctx context.Context) error {
return t.wrapper.TraceServiceCall(ctx, "user", "initialize", t.service.Initialize)
}
func (t *TracedUserService) HealthCheck(ctx context.Context) error {
return t.service.HealthCheck(ctx) // 不追踪健康检查
}
func (t *TracedUserService) Shutdown(ctx context.Context) error {
return t.wrapper.TraceServiceCall(ctx, "user", "shutdown", t.service.Shutdown)
}
2025-07-13 16:36:20 +08:00
func (t *TracedUserService) Register(ctx context.Context, req *commands.RegisterUserCommand) (*entities.User, error) {
2025-07-02 16:17:59 +08:00
var result *entities.User
var err error
traceErr := t.wrapper.TraceServiceCall(ctx, "user", "register", func(ctx context.Context) error {
result, err = t.service.Register(ctx, req)
return err
})
if traceErr != nil {
return nil, traceErr
}
return result, err
}
2025-07-13 16:36:20 +08:00
func (t *TracedUserService) LoginWithPassword(ctx context.Context, req *commands.LoginWithPasswordCommand) (*entities.User, error) {
2025-07-02 16:17:59 +08:00
var result *entities.User
var err error
traceErr := t.wrapper.TraceServiceCall(ctx, "user", "login_password", func(ctx context.Context) error {
result, err = t.service.LoginWithPassword(ctx, req)
return err
})
if traceErr != nil {
return nil, traceErr
}
return result, err
}
2025-07-13 16:36:20 +08:00
func (t *TracedUserService) LoginWithSMS(ctx context.Context, req *commands.LoginWithSMSCommand) (*entities.User, error) {
2025-07-02 16:17:59 +08:00
var result *entities.User
var err error
traceErr := t.wrapper.TraceServiceCall(ctx, "user", "login_sms", func(ctx context.Context) error {
result, err = t.service.LoginWithSMS(ctx, req)
return err
})
if traceErr != nil {
return nil, traceErr
}
return result, err
}
2025-07-13 16:36:20 +08:00
func (t *TracedUserService) ChangePassword(ctx context.Context, userID string, req *commands.ChangePasswordCommand) error {
2025-07-02 16:17:59 +08:00
return t.wrapper.TraceServiceCall(ctx, "user", "change_password", func(ctx context.Context) error {
return t.service.ChangePassword(ctx, userID, req)
})
}
func (t *TracedUserService) GetByID(ctx context.Context, id string) (*entities.User, error) {
var result *entities.User
var err error
traceErr := t.wrapper.TraceServiceCall(ctx, "user", "get_by_id", func(ctx context.Context) error {
result, err = t.service.GetByID(ctx, id)
return err
})
if traceErr != nil {
return nil, traceErr
}
return result, err
}