pkg/rules/goredisv8/setup.go (118 lines of code) (raw):

package goredisv8 import ( "context" "errors" "os" "strings" _ "unsafe" "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/api" redis "github.com/go-redis/redis/v8" "go.opentelemetry.io/otel/trace" ) var redisv8Instrumenter = BuildRedisv8Instrumenter() type redisV8InnerEnabler struct { enabled bool } func (g redisV8InnerEnabler) Enable() bool { return g.enabled } var rv8Enabler = redisV8InnerEnabler{os.Getenv("OTEL_INSTRUMENTATION_REDISV8_ENABLED") != "false"} var redisV8StartOptions = []trace.SpanStartOption{} //go:linkname afterNewRedisV8Client github.com/go-redis/redis/v8.afterNewRedisV8Client func afterNewRedisV8Client(call api.CallContext, client *redis.Client) { if !rv8Enabler.Enable() { return } client.AddHook(newOtRedisV8Hook(client.Options().Addr)) } //go:linkname afterNewFailOverRedisV8Client github.com/go-redis/redis/v8.afterNewFailOverRedisV8Client func afterNewFailOverRedisV8Client(call api.CallContext, client *redis.Client) { if !rv8Enabler.Enable() { return } client.AddHook(newOtRedisV8Hook(client.Options().Addr)) } //go:linkname afterNewConnRedisV8Client github.com/go-redis/redis/v8.afterNewConnRedisV8Client func afterNewConnRedisV8Client(call api.CallContext, conn *redis.Conn) { if !rv8Enabler.Enable() { return } conn.AddHook(newOtRedisV8Hook(conn.String())) } //go:linkname afterNewClusterV8Client github.com/go-redis/redis/v8.afterNewClusterV8Client func afterNewClusterV8Client(call api.CallContext, client *redis.ClusterClient) { if !rv8Enabler.Enable() { return } client.AddHook(newOtRedisV8Hook(strings.Join(client.Options().Addrs, ","))) } //go:linkname afterNewRingV8Client github.com/go-redis/redis/v8.afterNewRingV8Client func afterNewRingV8Client(call api.CallContext, client *redis.Ring) { if !rv8Enabler.Enable() { return } addrBuilder := strings.Builder{} for addr, _ := range client.Options().Addrs { addrBuilder.WriteString(addr) } client.AddHook(newOtRedisV8Hook(addrBuilder.String())) } type otRedisV8Hook struct { Addr string } func newOtRedisV8Hook(addr string) *otRedisV8Hook { return &otRedisV8Hook{ Addr: addr, } } func (o *otRedisV8Hook) BeforeProcess(ctx context.Context, cmd redis.Cmder) (context.Context, error) { request := redisv8Data{ cmd: cmd, Host: o.Addr, } newCtx := redisv8Instrumenter.Start(ctx, request, redisV8StartOptions...) ctx = context.WithValue(ctx, redisV8Context, newCtx) return ctx, nil } func (o *otRedisV8Hook) AfterProcess(ctx context.Context, cmd redis.Cmder) error { request := redisv8Data{ cmd: cmd, Host: o.Addr, } redisV8Ctx, ok := ctx.Value(redisV8Context).(context.Context) if !ok { redisV8Ctx = ctx } redisv8Instrumenter.End(redisV8Ctx, request, nil, cmd.Err()) return nil } func (o *otRedisV8Hook) BeforeProcessPipeline(ctx context.Context, cmds []redis.Cmder) (context.Context, error) { request := redisv8Data{ cmd: pipelineCmd, Host: o.Addr, } newCtx := redisv8Instrumenter.Start(ctx, request, redisV8StartOptions...) ctx = context.WithValue(ctx, redisV8Context, newCtx) return ctx, nil } func (o *otRedisV8Hook) AfterProcessPipeline(ctx context.Context, cmds []redis.Cmder) error { request := redisv8Data{ cmd: pipelineCmd, Host: o.Addr, } var tError error hasError := false errSb := strings.Builder{} for _, cmd := range cmds { if cmd.Err() != nil { errSb.WriteString(cmd.Err().Error()) hasError = true } } tError = errors.New(errSb.String()) redisV8Ctx, ok := ctx.Value(redisV8Context).(context.Context) if !ok { redisV8Ctx = ctx } if hasError { redisv8Instrumenter.End(redisV8Ctx, request, nil, tError) } else { redisv8Instrumenter.End(redisV8Ctx, request, nil, nil) } return nil }