Skip to content

Show Whole Command on Tracing #3290

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 0 additions & 18 deletions extra/rediscmd/rediscmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ func CmdString(cmd redis.Cmder) string {
}

func CmdsString(cmds []redis.Cmder) (string, string) {
const numCmdLimit = 100
const numNameLimit = 10

seen := make(map[string]struct{}, numNameLimit)
Expand All @@ -26,10 +25,6 @@ func CmdsString(cmds []redis.Cmder) (string, string) {
b := make([]byte, 0, 32*len(cmds))

for i, cmd := range cmds {
if i > numCmdLimit {
break
}

if i > 0 {
b = append(b, '\n')
}
Expand All @@ -51,12 +46,7 @@ func CmdsString(cmds []redis.Cmder) (string, string) {
}

func AppendCmd(b []byte, cmd redis.Cmder) []byte {
const numArgLimit = 32

for i, arg := range cmd.Args() {
if i > numArgLimit {
break
}
if i > 0 {
b = append(b, ' ')
}
Expand All @@ -72,20 +62,12 @@ func AppendCmd(b []byte, cmd redis.Cmder) []byte {
}

func appendArg(b []byte, v interface{}) []byte {
const argLenLimit = 64

switch v := v.(type) {
case nil:
return append(b, "<nil>"...)
case string:
if len(v) > argLenLimit {
v = v[:argLenLimit]
}
return appendUTF8String(b, Bytes(v))
case []byte:
if len(v) > argLenLimit {
v = v[:argLenLimit]
}
return appendUTF8String(b, v)
case int:
return strconv.AppendInt(b, int64(v), 10)
Expand Down
164 changes: 164 additions & 0 deletions extra/redisotel/tracing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"net"
"strings"
"testing"

"go.opentelemetry.io/otel/attribute"
Expand Down Expand Up @@ -222,6 +223,169 @@ func TestTracingHook_ProcessPipelineHook(t *testing.T) {
}
}

func TestTracingHook_ProcessHook_LongCommand(t *testing.T) {
imsb := tracetest.NewInMemoryExporter()
provider := sdktrace.NewTracerProvider(sdktrace.WithSyncer(imsb))
hook := newTracingHook(
"redis://localhost:6379",
WithTracerProvider(provider),
)
longValue := strings.Repeat("a", 102400)

tests := []struct {
name string
cmd redis.Cmder
expected string
}{
{
name: "short command",
cmd: redis.NewCmd(context.Background(), "SET", "key", "value"),
expected: "SET key value",
},
{
name: "set command with long key",
cmd: redis.NewCmd(context.Background(), "SET", longValue, "value"),
expected: "SET " + longValue + " value",
},
{
name: "set command with long value",
cmd: redis.NewCmd(context.Background(), "SET", "key", longValue),
expected: "SET key " + longValue,
},
{
name: "set command with long key and value",
cmd: redis.NewCmd(context.Background(), "SET", longValue, longValue),
expected: "SET " + longValue + " " + longValue,
},
{
name: "short command with many arguments",
cmd: redis.NewCmd(context.Background(), "MSET", "key1", "value1", "key2", "value2", "key3", "value3", "key4", "value4", "key5", "value5"),
expected: "MSET key1 value1 key2 value2 key3 value3 key4 value4 key5 value5",
},
{
name: "long command",
cmd: redis.NewCmd(context.Background(), longValue, "key", "value"),
expected: longValue + " key value",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
defer imsb.Reset()

processHook := hook.ProcessHook(func(ctx context.Context, cmd redis.Cmder) error {
return nil
})

if err := processHook(context.Background(), tt.cmd); err != nil {
t.Fatal(err)
}

assertEqual(t, 1, len(imsb.GetSpans()))

spanData := imsb.GetSpans()[0]

var dbStatement string
for _, attr := range spanData.Attributes {
if attr.Key == semconv.DBStatementKey {
dbStatement = attr.Value.AsString()
break
}
}

if dbStatement != tt.expected {
t.Errorf("Expected DB statement: %q\nGot: %q", tt.expected, dbStatement)
}
})
}
}

func TestTracingHook_ProcessPipelineHook_LongCommands(t *testing.T) {
imsb := tracetest.NewInMemoryExporter()
provider := sdktrace.NewTracerProvider(sdktrace.WithSyncer(imsb))
hook := newTracingHook(
"redis://localhost:6379",
WithTracerProvider(provider),
)

tests := []struct {
name string
cmds []redis.Cmder
expected string
}{
{
name: "multiple short commands",
cmds: []redis.Cmder{
redis.NewCmd(context.Background(), "SET", "key1", "value1"),
redis.NewCmd(context.Background(), "SET", "key2", "value2"),
},
expected: "SET key1 value1\nSET key2 value2",
},
{
name: "multiple short commands with long key",
cmds: []redis.Cmder{
redis.NewCmd(context.Background(), "SET", strings.Repeat("a", 102400), "value1"),
redis.NewCmd(context.Background(), "SET", strings.Repeat("b", 102400), "value2"),
},
expected: "SET " + strings.Repeat("a", 102400) + " value1\nSET " + strings.Repeat("b", 102400) + " value2",
},
{
name: "multiple short commands with long value",
cmds: []redis.Cmder{
redis.NewCmd(context.Background(), "SET", "key1", strings.Repeat("a", 102400)),
redis.NewCmd(context.Background(), "SET", "key2", strings.Repeat("b", 102400)),
},
expected: "SET key1 " + strings.Repeat("a", 102400) + "\nSET key2 " + strings.Repeat("b", 102400),
},
{
name: "multiple short commands with long key and value",
cmds: []redis.Cmder{
redis.NewCmd(context.Background(), "SET", strings.Repeat("a", 102400), strings.Repeat("b", 102400)),
redis.NewCmd(context.Background(), "SET", strings.Repeat("c", 102400), strings.Repeat("d", 102400)),
},
expected: "SET " + strings.Repeat("a", 102400) + " " + strings.Repeat("b", 102400) + "\nSET " + strings.Repeat("c", 102400) + " " + strings.Repeat("d", 102400),
},
{
name: "multiple long commands",
cmds: []redis.Cmder{
redis.NewCmd(context.Background(), strings.Repeat("a", 102400), "key1", "value1"),
redis.NewCmd(context.Background(), strings.Repeat("a", 102400), "key2", "value2"),
},
expected: strings.Repeat("a", 102400) + " key1 value1\n" + strings.Repeat("a", 102400) + " key2 value2",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
defer imsb.Reset()

processHook := hook.ProcessPipelineHook(func(ctx context.Context, cmds []redis.Cmder) error {
return nil
})

if err := processHook(context.Background(), tt.cmds); err != nil {
t.Fatal(err)
}

assertEqual(t, 1, len(imsb.GetSpans()))

spanData := imsb.GetSpans()[0]

var dbStatement string
for _, attr := range spanData.Attributes {
if attr.Key == semconv.DBStatementKey {
dbStatement = attr.Value.AsString()
break
}
}

if dbStatement != tt.expected {
t.Errorf("Expected DB statement:\n%q\nGot:\n%q", tt.expected, dbStatement)
}
})
}
}

func assertEqual(t *testing.T, expected, actual interface{}) {
t.Helper()
if expected != actual {
Expand Down
Loading