| 
									
										
										
										
											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 | 
					
						
							|  |  |  | } |