Skip to content

Add DBNamespaceFromDSN helper and fix AttributesFromDSN bugs#623

Open
cyrille-leclerc wants to merge 7 commits into
XSAM:mainfrom
cyrille-leclerc:extract-DBNamespaceFromDSN
Open

Add DBNamespaceFromDSN helper and fix AttributesFromDSN bugs#623
cyrille-leclerc wants to merge 7 commits into
XSAM:mainfrom
cyrille-leclerc:extract-DBNamespaceFromDSN

Conversation

@cyrille-leclerc
Copy link
Copy Markdown
Contributor

@cyrille-leclerc cyrille-leclerc commented Apr 12, 2026

Summary

I explore 2 solutions to add db.namespace.

In all cases, we extract db.namespace only for well-known DSN patterns to avoid mapping it to incorrect values. Well-known DSN patterns: “postgresql”, “postgres”, “mysql”, “clickhouse”, “sqlserver”, or “mssql”.

Solutions:

  • In this PR, we introduce an additional helper function DBNamespaceFromDSN, and users have to change their code to benefit of this improvement. New code style looks like:

     attrs := append(otelsql.AttributesFromDSN(mysqlDSN), semconv.DBSystemNameMySQL)
    
     if dbNamespace, err := otelsql.DBNamespaceFromDSN(mysqlDSN); err == nil {
     	attrs = append(attrs, dbNamespace)
     }
    
     db, err := otelsql.Open("mysql", mysqlDSN, otelsql.WithAttributes(attrs...,))
  • In PR Extract db.namespace from DSN in AttributesFromDSN #608, db.namespace is parsed in the AttributesFromDSN function, no code change for users to benefit of it. Code style remains:

     attrs := append(otelsql.AttributesFromDSN(mysqlDSN), semconv.DBSystemNameMySQL)
    
     db, err := otelsql.Open("mysql", mysqlDSN, otelsql.WithAttributes(attrs...,))

PR Summary

Add DBNamespaceFromDSN helper and fix AttributesFromDSN bugs

  • Introduce DBNamespaceFromDSN to extract the db.namespace OTel attribute
    from a DSN string, with support for Microsoft sqlserver (database query param) and
    an explicit error for oracle (DB_UNIQUE_NAME is not DSN-derivable).
  • Fix a panic in AttributesFromDSN when the closing protocol
    parenthesis is missing and the DSN has no path nor query string,
  • fix server.port parsing when the DSN has a query string but no path.

Introduce DBNamespaceFromDSN to extract the db.namespace OTel attribute
from a DSN string, with support for sqlserver (database query param) and
an explicit error for oracle (DB_UNIQUE_NAME is not DSN-derivable).

Also fix a panic in AttributesFromDSN when the closing protocol
parenthesis is missing and the DSN has no path nor query string, and fix
server.port parsing when the DSN has a query string but no path.
@cyrille-leclerc cyrille-leclerc requested a review from XSAM as a code owner April 12, 2026 21:33
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 12, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.0%. Comparing base (31f7989) to head (c85c616).

Additional details and impacted files
@@           Coverage Diff           @@
##            main    #623     +/-   ##
=======================================
+ Coverage   86.4%   87.0%   +0.5%     
=======================================
  Files         16      16             
  Lines        752     786     +34     
=======================================
+ Hits         650     684     +34     
  Misses        75      75             
  Partials      27      27             

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread helpers.go
// It makes the best effort to retrieve values for [semconv.ServerAddressKey] and [semconv.ServerPortKey].
func AttributesFromDSN(dsn string) []attribute.KeyValue {
// [scheme://][user[:password]@][protocol([addr])]/dbname[?param1=value1&paramN=valueN]
// [scheme://][user[:password]@][protocol([addr])][/path][?param1=value1&paramN=valueN]
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We see with sqlserver and oracle that the /path is not always the dbname

Comment thread helpers.go
// [protocol([addr])]/dbname[?param1=value1&paramN=valueN]
// [protocol([addr])][/path][?param1=value1&paramN=valueN]
// Find the '?' that separates the query string.
if questionMarkIndex := strings.Index(dsn, "?"); questionMarkIndex != -1 {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix bug in server.port parsing when DSN has no path but a query string.

Comment thread helpers.go
// Find the '(' that starts the address part.
openParen := strings.Index(dsn, "(")
if openParen != -1 {
rest := dsn[openParen+1:]
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix panic in server.address parsing when a protocol is specified but a parenthesis is missing and DSN has no /path nor query string

@cyrille-leclerc cyrille-leclerc changed the title run aAdd DBNamespaceFromDSN helper and fix AttributesFromDSN bugs Add DBNamespaceFromDSN helper and fix AttributesFromDSN bugs Apr 12, 2026
Add //nolint:gosec to TestAttributesFromDSN and use require.NoError
instead of assert.NoError in TestDBNamespaceFromDSN.
- DBNamespaceFromDSN now returns errDBNamespaceNotFound for unknown and
  scheme-less DSNs; supported schemes are postgresql, postgres, mysql,
  clickhouse (path-based) and sqlserver, mssql (query param)
- Extract parseHostPort helper from AttributesFromDSN to reduce its
  cyclomatic complexity from 12 to 7
- Update test expectations and CHANGELOG accordingly
Copy link
Copy Markdown
Owner

@XSAM XSAM left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we separate this PR into two? One for the fix of AttributesFromDSN, one for DBNamespaceFromDSN?

Comment thread helpers_test.go
},
},
{
// Missing closing protocol parenthesis and no path/queryString shouldn't cause a panic
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main branch won't cause a panic in this case after #625

Comment thread helpers_test.go
// Missing closing protocol parenthesis and no path/queryString shouldn't cause a panic
dsn: "mysql://root:otel_password@tcp(example.com",
expected: []attribute.KeyValue{
semconv.ServerAddress("example.com"),
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mysql://root:otel_password@tcp(example.com does not look like a valid DSN. Maybe we should drop the value.

Comment thread helpers.go
Comment on lines +155 to +164
switch scheme {
case "sqlserver", "mssql":
if params, err := url.ParseQuery(queryString); err == nil {
if db := params.Get("database"); db != "" {
return semconv.DBNamespace(db), nil
}
}
case "postgresql", "postgres", "mysql", "clickhouse":
if path != "" {
return semconv.DBNamespace(path), nil
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure whether we should add this. Maybe this repo needs a contrib package to contain vendor-specific logic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants