diff --git a/tracing/tracing.go b/tracing/tracing.go index 57b555e..e0eff62 100644 --- a/tracing/tracing.go +++ b/tracing/tracing.go @@ -5,6 +5,8 @@ import ( "database/sql/driver" "fmt" "io" + "regexp" + "strings" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" @@ -16,7 +18,14 @@ import ( "gorm.io/plugin/opentelemetry/metrics" ) -var dbRowsAffected = attribute.Key("db.rows_affected") +var ( + firstWordRegex = regexp.MustCompile(`^\w+`) + cCommentRegex = regexp.MustCompile(`(?is)/\*.*?\*/`) + lineCommentRegex = regexp.MustCompile(`(?im)(?:--|#).*?$`) + sqlPrefixRegex = regexp.MustCompile(`^[\s;]*`) + + dbRowsAffected = attribute.Key("db.rows_affected") +) type otelPlugin struct { provider trace.TracerProvider @@ -124,7 +133,9 @@ func (p *otelPlugin) after() gormHookFunc { query = tx.Dialector.Explain(tx.Statement.SQL.String(), vars...) } - attrs = append(attrs, semconv.DBStatementKey.String(p.formatQuery(query))) + formatQuery := p.formatQuery(query) + attrs = append(attrs, semconv.DBStatementKey.String(formatQuery)) + attrs = append(attrs, semconv.DBOperationKey.String(dbOperation(formatQuery))) if tx.Statement.Table != "" { attrs = append(attrs, semconv.DBSQLTableKey.String(tx.Statement.Table)) } @@ -172,3 +183,10 @@ func dbSystem(tx *gorm.DB) attribute.KeyValue { return attribute.KeyValue{} } } + +func dbOperation(query string) string { + s := cCommentRegex.ReplaceAllString(query, "") + s = lineCommentRegex.ReplaceAllString(s, "") + s = sqlPrefixRegex.ReplaceAllString(s, "") + return strings.ToLower(firstWordRegex.FindString(s)) +} diff --git a/tracing/tracing_test.go b/tracing/tracing_test.go index b825a50..296b962 100644 --- a/tracing/tracing_test.go +++ b/tracing/tracing_test.go @@ -44,6 +44,10 @@ func TestOtel(t *testing.T) { stmt, ok := m[semconv.DBStatementKey] require.True(t, ok) require.Equal(t, "SELECT 42", stmt.AsString()) + + operation, ok := m[semconv.DBOperationKey] + require.True(t, ok) + require.Equal(t, "select", operation.AsString()) }, }, { @@ -69,6 +73,10 @@ func TestOtel(t *testing.T) { stmt, ok := m[semconv.DBStatementKey] require.True(t, ok) require.Equal(t, "SELECT foo_bar", stmt.AsString()) + + operation, ok := m[semconv.DBOperationKey] + require.True(t, ok) + require.Equal(t, "select", operation.AsString()) }, }, { @@ -98,6 +106,10 @@ func TestOtel(t *testing.T) { stmt, ok := m[semconv.DBStatementKey] require.True(t, ok) require.Equal(t, "SELECT id FROM `foo` WHERE id = ?", stmt.AsString()) + + operation, ok := m[semconv.DBOperationKey] + require.True(t, ok) + require.Equal(t, "select", operation.AsString()) }, }, }