diff --git a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/parser/JtdsUrlParser.java b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/parser/JtdsUrlParser.java index cebb3aa71bb9..45cc17221e58 100644 --- a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/parser/JtdsUrlParser.java +++ b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/parser/JtdsUrlParser.java @@ -66,9 +66,12 @@ public void parse(String jdbcUrl, ParseContext ctx) { instanceName = urlParams.get("instance"); } - // If no path, use databasename param as fallback for database - if (ctx.databaseName() == null && urlParams.containsKey("databasename")) { - ctx.databaseName(urlParams.get("databasename")); + // If no path, use databasename or database param as fallback for database + if (ctx.databaseName() == null) { + String databaseName = MssqlUrlParser.getDatabaseNameParam(urlParams); + if (databaseName != null) { + ctx.databaseName(databaseName); + } } } diff --git a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/parser/MssqlUrlParser.java b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/parser/MssqlUrlParser.java index 2c4718d7e00a..d2c8b29b2f89 100644 --- a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/parser/MssqlUrlParser.java +++ b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/parser/MssqlUrlParser.java @@ -6,6 +6,8 @@ package io.opentelemetry.instrumentation.jdbc.internal.parser; import io.opentelemetry.instrumentation.jdbc.internal.parser.UrlParsingUtils.HostPort; +import java.util.Map; +import javax.annotation.Nullable; /** * Parser for Microsoft SQL Server JDBC URLs. @@ -53,7 +55,11 @@ public void parse(String jdbcUrl, ParseContext ctx) { } // Layer 3: URL params (SQL Server-specific: servername) - ctx.applyCommonParams(jdbcUrl, ";", ";"); + // Parse semicolon-delimited parameters once and apply both standard and + // MSSQL-specific properties from the same map to avoid re-parsing the URL. + Map urlParams = UrlParsingUtils.extractSemicolonParams(jdbcUrl); + ctx.applyCommonParams(urlParams); + applyDatabaseAliasParam(ctx, urlParams); // Layer 4: Parse URL structure (host:port/path) String instanceName = parseUrlWithInstance(jdbcUrl, ctx); @@ -143,6 +149,33 @@ private static String parseUrlWithInstance(String jdbcUrl, ParseContext ctx) { return instanceName; } + /** + * Apply the {@code database} URL parameter alias when {@code databasename} has not already been + * set by {@link ParseContext#applyCommonParams(Map)}. + */ + private static void applyDatabaseAliasParam(ParseContext ctx, Map params) { + if (ctx.databaseName() != null) { + return; + } + String databaseName = getDatabaseNameParam(params); + if (databaseName != null) { + ctx.databaseName(databaseName); + } + } + + /** + * Resolve the SQL Server database name from URL parameters, trying {@code databasename} first and + * falling back to {@code database}. Returns {@code null} if neither key has a non-empty value. + */ + @Nullable + static String getDatabaseNameParam(Map params) { + String databaseName = params.get("databasename"); + if (databaseName == null || databaseName.isEmpty()) { + databaseName = params.get("database"); + } + return databaseName == null || databaseName.isEmpty() ? null : databaseName; + } + /** * Sets the namespace after parsing completes. * diff --git a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/parser/ParseContext.java b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/parser/ParseContext.java index a88fe3550304..b66f4f7bba3d 100644 --- a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/parser/ParseContext.java +++ b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/parser/ParseContext.java @@ -177,9 +177,17 @@ public Properties props() { * @param splitSeparator the separator between individual parameters (";" or "&") */ public void applyCommonParams(String jdbcUrl, String startDelimiter, String splitSeparator) { - Map params = - UrlParsingUtils.extractParams(jdbcUrl, startDelimiter, splitSeparator); + applyCommonParams(UrlParsingUtils.extractParams(jdbcUrl, startDelimiter, splitSeparator)); + } + /** + * Apply common parameters from a pre-parsed parameter map. Equivalent to {@link + * #applyCommonParams(String, String, String)} but avoids re-parsing the URL when the caller has + * already extracted the parameters. + * + * @param params the parameter map (keys must be lowercase) + */ + public void applyCommonParams(Map params) { if (params.isEmpty()) { return; } diff --git a/instrumentation/jdbc/library/src/test/java/io/opentelemetry/instrumentation/jdbc/internal/JdbcConnectionUrlParserTest.java b/instrumentation/jdbc/library/src/test/java/io/opentelemetry/instrumentation/jdbc/internal/JdbcConnectionUrlParserTest.java index 7b180beb992d..8cd9ca5126d0 100644 --- a/instrumentation/jdbc/library/src/test/java/io/opentelemetry/instrumentation/jdbc/internal/JdbcConnectionUrlParserTest.java +++ b/instrumentation/jdbc/library/src/test/java/io/opentelemetry/instrumentation/jdbc/internal/JdbcConnectionUrlParserTest.java @@ -557,6 +557,25 @@ private static Stream sqlServerArguments() { .setPort(1433) .setName("ssdb") .build(), + // database= alias (shorthand for databaseName) + arg("jdbc:sqlserver://ss.host;database=ssdb;") + .setShortUrl("sqlserver://ss.host:1433") + .setSystem("microsoft.sql_server") + .setOldSystem("mssql") + .setHost("ss.host") + .setPort(1433) + .setName("ssdb") + .build(), + arg("jdbc:sqlserver://ss.host\\ssinstance:44;database=ssdb;user=ssuser") + .setShortUrl("sqlserver://ss.host:44") + .setSystem("microsoft.sql_server") + .setOldSystem("mssql") + .setUser("ssuser") + .setHost("ss.host") + .setPort(44) + .setNamespace("ssinstance|ssdb") + .setName("ssinstance") + .build(), arg("jdbc:microsoft:sqlserver://ss.host:44;DatabaseName=ssdb;user=ssuser;password=pw;user=ssuser2;") .setShortUrl("microsoft:sqlserver://ss.host:44") .setSystem("microsoft.sql_server") @@ -659,6 +678,28 @@ private static Stream sqlServerArguments() { .setNamespace("ssinstance") .setName("ssinstance") .build(), + // database= alias (shorthand for databaseName) in jTDS URLs + arg("jdbc:jtds:sqlserver://ss.host/ssdb;instance=ssinstance;database=otherdb") + .setShortUrl("jtds:sqlserver://ss.host:1433") + .setSystem("microsoft.sql_server") + .setOldSystem("mssql") + .setSubtype("sqlserver") + .setHost("ss.host") + .setPort(1433) + .setNamespace("ssinstance|ssdb") + .setName("ssinstance") + .build(), + // database= param provides database name when there's no URL path + arg("jdbc:jtds:sqlserver://ss.host;instance=ssinstance;database=ssdb") + .setShortUrl("jtds:sqlserver://ss.host:1433") + .setSystem("microsoft.sql_server") + .setOldSystem("mssql") + .setSubtype("sqlserver") + .setHost("ss.host") + .setPort(1433) + .setNamespace("ssinstance|ssdb") + .setName("ssinstance") + .build(), arg("jdbc:jtds:sqlserver://ss.host:1444/urldb") .setProperties(stdProps()) .setShortUrl("jtds:sqlserver://stdServerName:9999")