Skip to content

Extract db.namespace from DSN in AttributesFromDSN#608

Open
cyrille-leclerc wants to merge 28 commits intoXSAM:mainfrom
cyrille-leclerc:extract-db-namespace-from-dsn-2
Open

Extract db.namespace from DSN in AttributesFromDSN#608
cyrille-leclerc wants to merge 28 commits intoXSAM:mainfrom
cyrille-leclerc:extract-db-namespace-from-dsn-2

Conversation

@cyrille-leclerc
Copy link
Copy Markdown
Contributor

@cyrille-leclerc cyrille-leclerc commented Mar 26, 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, db.namespace is parsed in the AttributesFromDSN function, no code change for users to benefit of it. The downside is a change of the existing behaviour. Code style remains:

     attrs := append(otelsql.AttributesFromDSN(mysqlDSN), semconv.DBSystemNameMySQL)
    
     db, err := otelsql.Open("mysql", mysqlDSN, otelsql.WithAttributes(attrs...,))
  • In PR Add DBNamespaceFromDSN helper and fix AttributesFromDSN bugs #623, 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...,))

PR Summary

  • AttributesFromDSN now extracts the database name for the schemes mysql, postgresql, postgres, clickhouse, sqlserver, and mssql, and sets it as the db.namespace attribute (semconv.DBNamespaceKey)
  • 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.

Fixes:

@cyrille-leclerc cyrille-leclerc requested a review from XSAM as a code owner March 26, 2026 08:02
@cyrille-leclerc cyrille-leclerc force-pushed the extract-db-namespace-from-dsn-2 branch from 093ef23 to c77428e Compare March 26, 2026 09:04
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 26, 2026

Codecov Report

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

Additional details and impacted files
@@           Coverage Diff           @@
##            main    #608     +/-   ##
=======================================
+ Coverage   86.4%   86.8%   +0.4%     
=======================================
  Files         16      16             
  Lines        752     778     +26     
=======================================
+ Hits         650     676     +26     
  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.

@cyrille-leclerc cyrille-leclerc force-pushed the extract-db-namespace-from-dsn-2 branch from c77428e to e4d5e0e Compare March 26, 2026 09:45
@cyrille-leclerc cyrille-leclerc changed the title Extract db.namespace from DSN in AttributesFromDSN Extract db.namespace and db.system.name from DSN in AttributesFromDSN Mar 26, 2026
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.

@cyrille-leclerc, thanks for raising the PR! I like the idea of adding db.namespace, but several comments need to be addressed.

Comment thread helpers.go Outdated
Comment thread helpers.go
AttributesFromDSN no longer captures the db.system.name attribute,
as callers are better positioned to set it based on the driver in use.
The dbSystemFromScheme helper and its scheme map are removed accordingly.
@cyrille-leclerc cyrille-leclerc changed the title Extract db.namespace and db.system.name from DSN in AttributesFromDSN Extract db.namespace from DSN in AttributesFromDSN Mar 31, 2026
@cyrille-leclerc
Copy link
Copy Markdown
Contributor Author

@XSAM I removed the extraction of the db.system.name attribute and restored the mistakenly removed code comments.

@cyrille-leclerc cyrille-leclerc requested a review from XSAM March 31, 2026 17:38
Comment thread CHANGELOG.md Outdated
Comment thread CHANGELOG.md Outdated
Comment thread helpers.go Outdated
Comment thread helpers.go Outdated
Comment thread helpers.go Outdated
Comment thread CHANGELOG.md Outdated
Comment thread Makefile Outdated
@cyrille-leclerc
Copy link
Copy Markdown
Contributor Author

@XSAM I have integrated all your feedback, please review

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.

I just realized SQL Server has a different URL schema than other databases. It uses sqlserver://username:password@host/instance?...&database=master.... So the db.namespace from AttributesFromDSN could be an instance name, instead of a db name.

