190 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			190 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package tracing
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"fmt"
 | |
| 	"time"
 | |
| 
 | |
| 	"go.opentelemetry.io/otel/attribute"
 | |
| 	"go.uber.org/zap"
 | |
| 
 | |
| 	"tyapi-server/internal/application/user/dto/commands"
 | |
| 	"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)
 | |
| }
 | |
| 
 | |
| func (t *TracedUserService) Register(ctx context.Context, req *commands.RegisterUserCommand) (*entities.User, error) {
 | |
| 	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
 | |
| }
 | |
| 
 | |
| func (t *TracedUserService) LoginWithPassword(ctx context.Context, req *commands.LoginWithPasswordCommand) (*entities.User, error) {
 | |
| 	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
 | |
| }
 | |
| 
 | |
| func (t *TracedUserService) LoginWithSMS(ctx context.Context, req *commands.LoginWithSMSCommand) (*entities.User, error) {
 | |
| 	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
 | |
| }
 | |
| 
 | |
| func (t *TracedUserService) ChangePassword(ctx context.Context, userID string, req *commands.ChangePasswordCommand) error {
 | |
| 	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
 | |
| }
 |