Skip to content

Commit

Permalink
fix(otelsql): record error and status when SQL returns an error
Browse files Browse the repository at this point in the history
The Span ends early when SQL returns an error, which prevents Otelsql from recording the error.
This commit fixes this issue by deferring the Span.End() call.

Fixes: #115
  • Loading branch information
empire committed Dec 10, 2023
1 parent 4700947 commit 1716db5
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 1 deletion.
46 changes: 46 additions & 0 deletions otelsql/internal/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
_ "modernc.org/sqlite"

"github.com/uptrace/opentelemetry-go-extra/otelsql"
"go.opentelemetry.io/otel/codes"
)

var dbRowsAffected = attribute.Key("db.rows_affected")
Expand Down Expand Up @@ -159,6 +160,40 @@ func TestConn(t *testing.T) {
}
},
},
{
do: func(ctx context.Context, db *sql.DB) {
_, err := db.ExecContext(ctx, "SELECT 1 FROM ABC")
require.Error(t, err)
},
require: func(t *testing.T, spans []sdktrace.ReadOnlySpan) {
require.Equal(t, 2, len(spans))
require.Equal(t, "db.Connect", spans[0].Name())
require.Equal(t, "db.Exec", spans[1].Name())

span := spans[1]
require.Equal(t, "db.Exec", span.Name())

m := attrMap(span.Attributes())

stmt, ok := m[semconv.DBStatementKey]
require.True(t, ok)
require.Equal(t, "SELECT 1 FROM ABC", stmt.AsString())

status := span.Status()
require.Equal(t, codes.Error, status.Code)
require.Equal(t, "SQL logic error: no such table: ABC (1)", status.Description)

e := eventAttrsMap(span.Events())

key, ok := e[semconv.ExceptionTypeKey]
require.True(t, ok)
require.Equal(t, "*sqlite.Error", key.AsString())

message, ok := e[semconv.ExceptionMessageKey]
require.True(t, ok)
require.Equal(t, "SQL logic error: no such table: ABC (1)", message.AsString())
},
},
}

for i, test := range tests {
Expand Down Expand Up @@ -188,3 +223,14 @@ func attrMap(attrs []attribute.KeyValue) map[attribute.Key]attribute.Value {
}
return m
}

func eventAttrsMap(events []sdktrace.Event) map[attribute.Key]attribute.Value {
m := make(map[attribute.Key]attribute.Value, len(events))
for _, event := range events {
for _, kv := range event.Attributes {
m[kv.Key] = kv.Value
}
}

return m
}
2 changes: 1 addition & 1 deletion otelsql/otel.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ func (t *dbInstrum) withSpan(
trace.WithSpanKind(trace.SpanKindClient),
trace.WithAttributes(attrs...))
err := fn(ctx, span)
span.End()
defer span.End()

if query != "" {
t.queryHistogram.Record(ctx, time.Since(startTime).Milliseconds(), metric.WithAttributes(t.attrs...))
Expand Down

0 comments on commit 1716db5

Please sign in to comment.