Given how unreliable it could become after adding this new logic to AttributesFromDSN, it might not be worth a breaking change.

Could you move the extraction of db.namespace to a new method DBNamespaceFromDSN returning string, with "" meaning “unknown"? Thank you!

parseDSN now extracts the query string before parsing the path, and
handles sqlserver DSNs specifically: the path segment is treated as the
instance name (not the database name), and db.namespace is read from the
"database" query param instead. Also fixes a bug where a bare
"host:port?param=val" DSN (no path) would leave the query string
attached to the host, causing net.SplitHostPort to drop the port.
Replace the manual &-split loop with url.ParseQuery, which always
returns a non-nil map even on error, making the err check unnecessary.
@cyrille-leclerc
Copy link
Copy Markdown
Contributor Author

cyrille-leclerc commented Apr 7, 2026

@XSAM the extraction of db.namespace, server.address, and server.port is tightly coupled, as shown in this PR.

Would you prefer introducing a dedicated parseDbNamespaceFromDSN function (even if it means parsing the DSN twice), or evolving the existing parsing logic with something like a parseDSNV2 that also extracts db.namespace?

Note that I think the logic to extract the database name is robust. I did extensive research on DSN patterns for Golang database/sql and sqlserver is the only one I found that doesn't use the path of the url to specify the database.
I researched looking at database/sql drivers and at existing OSS instrumentation code.

@XSAM
Copy link
Copy Markdown
Owner

XSAM commented Apr 8, 2026

Would you prefer introducing a dedicated parseDbNamespaceFromDSN function (even if it means parsing the DSN twice), or evolving the existing parsing logic with something like a parseDSNV2 that also extracts db.namespace?

I think the logic for DBNamespaceFromDSN can be separated from DBNamespaceFromDSN, as the logic in DBNamespaceFromDSN is quite simple:

  • Find ://, and remove the content on the left if any
  • Find /, and remove the content on the left if any
  • Find ?, and remove the content on the right if any

For that, we don't need to touch AttributesFromDSN at all.

Note that I think the logic to extract the database name is robust. I did extensive research on DSN patterns for Golang database/sql and sqlserver is the only one I found that doesn't use the path of the url to specify the database.
I researched looking at database/sql drivers and at existing OSS instrumentation code.

Oracledb has a similar concept like sqlserver. For instance, an OracleDB string: host:1521/orclpdb1. The orclpdb1 means service name, not database name.

@cyrille-leclerc
Copy link
Copy Markdown
Contributor Author

Thanks @XSAM , I'll follow your guidance.

@cyrille-leclerc
Copy link
Copy Markdown
Contributor Author

cyrille-leclerc commented Apr 12, 2026

I am exploring 2 solutions: this PR and:

…lexity

- Extract parseHostPort() helper so parseDSN cyclomatic complexity drops
  from 13 to 8 (limit is 10)
- Replace the catch-all else branch with an explicit switch: db.namespace
  is extracted from the URL path only for "postgresql", "postgres",
  "mysql", and "clickhouse" schemes; "sqlserver"/"mssql" continue to use
  the ?database= query param; all other schemes and scheme-less DSNs
  produce no db.namespace
- Update test expectations accordingly
Comment thread helpers.go
}

// [user[:password]@][protocol([addr])]/dbname[?param1=value1&paramN=valueN]
// [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 utils_test.go

func getDummyAttributesGetter() AttributesGetter {
return func(_ context.Context, method Method, query string, args []driver.NamedValue) []attribute.KeyValue {
//nolint:prealloc
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.

Running locally make command removes //nolint:prealloc and breaks CI so I preferred to fix the root cause.

@cyrille-leclerc
Copy link
Copy Markdown
Contributor Author

@XSAM I have now 2 PRs showing 2 slightly different user experiences. Would you mind reviewing them?

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, 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...,))
  • In PR Add DBNamespaceFromDSN helper and fix AttributesFromDSN bugs #623, 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...,))

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