package tracing import ( "context" "fmt" "reflect" "runtime" "strings" "time" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" "go.uber.org/zap" ) // TracableService 可追踪的服务接口 type TracableService interface { Name() string } // ServiceDecorator 服务装饰器 type ServiceDecorator struct { tracer *Tracer logger *zap.Logger config DecoratorConfig } // DecoratorConfig 装饰器配置 type DecoratorConfig struct { EnableMethodTracing bool ExcludePatterns []string IncludeArguments bool IncludeResults bool SlowMethodThreshold time.Duration } // DefaultDecoratorConfig 默认装饰器配置 func DefaultDecoratorConfig() DecoratorConfig { return DecoratorConfig{ EnableMethodTracing: true, ExcludePatterns: []string{"Health", "Ping", "Name"}, IncludeArguments: true, IncludeResults: false, SlowMethodThreshold: 100 * time.Millisecond, } } // NewServiceDecorator 创建服务装饰器 func NewServiceDecorator(tracer *Tracer, logger *zap.Logger) *ServiceDecorator { return &ServiceDecorator{ tracer: tracer, logger: logger, config: DefaultDecoratorConfig(), } } // WrapService 自动包装服务,为所有方法添加链路追踪 func (d *ServiceDecorator) WrapService(service interface{}) interface{} { serviceValue := reflect.ValueOf(service) serviceType := reflect.TypeOf(service) if serviceType.Kind() == reflect.Ptr { serviceType = serviceType.Elem() serviceValue = serviceValue.Elem() } // 创建代理结构 proxyType := d.createProxyType(serviceType) proxyValue := reflect.New(proxyType).Elem() // 设置原始服务字段 proxyValue.FieldByName("target").Set(reflect.ValueOf(service)) proxyValue.FieldByName("decorator").Set(reflect.ValueOf(d)) return proxyValue.Addr().Interface() } // createProxyType 创建代理类型 func (d *ServiceDecorator) createProxyType(serviceType reflect.Type) reflect.Type { // 获取服务名称 serviceName := d.getServiceName(serviceType) // 创建代理结构字段 fields := []reflect.StructField{ { Name: "target", Type: reflect.PtrTo(serviceType), }, { Name: "decorator", Type: reflect.TypeOf(d), }, } // 为每个方法创建包装器方法 for i := 0; i < serviceType.NumMethod(); i++ { method := serviceType.Method(i) if d.shouldTraceMethod(method.Name) { // 创建方法字段(用于存储方法实现) fields = append(fields, reflect.StructField{ Name: method.Name, Type: method.Type, }) } } // 创建新的结构类型 proxyType := reflect.StructOf(fields) // 实现接口方法 d.implementMethods(proxyType, serviceType, serviceName) return proxyType } // shouldTraceMethod 判断是否应该追踪方法 func (d *ServiceDecorator) shouldTraceMethod(methodName string) bool { if !d.config.EnableMethodTracing { return false } for _, pattern := range d.config.ExcludePatterns { if strings.Contains(methodName, pattern) { return false } } return true } // getServiceName 获取服务名称 func (d *ServiceDecorator) getServiceName(serviceType reflect.Type) string { serviceName := serviceType.Name() // 移除Service后缀 if strings.HasSuffix(serviceName, "Service") { serviceName = strings.TrimSuffix(serviceName, "Service") } return strings.ToLower(serviceName) } // TraceMethodCall 追踪方法调用 func (d *ServiceDecorator) TraceMethodCall( ctx context.Context, serviceName, methodName string, fn func(context.Context) ([]reflect.Value, error), args []reflect.Value, ) ([]reflect.Value, error) { // 创建span名称 spanName := fmt.Sprintf("%s.%s", serviceName, methodName) // 开始追踪 ctx, span := d.tracer.StartSpan(ctx, spanName) defer span.End() // 添加基础属性 d.tracer.AddSpanAttributes(span, attribute.String("service.name", serviceName), attribute.String("service.method", methodName), attribute.String("service.type", "business"), ) // 添加参数信息(如果启用) if d.config.IncludeArguments { d.addArgumentAttributes(span, args) } // 记录开始时间 startTime := time.Now() // 执行原始方法 results, err := fn(ctx) // 计算执行时间 duration := time.Since(startTime) d.tracer.AddSpanAttributes(span, attribute.Int64("service.duration_ms", duration.Milliseconds()), ) // 标记慢方法 if duration > d.config.SlowMethodThreshold { d.tracer.AddSpanAttributes(span, attribute.Bool("service.slow_method", true), ) d.logger.Warn("慢方法检测", zap.String("service", serviceName), zap.String("method", methodName), zap.Duration("duration", duration), zap.String("trace_id", d.tracer.GetTraceID(ctx)), ) } // 处理错误 if err != nil { d.tracer.SetSpanError(span, err) d.logger.Error("服务方法执行失败", zap.String("service", serviceName), zap.String("method", methodName), zap.Error(err), zap.String("trace_id", d.tracer.GetTraceID(ctx)), ) } else { d.tracer.SetSpanSuccess(span) // 添加结果信息(如果启用) if d.config.IncludeResults { d.addResultAttributes(span, results) } } return results, err } // addArgumentAttributes 添加参数属性 func (d *ServiceDecorator) addArgumentAttributes(span trace.Span, args []reflect.Value) { for i, arg := range args { if i == 0 && arg.Type().String() == "context.Context" { continue // 跳过context参数 } argName := fmt.Sprintf("service.arg_%d", i) argValue := d.extractValue(arg) if argValue != "" && len(argValue) < 1000 { // 限制长度避免性能问题 d.tracer.AddSpanAttributes(span, attribute.String(argName, argValue), ) } } } // addResultAttributes 添加结果属性 func (d *ServiceDecorator) addResultAttributes(span trace.Span, results []reflect.Value) { for i, result := range results { if result.Type().String() == "error" { continue // 错误在其他地方处理 } resultName := fmt.Sprintf("service.result_%d", i) resultValue := d.extractValue(result) if resultValue != "" && len(resultValue) < 1000 { d.tracer.AddSpanAttributes(span, attribute.String(resultName, resultValue), ) } } } // extractValue 提取值的字符串表示 func (d *ServiceDecorator) extractValue(value reflect.Value) string { if !value.IsValid() { return "" } switch value.Kind() { case reflect.String: return value.String() case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return fmt.Sprintf("%d", value.Int()) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: return fmt.Sprintf("%d", value.Uint()) case reflect.Float32, reflect.Float64: return fmt.Sprintf("%.2f", value.Float()) case reflect.Bool: return fmt.Sprintf("%t", value.Bool()) case reflect.Ptr: if value.IsNil() { return "nil" } return d.extractValue(value.Elem()) case reflect.Struct: // 对于结构体,只返回类型名 return value.Type().Name() case reflect.Slice, reflect.Array: return fmt.Sprintf("[%d items]", value.Len()) default: return value.Type().Name() } } // implementMethods 实现接口方法(占位符,实际需要运行时代理) func (d *ServiceDecorator) implementMethods(proxyType, serviceType reflect.Type, serviceName string) { // 这里是运行时方法实现的占位符 // 实际实现需要使用reflect.MakeFunc或其他运行时代理技术 } // GetFunctionName 获取函数名称 func GetFunctionName(fn interface{}) string { name := runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name() parts := strings.Split(name, ".") return parts[len(parts)-1] }