Skip to content

Commit

Permalink
Use pre-Explain SQL for WithoutQueryVariables (#15)
Browse files Browse the repository at this point in the history
The current implementation of `WithoutQueryVariables` substitutes `?` for any query variables and
calls `tx.Dialector.Explain`, which can result in a lot of string allocations. This implementation
avoids the substitution and uses whatever the default representation of the query parameters is for
the SQL dialect.
  • Loading branch information
chradcliffe committed Sep 16, 2023
1 parent 2a6e1e2 commit 0e6d07e
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 9 deletions.
13 changes: 5 additions & 8 deletions tracing/tracing.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,17 +116,14 @@ func (p *otelPlugin) after() gormHookFunc {
}

vars := tx.Statement.Vars
if p.excludeQueryVars {
// Replace query variables with '?' to mask them
vars = make([]interface{}, len(tx.Statement.Vars))

for i := 0; i < len(vars); i++ {
vars[i] = "?"
}
var query string
if p.excludeQueryVars {
query = tx.Statement.SQL.String()
} else {
query = tx.Dialector.Explain(tx.Statement.SQL.String(), vars...)
}

query := tx.Dialector.Explain(tx.Statement.SQL.String(), vars...)

attrs = append(attrs, semconv.DBStatementKey.String(p.formatQuery(query)))
if tx.Statement.Table != "" {
attrs = append(attrs, semconv.DBSQLTableKey.String(tx.Statement.Table))
Expand Down
32 changes: 31 additions & 1 deletion tracing/tracing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
)

type Test struct {
opts []Option
do func(ctx context.Context, db *gorm.DB)
require func(t *testing.T, spans []sdktrace.ReadOnlySpan)
}
Expand Down Expand Up @@ -70,6 +71,35 @@ func TestOtel(t *testing.T) {
require.Equal(t, "SELECT foo_bar", stmt.AsString())
},
},
{
opts: []Option{WithoutQueryVariables()},
do: func(ctx context.Context, db *gorm.DB) {
err := db.Exec("CREATE TABLE foo (id int)").Error
require.NoError(t, err)
var num int
param := 42
err = db.WithContext(ctx).Table("foo").Select("id", param).Where("id = ?", param).Scan(&num).Error
require.NoError(t, err)
},
require: func(t *testing.T, spans []sdktrace.ReadOnlySpan) {
for _, s := range spans {
fmt.Printf("span=%#v\n", s)
}
require.Equal(t, 2, len(spans))
require.Equal(t, "gorm.Row", spans[1].Name())
require.Equal(t, trace.SpanKindClient, spans[1].SpanKind())

m := attrMap(spans[1].Attributes())

sys, ok := m[semconv.DBSystemKey]
require.True(t, ok)
require.Equal(t, "sqlite", sys.AsString())

stmt, ok := m[semconv.DBStatementKey]
require.True(t, ok)
require.Equal(t, "SELECT id FROM `foo` WHERE id = ?", stmt.AsString())
},
},
}

for i, test := range tests {
Expand All @@ -80,7 +110,7 @@ func TestOtel(t *testing.T) {
db, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{})
require.NoError(t, err)

err = db.Use(NewPlugin(WithTracerProvider(provider)))
err = db.Use(NewPlugin(append(test.opts, WithTracerProvider(provider))...))
require.NoError(t, err)

test.do(context.TODO(), db)
Expand Down

0 comments on commit 0e6d07e

Please sign in to comment.