From 6100443443f1e8c8701e3d46415f3ba2634f059a Mon Sep 17 00:00:00 2001 From: Tyler Benson Date: Wed, 5 Jun 2019 18:01:33 -0700 Subject: [PATCH 1/7] Attempt to properly parse out instance name from JDBC url MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unfortunately implementations are INCREDIBLY inconsistent on the matter. Oracle implementation is still pending since it’s really complicated. --- .../jdbc/DriverInstrumentation.java | 61 ++ .../jdbc/JDBCConnectionUrlParser.java | 538 ++++++++++++++++++ .../instrumentation/jdbc/JDBCDecorator.java | 20 +- .../trace/instrumentation/jdbc/JDBCMaps.java | 8 +- .../trace/instrumentation/jdbc/JDBCUtils.java | 18 + .../groovy/JDBCConnectionUrlParserTest.groovy | 114 ++++ .../groovy/JDBCInstrumentationTest.groovy | 90 ++- 7 files changed, 787 insertions(+), 62 deletions(-) create mode 100644 dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DriverInstrumentation.java create mode 100644 dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCConnectionUrlParser.java create mode 100644 dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCConnectionUrlParserTest.groovy diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DriverInstrumentation.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DriverInstrumentation.java new file mode 100644 index 0000000000..8cd9d9819e --- /dev/null +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DriverInstrumentation.java @@ -0,0 +1,61 @@ +package datadog.trace.instrumentation.jdbc; + +import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static java.util.Collections.singletonMap; +import static net.bytebuddy.matcher.ElementMatchers.isInterface; +import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.not; +import static net.bytebuddy.matcher.ElementMatchers.returns; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +import com.google.auto.service.AutoService; +import datadog.trace.agent.tooling.Instrumenter; +import java.sql.Connection; +import java.util.Map; +import java.util.Properties; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +@AutoService(Instrumenter.class) +public final class DriverInstrumentation extends Instrumenter.Default { + + public DriverInstrumentation() { + super("jdbc"); + } + + @Override + public ElementMatcher typeMatcher() { + return not(isInterface()).and(safeHasSuperType(named("java.sql.Driver"))); + } + + @Override + public String[] helperClassNames() { + return new String[] { + packageName + ".JDBCConnectionUrlParser", + }; + } + + @Override + public Map, String> transformers() { + return singletonMap( + nameStartsWith("connect") + .and(takesArgument(0, String.class)) + .and(takesArgument(1, Properties.class)) + .and(returns(Connection.class)), + DriverAdvice.class.getName()); + } + + public static class DriverAdvice { + @Advice.OnMethodExit(suppress = Throwable.class) + public static void addDBInfo( + @Advice.Argument(0) final String url, + @Advice.Argument(1) final Properties props, + @Advice.Return final Connection connection) { + final JDBCMaps.DBInfo dbInfo = JDBCConnectionUrlParser.parse(url, props); + JDBCMaps.connectionInfo.put(connection, dbInfo); + } + } +} diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCConnectionUrlParser.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCConnectionUrlParser.java new file mode 100644 index 0000000000..7121468d5e --- /dev/null +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCConnectionUrlParser.java @@ -0,0 +1,538 @@ +package datadog.trace.instrumentation.jdbc; + +import static datadog.trace.instrumentation.jdbc.JDBCMaps.DBInfo.DEFAULT; + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URLDecoder; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Properties; + +/** + * Structured as an enum instead of a class hierarchy to allow iterating through the parsers, plus + * the added benefit of only a single class to inject. + */ +public enum JDBCConnectionUrlParser { + GENERIC_URL_LIKE() { + @Override + JDBCMaps.DBInfo doParse(final String jdbcUrl, final Properties props) { + try { + // Attempt generic parsing + final URI uri = new URI(jdbcUrl); + + String username = uri.getUserInfo(); + String databaseName = null; + if (uri.getQuery() != null) { + final Map queryParams = splitQuery(uri.getQuery(), "&"); + + if (username == null) { + username = queryParams.get("user"); + } + databaseName = queryParams.get("databasename"); + } + + String path = uri.getPath(); + if (path.startsWith("/")) { + path = path.substring(1); + } + + return new JDBCMaps.DBInfo( + uri.getScheme(), null, username, path, databaseName, uri.getHost(), uri.getPort()); + } catch (final Exception e) { + return DEFAULT; + } + } + }, + + MODIFIED_URL_LIKE() { + private static final String DEFAULT_HOST = "localhost"; + + @Override + JDBCMaps.DBInfo doParse(final String jdbcUrl, final Properties props) { + try { + + final String type; + String serverName = ""; + Integer port = null; + String databaseName = null; + String instanceName = null; + String username = null; + + final int hostIndex = jdbcUrl.indexOf("://"); + + if (hostIndex <= 0) { + return DEFAULT; + } + + type = jdbcUrl.substring(0, hostIndex); + + final String[] split; + if (type.equals("db2") || type.equals("as400")) { + if (jdbcUrl.contains("=")) { + final int paramLoc = jdbcUrl.lastIndexOf(":"); + split = new String[] {jdbcUrl.substring(0, paramLoc), jdbcUrl.substring(paramLoc + 1)}; + } else { + split = new String[] {jdbcUrl}; + } + } else { + split = jdbcUrl.split(";", 2); + } + + if (split.length > 1) { + final Map urlProps = splitQuery(split[1], ";"); + if (urlProps.containsKey("servername")) { + serverName = urlProps.get("servername"); + } + if (urlProps.containsKey("instancename")) { + instanceName = urlProps.get("instancename"); + } + if (urlProps.containsKey("databasename")) { + databaseName = urlProps.get("databasename"); + } + if (urlProps.containsKey("user")) { + username = urlProps.get("user"); + } + } + + final String urlServerName = split[0].substring(hostIndex + 3); + if (!urlServerName.isEmpty()) { + serverName = urlServerName; + } + + int instanceLoc = serverName.indexOf("/"); + if (instanceLoc > 1) { + instanceName = serverName.substring(instanceLoc + 1); + serverName = serverName.substring(0, instanceLoc); + } + + final int portLoc = serverName.indexOf(":"); + + if (portLoc > 1) { + port = Integer.parseInt(serverName.substring(portLoc + 1)); + serverName = serverName.substring(0, portLoc); + } + + instanceLoc = serverName.indexOf("\\"); + if (instanceLoc > 1) { + instanceName = serverName.substring(instanceLoc + 1); + serverName = serverName.substring(0, instanceLoc); + } + + if (serverName.isEmpty()) { + serverName = DEFAULT_HOST; + } + + return new JDBCMaps.DBInfo( + type, null, username, instanceName, null /* databaseName */, serverName, port); + } catch (final UnsupportedEncodingException e) { + return DEFAULT; + } + } + }, + + POSTGRES("postgresql") { + private static final String DEFAULT_HOST = "localhost"; + private static final int DEFAULT_PORT = 5432; + + @Override + JDBCMaps.DBInfo doParse(final String jdbcUrl, final Properties props) { + final JDBCMaps.DBInfo dbInfo = GENERIC_URL_LIKE.doParse(jdbcUrl, props); + final String host = dbInfo.getHost() == null ? DEFAULT_HOST : dbInfo.getHost(); + final int port = dbInfo.getPort() <= 0 ? DEFAULT_PORT : dbInfo.getPort(); + return new JDBCMaps.DBInfo( + dbInfo.getType(), + dbInfo.getUrl(), + dbInfo.getUser(), + dbInfo.getInstance(), + null, + host, + port); + } + }, + + MYSQL("mysql", "mariadb") { + private static final String DEFAULT_HOST = "localhost"; + private static final int DEFAULT_PORT = 3306; + + @Override + JDBCMaps.DBInfo doParse(final String jdbcUrl, final Properties props) { + final JDBCMaps.DBInfo dbInfo = GENERIC_URL_LIKE.doParse(jdbcUrl, props); + final String host = dbInfo.getHost() == null ? DEFAULT_HOST : dbInfo.getHost(); + final int port = dbInfo.getPort() <= 0 ? DEFAULT_PORT : dbInfo.getPort(); + return new JDBCMaps.DBInfo( + dbInfo.getType(), + dbInfo.getUrl(), + dbInfo.getUser(), + dbInfo.getInstance(), + null, + host, + port); + } + }, + + SAP("sap") { + private static final String DEFAULT_HOST = "localhost"; + + @Override + JDBCMaps.DBInfo doParse(final String jdbcUrl, final Properties props) { + final JDBCMaps.DBInfo dbInfo = GENERIC_URL_LIKE.doParse(jdbcUrl, props); + final String host = dbInfo.getHost() == null ? DEFAULT_HOST : dbInfo.getHost(); + return new JDBCMaps.DBInfo( + dbInfo.getType(), + dbInfo.getUrl(), + dbInfo.getUser(), + dbInfo.getDb(), + null, + host, + dbInfo.getPort()); + } + }, + + MSSQLSERVER("microsoft", "sqlserver") { + private static final int DEFAULT_PORT = 1433; + private static final String DEFAULT_INSTANCE = "MSSQLSERVER"; + + @Override + JDBCMaps.DBInfo doParse(String jdbcUrl, final Properties props) { + if (jdbcUrl.startsWith("microsoft:")) { + jdbcUrl = jdbcUrl.substring("microsoft:".length()); + } + if (!jdbcUrl.startsWith("sqlserver://")) { + return DEFAULT; + } + + final JDBCMaps.DBInfo dbInfo = MODIFIED_URL_LIKE.doParse(jdbcUrl, props); + + return new JDBCMaps.DBInfo( + "sqlserver", + dbInfo.getUrl(), + dbInfo.getUser(), + dbInfo.getInstance() == null ? DEFAULT_INSTANCE : dbInfo.getInstance(), + dbInfo.getDb(), + dbInfo.getHost(), + dbInfo.getPort() == null ? DEFAULT_PORT : dbInfo.getPort()); + } + }, + + DB2("db2", "as400") { + private static final int DEFAULT_PORT = 50000; + + @Override + JDBCMaps.DBInfo doParse(final String jdbcUrl, final Properties props) { + final JDBCMaps.DBInfo dbInfo = MODIFIED_URL_LIKE.doParse(jdbcUrl, props); + return dbInfo.getPort() != null + ? dbInfo + : new JDBCMaps.DBInfo( + dbInfo.getType(), + dbInfo.getUrl(), + dbInfo.getUser(), + dbInfo.getInstance(), + dbInfo.getDb(), + dbInfo.getHost(), + DEFAULT_PORT); + } + }, + + H2("h2") { + private static final int DEFAULT_PORT = 8082; + + @Override + JDBCMaps.DBInfo doParse(final String jdbcUrl, final Properties props) { + String type = "h2"; + String instance = null; + + final String h2Url = jdbcUrl.substring("h2:".length()); + if (h2Url.startsWith("mem:")) { + type = "h2:mem"; + final int propLoc = h2Url.indexOf(";"); + if (propLoc >= 0) { + instance = h2Url.substring("mem:".length(), propLoc); + } else { + instance = h2Url.substring("mem:".length()); + } + } else if (h2Url.startsWith("file:")) { + type = "h2:file"; + final int propLoc = h2Url.indexOf(";"); + if (propLoc >= 0) { + instance = h2Url.substring("file:".length(), propLoc); + } else { + instance = h2Url.substring("file:".length()); + } + } else if (h2Url.startsWith("zip:")) { + type = "h2:zip"; + final int propLoc = h2Url.indexOf(";"); + if (propLoc >= 0) { + instance = h2Url.substring("zip:".length(), propLoc); + } else { + instance = h2Url.substring("zip:".length()); + } + } else if (h2Url.startsWith("tcp:")) { + final JDBCMaps.DBInfo dbInfo = MODIFIED_URL_LIKE.doParse(jdbcUrl, props); + + return new JDBCMaps.DBInfo( + "h2:tcp", + dbInfo.getUrl(), + dbInfo.getUser(), + dbInfo.getInstance(), + dbInfo.getDb(), + dbInfo.getHost(), + dbInfo.getPort() == null ? DEFAULT_PORT : dbInfo.getPort()); + } else if (h2Url.startsWith("ssl:")) { + final JDBCMaps.DBInfo dbInfo = MODIFIED_URL_LIKE.doParse(jdbcUrl, props); + + return new JDBCMaps.DBInfo( + "h2:ssl", + dbInfo.getUrl(), + dbInfo.getUser(), + dbInfo.getInstance(), + dbInfo.getDb(), + dbInfo.getHost(), + dbInfo.getPort() == null ? DEFAULT_PORT : dbInfo.getPort()); + } else { + type = "h2:file"; + final int propLoc = h2Url.indexOf(";"); + if (propLoc >= 0) { + instance = h2Url.substring(0, propLoc); + } else { + instance = h2Url; + } + } + return new JDBCMaps.DBInfo(type, null, null, instance, null, null, null); + } + }, + + HSQL("hsqldb") { + private static final String DEFAULT_USER = "SA"; + private static final int DEFAULT_PORT = 9001; + + @Override + JDBCMaps.DBInfo doParse(final String jdbcUrl, final Properties props) { + String type = "hsqldb"; + String instance = null; + final String hsqlUrl = jdbcUrl.substring("hsqldb:".length()); + if (hsqlUrl.startsWith("mem:")) { + type = "hsqldb:mem"; + instance = hsqlUrl.substring("mem:".length()); + } else if (hsqlUrl.startsWith("file:")) { + type = "hsqldb:file"; + instance = hsqlUrl.substring("file:".length()); + } else if (hsqlUrl.startsWith("res:")) { + type = "hsqldb:res"; + instance = hsqlUrl.substring("res:".length()); + } else if (hsqlUrl.startsWith("hsql:")) { + final JDBCMaps.DBInfo dbInfo = MODIFIED_URL_LIKE.doParse(jdbcUrl, props); + + return new JDBCMaps.DBInfo( + "hsqldb:hsql", + dbInfo.getUrl(), + dbInfo.getUser() == null ? DEFAULT_USER : dbInfo.getUser(), + dbInfo.getInstance(), + dbInfo.getDb(), + dbInfo.getHost(), + dbInfo.getPort() == null ? DEFAULT_PORT : dbInfo.getPort()); + + } else if (hsqlUrl.startsWith("hsqls:")) { + final JDBCMaps.DBInfo dbInfo = MODIFIED_URL_LIKE.doParse(jdbcUrl, props); + + return new JDBCMaps.DBInfo( + "hsqldb:hsqls", + dbInfo.getUrl(), + dbInfo.getUser() == null ? DEFAULT_USER : dbInfo.getUser(), + dbInfo.getInstance(), + dbInfo.getDb(), + dbInfo.getHost(), + dbInfo.getPort() == null ? DEFAULT_PORT : dbInfo.getPort()); + + } else if (hsqlUrl.startsWith("http:")) { + final JDBCMaps.DBInfo dbInfo = MODIFIED_URL_LIKE.doParse(jdbcUrl, props); + + return new JDBCMaps.DBInfo( + "hsqldb:http", + dbInfo.getUrl(), + dbInfo.getUser() == null ? DEFAULT_USER : dbInfo.getUser(), + dbInfo.getInstance(), + dbInfo.getDb(), + dbInfo.getHost(), + dbInfo.getPort() == null ? 80 : dbInfo.getPort()); + + } else if (hsqlUrl.startsWith("https:")) { + final JDBCMaps.DBInfo dbInfo = MODIFIED_URL_LIKE.doParse(jdbcUrl, props); + + return new JDBCMaps.DBInfo( + "hsqldb:https", + dbInfo.getUrl(), + dbInfo.getUser() == null ? DEFAULT_USER : dbInfo.getUser(), + dbInfo.getInstance(), + dbInfo.getDb(), + dbInfo.getHost(), + dbInfo.getPort() == null ? 443 : dbInfo.getPort()); + + } else { + type = "hsqldb:mem"; + instance = hsqlUrl; + } + return new JDBCMaps.DBInfo(type, null, DEFAULT_USER, instance, null, null, null); + } + }, + + DERBY("derby") { + private static final String DEFAULT_USER = "APP"; + private static final int DEFAULT_PORT = 1527; + + @Override + JDBCMaps.DBInfo doParse(final String jdbcUrl, final Properties props) { + String type = "derby"; + String instance = null; + String host = null; + Integer port = null; + String user = DEFAULT_USER; + + if (props != null) { + instance = props.getProperty("databasename"); + user = props.getProperty("user"); + } + final String derbyUrl = jdbcUrl.substring("derby:".length()); + final String[] split = derbyUrl.split(";", 2); + + if (split.length > 1) { + try { + final Map urlProps = splitQuery(split[1], ";"); + if (urlProps.containsKey("databasename")) { + instance = urlProps.get("databasename"); + } + if (urlProps.containsKey("user")) { + user = urlProps.get("user"); + } + if (urlProps.containsKey("servername")) { + host = urlProps.get("servername"); + } + if (urlProps.containsKey("portnumber")) { + port = Integer.parseInt(urlProps.get("portnumber")); + } + } catch (final Exception e) { + } + } + + if (split[0].startsWith("memory:")) { + type = "derby:memory"; + final String urlInstance = split[0].substring("memory:".length()); + if (!urlInstance.isEmpty()) { + instance = urlInstance; + } + } else if (split[0].startsWith("directory:")) { + type = "derby:directory"; + final String urlInstance = split[0].substring("directory:".length()); + if (!urlInstance.isEmpty()) { + instance = urlInstance; + } + } else if (split[0].startsWith("classpath:")) { + type = "derby:classpath"; + final String urlInstance = split[0].substring("classpath:".length()); + if (!urlInstance.isEmpty()) { + instance = urlInstance; + } + } else if (split[0].startsWith("jar:")) { + type = "derby:jar"; + final String urlInstance = split[0].substring("jar:".length()); + if (!urlInstance.isEmpty()) { + instance = urlInstance; + } + } else if (split[0].startsWith("//")) { + type = "derby:network"; + String url = split[0].substring("//".length()); + final int instanceLoc = url.indexOf("/"); + if (instanceLoc >= 0) { + instance = url.substring(instanceLoc + 1); + final int protoLoc = instance.indexOf(":"); + if (protoLoc >= 0) { + instance = instance.substring(protoLoc + 1); + } + url = url.substring(0, instanceLoc); + } + final int portLoc = url.indexOf(":"); + if (portLoc > 0) { + host = url.substring(0, portLoc); + port = Integer.parseInt(url.substring(portLoc + 1)); + } else { + host = url; + port = DEFAULT_PORT; + } + } else { + type = "derby:directory"; + final String urlInstance = split[0]; + if (!urlInstance.isEmpty()) { + instance = urlInstance; + } + } + + return new JDBCMaps.DBInfo(type, null, user, instance, null, host, port); + } + }; + + private static final Map typeParsers = new HashMap<>(); + + static { + for (final JDBCConnectionUrlParser parser : JDBCConnectionUrlParser.values()) { + for (final String key : parser.typeKeys) { + typeParsers.put(key, parser); + } + } + } + + private final String[] typeKeys; + + JDBCConnectionUrlParser(final String... typeKeys) { + this.typeKeys = typeKeys; + } + + abstract JDBCMaps.DBInfo doParse(String jdbcUrl, final Properties props); + + public static JDBCMaps.DBInfo parse(String connectionUrl, final Properties props) { + if (connectionUrl == null) { + return DEFAULT; + } + // Make this easer and ignore case. + connectionUrl = connectionUrl.toLowerCase(); + + if (!connectionUrl.startsWith("jdbc:")) { + return DEFAULT; + } + + final String jdbcUrl = connectionUrl.substring("jdbc:".length()); + final int typeLoc = jdbcUrl.indexOf(':'); + + if (typeLoc < 1) { + // Invalid format: `jdbc:` or `jdbc::` + return DEFAULT; + } + + final String baseType = jdbcUrl.substring(0, typeLoc); + + if (typeParsers.containsKey(baseType)) { + // Delegate to specific parser + return typeParsers.get(baseType).doParse(jdbcUrl, props); + } + return GENERIC_URL_LIKE.doParse(connectionUrl, props); + } + + // Source: https://stackoverflow.com/a/13592567 + private static Map splitQuery(final String query, final String separator) + throws UnsupportedEncodingException { + final Map query_pairs = new LinkedHashMap<>(); + final String[] pairs = query.split(separator); + for (final String pair : pairs) { + final int idx = pair.indexOf("="); + final String key = idx > 0 ? URLDecoder.decode(pair.substring(0, idx), "UTF-8") : pair; + if (!query_pairs.containsKey(key)) { + final String value = + idx > 0 && pair.length() > idx + 1 + ? URLDecoder.decode(pair.substring(idx + 1), "UTF-8") + : null; + query_pairs.put(key, value); + } + } + return query_pairs; + } +} diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCDecorator.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCDecorator.java index 7de8cca72f..213e18398c 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCDecorator.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCDecorator.java @@ -45,16 +45,17 @@ public class JDBCDecorator extends DatabaseClientDecorator { @Override protected String dbInstance(final JDBCMaps.DBInfo info) { - return info.getUrl(); + return info.getInstance(); } public Span onConnection(final Span span, final Connection connection) { JDBCMaps.DBInfo dbInfo = JDBCMaps.connectionInfo.get(connection); /** - * Logic to get the DBInfo from a JDBC Connection, if the connection was never seen before, the - * connectionInfo map will return null and will attempt to extract DBInfo from the connection. - * If the DBInfo can't be extracted, then the connection will be stored with the DEFAULT DBInfo - * as the value in the connectionInfo map to avoid retry overhead. + * Logic to get the DBInfo from a JDBC Connection, if the connection was not created via + * Driver.connect, or it has never seen before, the connectionInfo map will return null and will + * attempt to extract DBInfo from the connection. If the DBInfo can't be extracted, then the + * connection will be stored with the DEFAULT DBInfo as the value in the connectionInfo map to + * avoid retry overhead. */ { if (dbInfo == null) { @@ -62,14 +63,7 @@ public class JDBCDecorator extends DatabaseClientDecorator { final DatabaseMetaData metaData = connection.getMetaData(); final String url = metaData.getURL(); if (url != null) { - // Remove end of url to prevent passwords from leaking: - final String sanitizedURL = url.replaceAll("[?;].*", ""); - final String type = url.split(":", -1)[1]; - String user = metaData.getUserName(); - if (user != null && user.trim().equals("")) { - user = null; - } - dbInfo = new JDBCMaps.DBInfo(sanitizedURL, type, user); + dbInfo = JDBCConnectionUrlParser.parse(url, connection.getClientInfo()); } else { dbInfo = JDBCMaps.DBInfo.DEFAULT; } diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCMaps.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCMaps.java index 13bbe8865e..d4b4135125 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCMaps.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCMaps.java @@ -20,9 +20,13 @@ public class JDBCMaps { @Data public static class DBInfo { - public static DBInfo DEFAULT = new DBInfo("null", "database", null); - private final String url; + public static DBInfo DEFAULT = new DBInfo("database", null, null, null, null, null, null); private final String type; + private final String url; private final String user; + private final String instance; + private final String db; + private final String host; + private final Integer port; } } diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCUtils.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCUtils.java index 0fb70291f6..a7883679cc 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCUtils.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCUtils.java @@ -1,10 +1,12 @@ package datadog.trace.instrumentation.jdbc; import datadog.trace.bootstrap.ExceptionLogger; +import java.lang.reflect.Field; import java.sql.Connection; import java.sql.Statement; public abstract class JDBCUtils { + private static Field c3poField = null; /** * @param statement @@ -14,6 +16,13 @@ public abstract class JDBCUtils { Connection connection; try { connection = statement.getConnection(); + + if (c3poField != null) { + if (connection.getClass().getName().equals("com.mchange.v2.c3p0.impl.NewProxyConnection")) { + return (Connection) c3poField.get(connection); + } + } + try { // unwrap the connection to cache the underlying actual connection and to not cache proxy // objects @@ -21,6 +30,15 @@ public abstract class JDBCUtils { connection = connection.unwrap(Connection.class); } } catch (final Exception | AbstractMethodError e) { + // Attempt to work around c3po delegating to an connection that doesn't support unwrapping. + final Class connectionClass = connection.getClass(); + if (connectionClass.getName().equals("com.mchange.v2.c3p0.impl.NewProxyConnection")) { + final Field inner = connectionClass.getDeclaredField("inner"); + inner.setAccessible(true); + c3poField = inner; + return (Connection) c3poField.get(connection); + } + // perhaps wrapping isn't supported? // ex: org.h2.jdbc.JdbcConnection v1.3.175 // or: jdts.jdbc which always throws `AbstractMethodError` (at least up to version 1.3) diff --git a/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCConnectionUrlParserTest.groovy b/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCConnectionUrlParserTest.groovy new file mode 100644 index 0000000000..3a4a969d98 --- /dev/null +++ b/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCConnectionUrlParserTest.groovy @@ -0,0 +1,114 @@ +import datadog.trace.instrumentation.jdbc.JDBCMaps +import spock.lang.Specification + +import static datadog.trace.instrumentation.jdbc.JDBCConnectionUrlParser.parse + +class JDBCConnectionUrlParserTest extends Specification { + + def "invalid url returns default"() { + expect: + parse(url, null) == JDBCMaps.DBInfo.DEFAULT + + where: + url | _ + null | _ + "" | _ + "bogus:string" | _ + } + + def "verify #format parsing of #url"() { + setup: + def info = parse(url, null) + + expect: + info.url == expected.url + info.type == expected.type + info.host == expected.host + info.port == expected.port + info.user == expected.user + info.instance == expected.instance + + info == expected + + where: + url | format | user | host | port | instance + // https://jdbc.postgresql.org/documentation/94/connect.html + "jdbc:postgresql:///" | "postgresql" | null | "localhost" | 5432 | "" + "jdbc:postgresql://pghost" | "postgresql" | null | "pghost" | 5432 | "" + "jdbc:postgresql://pghost:11/pgdb?user=pguser&password=PW" | "postgresql" | "pguser" | "pghost" | 11 | "pgdb" + + // https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-configuration-properties.html + "jdbc:mysql:///" | "mysql" | null | "localhost" | 3306 | "" + "jdbc:mysql://myhost" | "mysql" | null | "myhost" | 3306 | "" + "jdbc:mysql://myhost?user=myuser&password=PW" | "mysql" | "myuser" | "myhost" | 3306 | "" + "jdbc:mysql://myhost:22/mydb?user=myuser&password=PW" | "mysql" | "myuser" | "myhost" | 22 | "mydb" + "jdbc:mariadb://mdbhost:33/mdbdb?user=mdbuser&password=PW" | "mariadb" | "mdbuser" | "mdbhost" | 33 | "mdbdb" + + //https://docs.microsoft.com/en-us/sql/connect/jdbc/building-the-connection-url + "jdbc:microsoft:sqlserver://;" | "sqlserver" | null | "localhost" | 1433 | "MSSQLSERVER" + "jdbc:sqlserver://sshost\\ssinstance:44;databaseName=ssdb;user=ssuser;password=pw" | "sqlserver" | "ssuser" | "sshost" | 44 | "ssinstance" + "jdbc:sqlserver://;serverName=sshost\\ssinstance:44;DatabaseName=;" | "sqlserver" | null | "sshost" | 44 | "ssinstance" + "jdbc:sqlserver://sshost;serverName=althost;DatabaseName=ssdb;" | "sqlserver" | null | "sshost" | 1433 | "MSSQLSERVER" + "jdbc:microsoft:sqlserver://sshost:44;DatabaseName=ssdb;user=ssuser;password=pw;user=ssuser2;" | "sqlserver" | "ssuser" | "sshost" | 44 | "MSSQLSERVER" + + // TODO: +// "jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST= localhost )(PORT= 1521))" + +// "(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=orcl)))" | "oracle" | "orcluser" | "orclhost" | 55 | "orcldb" +// "jdbc:oracle:drivertype:orcluser/PW@orclhost:55/orcldb" | "oracle" | "orcluser" | "orclhost" | 55 | "orcldb" + + // https://www.ibm.com/support/knowledgecenter/en/SSEPEK_10.0.0/java/src/tpc/imjcc_tjvjcccn.html + // https://www.ibm.com/support/knowledgecenter/en/SSEPGG_10.5.0/com.ibm.db2.luw.apdv.java.doc/src/tpc/imjcc_r0052342.html + "jdbc:as400://ashost:66/asdb:user=asuser;password=PW;" | "as400" | "asuser" | "ashost" | 66 | "asdb" + "jdbc:db2://db2host:77/db2db:user=db2user;password=PW;" | "db2" | "db2user" | "db2host" | 77 | "db2db" + + // https://help.sap.com/viewer/0eec0d68141541d1b07893a39944924e/2.0.03/en-US/ff15928cf5594d78b841fbbe649f04b4.html + "jdbc:sap://saphost:88/?databaseName=sapdb&user=sapuser&password=PW" | "sap" | "sapuser" | "saphost" | 88 | "sapdb" + + // TODO: +// "jdbc:informix-sqli://infxhost:99/infxdb:INFORMIXSERVER=infxsn;user=infxuser;password=PW" | "informix-sqli" | "infxuser" | "infxhost" | 99 | "infxdb" +// "jdbc:informix-direct://infxdb:999;user=infxuser;password=PW" | "informix-direct" | "infxuser" | "infxhost" | 999 | "infxdb" + + // http://www.h2database.com/html/features.html#database_url + "jdbc:h2:mem:" | "h2:mem" | null | null | null | "" + "jdbc:h2:mem:h2db" | "h2:mem" | null | null | null | "h2db" + "jdbc:h2:tcp://h2host:111/path/h2db;user=h2user;password=PW" | "h2:tcp" | "h2user" | "h2host" | 111 | "path/h2db" + "jdbc:h2:ssl://h2host:111/path/h2db;user=h2user;password=PW" | "h2:ssl" | "h2user" | "h2host" | 111 | "path/h2db" + "jdbc:h2:/data/h2file" | "h2:file" | null | null | null | "/data/h2file" + "jdbc:h2:file:~/h2file;USER=h2user;PASSWORD=PW" | "h2:file" | null | null | null | "~/h2file" + "jdbc:h2:file:/data/h2file" | "h2:file" | null | null | null | "/data/h2file" + "jdbc:h2:file:C:/data/h2file" | "h2:file" | null | null | null | "c:/data/h2file" + "jdbc:h2:zip:~/db.zip!/h2zip" | "h2:zip" | null | null | null | "~/db.zip!/h2zip" + + // http://hsqldb.org/doc/2.0/guide/dbproperties-chapt.html + "jdbc:hsqldb:hsdb" | "hsqldb:mem" | "SA" | null | null | "hsdb" + "jdbc:hsqldb:mem:hsdb" | "hsqldb:mem" | "SA" | null | null | "hsdb" + "jdbc:hsqldb:file:hsdb" | "hsqldb:file" | "SA" | null | null | "hsdb" + "jdbc:hsqldb:file:/loc/hsdb" | "hsqldb:file" | "SA" | null | null | "/loc/hsdb" + "jdbc:hsqldb:file:C:/hsdb" | "hsqldb:file" | "SA" | null | null | "c:/hsdb" + "jdbc:hsqldb:res:hsdb" | "hsqldb:res" | "SA" | null | null | "hsdb" + "jdbc:hsqldb:res:/cp/hsdb" | "hsqldb:res" | "SA" | null | null | "/cp/hsdb" + "jdbc:hsqldb:hsql://hshost:333/hsdb" | "hsqldb:hsql" | "SA" | "hshost" | 333 | "hsdb" + "jdbc:hsqldb:hsqls://hshost/hsdb" | "hsqldb:hsqls" | "SA" | "hshost" | 9001 | "hsdb" + "jdbc:hsqldb:http://hshost" | "hsqldb:http" | "SA" | "hshost" | 80 | null + "jdbc:hsqldb:http://hshost:333/hsdb" | "hsqldb:http" | "SA" | "hshost" | 333 | "hsdb" + "jdbc:hsqldb:https://127.0.0.1/hsdb" | "hsqldb:https" | "SA" | "127.0.0.1" | 443 | "hsdb" + + // https://db.apache.org/derby/papers/DerbyClientSpec.html#Connection+URL+Format + // https://db.apache.org/derby/docs/10.8/devguide/cdevdvlp34964.html + "jdbc:derby:derbydb" | "derby:directory" | "APP" | null | null | "derbydb" + "jdbc:derby:derbydb;user=derbyuser;password=pw" | "derby:directory" | "derbyuser" | null | null | "derbydb" + "jdbc:derby:memory:derbydb" | "derby:memory" | "APP" | null | null | "derbydb" + "jdbc:derby:memory:;databaseName=derbydb" | "derby:memory" | "APP" | null | null | "derbydb" + "jdbc:derby:memory:derbydb;databaseName=altdb" | "derby:memory" | "APP" | null | null | "derbydb" + "jdbc:derby:memory:derbydb;user=derbyuser;password=pw" | "derby:memory" | "derbyuser" | null | null | "derbydb" + "jdbc:derby://derbyhost:222/memory:derbydb;create=true" | "derby:network" | "APP" | "derbyhost" | 222 | "derbydb" + "jdbc:derby://derbyhost/memory:derbydb;create=true;user=derbyuser;password=pw" | "derby:network" | "derbyuser" | "derbyhost" | 1527 | "derbydb" + "jdbc:derby://127.0.0.1:1527/memory:derbydb;create=true;user=derbyuser;password=pw" | "derby:network" | "derbyuser" | "127.0.0.1" | 1527 | "derbydb" + "jdbc:derby:directory:derbydb;user=derbyuser;password=pw" | "derby:directory" | "derbyuser" | null | null | "derbydb" + "jdbc:derby:classpath:/some/derbydb;user=derbyuser;password=pw" | "derby:classpath" | "derbyuser" | null | null | "/some/derbydb" + "jdbc:derby:jar:/derbydb;user=derbyuser;password=pw" | "derby:jar" | "derbyuser" | null | null | "/derbydb" + "jdbc:derby:jar:(~/path/to/db.jar)/other/derbydb;user=derbyuser;password=pw" | "derby:jar" | "derbyuser" | null | null | "(~/path/to/db.jar)/other/derbydb" + + expected = new JDBCMaps.DBInfo(format, null, user, instance, null, host, port) + } +} diff --git a/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCInstrumentationTest.groovy b/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCInstrumentationTest.groovy index cc5a0e1ee5..c903b7fc33 100644 --- a/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCInstrumentationTest.groovy +++ b/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCInstrumentationTest.groovy @@ -4,13 +4,13 @@ import com.zaxxer.hikari.HikariDataSource import datadog.trace.agent.test.AgentTestRunner import datadog.trace.api.DDSpanTypes import io.opentracing.tag.Tags +import javax.sql.DataSource import org.apache.derby.jdbc.EmbeddedDriver import org.h2.Driver import org.hsqldb.jdbc.JDBCDriver import spock.lang.Shared import spock.lang.Unroll -import javax.sql.DataSource import java.sql.CallableStatement import java.sql.Connection import java.sql.PreparedStatement @@ -26,32 +26,42 @@ class JDBCInstrumentationTest extends AgentTestRunner { @Shared private Map jdbcUrls = [ - h2 : "jdbc:h2:mem:" + dbName, - derby : "jdbc:derby:memory:" + dbName, - hsqldb: "jdbc:hsqldb:mem:" + dbName + h2 : "jdbc:h2:mem:$dbName", + derby : "jdbc:derby:memory:$dbName", + hsqldb: "jdbc:hsqldb:mem:$dbName", ] @Shared private Map jdbcDriverClassNames = [ h2 : "org.h2.Driver", derby : "org.apache.derby.jdbc.EmbeddedDriver", - hsqldb: "org.hsqldb.jdbc.JDBCDriver" + hsqldb: "org.hsqldb.jdbc.JDBCDriver", ] @Shared private Map jdbcUserNames = [ h2 : null, derby : "APP", - hsqldb: "SA" + hsqldb: "SA", ] + @Shared + private Properties connectionProps = { + def props = new Properties() +// props.put("user", "someUser") +// props.put("password", "somePassword") + props.put("databaseName", "someDb") + props.put("OPEN_NEW", "true") // So H2 doesn't complain about username/password. + return props + }() + // JDBC Connection pool name (i.e. HikariCP) -> Map @Shared private Map> cpDatasources = new HashMap<>() def prepareConnectionPoolDatasources() { String[] connectionPoolNames = [ - "tomcat", "hikari", "c3p0" + "tomcat", "hikari", "c3p0", ] connectionPoolNames.each { cpName -> @@ -170,7 +180,7 @@ class JDBCInstrumentationTest extends AgentTestRunner { } "span.kind" Tags.SPAN_KIND_CLIENT "component" "java-jdbc-statement" - "db.instance" jdbcUrls.get(driver) + "db.instance" dbName.toLowerCase() "span.origin.type" String defaultTags() } @@ -183,19 +193,22 @@ class JDBCInstrumentationTest extends AgentTestRunner { connection.close() where: - driver | connection | username | query - "h2" | new Driver().connect(jdbcUrls.get("h2"), null) | null | "SELECT 3" - "derby" | new EmbeddedDriver().connect(jdbcUrls.get("derby"), null) | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "hsqldb" | new JDBCDriver().connect(jdbcUrls.get("hsqldb"), null) | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" - "h2" | cpDatasources.get("tomcat").get("h2").getConnection() | null | "SELECT 3" - "derby" | cpDatasources.get("tomcat").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "hsqldb" | cpDatasources.get("tomcat").get("hsqldb").getConnection() | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" - "h2" | cpDatasources.get("hikari").get("h2").getConnection() | null | "SELECT 3" - "derby" | cpDatasources.get("hikari").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "hsqldb" | cpDatasources.get("hikari").get("hsqldb").getConnection() | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" - "h2" | cpDatasources.get("c3p0").get("h2").getConnection() | null | "SELECT 3" - "derby" | cpDatasources.get("c3p0").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "hsqldb" | cpDatasources.get("c3p0").get("hsqldb").getConnection() | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" + driver | connection | username | query + "h2" | new Driver().connect(jdbcUrls.get("h2"), null) | null | "SELECT 3" + "derby" | new EmbeddedDriver().connect(jdbcUrls.get("derby"), null) | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "hsqldb" | new JDBCDriver().connect(jdbcUrls.get("hsqldb"), null) | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" + "h2" | new Driver().connect(jdbcUrls.get("h2"), connectionProps) | null | "SELECT 3" + "derby" | new EmbeddedDriver().connect(jdbcUrls.get("derby"), connectionProps) | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "hsqldb" | new JDBCDriver().connect(jdbcUrls.get("hsqldb"), connectionProps) | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" + "h2" | cpDatasources.get("tomcat").get("h2").getConnection() | null | "SELECT 3" + "derby" | cpDatasources.get("tomcat").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "hsqldb" | cpDatasources.get("tomcat").get("hsqldb").getConnection() | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" + "h2" | cpDatasources.get("hikari").get("h2").getConnection() | null | "SELECT 3" + "derby" | cpDatasources.get("hikari").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "hsqldb" | cpDatasources.get("hikari").get("hsqldb").getConnection() | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" + "h2" | cpDatasources.get("c3p0").get("h2").getConnection() | null | "SELECT 3" + "derby" | cpDatasources.get("c3p0").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "hsqldb" | cpDatasources.get("c3p0").get("hsqldb").getConnection() | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" } @Unroll @@ -230,7 +243,7 @@ class JDBCInstrumentationTest extends AgentTestRunner { } "span.kind" Tags.SPAN_KIND_CLIENT "component" "java-jdbc-prepared_statement" - "db.instance" jdbcUrls.get(driver) + "db.instance" dbName.toLowerCase() "span.origin.type" String defaultTags() } @@ -285,7 +298,7 @@ class JDBCInstrumentationTest extends AgentTestRunner { } "span.kind" Tags.SPAN_KIND_CLIENT "component" "java-jdbc-prepared_statement" - "db.instance" jdbcUrls.get(driver) + "db.instance" dbName.toLowerCase() "span.origin.type" String defaultTags() } @@ -340,7 +353,7 @@ class JDBCInstrumentationTest extends AgentTestRunner { } "span.kind" Tags.SPAN_KIND_CLIENT "component" "java-jdbc-prepared_statement" - "db.instance" jdbcUrls.get(driver) + "db.instance" dbName.toLowerCase() "span.origin.type" String defaultTags() } @@ -395,7 +408,7 @@ class JDBCInstrumentationTest extends AgentTestRunner { } "span.kind" Tags.SPAN_KIND_CLIENT "component" "java-jdbc-statement" - "db.instance" jdbcUrls.get(driver) + "db.instance" dbName.toLowerCase() "span.origin.type" String defaultTags() } @@ -453,7 +466,7 @@ class JDBCInstrumentationTest extends AgentTestRunner { } "span.kind" Tags.SPAN_KIND_CLIENT "component" "java-jdbc-prepared_statement" - "db.instance" jdbcUrls.get(driver) + "db.instance" dbName.toLowerCase() "span.origin.type" String defaultTags() } @@ -528,7 +541,7 @@ class JDBCInstrumentationTest extends AgentTestRunner { "component" "java-jdbc-statement" } "span.kind" Tags.SPAN_KIND_CLIENT - "db.instance" jdbcUrls.get(driver) + "db.instance" dbName.toLowerCase() "span.origin.type" String defaultTags() } @@ -585,7 +598,7 @@ class JDBCInstrumentationTest extends AgentTestRunner { res[i] == 3 } assertTraces(5) { - trace(0, 2) { + trace(0, 1) { span(0) { operationName "${dbType}.query" serviceName dbType @@ -597,24 +610,7 @@ class JDBCInstrumentationTest extends AgentTestRunner { "db.user" "SA" "component" "java-jdbc-prepared_statement" "span.kind" Tags.SPAN_KIND_CLIENT - "db.instance" jdbcUrls.get(dbType) - "span.origin.type" String - defaultTags() - } - } - span(1) { - operationName "${dbType}.query" - serviceName dbType - resourceName "CALL USER()" - spanType DDSpanTypes.SQL - errored false - childOf(span(0)) - tags { - "db.type" "hsqldb" - "db.user" "SA" - "component" "java-jdbc-statement" - "span.kind" Tags.SPAN_KIND_CLIENT - "db.instance" jdbcUrls.get(dbType) + "db.instance" dbName.toLowerCase() "span.origin.type" String defaultTags() } @@ -633,7 +629,7 @@ class JDBCInstrumentationTest extends AgentTestRunner { "db.user" "SA" "component" "java-jdbc-prepared_statement" "span.kind" Tags.SPAN_KIND_CLIENT - "db.instance" jdbcUrls.get(dbType) + "db.instance" dbName.toLowerCase() "span.origin.type" String defaultTags() } From ec60d679d6be0f0dbc49edfaa3737ac675155e5a Mon Sep 17 00:00:00 2001 From: Tyler Benson Date: Thu, 6 Jun 2019 18:03:56 -0700 Subject: [PATCH 2/7] Add Oracle support and fix muzzle. --- .../tooling/muzzle/ReferenceCreator.java | 10 +- .../jdbc/DriverInstrumentation.java | 16 +- .../jdbc/JDBCConnectionUrlParser.java | 200 ++++++++++++++++-- .../PreparedStatementInstrumentation.java | 28 ++- .../jdbc/StatementInstrumentation.java | 28 ++- .../groovy/JDBCConnectionUrlParserTest.groovy | 123 ++++++----- .../groovy/JDBCInstrumentationTest.groovy | 166 +++++++-------- 7 files changed, 397 insertions(+), 174 deletions(-) diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/ReferenceCreator.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/ReferenceCreator.java index 52289b56ff..6899cfeaba 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/ReferenceCreator.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/ReferenceCreator.java @@ -260,7 +260,10 @@ public class ReferenceCreator extends ClassVisitor { // * DONE field-source class (descriptor) // * DONE field-source visibility from this point (PRIVATE?) - final Type ownerType = Type.getType("L" + owner + ";"); + final Type ownerType = + owner.startsWith("[") + ? underlyingType(Type.getType(owner)) + : Type.getType("L" + owner + ";"); final Type fieldType = Type.getType(descriptor); final List fieldFlags = new ArrayList<>(); @@ -334,7 +337,10 @@ public class ReferenceCreator extends ClassVisitor { } } - final Type ownerType = Type.getType("L" + owner + ";"); + final Type ownerType = + owner.startsWith("[") + ? underlyingType(Type.getType(owner)) + : Type.getType("L" + owner + ";"); final List methodFlags = new ArrayList<>(); methodFlags.add( diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DriverInstrumentation.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DriverInstrumentation.java index 8cd9d9819e..7512065d5b 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DriverInstrumentation.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DriverInstrumentation.java @@ -12,6 +12,8 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; import datadog.trace.agent.tooling.Instrumenter; import java.sql.Connection; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.Properties; import net.bytebuddy.asm.Advice; @@ -33,9 +35,17 @@ public final class DriverInstrumentation extends Instrumenter.Default { @Override public String[] helperClassNames() { - return new String[] { - packageName + ".JDBCConnectionUrlParser", - }; + final JDBCConnectionUrlParser[] parsers = JDBCConnectionUrlParser.values(); + final List parserClasses = new ArrayList<>(parsers.length + 3); + + parserClasses.add(packageName + ".JDBCMaps"); + parserClasses.add(packageName + ".JDBCMaps$DBInfo"); + parserClasses.add(packageName + ".JDBCConnectionUrlParser"); + + for (final JDBCConnectionUrlParser parser : parsers) { + parserClasses.add(parser.getClass().getName()); + } + return parserClasses.toArray(new String[0]); } @Override diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCConnectionUrlParser.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCConnectionUrlParser.java index 7121468d5e..8cf475eb49 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCConnectionUrlParser.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCConnectionUrlParser.java @@ -2,6 +2,7 @@ package datadog.trace.instrumentation.jdbc; import static datadog.trace.instrumentation.jdbc.JDBCMaps.DBInfo.DEFAULT; +import datadog.trace.bootstrap.ExceptionLogger; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URLDecoder; @@ -9,6 +10,8 @@ import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * Structured as an enum instead of a class hierarchy to allow iterating through the parsers, plus @@ -22,13 +25,13 @@ public enum JDBCConnectionUrlParser { // Attempt generic parsing final URI uri = new URI(jdbcUrl); - String username = uri.getUserInfo(); + String user = uri.getUserInfo(); String databaseName = null; if (uri.getQuery() != null) { final Map queryParams = splitQuery(uri.getQuery(), "&"); - if (username == null) { - username = queryParams.get("user"); + if (user == null) { + user = queryParams.get("user"); } databaseName = queryParams.get("databasename"); } @@ -39,7 +42,7 @@ public enum JDBCConnectionUrlParser { } return new JDBCMaps.DBInfo( - uri.getScheme(), null, username, path, databaseName, uri.getHost(), uri.getPort()); + uri.getScheme(), null, user, path, databaseName, uri.getHost(), uri.getPort()); } catch (final Exception e) { return DEFAULT; } @@ -58,7 +61,7 @@ public enum JDBCConnectionUrlParser { Integer port = null; String databaseName = null; String instanceName = null; - String username = null; + String user = null; final int hostIndex = jdbcUrl.indexOf("://"); @@ -92,7 +95,7 @@ public enum JDBCConnectionUrlParser { databaseName = urlProps.get("databasename"); } if (urlProps.containsKey("user")) { - username = urlProps.get("user"); + user = urlProps.get("user"); } } @@ -125,7 +128,7 @@ public enum JDBCConnectionUrlParser { } return new JDBCMaps.DBInfo( - type, null, username, instanceName, null /* databaseName */, serverName, port); + type, null, user, instanceName, null /* databaseName */, serverName, port); } catch (final UnsupportedEncodingException e) { return DEFAULT; } @@ -235,6 +238,172 @@ public enum JDBCConnectionUrlParser { } }, + ORACLE("oracle") { + private static final int DEFAULT_PORT = 1521; + + @Override + JDBCMaps.DBInfo doParse(String jdbcUrl, final Properties props) { + final int typeEndIndex = jdbcUrl.indexOf(":", "oracle:".length()); + final String type = jdbcUrl.substring(0, typeEndIndex); + jdbcUrl = jdbcUrl.substring(typeEndIndex + 1); + + final JDBCMaps.DBInfo dbInfo; + if (jdbcUrl.contains("@")) { + dbInfo = ORACLE_AT.doParse(jdbcUrl, props); + } else { + dbInfo = ORACLE_CONNECT_INFO.doParse(jdbcUrl, props); + } + return new JDBCMaps.DBInfo( + type, + dbInfo.getUrl(), + dbInfo.getUser(), + dbInfo.getInstance(), + dbInfo.getDb(), + dbInfo.getHost(), + dbInfo.getPort() == null ? DEFAULT_PORT : dbInfo.getPort()); + } + }, + + ORACLE_CONNECT_INFO() { + @Override + JDBCMaps.DBInfo doParse(final String jdbcUrl, final Properties props) { + + final String host; + final Integer port; + final String instance; + + final int hostEnd = jdbcUrl.indexOf(":"); + final int instanceLoc = jdbcUrl.indexOf("/"); + if (hostEnd > 0) { + host = jdbcUrl.substring(0, hostEnd); + final int afterHostEnd = jdbcUrl.indexOf(":", hostEnd + 1); + if (afterHostEnd > 0) { + port = Integer.parseInt(jdbcUrl.substring(hostEnd + 1, afterHostEnd)); + instance = jdbcUrl.substring(afterHostEnd + 1); + } else { + if (instanceLoc > 0) { + instance = jdbcUrl.substring(instanceLoc + 1); + port = Integer.parseInt(jdbcUrl.substring(hostEnd + 1, instanceLoc)); + } else { + final String portOrInstance = jdbcUrl.substring(hostEnd + 1); + Integer parsedPort = null; + try { + parsedPort = Integer.parseInt(portOrInstance); + } catch (final NumberFormatException e) { + } + if (parsedPort == null) { + port = null; + instance = portOrInstance; + } else { + port = parsedPort; + instance = null; + } + } + } + } else { + if (instanceLoc > 0) { + host = jdbcUrl.substring(0, instanceLoc); + port = null; + instance = jdbcUrl.substring(instanceLoc + 1); + } else { + if (jdbcUrl.isEmpty()) { + return DEFAULT; + } else { + host = null; + port = null; + instance = jdbcUrl; + } + } + } + return new JDBCMaps.DBInfo(null, null, null, instance, null, host, port); + } + }, + + ORACLE_AT() { + @Override + JDBCMaps.DBInfo doParse(final String jdbcUrl, final Properties props) { + if (jdbcUrl.contains("@(description")) { + return ORACLE_AT_DESCRIPTION.doParse(jdbcUrl, props); + } + final String user; + + final String[] atSplit = jdbcUrl.split("@", 2); + + final int userInfoLoc = atSplit[0].indexOf("/"); + if (userInfoLoc > 0) { + user = atSplit[0].substring(0, userInfoLoc); + } else { + user = null; + } + + final String connectInfo = atSplit[1]; + final int hostStart; + if (connectInfo.startsWith("//")) { + hostStart = "//".length(); + } else if (connectInfo.startsWith("ldap://")) { + hostStart = "ldap://".length(); + } else { + hostStart = 0; + } + final JDBCMaps.DBInfo dbInfo = + ORACLE_CONNECT_INFO.doParse(connectInfo.substring(hostStart), props); + + return new JDBCMaps.DBInfo( + null, + dbInfo.getUrl(), + user, + dbInfo.getInstance(), + dbInfo.getDb(), + dbInfo.getHost(), + dbInfo.getPort()); + } + }, + + ORACLE_AT_DESCRIPTION() { + private final Pattern HOST_REGEX = Pattern.compile("\\(\\s*host\\s*=\\s*([^ )]+)\\s*\\)"); + private final Pattern PORT_REGEX = Pattern.compile("\\(\\s*port\\s*=\\s*([\\d]+)\\s*\\)"); + private final Pattern INSTANCE_REGEX = + Pattern.compile("\\(\\s*service_name\\s*=\\s*([^ )]+)\\s*\\)"); + + @Override + JDBCMaps.DBInfo doParse(final String jdbcUrl, final Properties props) { + final String user; + final String host; + final Integer port; + final String instance; + + final String[] atSplit = jdbcUrl.split("@", 2); + + final int userInfoLoc = atSplit[0].indexOf("/"); + if (userInfoLoc > 0) { + user = atSplit[0].substring(0, userInfoLoc); + } else { + user = null; + } + + final String description = atSplit[1]; + final Matcher hostMatcher = HOST_REGEX.matcher(description); + final Matcher portMatcher = PORT_REGEX.matcher(description); + final Matcher instanceMatcher = INSTANCE_REGEX.matcher(description); + if (hostMatcher.find()) { + host = hostMatcher.group(1); + } else { + host = null; + } + if (portMatcher.find()) { + port = Integer.parseInt(portMatcher.group(1)); + } else { + port = null; + } + if (instanceMatcher.find()) { + instance = instanceMatcher.group(1); + } else { + instance = null; + } + return new JDBCMaps.DBInfo(null, null, user, instance, null, host, port); + } + }, + H2("h2") { private static final int DEFAULT_PORT = 8082; @@ -390,8 +559,8 @@ public enum JDBCConnectionUrlParser { String user = DEFAULT_USER; if (props != null) { - instance = props.getProperty("databasename"); - user = props.getProperty("user"); + instance = props.getProperty("databasename", instance); + user = props.getProperty("user", user); } final String derbyUrl = jdbcUrl.substring("derby:".length()); final String[] split = derbyUrl.split(";", 2); @@ -510,11 +679,16 @@ public enum JDBCConnectionUrlParser { final String baseType = jdbcUrl.substring(0, typeLoc); - if (typeParsers.containsKey(baseType)) { - // Delegate to specific parser - return typeParsers.get(baseType).doParse(jdbcUrl, props); + try { + if (typeParsers.containsKey(baseType)) { + // Delegate to specific parser + return typeParsers.get(baseType).doParse(jdbcUrl, props); + } + return GENERIC_URL_LIKE.doParse(connectionUrl, props); + } catch (final Exception e) { + ExceptionLogger.LOGGER.debug("Error parsing URL", e); + return DEFAULT; } - return GENERIC_URL_LIKE.doParse(connectionUrl, props); } // Source: https://stackoverflow.com/a/13592567 diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/PreparedStatementInstrumentation.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/PreparedStatementInstrumentation.java index 56e73233d1..e457cb2000 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/PreparedStatementInstrumentation.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/PreparedStatementInstrumentation.java @@ -20,6 +20,8 @@ import io.opentracing.noop.NoopScopeManager; import io.opentracing.util.GlobalTracer; import java.sql.Connection; import java.sql.PreparedStatement; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.method.MethodDescription; @@ -40,15 +42,23 @@ public final class PreparedStatementInstrumentation extends Instrumenter.Default @Override public String[] helperClassNames() { - return new String[] { - "datadog.trace.agent.decorator.BaseDecorator", - "datadog.trace.agent.decorator.ClientDecorator", - "datadog.trace.agent.decorator.DatabaseClientDecorator", - packageName + ".JDBCDecorator", - packageName + ".JDBCMaps", - packageName + ".JDBCMaps$DBInfo", - packageName + ".JDBCUtils", - }; + final JDBCConnectionUrlParser[] parsers = JDBCConnectionUrlParser.values(); + final List parserClasses = new ArrayList<>(parsers.length + 8); + + parserClasses.add(packageName + ".JDBCUtils"); + parserClasses.add(packageName + ".JDBCMaps"); + parserClasses.add(packageName + ".JDBCMaps$DBInfo"); + parserClasses.add(packageName + ".JDBCConnectionUrlParser"); + + parserClasses.add("datadog.trace.agent.decorator.BaseDecorator"); + parserClasses.add("datadog.trace.agent.decorator.ClientDecorator"); + parserClasses.add("datadog.trace.agent.decorator.DatabaseClientDecorator"); + parserClasses.add(packageName + ".JDBCDecorator"); + + for (final JDBCConnectionUrlParser parser : parsers) { + parserClasses.add(parser.getClass().getName()); + } + return parserClasses.toArray(new String[0]); } @Override diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/StatementInstrumentation.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/StatementInstrumentation.java index a39e574f8d..a890fddece 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/StatementInstrumentation.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/StatementInstrumentation.java @@ -20,6 +20,8 @@ import io.opentracing.noop.NoopScopeManager; import io.opentracing.util.GlobalTracer; import java.sql.Connection; import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.method.MethodDescription; @@ -40,15 +42,23 @@ public final class StatementInstrumentation extends Instrumenter.Default { @Override public String[] helperClassNames() { - return new String[] { - "datadog.trace.agent.decorator.BaseDecorator", - "datadog.trace.agent.decorator.ClientDecorator", - "datadog.trace.agent.decorator.DatabaseClientDecorator", - packageName + ".JDBCDecorator", - packageName + ".JDBCMaps", - packageName + ".JDBCMaps$DBInfo", - packageName + ".JDBCUtils", - }; + final JDBCConnectionUrlParser[] parsers = JDBCConnectionUrlParser.values(); + final List parserClasses = new ArrayList<>(parsers.length + 8); + + parserClasses.add(packageName + ".JDBCUtils"); + parserClasses.add(packageName + ".JDBCMaps"); + parserClasses.add(packageName + ".JDBCMaps$DBInfo"); + parserClasses.add(packageName + ".JDBCConnectionUrlParser"); + + parserClasses.add("datadog.trace.agent.decorator.BaseDecorator"); + parserClasses.add("datadog.trace.agent.decorator.ClientDecorator"); + parserClasses.add("datadog.trace.agent.decorator.DatabaseClientDecorator"); + parserClasses.add(packageName + ".JDBCDecorator"); + + for (final JDBCConnectionUrlParser parser : parsers) { + parserClasses.add(parser.getClass().getName()); + } + return parserClasses.toArray(new String[0]); } @Override diff --git a/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCConnectionUrlParserTest.groovy b/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCConnectionUrlParserTest.groovy index 3a4a969d98..8707645ebe 100644 --- a/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCConnectionUrlParserTest.groovy +++ b/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCConnectionUrlParserTest.groovy @@ -31,83 +31,96 @@ class JDBCConnectionUrlParserTest extends Specification { info == expected where: - url | format | user | host | port | instance + url | format | user | host | port | instance // https://jdbc.postgresql.org/documentation/94/connect.html - "jdbc:postgresql:///" | "postgresql" | null | "localhost" | 5432 | "" - "jdbc:postgresql://pghost" | "postgresql" | null | "pghost" | 5432 | "" - "jdbc:postgresql://pghost:11/pgdb?user=pguser&password=PW" | "postgresql" | "pguser" | "pghost" | 11 | "pgdb" + "jdbc:postgresql:///" | "postgresql" | null | "localhost" | 5432 | "" + "jdbc:postgresql://pghost" | "postgresql" | null | "pghost" | 5432 | "" + "jdbc:postgresql://pghost:11/pgdb?user=pguser&password=PW" | "postgresql" | "pguser" | "pghost" | 11 | "pgdb" // https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-configuration-properties.html - "jdbc:mysql:///" | "mysql" | null | "localhost" | 3306 | "" - "jdbc:mysql://myhost" | "mysql" | null | "myhost" | 3306 | "" - "jdbc:mysql://myhost?user=myuser&password=PW" | "mysql" | "myuser" | "myhost" | 3306 | "" - "jdbc:mysql://myhost:22/mydb?user=myuser&password=PW" | "mysql" | "myuser" | "myhost" | 22 | "mydb" - "jdbc:mariadb://mdbhost:33/mdbdb?user=mdbuser&password=PW" | "mariadb" | "mdbuser" | "mdbhost" | 33 | "mdbdb" + "jdbc:mysql:///" | "mysql" | null | "localhost" | 3306 | "" + "jdbc:mysql://myhost" | "mysql" | null | "myhost" | 3306 | "" + "jdbc:mysql://myhost?user=myuser&password=PW" | "mysql" | "myuser" | "myhost" | 3306 | "" + "jdbc:mysql://myhost:22/mydb?user=myuser&password=PW" | "mysql" | "myuser" | "myhost" | 22 | "mydb" + "jdbc:mariadb://mdbhost:33/mdbdb?user=mdbuser&password=PW" | "mariadb" | "mdbuser" | "mdbhost" | 33 | "mdbdb" //https://docs.microsoft.com/en-us/sql/connect/jdbc/building-the-connection-url - "jdbc:microsoft:sqlserver://;" | "sqlserver" | null | "localhost" | 1433 | "MSSQLSERVER" - "jdbc:sqlserver://sshost\\ssinstance:44;databaseName=ssdb;user=ssuser;password=pw" | "sqlserver" | "ssuser" | "sshost" | 44 | "ssinstance" - "jdbc:sqlserver://;serverName=sshost\\ssinstance:44;DatabaseName=;" | "sqlserver" | null | "sshost" | 44 | "ssinstance" - "jdbc:sqlserver://sshost;serverName=althost;DatabaseName=ssdb;" | "sqlserver" | null | "sshost" | 1433 | "MSSQLSERVER" - "jdbc:microsoft:sqlserver://sshost:44;DatabaseName=ssdb;user=ssuser;password=pw;user=ssuser2;" | "sqlserver" | "ssuser" | "sshost" | 44 | "MSSQLSERVER" + "jdbc:microsoft:sqlserver://;" | "sqlserver" | null | "localhost" | 1433 | "MSSQLSERVER" + "jdbc:sqlserver://sshost\\ssinstance:44;databaseName=ssdb;user=ssuser;password=pw" | "sqlserver" | "ssuser" | "sshost" | 44 | "ssinstance" + "jdbc:sqlserver://;serverName=sshost\\ssinstance:44;DatabaseName=;" | "sqlserver" | null | "sshost" | 44 | "ssinstance" + "jdbc:sqlserver://sshost;serverName=althost;DatabaseName=ssdb;" | "sqlserver" | null | "sshost" | 1433 | "MSSQLSERVER" + "jdbc:microsoft:sqlserver://sshost:44;DatabaseName=ssdb;user=ssuser;password=pw;user=ssuser2;" | "sqlserver" | "ssuser" | "sshost" | 44 | "MSSQLSERVER" - // TODO: -// "jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST= localhost )(PORT= 1521))" + -// "(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=orcl)))" | "oracle" | "orcluser" | "orclhost" | 55 | "orcldb" -// "jdbc:oracle:drivertype:orcluser/PW@orclhost:55/orcldb" | "oracle" | "orcluser" | "orclhost" | 55 | "orcldb" + // https://docs.oracle.com/cd/B28359_01/java.111/b31224/urls.htm + // https://docs.oracle.com/cd/B28359_01/java.111/b31224/jdbcthin.htm + "jdbc:oracle:thin:orcluser/PW@localhost:55:orclsn" | "oracle:thin" | "orcluser" | "localhost" | 55 | "orclsn" + "jdbc:oracle:thin:orcluser/PW@//orclhost:55/orclsn" | "oracle:thin" | "orcluser" | "orclhost" | 55 | "orclsn" + "jdbc:oracle:thin:orcluser/PW@127.0.0.1:orclsn" | "oracle:thin" | "orcluser" | "127.0.0.1" | 1521 | "orclsn" + "jdbc:oracle:thin:orcluser/PW@//orclhost/orclsn" | "oracle:thin" | "orcluser" | "orclhost" | 1521 | "orclsn" + "jdbc:oracle:thin:@//orclhost:55/orclsn" | "oracle:thin" | null | "orclhost" | 55 | "orclsn" + "jdbc:oracle:thin:@ldap://orclhost:55/some,cn=OracleContext,dc=com" | "oracle:thin" | null | "orclhost" | 55 | "some,cn=oraclecontext,dc=com" + "jdbc:oracle:thin:127.0.0.1:orclsn" | "oracle:thin" | null | "127.0.0.1" | 1521 | "orclsn" + "jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST= 127.0.0.1 )(POR T= 666))" + + "(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=orclsn)))" | "oracle:thin" | null | "127.0.0.1" | 1521 | "orclsn" + // https://docs.oracle.com/cd/B28359_01/java.111/b31224/instclnt.htm + "jdbc:oracle:drivertype:orcluser/PW@orclhost:55/orclsn" | "oracle:drivertype" | "orcluser" | "orclhost" | 55 | "orclsn" + "jdbc:oracle:oci8:@" | "oracle:oci8" | null | null | 1521 | null + "jdbc:oracle:oci8:@orclsn" | "oracle:oci8" | null | null | 1521 | "orclsn" + "jdbc:oracle:oci:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)( HOST = orclhost )" + + "( PORT = 55 ))(CONNECT_DATA=(SERVICE_NAME =orclsn )))" | "oracle:oci" | null | "orclhost" | 55 | "orclsn" // https://www.ibm.com/support/knowledgecenter/en/SSEPEK_10.0.0/java/src/tpc/imjcc_tjvjcccn.html // https://www.ibm.com/support/knowledgecenter/en/SSEPGG_10.5.0/com.ibm.db2.luw.apdv.java.doc/src/tpc/imjcc_r0052342.html - "jdbc:as400://ashost:66/asdb:user=asuser;password=PW;" | "as400" | "asuser" | "ashost" | 66 | "asdb" - "jdbc:db2://db2host:77/db2db:user=db2user;password=PW;" | "db2" | "db2user" | "db2host" | 77 | "db2db" + "jdbc:as400://ashost:66/asdb:user=asuser;password=PW;" | "as400" | "asuser" | "ashost" | 66 | "asdb" + "jdbc:db2://db2host:77/db2db:user=db2user;password=PW;" | "db2" | "db2user" | "db2host" | 77 | "db2db" // https://help.sap.com/viewer/0eec0d68141541d1b07893a39944924e/2.0.03/en-US/ff15928cf5594d78b841fbbe649f04b4.html - "jdbc:sap://saphost:88/?databaseName=sapdb&user=sapuser&password=PW" | "sap" | "sapuser" | "saphost" | 88 | "sapdb" + "jdbc:sap://saphost:88/?databaseName=sapdb&user=sapuser&password=PW" | "sap" | "sapuser" | "saphost" | 88 | "sapdb" // TODO: // "jdbc:informix-sqli://infxhost:99/infxdb:INFORMIXSERVER=infxsn;user=infxuser;password=PW" | "informix-sqli" | "infxuser" | "infxhost" | 99 | "infxdb" // "jdbc:informix-direct://infxdb:999;user=infxuser;password=PW" | "informix-direct" | "infxuser" | "infxhost" | 999 | "infxdb" // http://www.h2database.com/html/features.html#database_url - "jdbc:h2:mem:" | "h2:mem" | null | null | null | "" - "jdbc:h2:mem:h2db" | "h2:mem" | null | null | null | "h2db" - "jdbc:h2:tcp://h2host:111/path/h2db;user=h2user;password=PW" | "h2:tcp" | "h2user" | "h2host" | 111 | "path/h2db" - "jdbc:h2:ssl://h2host:111/path/h2db;user=h2user;password=PW" | "h2:ssl" | "h2user" | "h2host" | 111 | "path/h2db" - "jdbc:h2:/data/h2file" | "h2:file" | null | null | null | "/data/h2file" - "jdbc:h2:file:~/h2file;USER=h2user;PASSWORD=PW" | "h2:file" | null | null | null | "~/h2file" - "jdbc:h2:file:/data/h2file" | "h2:file" | null | null | null | "/data/h2file" - "jdbc:h2:file:C:/data/h2file" | "h2:file" | null | null | null | "c:/data/h2file" - "jdbc:h2:zip:~/db.zip!/h2zip" | "h2:zip" | null | null | null | "~/db.zip!/h2zip" + "jdbc:h2:mem:" | "h2:mem" | null | null | null | "" + "jdbc:h2:mem:h2db" | "h2:mem" | null | null | null | "h2db" + "jdbc:h2:tcp://h2host:111/path/h2db;user=h2user;password=PW" | "h2:tcp" | "h2user" | "h2host" | 111 | "path/h2db" + "jdbc:h2:ssl://h2host:111/path/h2db;user=h2user;password=PW" | "h2:ssl" | "h2user" | "h2host" | 111 | "path/h2db" + "jdbc:h2:/data/h2file" | "h2:file" | null | null | null | "/data/h2file" + "jdbc:h2:file:~/h2file;USER=h2user;PASSWORD=PW" | "h2:file" | null | null | null | "~/h2file" + "jdbc:h2:file:/data/h2file" | "h2:file" | null | null | null | "/data/h2file" + "jdbc:h2:file:C:/data/h2file" | "h2:file" | null | null | null | "c:/data/h2file" + "jdbc:h2:zip:~/db.zip!/h2zip" | "h2:zip" | null | null | null | "~/db.zip!/h2zip" // http://hsqldb.org/doc/2.0/guide/dbproperties-chapt.html - "jdbc:hsqldb:hsdb" | "hsqldb:mem" | "SA" | null | null | "hsdb" - "jdbc:hsqldb:mem:hsdb" | "hsqldb:mem" | "SA" | null | null | "hsdb" - "jdbc:hsqldb:file:hsdb" | "hsqldb:file" | "SA" | null | null | "hsdb" - "jdbc:hsqldb:file:/loc/hsdb" | "hsqldb:file" | "SA" | null | null | "/loc/hsdb" - "jdbc:hsqldb:file:C:/hsdb" | "hsqldb:file" | "SA" | null | null | "c:/hsdb" - "jdbc:hsqldb:res:hsdb" | "hsqldb:res" | "SA" | null | null | "hsdb" - "jdbc:hsqldb:res:/cp/hsdb" | "hsqldb:res" | "SA" | null | null | "/cp/hsdb" - "jdbc:hsqldb:hsql://hshost:333/hsdb" | "hsqldb:hsql" | "SA" | "hshost" | 333 | "hsdb" - "jdbc:hsqldb:hsqls://hshost/hsdb" | "hsqldb:hsqls" | "SA" | "hshost" | 9001 | "hsdb" - "jdbc:hsqldb:http://hshost" | "hsqldb:http" | "SA" | "hshost" | 80 | null - "jdbc:hsqldb:http://hshost:333/hsdb" | "hsqldb:http" | "SA" | "hshost" | 333 | "hsdb" - "jdbc:hsqldb:https://127.0.0.1/hsdb" | "hsqldb:https" | "SA" | "127.0.0.1" | 443 | "hsdb" + "jdbc:hsqldb:hsdb" | "hsqldb:mem" | "SA" | null | null | "hsdb" + "jdbc:hsqldb:mem:hsdb" | "hsqldb:mem" | "SA" | null | null | "hsdb" + "jdbc:hsqldb:file:hsdb" | "hsqldb:file" | "SA" | null | null | "hsdb" + "jdbc:hsqldb:file:/loc/hsdb" | "hsqldb:file" | "SA" | null | null | "/loc/hsdb" + "jdbc:hsqldb:file:C:/hsdb" | "hsqldb:file" | "SA" | null | null | "c:/hsdb" + "jdbc:hsqldb:res:hsdb" | "hsqldb:res" | "SA" | null | null | "hsdb" + "jdbc:hsqldb:res:/cp/hsdb" | "hsqldb:res" | "SA" | null | null | "/cp/hsdb" + "jdbc:hsqldb:hsql://hshost:333/hsdb" | "hsqldb:hsql" | "SA" | "hshost" | 333 | "hsdb" + "jdbc:hsqldb:hsqls://hshost/hsdb" | "hsqldb:hsqls" | "SA" | "hshost" | 9001 | "hsdb" + "jdbc:hsqldb:http://hshost" | "hsqldb:http" | "SA" | "hshost" | 80 | null + "jdbc:hsqldb:http://hshost:333/hsdb" | "hsqldb:http" | "SA" | "hshost" | 333 | "hsdb" + "jdbc:hsqldb:https://127.0.0.1/hsdb" | "hsqldb:https" | "SA" | "127.0.0.1" | 443 | "hsdb" // https://db.apache.org/derby/papers/DerbyClientSpec.html#Connection+URL+Format // https://db.apache.org/derby/docs/10.8/devguide/cdevdvlp34964.html - "jdbc:derby:derbydb" | "derby:directory" | "APP" | null | null | "derbydb" - "jdbc:derby:derbydb;user=derbyuser;password=pw" | "derby:directory" | "derbyuser" | null | null | "derbydb" - "jdbc:derby:memory:derbydb" | "derby:memory" | "APP" | null | null | "derbydb" - "jdbc:derby:memory:;databaseName=derbydb" | "derby:memory" | "APP" | null | null | "derbydb" - "jdbc:derby:memory:derbydb;databaseName=altdb" | "derby:memory" | "APP" | null | null | "derbydb" - "jdbc:derby:memory:derbydb;user=derbyuser;password=pw" | "derby:memory" | "derbyuser" | null | null | "derbydb" - "jdbc:derby://derbyhost:222/memory:derbydb;create=true" | "derby:network" | "APP" | "derbyhost" | 222 | "derbydb" - "jdbc:derby://derbyhost/memory:derbydb;create=true;user=derbyuser;password=pw" | "derby:network" | "derbyuser" | "derbyhost" | 1527 | "derbydb" - "jdbc:derby://127.0.0.1:1527/memory:derbydb;create=true;user=derbyuser;password=pw" | "derby:network" | "derbyuser" | "127.0.0.1" | 1527 | "derbydb" - "jdbc:derby:directory:derbydb;user=derbyuser;password=pw" | "derby:directory" | "derbyuser" | null | null | "derbydb" - "jdbc:derby:classpath:/some/derbydb;user=derbyuser;password=pw" | "derby:classpath" | "derbyuser" | null | null | "/some/derbydb" - "jdbc:derby:jar:/derbydb;user=derbyuser;password=pw" | "derby:jar" | "derbyuser" | null | null | "/derbydb" - "jdbc:derby:jar:(~/path/to/db.jar)/other/derbydb;user=derbyuser;password=pw" | "derby:jar" | "derbyuser" | null | null | "(~/path/to/db.jar)/other/derbydb" + "jdbc:derby:derbydb" | "derby:directory" | "APP" | null | null | "derbydb" + "jdbc:derby:derbydb;user=derbyuser;password=pw" | "derby:directory" | "derbyuser" | null | null | "derbydb" + "jdbc:derby:memory:derbydb" | "derby:memory" | "APP" | null | null | "derbydb" + "jdbc:derby:memory:;databaseName=derbydb" | "derby:memory" | "APP" | null | null | "derbydb" + "jdbc:derby:memory:derbydb;databaseName=altdb" | "derby:memory" | "APP" | null | null | "derbydb" + "jdbc:derby:memory:derbydb;user=derbyuser;password=pw" | "derby:memory" | "derbyuser" | null | null | "derbydb" + "jdbc:derby://derbyhost:222/memory:derbydb;create=true" | "derby:network" | "APP" | "derbyhost" | 222 | "derbydb" + "jdbc:derby://derbyhost/memory:derbydb;create=true;user=derbyuser;password=pw" | "derby:network" | "derbyuser" | "derbyhost" | 1527 | "derbydb" + "jdbc:derby://127.0.0.1:1527/memory:derbydb;create=true;user=derbyuser;password=pw" | "derby:network" | "derbyuser" | "127.0.0.1" | 1527 | "derbydb" + "jdbc:derby:directory:derbydb;user=derbyuser;password=pw" | "derby:directory" | "derbyuser" | null | null | "derbydb" + "jdbc:derby:classpath:/some/derbydb;user=derbyuser;password=pw" | "derby:classpath" | "derbyuser" | null | null | "/some/derbydb" + "jdbc:derby:jar:/derbydb;user=derbyuser;password=pw" | "derby:jar" | "derbyuser" | null | null | "/derbydb" + "jdbc:derby:jar:(~/path/to/db.jar)/other/derbydb;user=derbyuser;password=pw" | "derby:jar" | "derbyuser" | null | null | "(~/path/to/db.jar)/other/derbydb" expected = new JDBCMaps.DBInfo(format, null, user, instance, null, host, port) } diff --git a/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCInstrumentationTest.groovy b/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCInstrumentationTest.groovy index c903b7fc33..995d6d71f9 100644 --- a/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCInstrumentationTest.groovy +++ b/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCInstrumentationTest.groovy @@ -26,23 +26,23 @@ class JDBCInstrumentationTest extends AgentTestRunner { @Shared private Map jdbcUrls = [ - h2 : "jdbc:h2:mem:$dbName", - derby : "jdbc:derby:memory:$dbName", - hsqldb: "jdbc:hsqldb:mem:$dbName", + "h2:mem" : "jdbc:h2:mem:$dbName", + "derby:memory": "jdbc:derby:memory:$dbName", + "hsqldb:mem" : "jdbc:hsqldb:mem:$dbName", ] @Shared private Map jdbcDriverClassNames = [ - h2 : "org.h2.Driver", - derby : "org.apache.derby.jdbc.EmbeddedDriver", - hsqldb: "org.hsqldb.jdbc.JDBCDriver", + "h2:mem" : "org.h2.Driver", + "derby:memory": "org.apache.derby.jdbc.EmbeddedDriver", + "hsqldb:mem" : "org.hsqldb.jdbc.JDBCDriver", ] @Shared private Map jdbcUserNames = [ - h2 : null, - derby : "APP", - hsqldb: "SA", + "h2:mem" : null, + "derby:memory": "APP", + "hsqldb:mem" : "SA", ] @Shared @@ -76,7 +76,7 @@ class JDBCInstrumentationTest extends AgentTestRunner { def createTomcatDS(String dbType, String jdbcUrl) { DataSource ds = new org.apache.tomcat.jdbc.pool.DataSource() - def jdbcUrlToSet = dbType == "derby" ? jdbcUrl + ";create=true" : jdbcUrl + def jdbcUrlToSet = dbType == "derby:memory" ? jdbcUrl + ";create=true" : jdbcUrl ds.setUrl(jdbcUrlToSet) ds.setDriverClassName(jdbcDriverClassNames.get(dbType)) String username = jdbcUserNames.get(dbType) @@ -91,7 +91,7 @@ class JDBCInstrumentationTest extends AgentTestRunner { def createHikariDS(String dbType, String jdbcUrl) { HikariConfig config = new HikariConfig() - def jdbcUrlToSet = dbType == "derby" ? jdbcUrl + ";create=true" : jdbcUrl + def jdbcUrlToSet = dbType == "derby:memory" ? jdbcUrl + ";create=true" : jdbcUrl config.setJdbcUrl(jdbcUrlToSet) String username = jdbcUserNames.get(dbType) if (username != null) { @@ -109,7 +109,7 @@ class JDBCInstrumentationTest extends AgentTestRunner { def createC3P0DS(String dbType, String jdbcUrl) { DataSource ds = new ComboPooledDataSource() ds.setDriverClass(jdbcDriverClassNames.get(dbType)) - def jdbcUrlToSet = dbType == "derby" ? jdbcUrl + ";create=true" : jdbcUrl + def jdbcUrlToSet = dbType == "derby:memory" ? jdbcUrl + ";create=true" : jdbcUrl ds.setJdbcUrl(jdbcUrlToSet) String username = jdbcUserNames.get(dbType) if (username != null) { @@ -193,22 +193,22 @@ class JDBCInstrumentationTest extends AgentTestRunner { connection.close() where: - driver | connection | username | query - "h2" | new Driver().connect(jdbcUrls.get("h2"), null) | null | "SELECT 3" - "derby" | new EmbeddedDriver().connect(jdbcUrls.get("derby"), null) | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "hsqldb" | new JDBCDriver().connect(jdbcUrls.get("hsqldb"), null) | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" - "h2" | new Driver().connect(jdbcUrls.get("h2"), connectionProps) | null | "SELECT 3" - "derby" | new EmbeddedDriver().connect(jdbcUrls.get("derby"), connectionProps) | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "hsqldb" | new JDBCDriver().connect(jdbcUrls.get("hsqldb"), connectionProps) | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" - "h2" | cpDatasources.get("tomcat").get("h2").getConnection() | null | "SELECT 3" - "derby" | cpDatasources.get("tomcat").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "hsqldb" | cpDatasources.get("tomcat").get("hsqldb").getConnection() | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" - "h2" | cpDatasources.get("hikari").get("h2").getConnection() | null | "SELECT 3" - "derby" | cpDatasources.get("hikari").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "hsqldb" | cpDatasources.get("hikari").get("hsqldb").getConnection() | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" - "h2" | cpDatasources.get("c3p0").get("h2").getConnection() | null | "SELECT 3" - "derby" | cpDatasources.get("c3p0").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "hsqldb" | cpDatasources.get("c3p0").get("hsqldb").getConnection() | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" + driver | connection | username | query + "h2:mem" | new Driver().connect(jdbcUrls.get("h2:mem"), null) | null | "SELECT 3" + "derby:memory" | new EmbeddedDriver().connect(jdbcUrls.get("derby:memory"), null) | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "hsqldb:mem" | new JDBCDriver().connect(jdbcUrls.get("hsqldb:mem"), null) | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" + "h2:mem" | new Driver().connect(jdbcUrls.get("h2:mem"), connectionProps) | null | "SELECT 3" + "derby:memory" | new EmbeddedDriver().connect(jdbcUrls.get("derby:memory"), connectionProps) | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "hsqldb:mem" | new JDBCDriver().connect(jdbcUrls.get("hsqldb:mem"), connectionProps) | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" + "h2:mem" | cpDatasources.get("tomcat").get("h2:mem").getConnection() | null | "SELECT 3" + "derby:memory" | cpDatasources.get("tomcat").get("derby:memory").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "hsqldb:mem" | cpDatasources.get("tomcat").get("hsqldb:mem").getConnection() | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" + "h2:mem" | cpDatasources.get("hikari").get("h2:mem").getConnection() | null | "SELECT 3" + "derby:memory" | cpDatasources.get("hikari").get("derby:memory").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "hsqldb:mem" | cpDatasources.get("hikari").get("hsqldb:mem").getConnection() | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" + "h2:mem" | cpDatasources.get("c3p0").get("h2:mem").getConnection() | null | "SELECT 3" + "derby:memory" | cpDatasources.get("c3p0").get("derby:memory").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "hsqldb:mem" | cpDatasources.get("c3p0").get("hsqldb:mem").getConnection() | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" } @Unroll @@ -256,15 +256,15 @@ class JDBCInstrumentationTest extends AgentTestRunner { connection.close() where: - driver | connection | username | query - "h2" | new Driver().connect(jdbcUrls.get("h2"), null) | null | "SELECT 3" - "derby" | new EmbeddedDriver().connect(jdbcUrls.get("derby"), null) | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "h2" | cpDatasources.get("tomcat").get("h2").getConnection() | null | "SELECT 3" - "derby" | cpDatasources.get("tomcat").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "h2" | cpDatasources.get("hikari").get("h2").getConnection() | null | "SELECT 3" - "derby" | cpDatasources.get("hikari").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "h2" | cpDatasources.get("c3p0").get("h2").getConnection() | null | "SELECT 3" - "derby" | cpDatasources.get("c3p0").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + driver | connection | username | query + "h2:mem" | new Driver().connect(jdbcUrls.get("h2:mem"), null) | null | "SELECT 3" + "derby:memory" | new EmbeddedDriver().connect(jdbcUrls.get("derby:memory"), null) | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "h2:mem" | cpDatasources.get("tomcat").get("h2:mem").getConnection() | null | "SELECT 3" + "derby:memory" | cpDatasources.get("tomcat").get("derby:memory").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "h2:mem" | cpDatasources.get("hikari").get("h2:mem").getConnection() | null | "SELECT 3" + "derby:memory" | cpDatasources.get("hikari").get("derby:memory").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "h2:mem" | cpDatasources.get("c3p0").get("h2:mem").getConnection() | null | "SELECT 3" + "derby:memory" | cpDatasources.get("c3p0").get("derby:memory").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" } @Unroll @@ -311,15 +311,15 @@ class JDBCInstrumentationTest extends AgentTestRunner { connection.close() where: - driver | connection | username | query - "h2" | new Driver().connect(jdbcUrls.get("h2"), null) | null | "SELECT 3" - "derby" | new EmbeddedDriver().connect(jdbcUrls.get("derby"), null) | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "h2" | cpDatasources.get("tomcat").get("h2").getConnection() | null | "SELECT 3" - "derby" | cpDatasources.get("tomcat").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "h2" | cpDatasources.get("hikari").get("h2").getConnection() | null | "SELECT 3" - "derby" | cpDatasources.get("hikari").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "h2" | cpDatasources.get("c3p0").get("h2").getConnection() | null | "SELECT 3" - "derby" | cpDatasources.get("c3p0").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + driver | connection | username | query + "h2:mem" | new Driver().connect(jdbcUrls.get("h2:mem"), null) | null | "SELECT 3" + "derby:memory" | new EmbeddedDriver().connect(jdbcUrls.get("derby:memory"), null) | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "h2:mem" | cpDatasources.get("tomcat").get("h2:mem").getConnection() | null | "SELECT 3" + "derby:memory" | cpDatasources.get("tomcat").get("derby:memory").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "h2:mem" | cpDatasources.get("hikari").get("h2:mem").getConnection() | null | "SELECT 3" + "derby:memory" | cpDatasources.get("hikari").get("derby:memory").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "h2:mem" | cpDatasources.get("c3p0").get("h2:mem").getConnection() | null | "SELECT 3" + "derby:memory" | cpDatasources.get("c3p0").get("derby:memory").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" } @Unroll @@ -366,15 +366,15 @@ class JDBCInstrumentationTest extends AgentTestRunner { connection.close() where: - driver | connection | username | query - "h2" | new Driver().connect(jdbcUrls.get("h2"), null) | null | "SELECT 3" - "derby" | new EmbeddedDriver().connect(jdbcUrls.get("derby"), null) | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "h2" | cpDatasources.get("tomcat").get("h2").getConnection() | null | "SELECT 3" - "derby" | cpDatasources.get("tomcat").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "h2" | cpDatasources.get("hikari").get("h2").getConnection() | null | "SELECT 3" - "derby" | cpDatasources.get("hikari").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "h2" | cpDatasources.get("c3p0").get("h2").getConnection() | null | "SELECT 3" - "derby" | cpDatasources.get("c3p0").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + driver | connection | username | query + "h2:mem" | new Driver().connect(jdbcUrls.get("h2:mem"), null) | null | "SELECT 3" + "derby:memory" | new EmbeddedDriver().connect(jdbcUrls.get("derby:memory"), null) | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "h2:mem" | cpDatasources.get("tomcat").get("h2:mem").getConnection() | null | "SELECT 3" + "derby:memory" | cpDatasources.get("tomcat").get("derby:memory").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "h2:mem" | cpDatasources.get("hikari").get("h2:mem").getConnection() | null | "SELECT 3" + "derby:memory" | cpDatasources.get("hikari").get("derby:memory").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "h2:mem" | cpDatasources.get("c3p0").get("h2:mem").getConnection() | null | "SELECT 3" + "derby:memory" | cpDatasources.get("c3p0").get("derby:memory").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" } @Unroll @@ -421,19 +421,19 @@ class JDBCInstrumentationTest extends AgentTestRunner { connection.close() where: - driver | connection | username | query - "h2" | new Driver().connect(jdbcUrls.get("h2"), null) | null | "CREATE TABLE S_H2 (id INTEGER not NULL, PRIMARY KEY ( id ))" - "derby" | new EmbeddedDriver().connect(jdbcUrls.get("derby"), null) | "APP" | "CREATE TABLE S_DERBY (id INTEGER not NULL, PRIMARY KEY ( id ))" - "hsqldb" | new JDBCDriver().connect(jdbcUrls.get("hsqldb"), null) | "SA" | "CREATE TABLE PUBLIC.S_HSQLDB (id INTEGER not NULL, PRIMARY KEY ( id ))" - "h2" | cpDatasources.get("tomcat").get("h2").getConnection() | null | "CREATE TABLE S_H2_TOMCAT (id INTEGER not NULL, PRIMARY KEY ( id ))" - "derby" | cpDatasources.get("tomcat").get("derby").getConnection() | "APP" | "CREATE TABLE S_DERBY_TOMCAT (id INTEGER not NULL, PRIMARY KEY ( id ))" - "hsqldb" | cpDatasources.get("tomcat").get("hsqldb").getConnection() | "SA" | "CREATE TABLE PUBLIC.S_HSQLDB_TOMCAT (id INTEGER not NULL, PRIMARY KEY ( id ))" - "h2" | cpDatasources.get("hikari").get("h2").getConnection() | null | "CREATE TABLE S_H2_HIKARI (id INTEGER not NULL, PRIMARY KEY ( id ))" - "derby" | cpDatasources.get("hikari").get("derby").getConnection() | "APP" | "CREATE TABLE S_DERBY_HIKARI (id INTEGER not NULL, PRIMARY KEY ( id ))" - "hsqldb" | cpDatasources.get("hikari").get("hsqldb").getConnection() | "SA" | "CREATE TABLE PUBLIC.S_HSQLDB_HIKARI (id INTEGER not NULL, PRIMARY KEY ( id ))" - "h2" | cpDatasources.get("c3p0").get("h2").getConnection() | null | "CREATE TABLE S_H2_C3P0 (id INTEGER not NULL, PRIMARY KEY ( id ))" - "derby" | cpDatasources.get("c3p0").get("derby").getConnection() | "APP" | "CREATE TABLE S_DERBY_C3P0 (id INTEGER not NULL, PRIMARY KEY ( id ))" - "hsqldb" | cpDatasources.get("c3p0").get("hsqldb").getConnection() | "SA" | "CREATE TABLE PUBLIC.S_HSQLDB_C3P0 (id INTEGER not NULL, PRIMARY KEY ( id ))" + driver | connection | username | query + "h2:mem" | new Driver().connect(jdbcUrls.get("h2:mem"), null) | null | "CREATE TABLE S_H2 (id INTEGER not NULL, PRIMARY KEY ( id ))" + "derby:memory" | new EmbeddedDriver().connect(jdbcUrls.get("derby:memory"), null) | "APP" | "CREATE TABLE S_DERBY (id INTEGER not NULL, PRIMARY KEY ( id ))" + "hsqldb:mem" | new JDBCDriver().connect(jdbcUrls.get("hsqldb:mem"), null) | "SA" | "CREATE TABLE PUBLIC.S_HSQLDB (id INTEGER not NULL, PRIMARY KEY ( id ))" + "h2:mem" | cpDatasources.get("tomcat").get("h2:mem").getConnection() | null | "CREATE TABLE S_H2_TOMCAT (id INTEGER not NULL, PRIMARY KEY ( id ))" + "derby:memory" | cpDatasources.get("tomcat").get("derby:memory").getConnection() | "APP" | "CREATE TABLE S_DERBY_TOMCAT (id INTEGER not NULL, PRIMARY KEY ( id ))" + "hsqldb:mem" | cpDatasources.get("tomcat").get("hsqldb:mem").getConnection() | "SA" | "CREATE TABLE PUBLIC.S_HSQLDB_TOMCAT (id INTEGER not NULL, PRIMARY KEY ( id ))" + "h2:mem" | cpDatasources.get("hikari").get("h2:mem").getConnection() | null | "CREATE TABLE S_H2_HIKARI (id INTEGER not NULL, PRIMARY KEY ( id ))" + "derby:memory" | cpDatasources.get("hikari").get("derby:memory").getConnection() | "APP" | "CREATE TABLE S_DERBY_HIKARI (id INTEGER not NULL, PRIMARY KEY ( id ))" + "hsqldb:mem" | cpDatasources.get("hikari").get("hsqldb:mem").getConnection() | "SA" | "CREATE TABLE PUBLIC.S_HSQLDB_HIKARI (id INTEGER not NULL, PRIMARY KEY ( id ))" + "h2:mem" | cpDatasources.get("c3p0").get("h2:mem").getConnection() | null | "CREATE TABLE S_H2_C3P0 (id INTEGER not NULL, PRIMARY KEY ( id ))" + "derby:memory" | cpDatasources.get("c3p0").get("derby:memory").getConnection() | "APP" | "CREATE TABLE S_DERBY_C3P0 (id INTEGER not NULL, PRIMARY KEY ( id ))" + "hsqldb:mem" | cpDatasources.get("c3p0").get("hsqldb:mem").getConnection() | "SA" | "CREATE TABLE PUBLIC.S_HSQLDB_C3P0 (id INTEGER not NULL, PRIMARY KEY ( id ))" } @Unroll @@ -479,15 +479,15 @@ class JDBCInstrumentationTest extends AgentTestRunner { connection.close() where: - driver | connection | username | query - "h2" | new Driver().connect(jdbcUrls.get("h2"), null) | null | "CREATE TABLE PS_H2 (id INTEGER not NULL, PRIMARY KEY ( id ))" - "derby" | new EmbeddedDriver().connect(jdbcUrls.get("derby"), null) | "APP" | "CREATE TABLE PS_DERBY (id INTEGER not NULL, PRIMARY KEY ( id ))" - "h2" | cpDatasources.get("tomcat").get("h2").getConnection() | null | "CREATE TABLE PS_H2_TOMCAT (id INTEGER not NULL, PRIMARY KEY ( id ))" - "derby" | cpDatasources.get("tomcat").get("derby").getConnection() | "APP" | "CREATE TABLE PS_DERBY_TOMCAT (id INTEGER not NULL, PRIMARY KEY ( id ))" - "h2" | cpDatasources.get("hikari").get("h2").getConnection() | null | "CREATE TABLE PS_H2_HIKARI (id INTEGER not NULL, PRIMARY KEY ( id ))" - "derby" | cpDatasources.get("hikari").get("derby").getConnection() | "APP" | "CREATE TABLE PS_DERBY_HIKARI (id INTEGER not NULL, PRIMARY KEY ( id ))" - "h2" | cpDatasources.get("c3p0").get("h2").getConnection() | null | "CREATE TABLE PS_H2_C3P0 (id INTEGER not NULL, PRIMARY KEY ( id ))" - "derby" | cpDatasources.get("c3p0").get("derby").getConnection() | "APP" | "CREATE TABLE PS_DERBY_C3P0 (id INTEGER not NULL, PRIMARY KEY ( id ))" + driver | connection | username | query + "h2:mem" | new Driver().connect(jdbcUrls.get("h2:mem"), null) | null | "CREATE TABLE PS_H2 (id INTEGER not NULL, PRIMARY KEY ( id ))" + "derby:memory" | new EmbeddedDriver().connect(jdbcUrls.get("derby:memory"), null) | "APP" | "CREATE TABLE PS_DERBY (id INTEGER not NULL, PRIMARY KEY ( id ))" + "h2:mem" | cpDatasources.get("tomcat").get("h2:mem").getConnection() | null | "CREATE TABLE PS_H2_TOMCAT (id INTEGER not NULL, PRIMARY KEY ( id ))" + "derby:memory" | cpDatasources.get("tomcat").get("derby:memory").getConnection() | "APP" | "CREATE TABLE PS_DERBY_TOMCAT (id INTEGER not NULL, PRIMARY KEY ( id ))" + "h2:mem" | cpDatasources.get("hikari").get("h2:mem").getConnection() | null | "CREATE TABLE PS_H2_HIKARI (id INTEGER not NULL, PRIMARY KEY ( id ))" + "derby:memory" | cpDatasources.get("hikari").get("derby:memory").getConnection() | "APP" | "CREATE TABLE PS_DERBY_HIKARI (id INTEGER not NULL, PRIMARY KEY ( id ))" + "h2:mem" | cpDatasources.get("c3p0").get("h2:mem").getConnection() | null | "CREATE TABLE PS_H2_C3P0 (id INTEGER not NULL, PRIMARY KEY ( id ))" + "derby:memory" | cpDatasources.get("c3p0").get("derby:memory").getConnection() | "APP" | "CREATE TABLE PS_DERBY_C3P0 (id INTEGER not NULL, PRIMARY KEY ( id ))" } @@ -558,17 +558,17 @@ class JDBCInstrumentationTest extends AgentTestRunner { } where: - prepareStatement | driver | driverClass | url | username | query - true | "h2" | new Driver() | "jdbc:h2:mem:" + dbName | null | "SELECT 3;" - true | "derby" | new EmbeddedDriver() | "jdbc:derby:memory:" + dbName + ";create=true" | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - false | "h2" | new Driver() | "jdbc:h2:mem:" + dbName | null | "SELECT 3;" - false | "derby" | new EmbeddedDriver() | "jdbc:derby:memory:" + dbName + ";create=true" | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + prepareStatement | driver | driverClass | url | username | query + true | "h2:mem" | new Driver() | "jdbc:h2:mem:" + dbName | null | "SELECT 3;" + true | "derby:memory" | new EmbeddedDriver() | "jdbc:derby:memory:" + dbName + ";create=true" | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + false | "h2:mem" | new Driver() | "jdbc:h2:mem:" + dbName | null | "SELECT 3;" + false | "derby:memory" | new EmbeddedDriver() | "jdbc:derby:memory:" + dbName + ";create=true" | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" } @Unroll def "#connectionPoolName connections should be cached in case of wrapped connections"() { setup: - String dbType = "hsqldb" + String dbType = "hsqldb:mem" DataSource ds = createDS(connectionPoolName, dbType, jdbcUrls.get(dbType)) String query = "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" int numQueries = 5 From 0807598d1602ddff36acf1334753d64c6a49105e Mon Sep 17 00:00:00 2001 From: Tyler Benson Date: Mon, 10 Jun 2019 12:02:14 -0700 Subject: [PATCH 3/7] Populate settings from properties and add MariaDB alt styles --- .../trace/instrumentation/jdbc/DBInfo.java | 17 + .../jdbc/DriverInstrumentation.java | 5 +- .../jdbc/JDBCConnectionUrlParser.java | 724 ++++++++++-------- .../instrumentation/jdbc/JDBCDecorator.java | 18 +- .../trace/instrumentation/jdbc/JDBCMaps.java | 15 - .../PreparedStatementInstrumentation.java | 3 +- .../jdbc/StatementInstrumentation.java | 3 +- .../groovy/JDBCConnectionUrlParserTest.groovy | 192 +++-- 8 files changed, 564 insertions(+), 413 deletions(-) create mode 100644 dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DBInfo.java diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DBInfo.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DBInfo.java new file mode 100644 index 0000000000..99adf4c8ff --- /dev/null +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DBInfo.java @@ -0,0 +1,17 @@ +package datadog.trace.instrumentation.jdbc; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder(builderClassName = "Builder", toBuilder = true) +public class DBInfo { + public static DBInfo DEFAULT = new Builder().type("database").build(); + private final String type; + private final String url; + private final String user; + private final String instance; + private final String db; + private final String host; + private final Integer port; +} diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DriverInstrumentation.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DriverInstrumentation.java index 7512065d5b..33c258284a 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DriverInstrumentation.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DriverInstrumentation.java @@ -38,8 +38,9 @@ public final class DriverInstrumentation extends Instrumenter.Default { final JDBCConnectionUrlParser[] parsers = JDBCConnectionUrlParser.values(); final List parserClasses = new ArrayList<>(parsers.length + 3); + parserClasses.add(packageName + ".DBInfo"); + parserClasses.add(packageName + ".DBInfo$Builder"); parserClasses.add(packageName + ".JDBCMaps"); - parserClasses.add(packageName + ".JDBCMaps$DBInfo"); parserClasses.add(packageName + ".JDBCConnectionUrlParser"); for (final JDBCConnectionUrlParser parser : parsers) { @@ -64,7 +65,7 @@ public final class DriverInstrumentation extends Instrumenter.Default { @Advice.Argument(0) final String url, @Advice.Argument(1) final Properties props, @Advice.Return final Connection connection) { - final JDBCMaps.DBInfo dbInfo = JDBCConnectionUrlParser.parse(url, props); + final DBInfo dbInfo = JDBCConnectionUrlParser.parse(url, props); JDBCMaps.connectionInfo.put(connection, dbInfo); } } diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCConnectionUrlParser.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCConnectionUrlParser.java index 8cf475eb49..7cd2453805 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCConnectionUrlParser.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCConnectionUrlParser.java @@ -1,11 +1,12 @@ package datadog.trace.instrumentation.jdbc; -import static datadog.trace.instrumentation.jdbc.JDBCMaps.DBInfo.DEFAULT; +import static datadog.trace.instrumentation.jdbc.DBInfo.DEFAULT; import datadog.trace.bootstrap.ExceptionLogger; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URLDecoder; +import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; @@ -14,124 +15,125 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; /** - * Structured as an enum instead of a class hierarchy to allow iterating through the parsers, plus - * the added benefit of only a single class to inject. + * Structured as an enum instead of a class hierarchy to allow iterating through the parsers + * automatically without having to maintain a separate list of parsers. */ public enum JDBCConnectionUrlParser { GENERIC_URL_LIKE() { @Override - JDBCMaps.DBInfo doParse(final String jdbcUrl, final Properties props) { + DBInfo.Builder doParse(final String jdbcUrl, final DBInfo.Builder builder) { try { // Attempt generic parsing final URI uri = new URI(jdbcUrl); - String user = uri.getUserInfo(); - String databaseName = null; - if (uri.getQuery() != null) { - final Map queryParams = splitQuery(uri.getQuery(), "&"); + populateStandardProperties(builder, splitQuery(uri.getQuery(), "&")); - if (user == null) { - user = queryParams.get("user"); - } - databaseName = queryParams.get("databasename"); + final String user = uri.getUserInfo(); + if (user != null) { + builder.user(user); } String path = uri.getPath(); if (path.startsWith("/")) { path = path.substring(1); } + if (!path.isEmpty()) { + builder.db(path); + } - return new JDBCMaps.DBInfo( - uri.getScheme(), null, user, path, databaseName, uri.getHost(), uri.getPort()); + if (uri.getHost() != null) { + builder.host(uri.getHost()); + } + + if (uri.getPort() > 0) { + builder.port(uri.getPort()); + } + + return builder.type(uri.getScheme()); } catch (final Exception e) { - return DEFAULT; + return builder; } } }, MODIFIED_URL_LIKE() { - private static final String DEFAULT_HOST = "localhost"; - @Override - JDBCMaps.DBInfo doParse(final String jdbcUrl, final Properties props) { - try { + DBInfo.Builder doParse(final String jdbcUrl, final DBInfo.Builder builder) { + final String type; + String serverName = ""; + Integer port = null; + String instanceName = null; + final String user = null; - final String type; - String serverName = ""; - Integer port = null; - String databaseName = null; - String instanceName = null; - String user = null; + final int hostIndex = jdbcUrl.indexOf("://"); - final int hostIndex = jdbcUrl.indexOf("://"); - - if (hostIndex <= 0) { - return DEFAULT; - } - - type = jdbcUrl.substring(0, hostIndex); - - final String[] split; - if (type.equals("db2") || type.equals("as400")) { - if (jdbcUrl.contains("=")) { - final int paramLoc = jdbcUrl.lastIndexOf(":"); - split = new String[] {jdbcUrl.substring(0, paramLoc), jdbcUrl.substring(paramLoc + 1)}; - } else { - split = new String[] {jdbcUrl}; - } - } else { - split = jdbcUrl.split(";", 2); - } - - if (split.length > 1) { - final Map urlProps = splitQuery(split[1], ";"); - if (urlProps.containsKey("servername")) { - serverName = urlProps.get("servername"); - } - if (urlProps.containsKey("instancename")) { - instanceName = urlProps.get("instancename"); - } - if (urlProps.containsKey("databasename")) { - databaseName = urlProps.get("databasename"); - } - if (urlProps.containsKey("user")) { - user = urlProps.get("user"); - } - } - - final String urlServerName = split[0].substring(hostIndex + 3); - if (!urlServerName.isEmpty()) { - serverName = urlServerName; - } - - int instanceLoc = serverName.indexOf("/"); - if (instanceLoc > 1) { - instanceName = serverName.substring(instanceLoc + 1); - serverName = serverName.substring(0, instanceLoc); - } - - final int portLoc = serverName.indexOf(":"); - - if (portLoc > 1) { - port = Integer.parseInt(serverName.substring(portLoc + 1)); - serverName = serverName.substring(0, portLoc); - } - - instanceLoc = serverName.indexOf("\\"); - if (instanceLoc > 1) { - instanceName = serverName.substring(instanceLoc + 1); - serverName = serverName.substring(0, instanceLoc); - } - - if (serverName.isEmpty()) { - serverName = DEFAULT_HOST; - } - - return new JDBCMaps.DBInfo( - type, null, user, instanceName, null /* databaseName */, serverName, port); - } catch (final UnsupportedEncodingException e) { - return DEFAULT; + if (hostIndex <= 0) { + return builder; } + + type = jdbcUrl.substring(0, hostIndex); + + final String[] split; + if (type.equals("db2") || type.equals("as400")) { + if (jdbcUrl.contains("=")) { + final int paramLoc = jdbcUrl.lastIndexOf(":"); + split = new String[] {jdbcUrl.substring(0, paramLoc), jdbcUrl.substring(paramLoc + 1)}; + } else { + split = new String[] {jdbcUrl}; + } + } else { + split = jdbcUrl.split(";", 2); + } + + if (split.length > 1) { + final Map props = splitQuery(split[1], ";"); + populateStandardProperties(builder, props); + if (props.containsKey("servername")) { + serverName = props.get("servername"); + } + } + + final String urlServerName = split[0].substring(hostIndex + 3); + if (!urlServerName.isEmpty()) { + serverName = urlServerName; + } + + int instanceLoc = serverName.indexOf("/"); + if (instanceLoc > 1) { + instanceName = serverName.substring(instanceLoc + 1); + serverName = serverName.substring(0, instanceLoc); + } + + final int portLoc = serverName.indexOf(":"); + + if (portLoc > 1) { + port = Integer.parseInt(serverName.substring(portLoc + 1)); + serverName = serverName.substring(0, portLoc); + } + + instanceLoc = serverName.indexOf("\\"); + if (instanceLoc > 1) { + instanceName = serverName.substring(instanceLoc + 1); + serverName = serverName.substring(0, instanceLoc); + } + + if (instanceName != null) { + builder.instance(instanceName); + } + + if (!serverName.isEmpty()) { + builder.host(serverName); + } + + if (port != null) { + builder.port(port); + } + + if (user != null) { + builder.user(user); + } + + return builder.type(type); } }, @@ -140,18 +142,15 @@ public enum JDBCConnectionUrlParser { private static final int DEFAULT_PORT = 5432; @Override - JDBCMaps.DBInfo doParse(final String jdbcUrl, final Properties props) { - final JDBCMaps.DBInfo dbInfo = GENERIC_URL_LIKE.doParse(jdbcUrl, props); - final String host = dbInfo.getHost() == null ? DEFAULT_HOST : dbInfo.getHost(); - final int port = dbInfo.getPort() <= 0 ? DEFAULT_PORT : dbInfo.getPort(); - return new JDBCMaps.DBInfo( - dbInfo.getType(), - dbInfo.getUrl(), - dbInfo.getUser(), - dbInfo.getInstance(), - null, - host, - port); + DBInfo.Builder doParse(final String jdbcUrl, final DBInfo.Builder builder) { + final DBInfo dbInfo = builder.build(); + if (dbInfo.getHost() == null) { + builder.host(DEFAULT_HOST); + } + if (dbInfo.getPort() == null) { + builder.port(DEFAULT_PORT); + } + return GENERIC_URL_LIKE.doParse(jdbcUrl, builder); } }, @@ -160,18 +159,123 @@ public enum JDBCConnectionUrlParser { private static final int DEFAULT_PORT = 3306; @Override - JDBCMaps.DBInfo doParse(final String jdbcUrl, final Properties props) { - final JDBCMaps.DBInfo dbInfo = GENERIC_URL_LIKE.doParse(jdbcUrl, props); - final String host = dbInfo.getHost() == null ? DEFAULT_HOST : dbInfo.getHost(); - final int port = dbInfo.getPort() <= 0 ? DEFAULT_PORT : dbInfo.getPort(); - return new JDBCMaps.DBInfo( - dbInfo.getType(), - dbInfo.getUrl(), - dbInfo.getUser(), - dbInfo.getInstance(), - null, - host, - port); + DBInfo.Builder doParse(final String jdbcUrl, final DBInfo.Builder builder) { + final DBInfo dbInfo = builder.build(); + if (dbInfo.getHost() == null) { + builder.host(DEFAULT_HOST); + } + if (dbInfo.getPort() == null) { + builder.port(DEFAULT_PORT); + } + final int protoLoc = jdbcUrl.indexOf("://"); + final int typeEndLoc = dbInfo.getType().length(); + if (protoLoc > typeEndLoc) { + return MARIA_SUBPROTO + .doParse(jdbcUrl.substring(protoLoc + 3), builder) + .type(jdbcUrl.substring(0, protoLoc)); + } + if (protoLoc > 0) { + return GENERIC_URL_LIKE.doParse(jdbcUrl, builder); + } + + final int hostEndLoc; + final int portLoc = jdbcUrl.indexOf(":", typeEndLoc + 1); + final int dbLoc = jdbcUrl.indexOf("/", typeEndLoc); + final int paramLoc = jdbcUrl.indexOf("?", dbLoc); + + if (paramLoc > 0) { + populateStandardProperties(builder, splitQuery(jdbcUrl.substring(paramLoc + 1), "&")); + builder.db(jdbcUrl.substring(dbLoc + 1, paramLoc)); + } else { + builder.db(jdbcUrl.substring(dbLoc + 1)); + } + + if (portLoc > 0) { + hostEndLoc = portLoc; + try { + builder.port(Integer.parseInt(jdbcUrl.substring(portLoc + 1, dbLoc))); + } catch (final NumberFormatException e) { + } + } else { + hostEndLoc = dbLoc; + } + + builder.host(jdbcUrl.substring(typeEndLoc + 1, hostEndLoc)); + + return builder; + } + }, + + MARIA_SUBPROTO() { + @Override + DBInfo.Builder doParse(final String jdbcUrl, final DBInfo.Builder builder) { + final int hostEndLoc; + final int clusterSepLoc = jdbcUrl.indexOf(","); + final int ipv6End = jdbcUrl.startsWith("[") ? jdbcUrl.indexOf("]") : -1; + int portLoc = jdbcUrl.indexOf(":", Math.max(0, ipv6End)); + portLoc = clusterSepLoc < portLoc ? -1 : portLoc; + final int dbLoc = jdbcUrl.indexOf("/", Math.max(portLoc, clusterSepLoc)); + + final int paramLoc = jdbcUrl.indexOf("?", dbLoc); + + if (paramLoc > 0) { + populateStandardProperties(builder, splitQuery(jdbcUrl.substring(paramLoc + 1), "&")); + builder.db(jdbcUrl.substring(dbLoc + 1, paramLoc)); + } else { + builder.db(jdbcUrl.substring(dbLoc + 1)); + } + + if (jdbcUrl.startsWith("address=")) { + return MARIA_ADDRESS.doParse(jdbcUrl, builder); + } + + if (portLoc > 0) { + hostEndLoc = portLoc; + final int portEndLoc = clusterSepLoc > 0 ? clusterSepLoc : dbLoc; + try { + builder.port(Integer.parseInt(jdbcUrl.substring(portLoc + 1, portEndLoc))); + } catch (final NumberFormatException e) { + } + } else { + hostEndLoc = clusterSepLoc > 0 ? clusterSepLoc : dbLoc; + } + + if (ipv6End > 0) { + builder.host(jdbcUrl.substring(1, ipv6End)); + } else { + builder.host(jdbcUrl.substring(0, hostEndLoc)); + } + return builder; + } + }, + + MARIA_ADDRESS() { + private final Pattern HOST_REGEX = Pattern.compile("\\(\\s*host\\s*=\\s*([^ )]+)\\s*\\)"); + private final Pattern PORT_REGEX = Pattern.compile("\\(\\s*port\\s*=\\s*([\\d]+)\\s*\\)"); + private final Pattern USER_REGEX = Pattern.compile("\\(\\s*user\\s*=\\s*([^ )]+)\\s*\\)"); + + @Override + DBInfo.Builder doParse(String jdbcUrl, final DBInfo.Builder builder) { + final int addressEnd = jdbcUrl.indexOf(",address="); + if (addressEnd > 0) { + jdbcUrl = jdbcUrl.substring(0, addressEnd); + } + final Matcher hostMatcher = HOST_REGEX.matcher(jdbcUrl); + if (hostMatcher.find()) { + builder.host(hostMatcher.group(1)); + } + + final Matcher portMatcher = PORT_REGEX.matcher(jdbcUrl); + if (portMatcher.find()) { + builder.port(Integer.parseInt(portMatcher.group(1))); + } + + final Matcher userMatcher = USER_REGEX.matcher(jdbcUrl); + if (userMatcher.find()) { + builder.user(userMatcher.group(1)); + } + + return builder; } }, @@ -179,43 +283,40 @@ public enum JDBCConnectionUrlParser { private static final String DEFAULT_HOST = "localhost"; @Override - JDBCMaps.DBInfo doParse(final String jdbcUrl, final Properties props) { - final JDBCMaps.DBInfo dbInfo = GENERIC_URL_LIKE.doParse(jdbcUrl, props); - final String host = dbInfo.getHost() == null ? DEFAULT_HOST : dbInfo.getHost(); - return new JDBCMaps.DBInfo( - dbInfo.getType(), - dbInfo.getUrl(), - dbInfo.getUser(), - dbInfo.getDb(), - null, - host, - dbInfo.getPort()); + DBInfo.Builder doParse(final String jdbcUrl, final DBInfo.Builder builder) { + final DBInfo dbInfo = builder.build(); + if (dbInfo.getHost() == null) { + builder.host(DEFAULT_HOST); + } + return GENERIC_URL_LIKE.doParse(jdbcUrl, builder); } }, MSSQLSERVER("microsoft", "sqlserver") { + private static final String DEFAULT_HOST = "localhost"; private static final int DEFAULT_PORT = 1433; private static final String DEFAULT_INSTANCE = "MSSQLSERVER"; @Override - JDBCMaps.DBInfo doParse(String jdbcUrl, final Properties props) { + DBInfo.Builder doParse(String jdbcUrl, final DBInfo.Builder builder) { if (jdbcUrl.startsWith("microsoft:")) { jdbcUrl = jdbcUrl.substring("microsoft:".length()); } if (!jdbcUrl.startsWith("sqlserver://")) { - return DEFAULT; + return builder; } - - final JDBCMaps.DBInfo dbInfo = MODIFIED_URL_LIKE.doParse(jdbcUrl, props); - - return new JDBCMaps.DBInfo( - "sqlserver", - dbInfo.getUrl(), - dbInfo.getUser(), - dbInfo.getInstance() == null ? DEFAULT_INSTANCE : dbInfo.getInstance(), - dbInfo.getDb(), - dbInfo.getHost(), - dbInfo.getPort() == null ? DEFAULT_PORT : dbInfo.getPort()); + builder.type("sqlserver"); + final DBInfo dbInfo = builder.build(); + if (dbInfo.getInstance() == null) { + builder.instance(DEFAULT_INSTANCE); + } + if (dbInfo.getHost() == null) { + builder.host(DEFAULT_HOST); + } + if (dbInfo.getPort() == null) { + builder.port(DEFAULT_PORT); + } + return MODIFIED_URL_LIKE.doParse(jdbcUrl, builder); } }, @@ -223,18 +324,12 @@ public enum JDBCConnectionUrlParser { private static final int DEFAULT_PORT = 50000; @Override - JDBCMaps.DBInfo doParse(final String jdbcUrl, final Properties props) { - final JDBCMaps.DBInfo dbInfo = MODIFIED_URL_LIKE.doParse(jdbcUrl, props); - return dbInfo.getPort() != null - ? dbInfo - : new JDBCMaps.DBInfo( - dbInfo.getType(), - dbInfo.getUrl(), - dbInfo.getUser(), - dbInfo.getInstance(), - dbInfo.getDb(), - dbInfo.getHost(), - DEFAULT_PORT); + DBInfo.Builder doParse(final String jdbcUrl, final DBInfo.Builder builder) { + final DBInfo dbInfo = builder.build(); + if (dbInfo.getPort() == null) { + builder.port(DEFAULT_PORT); + } + return MODIFIED_URL_LIKE.doParse(jdbcUrl, builder); } }, @@ -242,31 +337,28 @@ public enum JDBCConnectionUrlParser { private static final int DEFAULT_PORT = 1521; @Override - JDBCMaps.DBInfo doParse(String jdbcUrl, final Properties props) { + DBInfo.Builder doParse(String jdbcUrl, final DBInfo.Builder builder) { final int typeEndIndex = jdbcUrl.indexOf(":", "oracle:".length()); final String type = jdbcUrl.substring(0, typeEndIndex); jdbcUrl = jdbcUrl.substring(typeEndIndex + 1); - final JDBCMaps.DBInfo dbInfo; - if (jdbcUrl.contains("@")) { - dbInfo = ORACLE_AT.doParse(jdbcUrl, props); - } else { - dbInfo = ORACLE_CONNECT_INFO.doParse(jdbcUrl, props); + builder.type(type); + final DBInfo dbInfo = builder.build(); + if (dbInfo.getPort() == null) { + builder.port(DEFAULT_PORT); + } + + if (jdbcUrl.contains("@")) { + return ORACLE_AT.doParse(jdbcUrl, builder); + } else { + return ORACLE_CONNECT_INFO.doParse(jdbcUrl, builder); } - return new JDBCMaps.DBInfo( - type, - dbInfo.getUrl(), - dbInfo.getUser(), - dbInfo.getInstance(), - dbInfo.getDb(), - dbInfo.getHost(), - dbInfo.getPort() == null ? DEFAULT_PORT : dbInfo.getPort()); } }, ORACLE_CONNECT_INFO() { @Override - JDBCMaps.DBInfo doParse(final String jdbcUrl, final Properties props) { + DBInfo.Builder doParse(final String jdbcUrl, final DBInfo.Builder builder) { final String host; final Integer port; @@ -307,7 +399,7 @@ public enum JDBCConnectionUrlParser { instance = jdbcUrl.substring(instanceLoc + 1); } else { if (jdbcUrl.isEmpty()) { - return DEFAULT; + return builder; } else { host = null; port = null; @@ -315,15 +407,21 @@ public enum JDBCConnectionUrlParser { } } } - return new JDBCMaps.DBInfo(null, null, null, instance, null, host, port); + if (host != null) { + builder.host(host); + } + if (port != null) { + builder.port(port); + } + return builder.instance(instance); } }, ORACLE_AT() { @Override - JDBCMaps.DBInfo doParse(final String jdbcUrl, final Properties props) { + DBInfo.Builder doParse(final String jdbcUrl, final DBInfo.Builder builder) { if (jdbcUrl.contains("@(description")) { - return ORACLE_AT_DESCRIPTION.doParse(jdbcUrl, props); + return ORACLE_AT_DESCRIPTION.doParse(jdbcUrl, builder); } final String user; @@ -345,20 +443,17 @@ public enum JDBCConnectionUrlParser { } else { hostStart = 0; } - final JDBCMaps.DBInfo dbInfo = - ORACLE_CONNECT_INFO.doParse(connectInfo.substring(hostStart), props); - - return new JDBCMaps.DBInfo( - null, - dbInfo.getUrl(), - user, - dbInfo.getInstance(), - dbInfo.getDb(), - dbInfo.getHost(), - dbInfo.getPort()); + if (user != null) { + builder.user(user); + } + return ORACLE_CONNECT_INFO.doParse(connectInfo.substring(hostStart), builder); } }, + /** + * This parser can locate incorrect data if multiple addresses are defined but not everything is + * defined in the first block. (It would locate data from subsequent address blocks. + */ ORACLE_AT_DESCRIPTION() { private final Pattern HOST_REGEX = Pattern.compile("\\(\\s*host\\s*=\\s*([^ )]+)\\s*\\)"); private final Pattern PORT_REGEX = Pattern.compile("\\(\\s*port\\s*=\\s*([\\d]+)\\s*\\)"); @@ -366,41 +461,30 @@ public enum JDBCConnectionUrlParser { Pattern.compile("\\(\\s*service_name\\s*=\\s*([^ )]+)\\s*\\)"); @Override - JDBCMaps.DBInfo doParse(final String jdbcUrl, final Properties props) { - final String user; - final String host; - final Integer port; - final String instance; - + DBInfo.Builder doParse(final String jdbcUrl, final DBInfo.Builder builder) { final String[] atSplit = jdbcUrl.split("@", 2); final int userInfoLoc = atSplit[0].indexOf("/"); if (userInfoLoc > 0) { - user = atSplit[0].substring(0, userInfoLoc); - } else { - user = null; + builder.user(atSplit[0].substring(0, userInfoLoc)); } - final String description = atSplit[1]; - final Matcher hostMatcher = HOST_REGEX.matcher(description); - final Matcher portMatcher = PORT_REGEX.matcher(description); - final Matcher instanceMatcher = INSTANCE_REGEX.matcher(description); + final Matcher hostMatcher = HOST_REGEX.matcher(atSplit[1]); if (hostMatcher.find()) { - host = hostMatcher.group(1); - } else { - host = null; + builder.host(hostMatcher.group(1)); } + + final Matcher portMatcher = PORT_REGEX.matcher(atSplit[1]); if (portMatcher.find()) { - port = Integer.parseInt(portMatcher.group(1)); - } else { - port = null; + builder.port(Integer.parseInt(portMatcher.group(1))); } + + final Matcher instanceMatcher = INSTANCE_REGEX.matcher(atSplit[1]); if (instanceMatcher.find()) { - instance = instanceMatcher.group(1); - } else { - instance = null; + builder.instance(instanceMatcher.group(1)); } - return new JDBCMaps.DBInfo(null, null, user, instance, null, host, port); + + return builder; } }, @@ -408,9 +492,9 @@ public enum JDBCConnectionUrlParser { private static final int DEFAULT_PORT = 8082; @Override - JDBCMaps.DBInfo doParse(final String jdbcUrl, final Properties props) { + DBInfo.Builder doParse(final String jdbcUrl, final DBInfo.Builder builder) { String type = "h2"; - String instance = null; + final String instance; final String h2Url = jdbcUrl.substring("h2:".length()); if (h2Url.startsWith("mem:")) { @@ -438,27 +522,17 @@ public enum JDBCConnectionUrlParser { instance = h2Url.substring("zip:".length()); } } else if (h2Url.startsWith("tcp:")) { - final JDBCMaps.DBInfo dbInfo = MODIFIED_URL_LIKE.doParse(jdbcUrl, props); - - return new JDBCMaps.DBInfo( - "h2:tcp", - dbInfo.getUrl(), - dbInfo.getUser(), - dbInfo.getInstance(), - dbInfo.getDb(), - dbInfo.getHost(), - dbInfo.getPort() == null ? DEFAULT_PORT : dbInfo.getPort()); + final DBInfo dbInfo = builder.build(); + if (dbInfo.getPort() == null) { + builder.port(DEFAULT_PORT); + } + return MODIFIED_URL_LIKE.doParse(jdbcUrl, builder).type("h2:tcp"); } else if (h2Url.startsWith("ssl:")) { - final JDBCMaps.DBInfo dbInfo = MODIFIED_URL_LIKE.doParse(jdbcUrl, props); - - return new JDBCMaps.DBInfo( - "h2:ssl", - dbInfo.getUrl(), - dbInfo.getUser(), - dbInfo.getInstance(), - dbInfo.getDb(), - dbInfo.getHost(), - dbInfo.getPort() == null ? DEFAULT_PORT : dbInfo.getPort()); + final DBInfo dbInfo = builder.build(); + if (dbInfo.getPort() == null) { + builder.port(DEFAULT_PORT); + } + return MODIFIED_URL_LIKE.doParse(jdbcUrl, builder).type("h2:ssl"); } else { type = "h2:file"; final int propLoc = h2Url.indexOf(";"); @@ -468,7 +542,10 @@ public enum JDBCConnectionUrlParser { instance = h2Url; } } - return new JDBCMaps.DBInfo(type, null, null, instance, null, null, null); + if (!instance.isEmpty()) { + builder.instance(instance); + } + return builder.type(type); } }, @@ -477,9 +554,13 @@ public enum JDBCConnectionUrlParser { private static final int DEFAULT_PORT = 9001; @Override - JDBCMaps.DBInfo doParse(final String jdbcUrl, final Properties props) { + DBInfo.Builder doParse(final String jdbcUrl, final DBInfo.Builder builder) { String type = "hsqldb"; String instance = null; + final DBInfo dbInfo = builder.build(); + if (dbInfo.getUser() == null) { + builder.user(DEFAULT_USER); + } final String hsqlUrl = jdbcUrl.substring("hsqldb:".length()); if (hsqlUrl.startsWith("mem:")) { type = "hsqldb:mem"; @@ -491,58 +572,30 @@ public enum JDBCConnectionUrlParser { type = "hsqldb:res"; instance = hsqlUrl.substring("res:".length()); } else if (hsqlUrl.startsWith("hsql:")) { - final JDBCMaps.DBInfo dbInfo = MODIFIED_URL_LIKE.doParse(jdbcUrl, props); - - return new JDBCMaps.DBInfo( - "hsqldb:hsql", - dbInfo.getUrl(), - dbInfo.getUser() == null ? DEFAULT_USER : dbInfo.getUser(), - dbInfo.getInstance(), - dbInfo.getDb(), - dbInfo.getHost(), - dbInfo.getPort() == null ? DEFAULT_PORT : dbInfo.getPort()); - + if (dbInfo.getPort() == null) { + builder.port(DEFAULT_PORT); + } + return MODIFIED_URL_LIKE.doParse(jdbcUrl, builder).type("hsqldb:hsql"); } else if (hsqlUrl.startsWith("hsqls:")) { - final JDBCMaps.DBInfo dbInfo = MODIFIED_URL_LIKE.doParse(jdbcUrl, props); - - return new JDBCMaps.DBInfo( - "hsqldb:hsqls", - dbInfo.getUrl(), - dbInfo.getUser() == null ? DEFAULT_USER : dbInfo.getUser(), - dbInfo.getInstance(), - dbInfo.getDb(), - dbInfo.getHost(), - dbInfo.getPort() == null ? DEFAULT_PORT : dbInfo.getPort()); - + if (dbInfo.getPort() == null) { + builder.port(DEFAULT_PORT); + } + return MODIFIED_URL_LIKE.doParse(jdbcUrl, builder).type("hsqldb:hsqls"); } else if (hsqlUrl.startsWith("http:")) { - final JDBCMaps.DBInfo dbInfo = MODIFIED_URL_LIKE.doParse(jdbcUrl, props); - - return new JDBCMaps.DBInfo( - "hsqldb:http", - dbInfo.getUrl(), - dbInfo.getUser() == null ? DEFAULT_USER : dbInfo.getUser(), - dbInfo.getInstance(), - dbInfo.getDb(), - dbInfo.getHost(), - dbInfo.getPort() == null ? 80 : dbInfo.getPort()); - + if (dbInfo.getPort() == null) { + builder.port(80); + } + return MODIFIED_URL_LIKE.doParse(jdbcUrl, builder).type("hsqldb:http"); } else if (hsqlUrl.startsWith("https:")) { - final JDBCMaps.DBInfo dbInfo = MODIFIED_URL_LIKE.doParse(jdbcUrl, props); - - return new JDBCMaps.DBInfo( - "hsqldb:https", - dbInfo.getUrl(), - dbInfo.getUser() == null ? DEFAULT_USER : dbInfo.getUser(), - dbInfo.getInstance(), - dbInfo.getDb(), - dbInfo.getHost(), - dbInfo.getPort() == null ? 443 : dbInfo.getPort()); - + if (dbInfo.getPort() == null) { + builder.port(443); + } + return MODIFIED_URL_LIKE.doParse(jdbcUrl, builder).type("hsqldb:https"); } else { type = "hsqldb:mem"; instance = hsqlUrl; } - return new JDBCMaps.DBInfo(type, null, DEFAULT_USER, instance, null, null, null); + return builder.type(type).instance(instance); } }, @@ -551,37 +604,21 @@ public enum JDBCConnectionUrlParser { private static final int DEFAULT_PORT = 1527; @Override - JDBCMaps.DBInfo doParse(final String jdbcUrl, final Properties props) { - String type = "derby"; + DBInfo.Builder doParse(final String jdbcUrl, final DBInfo.Builder builder) { + final String type; String instance = null; String host = null; - Integer port = null; - String user = DEFAULT_USER; - if (props != null) { - instance = props.getProperty("databasename", instance); - user = props.getProperty("user", user); + final DBInfo dbInfo = builder.build(); + if (dbInfo.getUser() == null) { + builder.user(DEFAULT_USER); } + final String derbyUrl = jdbcUrl.substring("derby:".length()); final String[] split = derbyUrl.split(";", 2); if (split.length > 1) { - try { - final Map urlProps = splitQuery(split[1], ";"); - if (urlProps.containsKey("databasename")) { - instance = urlProps.get("databasename"); - } - if (urlProps.containsKey("user")) { - user = urlProps.get("user"); - } - if (urlProps.containsKey("servername")) { - host = urlProps.get("servername"); - } - if (urlProps.containsKey("portnumber")) { - port = Integer.parseInt(urlProps.get("portnumber")); - } - } catch (final Exception e) { - } + populateStandardProperties(builder, splitQuery(split[1], ";")); } if (split[0].startsWith("memory:")) { @@ -610,6 +647,9 @@ public enum JDBCConnectionUrlParser { } } else if (split[0].startsWith("//")) { type = "derby:network"; + if (dbInfo.getPort() == null) { + builder.port(DEFAULT_PORT); + } String url = split[0].substring("//".length()); final int instanceLoc = url.indexOf("/"); if (instanceLoc >= 0) { @@ -623,10 +663,9 @@ public enum JDBCConnectionUrlParser { final int portLoc = url.indexOf(":"); if (portLoc > 0) { host = url.substring(0, portLoc); - port = Integer.parseInt(url.substring(portLoc + 1)); + builder.port(Integer.parseInt(url.substring(portLoc + 1))); } else { host = url; - port = DEFAULT_PORT; } } else { type = "derby:directory"; @@ -636,7 +675,10 @@ public enum JDBCConnectionUrlParser { } } - return new JDBCMaps.DBInfo(type, null, user, instance, null, host, port); + if (host != null) { + builder.host(host); + } + return builder.type(type).instance(instance); } }; @@ -656,9 +698,9 @@ public enum JDBCConnectionUrlParser { this.typeKeys = typeKeys; } - abstract JDBCMaps.DBInfo doParse(String jdbcUrl, final Properties props); + abstract DBInfo.Builder doParse(String jdbcUrl, final DBInfo.Builder builder); - public static JDBCMaps.DBInfo parse(String connectionUrl, final Properties props) { + public static DBInfo parse(String connectionUrl, final Properties props) { if (connectionUrl == null) { return DEFAULT; } @@ -679,34 +721,84 @@ public enum JDBCConnectionUrlParser { final String baseType = jdbcUrl.substring(0, typeLoc); + final DBInfo.Builder parsedProps = DEFAULT.toBuilder().type(baseType); + populateStandardProperties(parsedProps, props); + try { if (typeParsers.containsKey(baseType)) { // Delegate to specific parser - return typeParsers.get(baseType).doParse(jdbcUrl, props); + return typeParsers.get(baseType).doParse(jdbcUrl, parsedProps).build(); } - return GENERIC_URL_LIKE.doParse(connectionUrl, props); + return GENERIC_URL_LIKE.doParse(connectionUrl, parsedProps).build(); } catch (final Exception e) { ExceptionLogger.LOGGER.debug("Error parsing URL", e); - return DEFAULT; + return parsedProps.build(); } } // Source: https://stackoverflow.com/a/13592567 - private static Map splitQuery(final String query, final String separator) - throws UnsupportedEncodingException { + private static Map splitQuery(final String query, final String separator) { + if (query == null || query.isEmpty()) { + return Collections.emptyMap(); + } final Map query_pairs = new LinkedHashMap<>(); final String[] pairs = query.split(separator); for (final String pair : pairs) { - final int idx = pair.indexOf("="); - final String key = idx > 0 ? URLDecoder.decode(pair.substring(0, idx), "UTF-8") : pair; - if (!query_pairs.containsKey(key)) { - final String value = - idx > 0 && pair.length() > idx + 1 - ? URLDecoder.decode(pair.substring(idx + 1), "UTF-8") - : null; - query_pairs.put(key, value); + try { + final int idx = pair.indexOf("="); + final String key = idx > 0 ? URLDecoder.decode(pair.substring(0, idx), "UTF-8") : pair; + if (!query_pairs.containsKey(key)) { + final String value = + idx > 0 && pair.length() > idx + 1 + ? URLDecoder.decode(pair.substring(idx + 1), "UTF-8") + : null; + query_pairs.put(key, value); + } + } catch (final UnsupportedEncodingException e) { + // Ignore. } } return query_pairs; } + + private static void populateStandardProperties( + final DBInfo.Builder builder, final Map props) { + if (props != null && !props.isEmpty()) { + if (props.containsKey("user")) { + builder.user((String) props.get("user")); + } + + if (props.containsKey("databasename")) { + builder.db((String) props.get("databasename")); + } + if (props.containsKey("databaseName")) { + builder.db((String) props.get("databaseName")); + } + + if (props.containsKey("servername")) { + builder.host((String) props.get("servername")); + } + if (props.containsKey("serverName")) { + builder.host((String) props.get("serverName")); + } + + if (props.containsKey("portnumber")) { + final String portNumber = (String) props.get("portnumber"); + try { + builder.port(Integer.parseInt(portNumber)); + } catch (final NumberFormatException e) { + ExceptionLogger.LOGGER.debug("Error parsing portnumber property: " + portNumber, e); + } + } + + if (props.containsKey("portNumber")) { + final String portNumber = (String) props.get("portNumber"); + try { + builder.port(Integer.parseInt(portNumber)); + } catch (final NumberFormatException e) { + ExceptionLogger.LOGGER.debug("Error parsing portNumber property: " + portNumber, e); + } + } + } + } } diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCDecorator.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCDecorator.java index 213e18398c..8540f2ab67 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCDecorator.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCDecorator.java @@ -10,9 +10,11 @@ import java.sql.DatabaseMetaData; import java.sql.PreparedStatement; import java.sql.SQLException; -public class JDBCDecorator extends DatabaseClientDecorator { +public class JDBCDecorator extends DatabaseClientDecorator { public static final JDBCDecorator DECORATE = new JDBCDecorator(); + private static final String DB_QUERY = "DB Query"; + @Override protected String[] instrumentationNames() { return new String[] {"jdbc"}; @@ -39,17 +41,17 @@ public class JDBCDecorator extends DatabaseClientDecorator { } @Override - protected String dbUser(final JDBCMaps.DBInfo info) { + protected String dbUser(final DBInfo info) { return info.getUser(); } @Override - protected String dbInstance(final JDBCMaps.DBInfo info) { + protected String dbInstance(final DBInfo info) { return info.getInstance(); } public Span onConnection(final Span span, final Connection connection) { - JDBCMaps.DBInfo dbInfo = JDBCMaps.connectionInfo.get(connection); + DBInfo dbInfo = JDBCMaps.connectionInfo.get(connection); /** * Logic to get the DBInfo from a JDBC Connection, if the connection was not created via * Driver.connect, or it has never seen before, the connectionInfo map will return null and will @@ -65,10 +67,10 @@ public class JDBCDecorator extends DatabaseClientDecorator { if (url != null) { dbInfo = JDBCConnectionUrlParser.parse(url, connection.getClientInfo()); } else { - dbInfo = JDBCMaps.DBInfo.DEFAULT; + dbInfo = DBInfo.DEFAULT; } } catch (final SQLException se) { - dbInfo = JDBCMaps.DBInfo.DEFAULT; + dbInfo = DBInfo.DEFAULT; } JDBCMaps.connectionInfo.put(connection, dbInfo); } @@ -83,7 +85,7 @@ public class JDBCDecorator extends DatabaseClientDecorator { @Override public Span onStatement(final Span span, final String statement) { - final String resourceName = statement == null ? JDBCMaps.DB_QUERY : statement; + final String resourceName = statement == null ? DB_QUERY : statement; span.setTag(DDTags.RESOURCE_NAME, resourceName); Tags.COMPONENT.set(span, "java-jdbc-statement"); return super.onStatement(span, statement); @@ -91,7 +93,7 @@ public class JDBCDecorator extends DatabaseClientDecorator { public Span onPreparedStatement(final Span span, final PreparedStatement statement) { final String sql = JDBCMaps.preparedStatements.get(statement); - final String resourceName = sql == null ? JDBCMaps.DB_QUERY : sql; + final String resourceName = sql == null ? DB_QUERY : sql; span.setTag(DDTags.RESOURCE_NAME, resourceName); Tags.COMPONENT.set(span, "java-jdbc-prepared_statement"); return super.onStatement(span, sql); diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCMaps.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCMaps.java index d4b4135125..1d91031775 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCMaps.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCMaps.java @@ -5,7 +5,6 @@ import static datadog.trace.bootstrap.WeakMap.Provider.newWeakMap; import datadog.trace.bootstrap.WeakMap; import java.sql.Connection; import java.sql.PreparedStatement; -import lombok.Data; /** * JDBC instrumentation shares a global map of connection info. @@ -15,18 +14,4 @@ import lombok.Data; public class JDBCMaps { public static final WeakMap connectionInfo = newWeakMap(); public static final WeakMap preparedStatements = newWeakMap(); - - public static final String DB_QUERY = "DB Query"; - - @Data - public static class DBInfo { - public static DBInfo DEFAULT = new DBInfo("database", null, null, null, null, null, null); - private final String type; - private final String url; - private final String user; - private final String instance; - private final String db; - private final String host; - private final Integer port; - } } diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/PreparedStatementInstrumentation.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/PreparedStatementInstrumentation.java index e457cb2000..1b4b0d7da6 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/PreparedStatementInstrumentation.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/PreparedStatementInstrumentation.java @@ -45,9 +45,10 @@ public final class PreparedStatementInstrumentation extends Instrumenter.Default final JDBCConnectionUrlParser[] parsers = JDBCConnectionUrlParser.values(); final List parserClasses = new ArrayList<>(parsers.length + 8); + parserClasses.add(packageName + ".DBInfo"); + parserClasses.add(packageName + ".DBInfo$Builder"); parserClasses.add(packageName + ".JDBCUtils"); parserClasses.add(packageName + ".JDBCMaps"); - parserClasses.add(packageName + ".JDBCMaps$DBInfo"); parserClasses.add(packageName + ".JDBCConnectionUrlParser"); parserClasses.add("datadog.trace.agent.decorator.BaseDecorator"); diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/StatementInstrumentation.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/StatementInstrumentation.java index a890fddece..9d513319e9 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/StatementInstrumentation.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/StatementInstrumentation.java @@ -45,9 +45,10 @@ public final class StatementInstrumentation extends Instrumenter.Default { final JDBCConnectionUrlParser[] parsers = JDBCConnectionUrlParser.values(); final List parserClasses = new ArrayList<>(parsers.length + 8); + parserClasses.add(packageName + ".DBInfo"); + parserClasses.add(packageName + ".DBInfo$Builder"); parserClasses.add(packageName + ".JDBCUtils"); parserClasses.add(packageName + ".JDBCMaps"); - parserClasses.add(packageName + ".JDBCMaps$DBInfo"); parserClasses.add(packageName + ".JDBCConnectionUrlParser"); parserClasses.add("datadog.trace.agent.decorator.BaseDecorator"); diff --git a/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCConnectionUrlParserTest.groovy b/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCConnectionUrlParserTest.groovy index 8707645ebe..b6efb455b0 100644 --- a/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCConnectionUrlParserTest.groovy +++ b/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCConnectionUrlParserTest.groovy @@ -1,13 +1,30 @@ -import datadog.trace.instrumentation.jdbc.JDBCMaps +import datadog.trace.instrumentation.jdbc.DBInfo +import spock.lang.Shared import spock.lang.Specification import static datadog.trace.instrumentation.jdbc.JDBCConnectionUrlParser.parse class JDBCConnectionUrlParserTest extends Specification { + @Shared + def stdProps = { + def prop = new Properties() + // https://download.oracle.com/otn-pub/jcp/jdbc-4_1-mrel-spec/jdbc4.1-fr-spec.pdf + prop.setProperty("databaseName", "stdDatabaseName") + prop.setProperty("dataSourceName", "stdDatasourceName") + prop.setProperty("description", "Some description") + prop.setProperty("networkProtocol", "stdProto") + prop.setProperty("password", "PASSWORD!") + prop.setProperty("portNumber", "9999") + prop.setProperty("roleName", "stdRoleName") + prop.setProperty("serverName", "stdServerName") + prop.setProperty("user", "stdUserName") + return prop + }() + def "invalid url returns default"() { expect: - parse(url, null) == JDBCMaps.DBInfo.DEFAULT + parse(url, null) == DBInfo.DEFAULT where: url | _ @@ -18,7 +35,7 @@ class JDBCConnectionUrlParserTest extends Specification { def "verify #format parsing of #url"() { setup: - def info = parse(url, null) + def info = parse(url, props) expect: info.url == expected.url @@ -31,97 +48,132 @@ class JDBCConnectionUrlParserTest extends Specification { info == expected where: - url | format | user | host | port | instance + url | props | format | user | host | port | instance | db // https://jdbc.postgresql.org/documentation/94/connect.html - "jdbc:postgresql:///" | "postgresql" | null | "localhost" | 5432 | "" - "jdbc:postgresql://pghost" | "postgresql" | null | "pghost" | 5432 | "" - "jdbc:postgresql://pghost:11/pgdb?user=pguser&password=PW" | "postgresql" | "pguser" | "pghost" | 11 | "pgdb" + "jdbc:postgresql:///" | null | "postgresql" | null | "localhost" | 5432 | null | null + "jdbc:postgresql:///" | stdProps | "postgresql" | "stdUserName" | "stdServerName" | 9999 | null | "stdDatabaseName" + "jdbc:postgresql://pg.host" | null | "postgresql" | null | "pg.host" | 5432 | null | null + "jdbc:postgresql://pg.host:11/pgdb?user=pguser&password=PW" | null | "postgresql" | "pguser" | "pg.host" | 11 | null | "pgdb" + "jdbc:postgresql://pg.host:11/pgdb?user=pguser&password=PW" | stdProps | "postgresql" | "pguser" | "pg.host" | 11 | null | "pgdb" + // https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-jdbc-url-format.html // https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-configuration-properties.html - "jdbc:mysql:///" | "mysql" | null | "localhost" | 3306 | "" - "jdbc:mysql://myhost" | "mysql" | null | "myhost" | 3306 | "" - "jdbc:mysql://myhost?user=myuser&password=PW" | "mysql" | "myuser" | "myhost" | 3306 | "" - "jdbc:mysql://myhost:22/mydb?user=myuser&password=PW" | "mysql" | "myuser" | "myhost" | 22 | "mydb" - "jdbc:mariadb://mdbhost:33/mdbdb?user=mdbuser&password=PW" | "mariadb" | "mdbuser" | "mdbhost" | 33 | "mdbdb" + "jdbc:mysql:///" | null | "mysql" | null | "localhost" | 3306 | null | null + "jdbc:mysql:///" | stdProps | "mysql" | "stdUserName" | "stdServerName" | 9999 | null | "stdDatabaseName" + "jdbc:mysql://my.host" | null | "mysql" | null | "my.host" | 3306 | null | null + "jdbc:mysql://my.host?user=myuser&password=PW" | null | "mysql" | "myuser" | "my.host" | 3306 | null | null + "jdbc:mysql://my.host:22/mydb?user=myuser&password=PW" | null | "mysql" | "myuser" | "my.host" | 22 | null | "mydb" + "jdbc:mysql://127.0.0.1:22/mydb?user=myuser&password=PW" | stdProps | "mysql" | "myuser" | "127.0.0.1" | 22 | null | "mydb" + + // https://mariadb.com/kb/en/library/about-mariadb-connector-j/#connection-strings + "jdbc:mariadb:127.0.0.1:33/mdbdb" | null | "mariadb" | null | "127.0.0.1" | 33 | null | "mdbdb" + "jdbc:mariadb:localhost/mdbdb" | null | "mariadb" | null | "localhost" | 3306 | null | "mdbdb" + "jdbc:mariadb:localhost/mdbdb?user=mdbuser&password=PW" | stdProps | "mariadb" | "mdbuser" | "localhost" | 9999 | null | "mdbdb" + "jdbc:mariadb:localhost:33/mdbdb" | stdProps | "mariadb" | "stdUserName" | "localhost" | 33 | null | "mdbdb" + "jdbc:mariadb://mdb.host:33/mdbdb?user=mdbuser&password=PW" | null | "mariadb" | "mdbuser" | "mdb.host" | 33 | null | "mdbdb" + "jdbc:mariadb:aurora://mdb.host/mdbdb" | null | "mariadb:aurora" | null | "mdb.host" | 3306 | null | "mdbdb" + "jdbc:mysql:aurora://mdb.host/mdbdb" | null | "mysql:aurora" | null | "mdb.host" | 3306 | null | "mdbdb" + "jdbc:mysql:failover://localhost/mdbdb?autoReconnect=true" | null | "mysql:failover" | null | "localhost" | 3306 | null | "mdbdb" + "jdbc:mariadb:failover://mdb.host1:33,mdb.host/mdbdb?characterEncoding=utf8" | null | "mariadb:failover" | null | "mdb.host1" | 33 | null | "mdbdb" + "jdbc:mariadb:sequential://mdb.host1,mdb.host2:33/mdbdb" | null | "mariadb:sequential" | null | "mdb.host1" | 3306 | null | "mdbdb" + "jdbc:mariadb:loadbalance://127.0.0.1:33,mdb.host/mdbdb" | null | "mariadb:loadbalance" | null | "127.0.0.1" | 33 | null | "mdbdb" + "jdbc:mariadb:loadbalance://[2001:0660:7401:0200:0000:0000:0edf:bdd7]:33,mdb.host/mdbdb" | null | "mariadb:loadbalance" | null | "2001:0660:7401:0200:0000:0000:0edf:bdd7" | 33 | null | "mdbdb" + "jdbc:mysql:loadbalance://127.0.0.1,127.0.0.1:3306/mdbdb?user=mdbuser&password=PW" | null | "mysql:loadbalance" | "mdbuser" | "127.0.0.1" | 3306 | null | "mdbdb" + "jdbc:mariadb:replication://localhost:33,anotherhost:3306/mdbdb" | null | "mariadb:replication" | null | "localhost" | 33 | null | "mdbdb" + "jdbc:mysql:replication://address=(HOST=127.0.0.1)(port=33)(user=mdbuser)(password=PW)," + + "address=(host=mdb.host)(port=3306)(user=otheruser)(password=PW)/mdbdb?user=wrong&password=PW" | null | "mysql:replication" | "mdbuser" | "127.0.0.1" | 33 | null | "mdbdb" + "jdbc:mysql:replication://address=(HOST=mdb.host)," + + "address=(host=anotherhost)(port=3306)(user=wrong)(password=PW)/mdbdb?user=mdbuser&password=PW" | null | "mysql:replication" | "mdbuser" | "mdb.host" | 3306 | null | "mdbdb" //https://docs.microsoft.com/en-us/sql/connect/jdbc/building-the-connection-url - "jdbc:microsoft:sqlserver://;" | "sqlserver" | null | "localhost" | 1433 | "MSSQLSERVER" - "jdbc:sqlserver://sshost\\ssinstance:44;databaseName=ssdb;user=ssuser;password=pw" | "sqlserver" | "ssuser" | "sshost" | 44 | "ssinstance" - "jdbc:sqlserver://;serverName=sshost\\ssinstance:44;DatabaseName=;" | "sqlserver" | null | "sshost" | 44 | "ssinstance" - "jdbc:sqlserver://sshost;serverName=althost;DatabaseName=ssdb;" | "sqlserver" | null | "sshost" | 1433 | "MSSQLSERVER" - "jdbc:microsoft:sqlserver://sshost:44;DatabaseName=ssdb;user=ssuser;password=pw;user=ssuser2;" | "sqlserver" | "ssuser" | "sshost" | 44 | "MSSQLSERVER" + "jdbc:microsoft:sqlserver://;" | null | "sqlserver" | null | "localhost" | 1433 | "MSSQLSERVER" | null + "jdbc:microsoft:sqlserver://;" | stdProps | "sqlserver" | "stdUserName" | "stdServerName" | 9999 | "MSSQLSERVER" | "stdDatabaseName" + "jdbc:sqlserver://ss.host\\ssinstance:44;databaseName=ssdb;user=ssuser;password=pw" | null | "sqlserver" | "ssuser" | "ss.host" | 44 | "ssinstance" | "ssdb" + "jdbc:sqlserver://;serverName=ss.host\\ssinstance:44;DatabaseName=;" | null | "sqlserver" | null | "ss.host" | 44 | "ssinstance" | null + "jdbc:sqlserver://ss.host;serverName=althost;DatabaseName=ssdb;" | null | "sqlserver" | null | "ss.host" | 1433 | "MSSQLSERVER" | "ssdb" + "jdbc:microsoft:sqlserver://ss.host:44;DatabaseName=ssdb;user=ssuser;password=pw;user=ssuser2;" | null | "sqlserver" | "ssuser" | "ss.host" | 44 | "MSSQLSERVER" | "ssdb" // https://docs.oracle.com/cd/B28359_01/java.111/b31224/urls.htm // https://docs.oracle.com/cd/B28359_01/java.111/b31224/jdbcthin.htm - "jdbc:oracle:thin:orcluser/PW@localhost:55:orclsn" | "oracle:thin" | "orcluser" | "localhost" | 55 | "orclsn" - "jdbc:oracle:thin:orcluser/PW@//orclhost:55/orclsn" | "oracle:thin" | "orcluser" | "orclhost" | 55 | "orclsn" - "jdbc:oracle:thin:orcluser/PW@127.0.0.1:orclsn" | "oracle:thin" | "orcluser" | "127.0.0.1" | 1521 | "orclsn" - "jdbc:oracle:thin:orcluser/PW@//orclhost/orclsn" | "oracle:thin" | "orcluser" | "orclhost" | 1521 | "orclsn" - "jdbc:oracle:thin:@//orclhost:55/orclsn" | "oracle:thin" | null | "orclhost" | 55 | "orclsn" - "jdbc:oracle:thin:@ldap://orclhost:55/some,cn=OracleContext,dc=com" | "oracle:thin" | null | "orclhost" | 55 | "some,cn=oraclecontext,dc=com" - "jdbc:oracle:thin:127.0.0.1:orclsn" | "oracle:thin" | null | "127.0.0.1" | 1521 | "orclsn" + "jdbc:oracle:thin:orcluser/PW@localhost:55:orclsn" | null | "oracle:thin" | "orcluser" | "localhost" | 55 | "orclsn" | null + "jdbc:oracle:thin:orcluser/PW@//orcl.host:55/orclsn" | null | "oracle:thin" | "orcluser" | "orcl.host" | 55 | "orclsn" | null + "jdbc:oracle:thin:orcluser/PW@127.0.0.1:orclsn" | null | "oracle:thin" | "orcluser" | "127.0.0.1" | 1521 | "orclsn" | null + "jdbc:oracle:thin:orcluser/PW@//orcl.host/orclsn" | null | "oracle:thin" | "orcluser" | "orcl.host" | 1521 | "orclsn" | null + "jdbc:oracle:thin:@//orcl.host:55/orclsn" | null | "oracle:thin" | null | "orcl.host" | 55 | "orclsn" | null + "jdbc:oracle:thin:@ldap://orcl.host:55/some,cn=OracleContext,dc=com" | null | "oracle:thin" | null | "orcl.host" | 55 | "some,cn=oraclecontext,dc=com" | null + "jdbc:oracle:thin:127.0.0.1:orclsn" | null | "oracle:thin" | null | "127.0.0.1" | 1521 | "orclsn" | null + "jdbc:oracle:thin:orcl.host:orclsn" | stdProps | "oracle:thin" | "stdUserName" | "orcl.host" | 9999 | "orclsn" | "stdDatabaseName" "jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST= 127.0.0.1 )(POR T= 666))" + - "(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=orclsn)))" | "oracle:thin" | null | "127.0.0.1" | 1521 | "orclsn" + "(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=orclsn)))" | null | "oracle:thin" | null | "127.0.0.1" | 1521 | "orclsn" | null // https://docs.oracle.com/cd/B28359_01/java.111/b31224/instclnt.htm - "jdbc:oracle:drivertype:orcluser/PW@orclhost:55/orclsn" | "oracle:drivertype" | "orcluser" | "orclhost" | 55 | "orclsn" - "jdbc:oracle:oci8:@" | "oracle:oci8" | null | null | 1521 | null - "jdbc:oracle:oci8:@orclsn" | "oracle:oci8" | null | null | 1521 | "orclsn" - "jdbc:oracle:oci:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)( HOST = orclhost )" + - "( PORT = 55 ))(CONNECT_DATA=(SERVICE_NAME =orclsn )))" | "oracle:oci" | null | "orclhost" | 55 | "orclsn" + "jdbc:oracle:drivertype:orcluser/PW@orcl.host:55/orclsn" | null | "oracle:drivertype" | "orcluser" | "orcl.host" | 55 | "orclsn" | null + "jdbc:oracle:oci8:@" | null | "oracle:oci8" | null | null | 1521 | null | null + "jdbc:oracle:oci8:@" | stdProps | "oracle:oci8" | "stdUserName" | "stdServerName" | 9999 | null | "stdDatabaseName" + "jdbc:oracle:oci8:@orclsn" | null | "oracle:oci8" | null | null | 1521 | "orclsn" | null + "jdbc:oracle:oci:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)( HOST = orcl.host )" + + "( PORT = 55 ))(CONNECT_DATA=(SERVICE_NAME =orclsn )))" | null | "oracle:oci" | null | "orcl.host" | 55 | "orclsn" | null // https://www.ibm.com/support/knowledgecenter/en/SSEPEK_10.0.0/java/src/tpc/imjcc_tjvjcccn.html // https://www.ibm.com/support/knowledgecenter/en/SSEPGG_10.5.0/com.ibm.db2.luw.apdv.java.doc/src/tpc/imjcc_r0052342.html - "jdbc:as400://ashost:66/asdb:user=asuser;password=PW;" | "as400" | "asuser" | "ashost" | 66 | "asdb" - "jdbc:db2://db2host:77/db2db:user=db2user;password=PW;" | "db2" | "db2user" | "db2host" | 77 | "db2db" + "jdbc:db2://db2.host" | null | "db2" | null | "db2.host" | 50000 | null | null + "jdbc:db2://db2.host" | stdProps | "db2" | "stdUserName" | "db2.host" | 9999 | null | "stdDatabaseName" + "jdbc:db2://db2.host:77/db2db:user=db2user;password=PW;" | null | "db2" | "db2user" | "db2.host" | 77 | "db2db" | null + "jdbc:db2://db2.host:77/db2db:user=db2user;password=PW;" | stdProps | "db2" | "db2user" | "db2.host" | 77 | "db2db" | "stdDatabaseName" + "jdbc:as400://ashost:66/asdb:user=asuser;password=PW;" | null | "as400" | "asuser" | "ashost" | 66 | "asdb" | null // https://help.sap.com/viewer/0eec0d68141541d1b07893a39944924e/2.0.03/en-US/ff15928cf5594d78b841fbbe649f04b4.html - "jdbc:sap://saphost:88/?databaseName=sapdb&user=sapuser&password=PW" | "sap" | "sapuser" | "saphost" | 88 | "sapdb" + "jdbc:sap://sap.host" | null | "sap" | null | "sap.host" | null | null | null + "jdbc:sap://sap.host" | stdProps | "sap" | "stdUserName" | "sap.host" | 9999 | null | "stdDatabaseName" + "jdbc:sap://sap.host:88/?databaseName=sapdb&user=sapuser&password=PW" | null | "sap" | "sapuser" | "sap.host" | 88 | null | "sapdb" // TODO: -// "jdbc:informix-sqli://infxhost:99/infxdb:INFORMIXSERVER=infxsn;user=infxuser;password=PW" | "informix-sqli" | "infxuser" | "infxhost" | 99 | "infxdb" -// "jdbc:informix-direct://infxdb:999;user=infxuser;password=PW" | "informix-direct" | "infxuser" | "infxhost" | 999 | "infxdb" +// "jdbc:informix-sqli://infxhost:99/infxdb:INFORMIXSERVER=infxsn;user=infxuser;password=PW" | null | "informix-sqli" | "infxuser" | "infxhost" | 99 | "infxdb"| null +// "jdbc:informix-direct://infxdb:999;user=infxuser;password=PW" | null | "informix-direct" | "infxuser" | "infxhost" | 999 | "infxdb"| null // http://www.h2database.com/html/features.html#database_url - "jdbc:h2:mem:" | "h2:mem" | null | null | null | "" - "jdbc:h2:mem:h2db" | "h2:mem" | null | null | null | "h2db" - "jdbc:h2:tcp://h2host:111/path/h2db;user=h2user;password=PW" | "h2:tcp" | "h2user" | "h2host" | 111 | "path/h2db" - "jdbc:h2:ssl://h2host:111/path/h2db;user=h2user;password=PW" | "h2:ssl" | "h2user" | "h2host" | 111 | "path/h2db" - "jdbc:h2:/data/h2file" | "h2:file" | null | null | null | "/data/h2file" - "jdbc:h2:file:~/h2file;USER=h2user;PASSWORD=PW" | "h2:file" | null | null | null | "~/h2file" - "jdbc:h2:file:/data/h2file" | "h2:file" | null | null | null | "/data/h2file" - "jdbc:h2:file:C:/data/h2file" | "h2:file" | null | null | null | "c:/data/h2file" - "jdbc:h2:zip:~/db.zip!/h2zip" | "h2:zip" | null | null | null | "~/db.zip!/h2zip" + "jdbc:h2:mem:" | null | "h2:mem" | null | null | null | null | null + "jdbc:h2:mem:" | stdProps | "h2:mem" | "stdUserName" | "stdServerName" | 9999 | null | "stdDatabaseName" + "jdbc:h2:mem:h2db" | null | "h2:mem" | null | null | null | "h2db" | null + "jdbc:h2:tcp://h2.host:111/path/h2db;user=h2user;password=PW" | null | "h2:tcp" | "h2user" | "h2.host" | 111 | "path/h2db" | null + "jdbc:h2:ssl://h2.host:111/path/h2db;user=h2user;password=PW" | null | "h2:ssl" | "h2user" | "h2.host" | 111 | "path/h2db" | null + "jdbc:h2:/data/h2file" | null | "h2:file" | null | null | null | "/data/h2file" | null + "jdbc:h2:file:~/h2file;USER=h2user;PASSWORD=PW" | null | "h2:file" | null | null | null | "~/h2file" | null + "jdbc:h2:file:/data/h2file" | null | "h2:file" | null | null | null | "/data/h2file" | null + "jdbc:h2:file:C:/data/h2file" | null | "h2:file" | null | null | null | "c:/data/h2file" | null + "jdbc:h2:zip:~/db.zip!/h2zip" | null | "h2:zip" | null | null | null | "~/db.zip!/h2zip" | null // http://hsqldb.org/doc/2.0/guide/dbproperties-chapt.html - "jdbc:hsqldb:hsdb" | "hsqldb:mem" | "SA" | null | null | "hsdb" - "jdbc:hsqldb:mem:hsdb" | "hsqldb:mem" | "SA" | null | null | "hsdb" - "jdbc:hsqldb:file:hsdb" | "hsqldb:file" | "SA" | null | null | "hsdb" - "jdbc:hsqldb:file:/loc/hsdb" | "hsqldb:file" | "SA" | null | null | "/loc/hsdb" - "jdbc:hsqldb:file:C:/hsdb" | "hsqldb:file" | "SA" | null | null | "c:/hsdb" - "jdbc:hsqldb:res:hsdb" | "hsqldb:res" | "SA" | null | null | "hsdb" - "jdbc:hsqldb:res:/cp/hsdb" | "hsqldb:res" | "SA" | null | null | "/cp/hsdb" - "jdbc:hsqldb:hsql://hshost:333/hsdb" | "hsqldb:hsql" | "SA" | "hshost" | 333 | "hsdb" - "jdbc:hsqldb:hsqls://hshost/hsdb" | "hsqldb:hsqls" | "SA" | "hshost" | 9001 | "hsdb" - "jdbc:hsqldb:http://hshost" | "hsqldb:http" | "SA" | "hshost" | 80 | null - "jdbc:hsqldb:http://hshost:333/hsdb" | "hsqldb:http" | "SA" | "hshost" | 333 | "hsdb" - "jdbc:hsqldb:https://127.0.0.1/hsdb" | "hsqldb:https" | "SA" | "127.0.0.1" | 443 | "hsdb" + "jdbc:hsqldb:hsdb" | null | "hsqldb:mem" | "SA" | null | null | "hsdb" | null + "jdbc:hsqldb:hsdb" | stdProps | "hsqldb:mem" | "stdUserName" | "stdServerName" | 9999 | "hsdb" | "stdDatabaseName" + "jdbc:hsqldb:mem:hsdb" | null | "hsqldb:mem" | "SA" | null | null | "hsdb" | null + "jdbc:hsqldb:file:hsdb" | null | "hsqldb:file" | "SA" | null | null | "hsdb" | null + "jdbc:hsqldb:file:/loc/hsdb" | null | "hsqldb:file" | "SA" | null | null | "/loc/hsdb" | null + "jdbc:hsqldb:file:C:/hsdb" | null | "hsqldb:file" | "SA" | null | null | "c:/hsdb" | null + "jdbc:hsqldb:res:hsdb" | null | "hsqldb:res" | "SA" | null | null | "hsdb" | null + "jdbc:hsqldb:res:/cp/hsdb" | null | "hsqldb:res" | "SA" | null | null | "/cp/hsdb" | null + "jdbc:hsqldb:hsql://hs.host:333/hsdb" | null | "hsqldb:hsql" | "SA" | "hs.host" | 333 | "hsdb" | null + "jdbc:hsqldb:hsqls://hs.host/hsdb" | null | "hsqldb:hsqls" | "SA" | "hs.host" | 9001 | "hsdb" | null + "jdbc:hsqldb:http://hs.host" | null | "hsqldb:http" | "SA" | "hs.host" | 80 | null | null + "jdbc:hsqldb:http://hs.host:333/hsdb" | null | "hsqldb:http" | "SA" | "hs.host" | 333 | "hsdb" | null + "jdbc:hsqldb:https://127.0.0.1/hsdb" | null | "hsqldb:https" | "SA" | "127.0.0.1" | 443 | "hsdb" | null // https://db.apache.org/derby/papers/DerbyClientSpec.html#Connection+URL+Format // https://db.apache.org/derby/docs/10.8/devguide/cdevdvlp34964.html - "jdbc:derby:derbydb" | "derby:directory" | "APP" | null | null | "derbydb" - "jdbc:derby:derbydb;user=derbyuser;password=pw" | "derby:directory" | "derbyuser" | null | null | "derbydb" - "jdbc:derby:memory:derbydb" | "derby:memory" | "APP" | null | null | "derbydb" - "jdbc:derby:memory:;databaseName=derbydb" | "derby:memory" | "APP" | null | null | "derbydb" - "jdbc:derby:memory:derbydb;databaseName=altdb" | "derby:memory" | "APP" | null | null | "derbydb" - "jdbc:derby:memory:derbydb;user=derbyuser;password=pw" | "derby:memory" | "derbyuser" | null | null | "derbydb" - "jdbc:derby://derbyhost:222/memory:derbydb;create=true" | "derby:network" | "APP" | "derbyhost" | 222 | "derbydb" - "jdbc:derby://derbyhost/memory:derbydb;create=true;user=derbyuser;password=pw" | "derby:network" | "derbyuser" | "derbyhost" | 1527 | "derbydb" - "jdbc:derby://127.0.0.1:1527/memory:derbydb;create=true;user=derbyuser;password=pw" | "derby:network" | "derbyuser" | "127.0.0.1" | 1527 | "derbydb" - "jdbc:derby:directory:derbydb;user=derbyuser;password=pw" | "derby:directory" | "derbyuser" | null | null | "derbydb" - "jdbc:derby:classpath:/some/derbydb;user=derbyuser;password=pw" | "derby:classpath" | "derbyuser" | null | null | "/some/derbydb" - "jdbc:derby:jar:/derbydb;user=derbyuser;password=pw" | "derby:jar" | "derbyuser" | null | null | "/derbydb" - "jdbc:derby:jar:(~/path/to/db.jar)/other/derbydb;user=derbyuser;password=pw" | "derby:jar" | "derbyuser" | null | null | "(~/path/to/db.jar)/other/derbydb" + "jdbc:derby:derbydb" | null | "derby:directory" | "APP" | null | null | "derbydb" | null + "jdbc:derby:derbydb" | stdProps | "derby:directory" | "stdUserName" | "stdServerName" | 9999 | "derbydb" | "stdDatabaseName" + "jdbc:derby:derbydb;user=derbyuser;password=pw" | null | "derby:directory" | "derbyuser" | null | null | "derbydb" | null + "jdbc:derby:memory:derbydb" | null | "derby:memory" | "APP" | null | null | "derbydb" | null + "jdbc:derby:memory:;databaseName=derbydb" | null | "derby:memory" | "APP" | null | null | null | "derbydb" + "jdbc:derby:memory:derbydb;databaseName=altdb" | null | "derby:memory" | "APP" | null | null | "derbydb" | "altdb" + "jdbc:derby:memory:derbydb;user=derbyuser;password=pw" | null | "derby:memory" | "derbyuser" | null | null | "derbydb" | null + "jdbc:derby://derby.host:222/memory:derbydb;create=true" | null | "derby:network" | "APP" | "derby.host" | 222 | "derbydb" | null + "jdbc:derby://derby.host/memory:derbydb;create=true;user=derbyuser;password=pw" | null | "derby:network" | "derbyuser" | "derby.host" | 1527 | "derbydb" | null + "jdbc:derby://127.0.0.1:1527/memory:derbydb;create=true;user=derbyuser;password=pw" | null | "derby:network" | "derbyuser" | "127.0.0.1" | 1527 | "derbydb" | null + "jdbc:derby:directory:derbydb;user=derbyuser;password=pw" | null | "derby:directory" | "derbyuser" | null | null | "derbydb" | null + "jdbc:derby:classpath:/some/derbydb;user=derbyuser;password=pw" | null | "derby:classpath" | "derbyuser" | null | null | "/some/derbydb" | null + "jdbc:derby:jar:/derbydb;user=derbyuser;password=pw" | null | "derby:jar" | "derbyuser" | null | null | "/derbydb" | null + "jdbc:derby:jar:(~/path/to/db.jar)/other/derbydb;user=derbyuser;password=pw" | null | "derby:jar" | "derbyuser" | null | null | "(~/path/to/db.jar)/other/derbydb" | null - expected = new JDBCMaps.DBInfo(format, null, user, instance, null, host, port) + expected = new DBInfo.Builder().type(format).user(user).instance(instance).db(db).host(host).port(port).build() } } From 288add2a60ae98a65063be7f0b7f73b2abe69a32 Mon Sep 17 00:00:00 2001 From: Tyler Benson Date: Mon, 10 Jun 2019 15:20:56 -0700 Subject: [PATCH 4/7] Fix slickdb test --- .../java-concurrent/src/slickTest/groovy/SlickTest.groovy | 2 +- .../java-concurrent/src/slickTest/scala/SlickUtils.scala | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/dd-java-agent/instrumentation/java-concurrent/src/slickTest/groovy/SlickTest.groovy b/dd-java-agent/instrumentation/java-concurrent/src/slickTest/groovy/SlickTest.groovy index 99f16f99ae..6bd75f2787 100644 --- a/dd-java-agent/instrumentation/java-concurrent/src/slickTest/groovy/SlickTest.groovy +++ b/dd-java-agent/instrumentation/java-concurrent/src/slickTest/groovy/SlickTest.groovy @@ -42,7 +42,7 @@ class SlickTest extends AgentTestRunner { "$Tags.DB_TYPE.key" SlickUtils.Driver() "$Tags.DB_USER.key" SlickUtils.Username() - "db.instance" SlickUtils.Url() + "db.instance" SlickUtils.Db() "span.origin.type" "org.h2.jdbc.JdbcPreparedStatement" defaultTags() diff --git a/dd-java-agent/instrumentation/java-concurrent/src/slickTest/scala/SlickUtils.scala b/dd-java-agent/instrumentation/java-concurrent/src/slickTest/scala/SlickUtils.scala index c1cb3514f0..85a742bbb4 100644 --- a/dd-java-agent/instrumentation/java-concurrent/src/slickTest/scala/SlickUtils.scala +++ b/dd-java-agent/instrumentation/java-concurrent/src/slickTest/scala/SlickUtils.scala @@ -34,9 +34,10 @@ class SlickUtils { object SlickUtils { - val Driver = "h2" + val Driver = "h2:mem" + val Db = "test" val Username = "TESTUSER" - val Url = s"jdbc:${Driver}:mem:test" + val Url = s"jdbc:${Driver}:${Db}" val TestValue = 3 val TestQuery = "SELECT 3" From 4469c7fb119df0f4c1007ab4242a4fa03432a065 Mon Sep 17 00:00:00 2001 From: Tyler Benson Date: Mon, 10 Jun 2019 16:17:36 -0700 Subject: [PATCH 5/7] separate out driver subtype to avoid changing existing service names --- .../src/slickTest/scala/SlickUtils.scala | 4 +- .../trace/instrumentation/jdbc/DBInfo.java | 1 + .../jdbc/JDBCConnectionUrlParser.java | 55 +++-- .../groovy/JDBCConnectionUrlParserTest.groovy | 194 +++++++++--------- .../groovy/JDBCInstrumentationTest.groovy | 166 +++++++-------- 5 files changed, 209 insertions(+), 211 deletions(-) diff --git a/dd-java-agent/instrumentation/java-concurrent/src/slickTest/scala/SlickUtils.scala b/dd-java-agent/instrumentation/java-concurrent/src/slickTest/scala/SlickUtils.scala index 85a742bbb4..1bc64c19e9 100644 --- a/dd-java-agent/instrumentation/java-concurrent/src/slickTest/scala/SlickUtils.scala +++ b/dd-java-agent/instrumentation/java-concurrent/src/slickTest/scala/SlickUtils.scala @@ -34,10 +34,10 @@ class SlickUtils { object SlickUtils { - val Driver = "h2:mem" + val Driver = "h2" val Db = "test" val Username = "TESTUSER" - val Url = s"jdbc:${Driver}:${Db}" + val Url = s"jdbc:${Driver}:mem:${Db}" val TestValue = 3 val TestQuery = "SELECT 3" diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DBInfo.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DBInfo.java index 99adf4c8ff..d59e343c72 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DBInfo.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DBInfo.java @@ -8,6 +8,7 @@ import lombok.Data; public class DBInfo { public static DBInfo DEFAULT = new Builder().type("database").build(); private final String type; + private final String subtype; private final String url; private final String user; private final String instance; diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCConnectionUrlParser.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCConnectionUrlParser.java index 7cd2453805..ba5cdf4a30 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCConnectionUrlParser.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCConnectionUrlParser.java @@ -172,7 +172,7 @@ public enum JDBCConnectionUrlParser { if (protoLoc > typeEndLoc) { return MARIA_SUBPROTO .doParse(jdbcUrl.substring(protoLoc + 3), builder) - .type(jdbcUrl.substring(0, protoLoc)); + .subtype(jdbcUrl.substring(typeEndLoc + 1, protoLoc)); } if (protoLoc > 0) { return GENERIC_URL_LIKE.doParse(jdbcUrl, builder); @@ -339,10 +339,10 @@ public enum JDBCConnectionUrlParser { @Override DBInfo.Builder doParse(String jdbcUrl, final DBInfo.Builder builder) { final int typeEndIndex = jdbcUrl.indexOf(":", "oracle:".length()); - final String type = jdbcUrl.substring(0, typeEndIndex); + final String subtype = jdbcUrl.substring("oracle:".length(), typeEndIndex); jdbcUrl = jdbcUrl.substring(typeEndIndex + 1); - builder.type(type); + builder.subtype(subtype); final DBInfo dbInfo = builder.build(); if (dbInfo.getPort() == null) { builder.port(DEFAULT_PORT); @@ -493,12 +493,11 @@ public enum JDBCConnectionUrlParser { @Override DBInfo.Builder doParse(final String jdbcUrl, final DBInfo.Builder builder) { - String type = "h2"; final String instance; final String h2Url = jdbcUrl.substring("h2:".length()); if (h2Url.startsWith("mem:")) { - type = "h2:mem"; + builder.subtype("mem"); final int propLoc = h2Url.indexOf(";"); if (propLoc >= 0) { instance = h2Url.substring("mem:".length(), propLoc); @@ -506,7 +505,7 @@ public enum JDBCConnectionUrlParser { instance = h2Url.substring("mem:".length()); } } else if (h2Url.startsWith("file:")) { - type = "h2:file"; + builder.subtype("file"); final int propLoc = h2Url.indexOf(";"); if (propLoc >= 0) { instance = h2Url.substring("file:".length(), propLoc); @@ -514,7 +513,7 @@ public enum JDBCConnectionUrlParser { instance = h2Url.substring("file:".length()); } } else if (h2Url.startsWith("zip:")) { - type = "h2:zip"; + builder.subtype("zip"); final int propLoc = h2Url.indexOf(";"); if (propLoc >= 0) { instance = h2Url.substring("zip:".length(), propLoc); @@ -526,15 +525,15 @@ public enum JDBCConnectionUrlParser { if (dbInfo.getPort() == null) { builder.port(DEFAULT_PORT); } - return MODIFIED_URL_LIKE.doParse(jdbcUrl, builder).type("h2:tcp"); + return MODIFIED_URL_LIKE.doParse(jdbcUrl, builder).type("h2").subtype("tcp"); } else if (h2Url.startsWith("ssl:")) { final DBInfo dbInfo = builder.build(); if (dbInfo.getPort() == null) { builder.port(DEFAULT_PORT); } - return MODIFIED_URL_LIKE.doParse(jdbcUrl, builder).type("h2:ssl"); + return MODIFIED_URL_LIKE.doParse(jdbcUrl, builder).type("h2").subtype("ssl"); } else { - type = "h2:file"; + builder.subtype("file"); final int propLoc = h2Url.indexOf(";"); if (propLoc >= 0) { instance = h2Url.substring(0, propLoc); @@ -545,7 +544,7 @@ public enum JDBCConnectionUrlParser { if (!instance.isEmpty()) { builder.instance(instance); } - return builder.type(type); + return builder; } }, @@ -555,7 +554,6 @@ public enum JDBCConnectionUrlParser { @Override DBInfo.Builder doParse(final String jdbcUrl, final DBInfo.Builder builder) { - String type = "hsqldb"; String instance = null; final DBInfo dbInfo = builder.build(); if (dbInfo.getUser() == null) { @@ -563,39 +561,39 @@ public enum JDBCConnectionUrlParser { } final String hsqlUrl = jdbcUrl.substring("hsqldb:".length()); if (hsqlUrl.startsWith("mem:")) { - type = "hsqldb:mem"; + builder.subtype("mem"); instance = hsqlUrl.substring("mem:".length()); } else if (hsqlUrl.startsWith("file:")) { - type = "hsqldb:file"; + builder.subtype("file"); instance = hsqlUrl.substring("file:".length()); } else if (hsqlUrl.startsWith("res:")) { - type = "hsqldb:res"; + builder.subtype("res"); instance = hsqlUrl.substring("res:".length()); } else if (hsqlUrl.startsWith("hsql:")) { if (dbInfo.getPort() == null) { builder.port(DEFAULT_PORT); } - return MODIFIED_URL_LIKE.doParse(jdbcUrl, builder).type("hsqldb:hsql"); + return MODIFIED_URL_LIKE.doParse(jdbcUrl, builder).type("hsqldb").subtype("hsql"); } else if (hsqlUrl.startsWith("hsqls:")) { if (dbInfo.getPort() == null) { builder.port(DEFAULT_PORT); } - return MODIFIED_URL_LIKE.doParse(jdbcUrl, builder).type("hsqldb:hsqls"); + return MODIFIED_URL_LIKE.doParse(jdbcUrl, builder).type("hsqldb").subtype("hsqls"); } else if (hsqlUrl.startsWith("http:")) { if (dbInfo.getPort() == null) { builder.port(80); } - return MODIFIED_URL_LIKE.doParse(jdbcUrl, builder).type("hsqldb:http"); + return MODIFIED_URL_LIKE.doParse(jdbcUrl, builder).type("hsqldb").subtype("http"); } else if (hsqlUrl.startsWith("https:")) { if (dbInfo.getPort() == null) { builder.port(443); } - return MODIFIED_URL_LIKE.doParse(jdbcUrl, builder).type("hsqldb:https"); + return MODIFIED_URL_LIKE.doParse(jdbcUrl, builder).type("hsqldb").subtype("https"); } else { - type = "hsqldb:mem"; + builder.subtype("mem"); instance = hsqlUrl; } - return builder.type(type).instance(instance); + return builder.instance(instance); } }, @@ -605,7 +603,6 @@ public enum JDBCConnectionUrlParser { @Override DBInfo.Builder doParse(final String jdbcUrl, final DBInfo.Builder builder) { - final String type; String instance = null; String host = null; @@ -622,31 +619,31 @@ public enum JDBCConnectionUrlParser { } if (split[0].startsWith("memory:")) { - type = "derby:memory"; + builder.subtype("memory"); final String urlInstance = split[0].substring("memory:".length()); if (!urlInstance.isEmpty()) { instance = urlInstance; } } else if (split[0].startsWith("directory:")) { - type = "derby:directory"; + builder.subtype("directory"); final String urlInstance = split[0].substring("directory:".length()); if (!urlInstance.isEmpty()) { instance = urlInstance; } } else if (split[0].startsWith("classpath:")) { - type = "derby:classpath"; + builder.subtype("classpath"); final String urlInstance = split[0].substring("classpath:".length()); if (!urlInstance.isEmpty()) { instance = urlInstance; } } else if (split[0].startsWith("jar:")) { - type = "derby:jar"; + builder.subtype("jar"); final String urlInstance = split[0].substring("jar:".length()); if (!urlInstance.isEmpty()) { instance = urlInstance; } } else if (split[0].startsWith("//")) { - type = "derby:network"; + builder.subtype("network"); if (dbInfo.getPort() == null) { builder.port(DEFAULT_PORT); } @@ -668,7 +665,7 @@ public enum JDBCConnectionUrlParser { host = url; } } else { - type = "derby:directory"; + builder.subtype("directory"); final String urlInstance = split[0]; if (!urlInstance.isEmpty()) { instance = urlInstance; @@ -678,7 +675,7 @@ public enum JDBCConnectionUrlParser { if (host != null) { builder.host(host); } - return builder.type(type).instance(instance); + return builder.instance(instance); } }; diff --git a/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCConnectionUrlParserTest.groovy b/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCConnectionUrlParserTest.groovy index b6efb455b0..3e70935b54 100644 --- a/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCConnectionUrlParserTest.groovy +++ b/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCConnectionUrlParserTest.groovy @@ -33,7 +33,7 @@ class JDBCConnectionUrlParserTest extends Specification { "bogus:string" | _ } - def "verify #format parsing of #url"() { + def "verify #type:#subtype parsing of #url"() { setup: def info = parse(url, props) @@ -48,132 +48,132 @@ class JDBCConnectionUrlParserTest extends Specification { info == expected where: - url | props | format | user | host | port | instance | db + url | props | type | subtype | user | host | port | instance | db // https://jdbc.postgresql.org/documentation/94/connect.html - "jdbc:postgresql:///" | null | "postgresql" | null | "localhost" | 5432 | null | null - "jdbc:postgresql:///" | stdProps | "postgresql" | "stdUserName" | "stdServerName" | 9999 | null | "stdDatabaseName" - "jdbc:postgresql://pg.host" | null | "postgresql" | null | "pg.host" | 5432 | null | null - "jdbc:postgresql://pg.host:11/pgdb?user=pguser&password=PW" | null | "postgresql" | "pguser" | "pg.host" | 11 | null | "pgdb" - "jdbc:postgresql://pg.host:11/pgdb?user=pguser&password=PW" | stdProps | "postgresql" | "pguser" | "pg.host" | 11 | null | "pgdb" + "jdbc:postgresql:///" | null | "postgresql" | null | null | "localhost" | 5432 | null | null + "jdbc:postgresql:///" | stdProps | "postgresql" | null | "stdUserName" | "stdServerName" | 9999 | null | "stdDatabaseName" + "jdbc:postgresql://pg.host" | null | "postgresql" | null | null | "pg.host" | 5432 | null | null + "jdbc:postgresql://pg.host:11/pgdb?user=pguser&password=PW" | null | "postgresql" | null | "pguser" | "pg.host" | 11 | null | "pgdb" + "jdbc:postgresql://pg.host:11/pgdb?user=pguser&password=PW" | stdProps | "postgresql" | null | "pguser" | "pg.host" | 11 | null | "pgdb" // https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-jdbc-url-format.html // https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-configuration-properties.html - "jdbc:mysql:///" | null | "mysql" | null | "localhost" | 3306 | null | null - "jdbc:mysql:///" | stdProps | "mysql" | "stdUserName" | "stdServerName" | 9999 | null | "stdDatabaseName" - "jdbc:mysql://my.host" | null | "mysql" | null | "my.host" | 3306 | null | null - "jdbc:mysql://my.host?user=myuser&password=PW" | null | "mysql" | "myuser" | "my.host" | 3306 | null | null - "jdbc:mysql://my.host:22/mydb?user=myuser&password=PW" | null | "mysql" | "myuser" | "my.host" | 22 | null | "mydb" - "jdbc:mysql://127.0.0.1:22/mydb?user=myuser&password=PW" | stdProps | "mysql" | "myuser" | "127.0.0.1" | 22 | null | "mydb" + "jdbc:mysql:///" | null | "mysql" | null | null | "localhost" | 3306 | null | null + "jdbc:mysql:///" | stdProps | "mysql" | null | "stdUserName" | "stdServerName" | 9999 | null | "stdDatabaseName" + "jdbc:mysql://my.host" | null | "mysql" | null | null | "my.host" | 3306 | null | null + "jdbc:mysql://my.host?user=myuser&password=PW" | null | "mysql" | null | "myuser" | "my.host" | 3306 | null | null + "jdbc:mysql://my.host:22/mydb?user=myuser&password=PW" | null | "mysql" | null | "myuser" | "my.host" | 22 | null | "mydb" + "jdbc:mysql://127.0.0.1:22/mydb?user=myuser&password=PW" | stdProps | "mysql" | null | "myuser" | "127.0.0.1" | 22 | null | "mydb" // https://mariadb.com/kb/en/library/about-mariadb-connector-j/#connection-strings - "jdbc:mariadb:127.0.0.1:33/mdbdb" | null | "mariadb" | null | "127.0.0.1" | 33 | null | "mdbdb" - "jdbc:mariadb:localhost/mdbdb" | null | "mariadb" | null | "localhost" | 3306 | null | "mdbdb" - "jdbc:mariadb:localhost/mdbdb?user=mdbuser&password=PW" | stdProps | "mariadb" | "mdbuser" | "localhost" | 9999 | null | "mdbdb" - "jdbc:mariadb:localhost:33/mdbdb" | stdProps | "mariadb" | "stdUserName" | "localhost" | 33 | null | "mdbdb" - "jdbc:mariadb://mdb.host:33/mdbdb?user=mdbuser&password=PW" | null | "mariadb" | "mdbuser" | "mdb.host" | 33 | null | "mdbdb" - "jdbc:mariadb:aurora://mdb.host/mdbdb" | null | "mariadb:aurora" | null | "mdb.host" | 3306 | null | "mdbdb" - "jdbc:mysql:aurora://mdb.host/mdbdb" | null | "mysql:aurora" | null | "mdb.host" | 3306 | null | "mdbdb" - "jdbc:mysql:failover://localhost/mdbdb?autoReconnect=true" | null | "mysql:failover" | null | "localhost" | 3306 | null | "mdbdb" - "jdbc:mariadb:failover://mdb.host1:33,mdb.host/mdbdb?characterEncoding=utf8" | null | "mariadb:failover" | null | "mdb.host1" | 33 | null | "mdbdb" - "jdbc:mariadb:sequential://mdb.host1,mdb.host2:33/mdbdb" | null | "mariadb:sequential" | null | "mdb.host1" | 3306 | null | "mdbdb" - "jdbc:mariadb:loadbalance://127.0.0.1:33,mdb.host/mdbdb" | null | "mariadb:loadbalance" | null | "127.0.0.1" | 33 | null | "mdbdb" - "jdbc:mariadb:loadbalance://[2001:0660:7401:0200:0000:0000:0edf:bdd7]:33,mdb.host/mdbdb" | null | "mariadb:loadbalance" | null | "2001:0660:7401:0200:0000:0000:0edf:bdd7" | 33 | null | "mdbdb" - "jdbc:mysql:loadbalance://127.0.0.1,127.0.0.1:3306/mdbdb?user=mdbuser&password=PW" | null | "mysql:loadbalance" | "mdbuser" | "127.0.0.1" | 3306 | null | "mdbdb" - "jdbc:mariadb:replication://localhost:33,anotherhost:3306/mdbdb" | null | "mariadb:replication" | null | "localhost" | 33 | null | "mdbdb" + "jdbc:mariadb:127.0.0.1:33/mdbdb" | null | "mariadb" | null | null | "127.0.0.1" | 33 | null | "mdbdb" + "jdbc:mariadb:localhost/mdbdb" | null | "mariadb" | null | null | "localhost" | 3306 | null | "mdbdb" + "jdbc:mariadb:localhost/mdbdb?user=mdbuser&password=PW" | stdProps | "mariadb" | null | "mdbuser" | "localhost" | 9999 | null | "mdbdb" + "jdbc:mariadb:localhost:33/mdbdb" | stdProps | "mariadb" | null | "stdUserName" | "localhost" | 33 | null | "mdbdb" + "jdbc:mariadb://mdb.host:33/mdbdb?user=mdbuser&password=PW" | null | "mariadb" | null | "mdbuser" | "mdb.host" | 33 | null | "mdbdb" + "jdbc:mariadb:aurora://mdb.host/mdbdb" | null | "mariadb" | "aurora" | null | "mdb.host" | 3306 | null | "mdbdb" + "jdbc:mysql:aurora://mdb.host/mdbdb" | null | "mysql" | "aurora" | null | "mdb.host" | 3306 | null | "mdbdb" + "jdbc:mysql:failover://localhost/mdbdb?autoReconnect=true" | null | "mysql" | "failover" | null | "localhost" | 3306 | null | "mdbdb" + "jdbc:mariadb:failover://mdb.host1:33,mdb.host/mdbdb?characterEncoding=utf8" | null | "mariadb" | "failover" | null | "mdb.host1" | 33 | null | "mdbdb" + "jdbc:mariadb:sequential://mdb.host1,mdb.host2:33/mdbdb" | null | "mariadb" | "sequential" | null | "mdb.host1" | 3306 | null | "mdbdb" + "jdbc:mariadb:loadbalance://127.0.0.1:33,mdb.host/mdbdb" | null | "mariadb" | "loadbalance" | null | "127.0.0.1" | 33 | null | "mdbdb" + "jdbc:mariadb:loadbalance://[2001:0660:7401:0200:0000:0000:0edf:bdd7]:33,mdb.host/mdbdb" | null | "mariadb" | "loadbalance" | null | "2001:0660:7401:0200:0000:0000:0edf:bdd7" | 33 | null | "mdbdb" + "jdbc:mysql:loadbalance://127.0.0.1,127.0.0.1:3306/mdbdb?user=mdbuser&password=PW" | null | "mysql" | "loadbalance" | "mdbuser" | "127.0.0.1" | 3306 | null | "mdbdb" + "jdbc:mariadb:replication://localhost:33,anotherhost:3306/mdbdb" | null | "mariadb" | "replication" | null | "localhost" | 33 | null | "mdbdb" "jdbc:mysql:replication://address=(HOST=127.0.0.1)(port=33)(user=mdbuser)(password=PW)," + - "address=(host=mdb.host)(port=3306)(user=otheruser)(password=PW)/mdbdb?user=wrong&password=PW" | null | "mysql:replication" | "mdbuser" | "127.0.0.1" | 33 | null | "mdbdb" + "address=(host=mdb.host)(port=3306)(user=otheruser)(password=PW)/mdbdb?user=wrong&password=PW" | null | "mysql" | "replication" | "mdbuser" | "127.0.0.1" | 33 | null | "mdbdb" "jdbc:mysql:replication://address=(HOST=mdb.host)," + - "address=(host=anotherhost)(port=3306)(user=wrong)(password=PW)/mdbdb?user=mdbuser&password=PW" | null | "mysql:replication" | "mdbuser" | "mdb.host" | 3306 | null | "mdbdb" + "address=(host=anotherhost)(port=3306)(user=wrong)(password=PW)/mdbdb?user=mdbuser&password=PW" | null | "mysql" | "replication" | "mdbuser" | "mdb.host" | 3306 | null | "mdbdb" //https://docs.microsoft.com/en-us/sql/connect/jdbc/building-the-connection-url - "jdbc:microsoft:sqlserver://;" | null | "sqlserver" | null | "localhost" | 1433 | "MSSQLSERVER" | null - "jdbc:microsoft:sqlserver://;" | stdProps | "sqlserver" | "stdUserName" | "stdServerName" | 9999 | "MSSQLSERVER" | "stdDatabaseName" - "jdbc:sqlserver://ss.host\\ssinstance:44;databaseName=ssdb;user=ssuser;password=pw" | null | "sqlserver" | "ssuser" | "ss.host" | 44 | "ssinstance" | "ssdb" - "jdbc:sqlserver://;serverName=ss.host\\ssinstance:44;DatabaseName=;" | null | "sqlserver" | null | "ss.host" | 44 | "ssinstance" | null - "jdbc:sqlserver://ss.host;serverName=althost;DatabaseName=ssdb;" | null | "sqlserver" | null | "ss.host" | 1433 | "MSSQLSERVER" | "ssdb" - "jdbc:microsoft:sqlserver://ss.host:44;DatabaseName=ssdb;user=ssuser;password=pw;user=ssuser2;" | null | "sqlserver" | "ssuser" | "ss.host" | 44 | "MSSQLSERVER" | "ssdb" + "jdbc:microsoft:sqlserver://;" | null | "sqlserver" | null | null | "localhost" | 1433 | "MSSQLSERVER" | null + "jdbc:microsoft:sqlserver://;" | stdProps | "sqlserver" | null | "stdUserName" | "stdServerName" | 9999 | "MSSQLSERVER" | "stdDatabaseName" + "jdbc:sqlserver://ss.host\\ssinstance:44;databaseName=ssdb;user=ssuser;password=pw" | null | "sqlserver" | null | "ssuser" | "ss.host" | 44 | "ssinstance" | "ssdb" + "jdbc:sqlserver://;serverName=ss.host\\ssinstance:44;DatabaseName=;" | null | "sqlserver" | null | null | "ss.host" | 44 | "ssinstance" | null + "jdbc:sqlserver://ss.host;serverName=althost;DatabaseName=ssdb;" | null | "sqlserver" | null | null | "ss.host" | 1433 | "MSSQLSERVER" | "ssdb" + "jdbc:microsoft:sqlserver://ss.host:44;DatabaseName=ssdb;user=ssuser;password=pw;user=ssuser2;" | null | "sqlserver" | null | "ssuser" | "ss.host" | 44 | "MSSQLSERVER" | "ssdb" // https://docs.oracle.com/cd/B28359_01/java.111/b31224/urls.htm // https://docs.oracle.com/cd/B28359_01/java.111/b31224/jdbcthin.htm - "jdbc:oracle:thin:orcluser/PW@localhost:55:orclsn" | null | "oracle:thin" | "orcluser" | "localhost" | 55 | "orclsn" | null - "jdbc:oracle:thin:orcluser/PW@//orcl.host:55/orclsn" | null | "oracle:thin" | "orcluser" | "orcl.host" | 55 | "orclsn" | null - "jdbc:oracle:thin:orcluser/PW@127.0.0.1:orclsn" | null | "oracle:thin" | "orcluser" | "127.0.0.1" | 1521 | "orclsn" | null - "jdbc:oracle:thin:orcluser/PW@//orcl.host/orclsn" | null | "oracle:thin" | "orcluser" | "orcl.host" | 1521 | "orclsn" | null - "jdbc:oracle:thin:@//orcl.host:55/orclsn" | null | "oracle:thin" | null | "orcl.host" | 55 | "orclsn" | null - "jdbc:oracle:thin:@ldap://orcl.host:55/some,cn=OracleContext,dc=com" | null | "oracle:thin" | null | "orcl.host" | 55 | "some,cn=oraclecontext,dc=com" | null - "jdbc:oracle:thin:127.0.0.1:orclsn" | null | "oracle:thin" | null | "127.0.0.1" | 1521 | "orclsn" | null - "jdbc:oracle:thin:orcl.host:orclsn" | stdProps | "oracle:thin" | "stdUserName" | "orcl.host" | 9999 | "orclsn" | "stdDatabaseName" + "jdbc:oracle:thin:orcluser/PW@localhost:55:orclsn" | null | "oracle" | "thin" | "orcluser" | "localhost" | 55 | "orclsn" | null + "jdbc:oracle:thin:orcluser/PW@//orcl.host:55/orclsn" | null | "oracle" | "thin" | "orcluser" | "orcl.host" | 55 | "orclsn" | null + "jdbc:oracle:thin:orcluser/PW@127.0.0.1:orclsn" | null | "oracle" | "thin" | "orcluser" | "127.0.0.1" | 1521 | "orclsn" | null + "jdbc:oracle:thin:orcluser/PW@//orcl.host/orclsn" | null | "oracle" | "thin" | "orcluser" | "orcl.host" | 1521 | "orclsn" | null + "jdbc:oracle:thin:@//orcl.host:55/orclsn" | null | "oracle" | "thin" | null | "orcl.host" | 55 | "orclsn" | null + "jdbc:oracle:thin:@ldap://orcl.host:55/some,cn=OracleContext,dc=com" | null | "oracle" | "thin" | null | "orcl.host" | 55 | "some,cn=oraclecontext,dc=com" | null + "jdbc:oracle:thin:127.0.0.1:orclsn" | null | "oracle" | "thin" | null | "127.0.0.1" | 1521 | "orclsn" | null + "jdbc:oracle:thin:orcl.host:orclsn" | stdProps | "oracle" | "thin" | "stdUserName" | "orcl.host" | 9999 | "orclsn" | "stdDatabaseName" "jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST= 127.0.0.1 )(POR T= 666))" + - "(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=orclsn)))" | null | "oracle:thin" | null | "127.0.0.1" | 1521 | "orclsn" | null + "(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=orclsn)))" | null | "oracle" | "thin" | null | "127.0.0.1" | 1521 | "orclsn" | null // https://docs.oracle.com/cd/B28359_01/java.111/b31224/instclnt.htm - "jdbc:oracle:drivertype:orcluser/PW@orcl.host:55/orclsn" | null | "oracle:drivertype" | "orcluser" | "orcl.host" | 55 | "orclsn" | null - "jdbc:oracle:oci8:@" | null | "oracle:oci8" | null | null | 1521 | null | null - "jdbc:oracle:oci8:@" | stdProps | "oracle:oci8" | "stdUserName" | "stdServerName" | 9999 | null | "stdDatabaseName" - "jdbc:oracle:oci8:@orclsn" | null | "oracle:oci8" | null | null | 1521 | "orclsn" | null + "jdbc:oracle:drivertype:orcluser/PW@orcl.host:55/orclsn" | null | "oracle" | "drivertype" | "orcluser" | "orcl.host" | 55 | "orclsn" | null + "jdbc:oracle:oci8:@" | null | "oracle" | "oci8" | null | null | 1521 | null | null + "jdbc:oracle:oci8:@" | stdProps | "oracle" | "oci8" | "stdUserName" | "stdServerName" | 9999 | null | "stdDatabaseName" + "jdbc:oracle:oci8:@orclsn" | null | "oracle" | "oci8" | null | null | 1521 | "orclsn" | null "jdbc:oracle:oci:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)( HOST = orcl.host )" + - "( PORT = 55 ))(CONNECT_DATA=(SERVICE_NAME =orclsn )))" | null | "oracle:oci" | null | "orcl.host" | 55 | "orclsn" | null + "( PORT = 55 ))(CONNECT_DATA=(SERVICE_NAME =orclsn )))" | null | "oracle" | "oci" | null | "orcl.host" | 55 | "orclsn" | null // https://www.ibm.com/support/knowledgecenter/en/SSEPEK_10.0.0/java/src/tpc/imjcc_tjvjcccn.html // https://www.ibm.com/support/knowledgecenter/en/SSEPGG_10.5.0/com.ibm.db2.luw.apdv.java.doc/src/tpc/imjcc_r0052342.html - "jdbc:db2://db2.host" | null | "db2" | null | "db2.host" | 50000 | null | null - "jdbc:db2://db2.host" | stdProps | "db2" | "stdUserName" | "db2.host" | 9999 | null | "stdDatabaseName" - "jdbc:db2://db2.host:77/db2db:user=db2user;password=PW;" | null | "db2" | "db2user" | "db2.host" | 77 | "db2db" | null - "jdbc:db2://db2.host:77/db2db:user=db2user;password=PW;" | stdProps | "db2" | "db2user" | "db2.host" | 77 | "db2db" | "stdDatabaseName" - "jdbc:as400://ashost:66/asdb:user=asuser;password=PW;" | null | "as400" | "asuser" | "ashost" | 66 | "asdb" | null + "jdbc:db2://db2.host" | null | "db2" | null | null | "db2.host" | 50000 | null | null + "jdbc:db2://db2.host" | stdProps | "db2" | null | "stdUserName" | "db2.host" | 9999 | null | "stdDatabaseName" + "jdbc:db2://db2.host:77/db2db:user=db2user;password=PW;" | null | "db2" | null | "db2user" | "db2.host" | 77 | "db2db" | null + "jdbc:db2://db2.host:77/db2db:user=db2user;password=PW;" | stdProps | "db2" | null | "db2user" | "db2.host" | 77 | "db2db" | "stdDatabaseName" + "jdbc:as400://ashost:66/asdb:user=asuser;password=PW;" | null | "as400" | null | "asuser" | "ashost" | 66 | "asdb" | null // https://help.sap.com/viewer/0eec0d68141541d1b07893a39944924e/2.0.03/en-US/ff15928cf5594d78b841fbbe649f04b4.html - "jdbc:sap://sap.host" | null | "sap" | null | "sap.host" | null | null | null - "jdbc:sap://sap.host" | stdProps | "sap" | "stdUserName" | "sap.host" | 9999 | null | "stdDatabaseName" - "jdbc:sap://sap.host:88/?databaseName=sapdb&user=sapuser&password=PW" | null | "sap" | "sapuser" | "sap.host" | 88 | null | "sapdb" + "jdbc:sap://sap.host" | null | "sap" | null | null | "sap.host" | null | null | null + "jdbc:sap://sap.host" | stdProps | "sap" | null | "stdUserName" | "sap.host" | 9999 | null | "stdDatabaseName" + "jdbc:sap://sap.host:88/?databaseName=sapdb&user=sapuser&password=PW" | null | "sap" | null | "sapuser" | "sap.host" | 88 | null | "sapdb" // TODO: -// "jdbc:informix-sqli://infxhost:99/infxdb:INFORMIXSERVER=infxsn;user=infxuser;password=PW" | null | "informix-sqli" | "infxuser" | "infxhost" | 99 | "infxdb"| null -// "jdbc:informix-direct://infxdb:999;user=infxuser;password=PW" | null | "informix-direct" | "infxuser" | "infxhost" | 999 | "infxdb"| null +// "jdbc:informix-sqli://infxhost:99/infxdb:INFORMIXSERVER=infxsn;user=infxuser;password=PW" | null | "informix-sqli" | null | "infxuser" | "infxhost" | 99 | "infxdb"| null +// "jdbc:informix-direct://infxdb:999;user=infxuser;password=PW" | null | "informix-direct" | null | "infxuser" | "infxhost" | 999 | "infxdb"| null // http://www.h2database.com/html/features.html#database_url - "jdbc:h2:mem:" | null | "h2:mem" | null | null | null | null | null - "jdbc:h2:mem:" | stdProps | "h2:mem" | "stdUserName" | "stdServerName" | 9999 | null | "stdDatabaseName" - "jdbc:h2:mem:h2db" | null | "h2:mem" | null | null | null | "h2db" | null - "jdbc:h2:tcp://h2.host:111/path/h2db;user=h2user;password=PW" | null | "h2:tcp" | "h2user" | "h2.host" | 111 | "path/h2db" | null - "jdbc:h2:ssl://h2.host:111/path/h2db;user=h2user;password=PW" | null | "h2:ssl" | "h2user" | "h2.host" | 111 | "path/h2db" | null - "jdbc:h2:/data/h2file" | null | "h2:file" | null | null | null | "/data/h2file" | null - "jdbc:h2:file:~/h2file;USER=h2user;PASSWORD=PW" | null | "h2:file" | null | null | null | "~/h2file" | null - "jdbc:h2:file:/data/h2file" | null | "h2:file" | null | null | null | "/data/h2file" | null - "jdbc:h2:file:C:/data/h2file" | null | "h2:file" | null | null | null | "c:/data/h2file" | null - "jdbc:h2:zip:~/db.zip!/h2zip" | null | "h2:zip" | null | null | null | "~/db.zip!/h2zip" | null + "jdbc:h2:mem:" | null | "h2" | "mem" | null | null | null | null | null + "jdbc:h2:mem:" | stdProps | "h2" | "mem" | "stdUserName" | "stdServerName" | 9999 | null | "stdDatabaseName" + "jdbc:h2:mem:h2db" | null | "h2" | "mem" | null | null | null | "h2db" | null + "jdbc:h2:tcp://h2.host:111/path/h2db;user=h2user;password=PW" | null | "h2" | "tcp" | "h2user" | "h2.host" | 111 | "path/h2db" | null + "jdbc:h2:ssl://h2.host:111/path/h2db;user=h2user;password=PW" | null | "h2" | "ssl" | "h2user" | "h2.host" | 111 | "path/h2db" | null + "jdbc:h2:/data/h2file" | null | "h2" | "file" | null | null | null | "/data/h2file" | null + "jdbc:h2:file:~/h2file;USER=h2user;PASSWORD=PW" | null | "h2" | "file" | null | null | null | "~/h2file" | null + "jdbc:h2:file:/data/h2file" | null | "h2" | "file" | null | null | null | "/data/h2file" | null + "jdbc:h2:file:C:/data/h2file" | null | "h2" | "file" | null | null | null | "c:/data/h2file" | null + "jdbc:h2:zip:~/db.zip!/h2zip" | null | "h2" | "zip" | null | null | null | "~/db.zip!/h2zip" | null // http://hsqldb.org/doc/2.0/guide/dbproperties-chapt.html - "jdbc:hsqldb:hsdb" | null | "hsqldb:mem" | "SA" | null | null | "hsdb" | null - "jdbc:hsqldb:hsdb" | stdProps | "hsqldb:mem" | "stdUserName" | "stdServerName" | 9999 | "hsdb" | "stdDatabaseName" - "jdbc:hsqldb:mem:hsdb" | null | "hsqldb:mem" | "SA" | null | null | "hsdb" | null - "jdbc:hsqldb:file:hsdb" | null | "hsqldb:file" | "SA" | null | null | "hsdb" | null - "jdbc:hsqldb:file:/loc/hsdb" | null | "hsqldb:file" | "SA" | null | null | "/loc/hsdb" | null - "jdbc:hsqldb:file:C:/hsdb" | null | "hsqldb:file" | "SA" | null | null | "c:/hsdb" | null - "jdbc:hsqldb:res:hsdb" | null | "hsqldb:res" | "SA" | null | null | "hsdb" | null - "jdbc:hsqldb:res:/cp/hsdb" | null | "hsqldb:res" | "SA" | null | null | "/cp/hsdb" | null - "jdbc:hsqldb:hsql://hs.host:333/hsdb" | null | "hsqldb:hsql" | "SA" | "hs.host" | 333 | "hsdb" | null - "jdbc:hsqldb:hsqls://hs.host/hsdb" | null | "hsqldb:hsqls" | "SA" | "hs.host" | 9001 | "hsdb" | null - "jdbc:hsqldb:http://hs.host" | null | "hsqldb:http" | "SA" | "hs.host" | 80 | null | null - "jdbc:hsqldb:http://hs.host:333/hsdb" | null | "hsqldb:http" | "SA" | "hs.host" | 333 | "hsdb" | null - "jdbc:hsqldb:https://127.0.0.1/hsdb" | null | "hsqldb:https" | "SA" | "127.0.0.1" | 443 | "hsdb" | null + "jdbc:hsqldb:hsdb" | null | "hsqldb" | "mem" | "SA" | null | null | "hsdb" | null + "jdbc:hsqldb:hsdb" | stdProps | "hsqldb" | "mem" | "stdUserName" | "stdServerName" | 9999 | "hsdb" | "stdDatabaseName" + "jdbc:hsqldb:mem:hsdb" | null | "hsqldb" | "mem" | "SA" | null | null | "hsdb" | null + "jdbc:hsqldb:file:hsdb" | null | "hsqldb" | "file" | "SA" | null | null | "hsdb" | null + "jdbc:hsqldb:file:/loc/hsdb" | null | "hsqldb" | "file" | "SA" | null | null | "/loc/hsdb" | null + "jdbc:hsqldb:file:C:/hsdb" | null | "hsqldb" | "file" | "SA" | null | null | "c:/hsdb" | null + "jdbc:hsqldb:res:hsdb" | null | "hsqldb" | "res" | "SA" | null | null | "hsdb" | null + "jdbc:hsqldb:res:/cp/hsdb" | null | "hsqldb" | "res" | "SA" | null | null | "/cp/hsdb" | null + "jdbc:hsqldb:hsql://hs.host:333/hsdb" | null | "hsqldb" | "hsql" | "SA" | "hs.host" | 333 | "hsdb" | null + "jdbc:hsqldb:hsqls://hs.host/hsdb" | null | "hsqldb" | "hsqls" | "SA" | "hs.host" | 9001 | "hsdb" | null + "jdbc:hsqldb:http://hs.host" | null | "hsqldb" | "http" | "SA" | "hs.host" | 80 | null | null + "jdbc:hsqldb:http://hs.host:333/hsdb" | null | "hsqldb" | "http" | "SA" | "hs.host" | 333 | "hsdb" | null + "jdbc:hsqldb:https://127.0.0.1/hsdb" | null | "hsqldb" | "https" | "SA" | "127.0.0.1" | 443 | "hsdb" | null // https://db.apache.org/derby/papers/DerbyClientSpec.html#Connection+URL+Format // https://db.apache.org/derby/docs/10.8/devguide/cdevdvlp34964.html - "jdbc:derby:derbydb" | null | "derby:directory" | "APP" | null | null | "derbydb" | null - "jdbc:derby:derbydb" | stdProps | "derby:directory" | "stdUserName" | "stdServerName" | 9999 | "derbydb" | "stdDatabaseName" - "jdbc:derby:derbydb;user=derbyuser;password=pw" | null | "derby:directory" | "derbyuser" | null | null | "derbydb" | null - "jdbc:derby:memory:derbydb" | null | "derby:memory" | "APP" | null | null | "derbydb" | null - "jdbc:derby:memory:;databaseName=derbydb" | null | "derby:memory" | "APP" | null | null | null | "derbydb" - "jdbc:derby:memory:derbydb;databaseName=altdb" | null | "derby:memory" | "APP" | null | null | "derbydb" | "altdb" - "jdbc:derby:memory:derbydb;user=derbyuser;password=pw" | null | "derby:memory" | "derbyuser" | null | null | "derbydb" | null - "jdbc:derby://derby.host:222/memory:derbydb;create=true" | null | "derby:network" | "APP" | "derby.host" | 222 | "derbydb" | null - "jdbc:derby://derby.host/memory:derbydb;create=true;user=derbyuser;password=pw" | null | "derby:network" | "derbyuser" | "derby.host" | 1527 | "derbydb" | null - "jdbc:derby://127.0.0.1:1527/memory:derbydb;create=true;user=derbyuser;password=pw" | null | "derby:network" | "derbyuser" | "127.0.0.1" | 1527 | "derbydb" | null - "jdbc:derby:directory:derbydb;user=derbyuser;password=pw" | null | "derby:directory" | "derbyuser" | null | null | "derbydb" | null - "jdbc:derby:classpath:/some/derbydb;user=derbyuser;password=pw" | null | "derby:classpath" | "derbyuser" | null | null | "/some/derbydb" | null - "jdbc:derby:jar:/derbydb;user=derbyuser;password=pw" | null | "derby:jar" | "derbyuser" | null | null | "/derbydb" | null - "jdbc:derby:jar:(~/path/to/db.jar)/other/derbydb;user=derbyuser;password=pw" | null | "derby:jar" | "derbyuser" | null | null | "(~/path/to/db.jar)/other/derbydb" | null + "jdbc:derby:derbydb" | null | "derby" | "directory" | "APP" | null | null | "derbydb" | null + "jdbc:derby:derbydb" | stdProps | "derby" | "directory" | "stdUserName" | "stdServerName" | 9999 | "derbydb" | "stdDatabaseName" + "jdbc:derby:derbydb;user=derbyuser;password=pw" | null | "derby" | "directory" | "derbyuser" | null | null | "derbydb" | null + "jdbc:derby:memory:derbydb" | null | "derby" | "memory" | "APP" | null | null | "derbydb" | null + "jdbc:derby:memory:;databaseName=derbydb" | null | "derby" | "memory" | "APP" | null | null | null | "derbydb" + "jdbc:derby:memory:derbydb;databaseName=altdb" | null | "derby" | "memory" | "APP" | null | null | "derbydb" | "altdb" + "jdbc:derby:memory:derbydb;user=derbyuser;password=pw" | null | "derby" | "memory" | "derbyuser" | null | null | "derbydb" | null + "jdbc:derby://derby.host:222/memory:derbydb;create=true" | null | "derby" | "network" | "APP" | "derby.host" | 222 | "derbydb" | null + "jdbc:derby://derby.host/memory:derbydb;create=true;user=derbyuser;password=pw" | null | "derby" | "network" | "derbyuser" | "derby.host" | 1527 | "derbydb" | null + "jdbc:derby://127.0.0.1:1527/memory:derbydb;create=true;user=derbyuser;password=pw" | null | "derby" | "network" | "derbyuser" | "127.0.0.1" | 1527 | "derbydb" | null + "jdbc:derby:directory:derbydb;user=derbyuser;password=pw" | null | "derby" | "directory" | "derbyuser" | null | null | "derbydb" | null + "jdbc:derby:classpath:/some/derbydb;user=derbyuser;password=pw" | null | "derby" | "classpath" | "derbyuser" | null | null | "/some/derbydb" | null + "jdbc:derby:jar:/derbydb;user=derbyuser;password=pw" | null | "derby" | "jar" | "derbyuser" | null | null | "/derbydb" | null + "jdbc:derby:jar:(~/path/to/db.jar)/other/derbydb;user=derbyuser;password=pw" | null | "derby" | "jar" | "derbyuser" | null | null | "(~/path/to/db.jar)/other/derbydb" | null - expected = new DBInfo.Builder().type(format).user(user).instance(instance).db(db).host(host).port(port).build() + expected = new DBInfo.Builder().type(type).subtype(subtype).user(user).instance(instance).db(db).host(host).port(port).build() } } diff --git a/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCInstrumentationTest.groovy b/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCInstrumentationTest.groovy index 995d6d71f9..9ecc358c19 100644 --- a/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCInstrumentationTest.groovy +++ b/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCInstrumentationTest.groovy @@ -26,23 +26,23 @@ class JDBCInstrumentationTest extends AgentTestRunner { @Shared private Map jdbcUrls = [ - "h2:mem" : "jdbc:h2:mem:$dbName", - "derby:memory": "jdbc:derby:memory:$dbName", - "hsqldb:mem" : "jdbc:hsqldb:mem:$dbName", + "h2" : "jdbc:h2:mem:$dbName", + "derby" : "jdbc:derby:memory:$dbName", + "hsqldb": "jdbc:hsqldb:mem:$dbName", ] @Shared private Map jdbcDriverClassNames = [ - "h2:mem" : "org.h2.Driver", - "derby:memory": "org.apache.derby.jdbc.EmbeddedDriver", - "hsqldb:mem" : "org.hsqldb.jdbc.JDBCDriver", + "h2" : "org.h2.Driver", + "derby" : "org.apache.derby.jdbc.EmbeddedDriver", + "hsqldb": "org.hsqldb.jdbc.JDBCDriver", ] @Shared private Map jdbcUserNames = [ - "h2:mem" : null, - "derby:memory": "APP", - "hsqldb:mem" : "SA", + "h2" : null, + "derby" : "APP", + "hsqldb": "SA", ] @Shared @@ -76,7 +76,7 @@ class JDBCInstrumentationTest extends AgentTestRunner { def createTomcatDS(String dbType, String jdbcUrl) { DataSource ds = new org.apache.tomcat.jdbc.pool.DataSource() - def jdbcUrlToSet = dbType == "derby:memory" ? jdbcUrl + ";create=true" : jdbcUrl + def jdbcUrlToSet = dbType == "derby" ? jdbcUrl + ";create=true" : jdbcUrl ds.setUrl(jdbcUrlToSet) ds.setDriverClassName(jdbcDriverClassNames.get(dbType)) String username = jdbcUserNames.get(dbType) @@ -91,7 +91,7 @@ class JDBCInstrumentationTest extends AgentTestRunner { def createHikariDS(String dbType, String jdbcUrl) { HikariConfig config = new HikariConfig() - def jdbcUrlToSet = dbType == "derby:memory" ? jdbcUrl + ";create=true" : jdbcUrl + def jdbcUrlToSet = dbType == "derby" ? jdbcUrl + ";create=true" : jdbcUrl config.setJdbcUrl(jdbcUrlToSet) String username = jdbcUserNames.get(dbType) if (username != null) { @@ -109,7 +109,7 @@ class JDBCInstrumentationTest extends AgentTestRunner { def createC3P0DS(String dbType, String jdbcUrl) { DataSource ds = new ComboPooledDataSource() ds.setDriverClass(jdbcDriverClassNames.get(dbType)) - def jdbcUrlToSet = dbType == "derby:memory" ? jdbcUrl + ";create=true" : jdbcUrl + def jdbcUrlToSet = dbType == "derby" ? jdbcUrl + ";create=true" : jdbcUrl ds.setJdbcUrl(jdbcUrlToSet) String username = jdbcUserNames.get(dbType) if (username != null) { @@ -193,22 +193,22 @@ class JDBCInstrumentationTest extends AgentTestRunner { connection.close() where: - driver | connection | username | query - "h2:mem" | new Driver().connect(jdbcUrls.get("h2:mem"), null) | null | "SELECT 3" - "derby:memory" | new EmbeddedDriver().connect(jdbcUrls.get("derby:memory"), null) | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "hsqldb:mem" | new JDBCDriver().connect(jdbcUrls.get("hsqldb:mem"), null) | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" - "h2:mem" | new Driver().connect(jdbcUrls.get("h2:mem"), connectionProps) | null | "SELECT 3" - "derby:memory" | new EmbeddedDriver().connect(jdbcUrls.get("derby:memory"), connectionProps) | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "hsqldb:mem" | new JDBCDriver().connect(jdbcUrls.get("hsqldb:mem"), connectionProps) | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" - "h2:mem" | cpDatasources.get("tomcat").get("h2:mem").getConnection() | null | "SELECT 3" - "derby:memory" | cpDatasources.get("tomcat").get("derby:memory").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "hsqldb:mem" | cpDatasources.get("tomcat").get("hsqldb:mem").getConnection() | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" - "h2:mem" | cpDatasources.get("hikari").get("h2:mem").getConnection() | null | "SELECT 3" - "derby:memory" | cpDatasources.get("hikari").get("derby:memory").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "hsqldb:mem" | cpDatasources.get("hikari").get("hsqldb:mem").getConnection() | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" - "h2:mem" | cpDatasources.get("c3p0").get("h2:mem").getConnection() | null | "SELECT 3" - "derby:memory" | cpDatasources.get("c3p0").get("derby:memory").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "hsqldb:mem" | cpDatasources.get("c3p0").get("hsqldb:mem").getConnection() | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" + driver | connection | username | query + "h2" | new Driver().connect(jdbcUrls.get("h2"), null) | null | "SELECT 3" + "derby" | new EmbeddedDriver().connect(jdbcUrls.get("derby"), null) | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "hsqldb" | new JDBCDriver().connect(jdbcUrls.get("hsqldb"), null) | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" + "h2" | new Driver().connect(jdbcUrls.get("h2"), connectionProps) | null | "SELECT 3" + "derby" | new EmbeddedDriver().connect(jdbcUrls.get("derby"), connectionProps) | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "hsqldb" | new JDBCDriver().connect(jdbcUrls.get("hsqldb"), connectionProps) | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" + "h2" | cpDatasources.get("tomcat").get("h2").getConnection() | null | "SELECT 3" + "derby" | cpDatasources.get("tomcat").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "hsqldb" | cpDatasources.get("tomcat").get("hsqldb").getConnection() | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" + "h2" | cpDatasources.get("hikari").get("h2").getConnection() | null | "SELECT 3" + "derby" | cpDatasources.get("hikari").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "hsqldb" | cpDatasources.get("hikari").get("hsqldb").getConnection() | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" + "h2" | cpDatasources.get("c3p0").get("h2").getConnection() | null | "SELECT 3" + "derby" | cpDatasources.get("c3p0").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "hsqldb" | cpDatasources.get("c3p0").get("hsqldb").getConnection() | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" } @Unroll @@ -256,15 +256,15 @@ class JDBCInstrumentationTest extends AgentTestRunner { connection.close() where: - driver | connection | username | query - "h2:mem" | new Driver().connect(jdbcUrls.get("h2:mem"), null) | null | "SELECT 3" - "derby:memory" | new EmbeddedDriver().connect(jdbcUrls.get("derby:memory"), null) | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "h2:mem" | cpDatasources.get("tomcat").get("h2:mem").getConnection() | null | "SELECT 3" - "derby:memory" | cpDatasources.get("tomcat").get("derby:memory").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "h2:mem" | cpDatasources.get("hikari").get("h2:mem").getConnection() | null | "SELECT 3" - "derby:memory" | cpDatasources.get("hikari").get("derby:memory").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "h2:mem" | cpDatasources.get("c3p0").get("h2:mem").getConnection() | null | "SELECT 3" - "derby:memory" | cpDatasources.get("c3p0").get("derby:memory").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + driver | connection | username | query + "h2" | new Driver().connect(jdbcUrls.get("h2"), null) | null | "SELECT 3" + "derby" | new EmbeddedDriver().connect(jdbcUrls.get("derby"), null) | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "h2" | cpDatasources.get("tomcat").get("h2").getConnection() | null | "SELECT 3" + "derby" | cpDatasources.get("tomcat").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "h2" | cpDatasources.get("hikari").get("h2").getConnection() | null | "SELECT 3" + "derby" | cpDatasources.get("hikari").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "h2" | cpDatasources.get("c3p0").get("h2").getConnection() | null | "SELECT 3" + "derby" | cpDatasources.get("c3p0").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" } @Unroll @@ -311,15 +311,15 @@ class JDBCInstrumentationTest extends AgentTestRunner { connection.close() where: - driver | connection | username | query - "h2:mem" | new Driver().connect(jdbcUrls.get("h2:mem"), null) | null | "SELECT 3" - "derby:memory" | new EmbeddedDriver().connect(jdbcUrls.get("derby:memory"), null) | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "h2:mem" | cpDatasources.get("tomcat").get("h2:mem").getConnection() | null | "SELECT 3" - "derby:memory" | cpDatasources.get("tomcat").get("derby:memory").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "h2:mem" | cpDatasources.get("hikari").get("h2:mem").getConnection() | null | "SELECT 3" - "derby:memory" | cpDatasources.get("hikari").get("derby:memory").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "h2:mem" | cpDatasources.get("c3p0").get("h2:mem").getConnection() | null | "SELECT 3" - "derby:memory" | cpDatasources.get("c3p0").get("derby:memory").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + driver | connection | username | query + "h2" | new Driver().connect(jdbcUrls.get("h2"), null) | null | "SELECT 3" + "derby" | new EmbeddedDriver().connect(jdbcUrls.get("derby"), null) | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "h2" | cpDatasources.get("tomcat").get("h2").getConnection() | null | "SELECT 3" + "derby" | cpDatasources.get("tomcat").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "h2" | cpDatasources.get("hikari").get("h2").getConnection() | null | "SELECT 3" + "derby" | cpDatasources.get("hikari").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "h2" | cpDatasources.get("c3p0").get("h2").getConnection() | null | "SELECT 3" + "derby" | cpDatasources.get("c3p0").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" } @Unroll @@ -366,15 +366,15 @@ class JDBCInstrumentationTest extends AgentTestRunner { connection.close() where: - driver | connection | username | query - "h2:mem" | new Driver().connect(jdbcUrls.get("h2:mem"), null) | null | "SELECT 3" - "derby:memory" | new EmbeddedDriver().connect(jdbcUrls.get("derby:memory"), null) | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "h2:mem" | cpDatasources.get("tomcat").get("h2:mem").getConnection() | null | "SELECT 3" - "derby:memory" | cpDatasources.get("tomcat").get("derby:memory").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "h2:mem" | cpDatasources.get("hikari").get("h2:mem").getConnection() | null | "SELECT 3" - "derby:memory" | cpDatasources.get("hikari").get("derby:memory").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "h2:mem" | cpDatasources.get("c3p0").get("h2:mem").getConnection() | null | "SELECT 3" - "derby:memory" | cpDatasources.get("c3p0").get("derby:memory").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + driver | connection | username | query + "h2" | new Driver().connect(jdbcUrls.get("h2"), null) | null | "SELECT 3" + "derby" | new EmbeddedDriver().connect(jdbcUrls.get("derby"), null) | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "h2" | cpDatasources.get("tomcat").get("h2").getConnection() | null | "SELECT 3" + "derby" | cpDatasources.get("tomcat").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "h2" | cpDatasources.get("hikari").get("h2").getConnection() | null | "SELECT 3" + "derby" | cpDatasources.get("hikari").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "h2" | cpDatasources.get("c3p0").get("h2").getConnection() | null | "SELECT 3" + "derby" | cpDatasources.get("c3p0").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" } @Unroll @@ -421,19 +421,19 @@ class JDBCInstrumentationTest extends AgentTestRunner { connection.close() where: - driver | connection | username | query - "h2:mem" | new Driver().connect(jdbcUrls.get("h2:mem"), null) | null | "CREATE TABLE S_H2 (id INTEGER not NULL, PRIMARY KEY ( id ))" - "derby:memory" | new EmbeddedDriver().connect(jdbcUrls.get("derby:memory"), null) | "APP" | "CREATE TABLE S_DERBY (id INTEGER not NULL, PRIMARY KEY ( id ))" - "hsqldb:mem" | new JDBCDriver().connect(jdbcUrls.get("hsqldb:mem"), null) | "SA" | "CREATE TABLE PUBLIC.S_HSQLDB (id INTEGER not NULL, PRIMARY KEY ( id ))" - "h2:mem" | cpDatasources.get("tomcat").get("h2:mem").getConnection() | null | "CREATE TABLE S_H2_TOMCAT (id INTEGER not NULL, PRIMARY KEY ( id ))" - "derby:memory" | cpDatasources.get("tomcat").get("derby:memory").getConnection() | "APP" | "CREATE TABLE S_DERBY_TOMCAT (id INTEGER not NULL, PRIMARY KEY ( id ))" - "hsqldb:mem" | cpDatasources.get("tomcat").get("hsqldb:mem").getConnection() | "SA" | "CREATE TABLE PUBLIC.S_HSQLDB_TOMCAT (id INTEGER not NULL, PRIMARY KEY ( id ))" - "h2:mem" | cpDatasources.get("hikari").get("h2:mem").getConnection() | null | "CREATE TABLE S_H2_HIKARI (id INTEGER not NULL, PRIMARY KEY ( id ))" - "derby:memory" | cpDatasources.get("hikari").get("derby:memory").getConnection() | "APP" | "CREATE TABLE S_DERBY_HIKARI (id INTEGER not NULL, PRIMARY KEY ( id ))" - "hsqldb:mem" | cpDatasources.get("hikari").get("hsqldb:mem").getConnection() | "SA" | "CREATE TABLE PUBLIC.S_HSQLDB_HIKARI (id INTEGER not NULL, PRIMARY KEY ( id ))" - "h2:mem" | cpDatasources.get("c3p0").get("h2:mem").getConnection() | null | "CREATE TABLE S_H2_C3P0 (id INTEGER not NULL, PRIMARY KEY ( id ))" - "derby:memory" | cpDatasources.get("c3p0").get("derby:memory").getConnection() | "APP" | "CREATE TABLE S_DERBY_C3P0 (id INTEGER not NULL, PRIMARY KEY ( id ))" - "hsqldb:mem" | cpDatasources.get("c3p0").get("hsqldb:mem").getConnection() | "SA" | "CREATE TABLE PUBLIC.S_HSQLDB_C3P0 (id INTEGER not NULL, PRIMARY KEY ( id ))" + driver | connection | username | query + "h2" | new Driver().connect(jdbcUrls.get("h2"), null) | null | "CREATE TABLE S_H2 (id INTEGER not NULL, PRIMARY KEY ( id ))" + "derby" | new EmbeddedDriver().connect(jdbcUrls.get("derby"), null) | "APP" | "CREATE TABLE S_DERBY (id INTEGER not NULL, PRIMARY KEY ( id ))" + "hsqldb" | new JDBCDriver().connect(jdbcUrls.get("hsqldb"), null) | "SA" | "CREATE TABLE PUBLIC.S_HSQLDB (id INTEGER not NULL, PRIMARY KEY ( id ))" + "h2" | cpDatasources.get("tomcat").get("h2").getConnection() | null | "CREATE TABLE S_H2_TOMCAT (id INTEGER not NULL, PRIMARY KEY ( id ))" + "derby" | cpDatasources.get("tomcat").get("derby").getConnection() | "APP" | "CREATE TABLE S_DERBY_TOMCAT (id INTEGER not NULL, PRIMARY KEY ( id ))" + "hsqldb" | cpDatasources.get("tomcat").get("hsqldb").getConnection() | "SA" | "CREATE TABLE PUBLIC.S_HSQLDB_TOMCAT (id INTEGER not NULL, PRIMARY KEY ( id ))" + "h2" | cpDatasources.get("hikari").get("h2").getConnection() | null | "CREATE TABLE S_H2_HIKARI (id INTEGER not NULL, PRIMARY KEY ( id ))" + "derby" | cpDatasources.get("hikari").get("derby").getConnection() | "APP" | "CREATE TABLE S_DERBY_HIKARI (id INTEGER not NULL, PRIMARY KEY ( id ))" + "hsqldb" | cpDatasources.get("hikari").get("hsqldb").getConnection() | "SA" | "CREATE TABLE PUBLIC.S_HSQLDB_HIKARI (id INTEGER not NULL, PRIMARY KEY ( id ))" + "h2" | cpDatasources.get("c3p0").get("h2").getConnection() | null | "CREATE TABLE S_H2_C3P0 (id INTEGER not NULL, PRIMARY KEY ( id ))" + "derby" | cpDatasources.get("c3p0").get("derby").getConnection() | "APP" | "CREATE TABLE S_DERBY_C3P0 (id INTEGER not NULL, PRIMARY KEY ( id ))" + "hsqldb" | cpDatasources.get("c3p0").get("hsqldb").getConnection() | "SA" | "CREATE TABLE PUBLIC.S_HSQLDB_C3P0 (id INTEGER not NULL, PRIMARY KEY ( id ))" } @Unroll @@ -479,15 +479,15 @@ class JDBCInstrumentationTest extends AgentTestRunner { connection.close() where: - driver | connection | username | query - "h2:mem" | new Driver().connect(jdbcUrls.get("h2:mem"), null) | null | "CREATE TABLE PS_H2 (id INTEGER not NULL, PRIMARY KEY ( id ))" - "derby:memory" | new EmbeddedDriver().connect(jdbcUrls.get("derby:memory"), null) | "APP" | "CREATE TABLE PS_DERBY (id INTEGER not NULL, PRIMARY KEY ( id ))" - "h2:mem" | cpDatasources.get("tomcat").get("h2:mem").getConnection() | null | "CREATE TABLE PS_H2_TOMCAT (id INTEGER not NULL, PRIMARY KEY ( id ))" - "derby:memory" | cpDatasources.get("tomcat").get("derby:memory").getConnection() | "APP" | "CREATE TABLE PS_DERBY_TOMCAT (id INTEGER not NULL, PRIMARY KEY ( id ))" - "h2:mem" | cpDatasources.get("hikari").get("h2:mem").getConnection() | null | "CREATE TABLE PS_H2_HIKARI (id INTEGER not NULL, PRIMARY KEY ( id ))" - "derby:memory" | cpDatasources.get("hikari").get("derby:memory").getConnection() | "APP" | "CREATE TABLE PS_DERBY_HIKARI (id INTEGER not NULL, PRIMARY KEY ( id ))" - "h2:mem" | cpDatasources.get("c3p0").get("h2:mem").getConnection() | null | "CREATE TABLE PS_H2_C3P0 (id INTEGER not NULL, PRIMARY KEY ( id ))" - "derby:memory" | cpDatasources.get("c3p0").get("derby:memory").getConnection() | "APP" | "CREATE TABLE PS_DERBY_C3P0 (id INTEGER not NULL, PRIMARY KEY ( id ))" + driver | connection | username | query + "h2" | new Driver().connect(jdbcUrls.get("h2"), null) | null | "CREATE TABLE PS_H2 (id INTEGER not NULL, PRIMARY KEY ( id ))" + "derby" | new EmbeddedDriver().connect(jdbcUrls.get("derby"), null) | "APP" | "CREATE TABLE PS_DERBY (id INTEGER not NULL, PRIMARY KEY ( id ))" + "h2" | cpDatasources.get("tomcat").get("h2").getConnection() | null | "CREATE TABLE PS_H2_TOMCAT (id INTEGER not NULL, PRIMARY KEY ( id ))" + "derby" | cpDatasources.get("tomcat").get("derby").getConnection() | "APP" | "CREATE TABLE PS_DERBY_TOMCAT (id INTEGER not NULL, PRIMARY KEY ( id ))" + "h2" | cpDatasources.get("hikari").get("h2").getConnection() | null | "CREATE TABLE PS_H2_HIKARI (id INTEGER not NULL, PRIMARY KEY ( id ))" + "derby" | cpDatasources.get("hikari").get("derby").getConnection() | "APP" | "CREATE TABLE PS_DERBY_HIKARI (id INTEGER not NULL, PRIMARY KEY ( id ))" + "h2" | cpDatasources.get("c3p0").get("h2").getConnection() | null | "CREATE TABLE PS_H2_C3P0 (id INTEGER not NULL, PRIMARY KEY ( id ))" + "derby" | cpDatasources.get("c3p0").get("derby").getConnection() | "APP" | "CREATE TABLE PS_DERBY_C3P0 (id INTEGER not NULL, PRIMARY KEY ( id ))" } @@ -558,17 +558,17 @@ class JDBCInstrumentationTest extends AgentTestRunner { } where: - prepareStatement | driver | driverClass | url | username | query - true | "h2:mem" | new Driver() | "jdbc:h2:mem:" + dbName | null | "SELECT 3;" - true | "derby:memory" | new EmbeddedDriver() | "jdbc:derby:memory:" + dbName + ";create=true" | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - false | "h2:mem" | new Driver() | "jdbc:h2:mem:" + dbName | null | "SELECT 3;" - false | "derby:memory" | new EmbeddedDriver() | "jdbc:derby:memory:" + dbName + ";create=true" | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + prepareStatement | driver | driverClass | url | username | query + true | "h2" | new Driver() | "jdbc:h2:mem:" + dbName | null | "SELECT 3;" + true | "derby" | new EmbeddedDriver() | "jdbc:derby:memory:" + dbName + ";create=true" | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + false | "h2" | new Driver() | "jdbc:h2:mem:" + dbName | null | "SELECT 3;" + false | "derby" | new EmbeddedDriver() | "jdbc:derby:memory:" + dbName + ";create=true" | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" } @Unroll def "#connectionPoolName connections should be cached in case of wrapped connections"() { setup: - String dbType = "hsqldb:mem" + String dbType = "hsqldb" DataSource ds = createDS(connectionPoolName, dbType, jdbcUrls.get(dbType)) String query = "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" int numQueries = 5 From 1a5a70650c20b0bdd7815b6fb37896fa77e468a0 Mon Sep 17 00:00:00 2001 From: Tyler Benson Date: Mon, 10 Jun 2019 16:49:57 -0700 Subject: [PATCH 6/7] Fix SpringJpaTest --- .../src/test/groovy/SpringJpaTest.groovy | 55 +++++++------------ .../agent/test/asserts/SpanAssert.groovy | 7 +++ 2 files changed, 26 insertions(+), 36 deletions(-) diff --git a/dd-java-agent/instrumentation/hibernate/core-4.3/src/test/groovy/SpringJpaTest.groovy b/dd-java-agent/instrumentation/hibernate/core-4.3/src/test/groovy/SpringJpaTest.groovy index b936663e61..6a33ef9b3d 100644 --- a/dd-java-agent/instrumentation/hibernate/core-4.3/src/test/groovy/SpringJpaTest.groovy +++ b/dd-java-agent/instrumentation/hibernate/core-4.3/src/test/groovy/SpringJpaTest.groovy @@ -26,16 +26,12 @@ class SpringJpaTest extends AgentTestRunner { !repo.findAll().iterator().hasNext() assertTraces(1) { - trace(0, 2) { + trace(0, 1) { span(0) { serviceName "hsqldb" + resourceName "select customer0_.id as id1_0_, customer0_.firstName as firstNam2_0_, customer0_.lastName as lastName3_0_ from Customer customer0_" spanType "sql" } - span(1) { - serviceName "hsqldb" - spanType "sql" - childOf(span(0)) - } } } TEST_WRITER.clear() @@ -49,25 +45,22 @@ class SpringJpaTest extends AgentTestRunner { // Behavior changed in new version: def extraTrace = TEST_WRITER.size() == 2 assertTraces(extraTrace ? 2 : 1) { - trace(0, 2) { - span(0) { - serviceName "hsqldb" - spanType "sql" - } - span(1) { - serviceName "hsqldb" - spanType "sql" - childOf(span(0)) - } - } if (extraTrace) { - trace(1, 1) { + trace(0, 1) { span(0) { serviceName "hsqldb" + resourceName "call next value for hibernate_sequence" spanType "sql" } } } + trace(extraTrace ? 1 : 0, 1) { + span(0) { + serviceName "hsqldb" + resourceName ~/insert into Customer \(.*\) values \(.*, \?, \?\)/ + spanType "sql" + } + } } TEST_WRITER.clear() @@ -78,20 +71,17 @@ class SpringJpaTest extends AgentTestRunner { then: customer.id == savedId assertTraces(2) { - trace(0, 2) { + trace(0, 1) { span(0) { serviceName "hsqldb" + resourceName "select customer0_.id as id1_0_0_, customer0_.firstName as firstNam2_0_0_, customer0_.lastName as lastName3_0_0_ from Customer customer0_ where customer0_.id=?" spanType "sql" } - span(1) { - serviceName "hsqldb" - spanType "sql" - childOf(span(0)) - } } trace(1, 1) { span(0) { serviceName "hsqldb" + resourceName "update Customer set firstName=?, lastName=? where id=?" spanType "sql" } } @@ -105,16 +95,12 @@ class SpringJpaTest extends AgentTestRunner { customer.id == savedId customer.firstName == "Bill" assertTraces(1) { - trace(0, 2) { + trace(0, 1) { span(0) { serviceName "hsqldb" + resourceName "select customer0_.id as id1_0_, customer0_.firstName as firstNam2_0_, customer0_.lastName as lastName3_0_ from Customer customer0_ where customer0_.lastName=?" spanType "sql" } - span(1) { - serviceName "hsqldb" - spanType "sql" - childOf(span(0)) - } } } TEST_WRITER.clear() @@ -124,20 +110,17 @@ class SpringJpaTest extends AgentTestRunner { then: assertTraces(2) { - trace(0, 2) { + trace(0, 1) { span(0) { serviceName "hsqldb" + resourceName "select customer0_.id as id1_0_0_, customer0_.firstName as firstNam2_0_0_, customer0_.lastName as lastName3_0_0_ from Customer customer0_ where customer0_.id=?" spanType "sql" } - span(1) { - serviceName "hsqldb" - spanType "sql" - childOf(span(0)) - } } trace(1, 1) { span(0) { serviceName "hsqldb" + resourceName "delete from Customer where id=?" spanType "sql" } } diff --git a/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/asserts/SpanAssert.groovy b/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/asserts/SpanAssert.groovy index 319d6916e1..c5a9351885 100644 --- a/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/asserts/SpanAssert.groovy +++ b/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/asserts/SpanAssert.groovy @@ -4,6 +4,8 @@ import datadog.opentracing.DDSpan import groovy.transform.stc.ClosureParams import groovy.transform.stc.SimpleType +import java.util.regex.Pattern + import static TagsAssert.assertTags class SpanAssert { @@ -52,6 +54,11 @@ class SpanAssert { checked.operationName = true } + def resourceName(Pattern pattern) { + assert span.resourceName.matches(pattern) + checked.resourceName = true + } + def resourceName(String name) { assert span.resourceName == name checked.resourceName = true From 3c68c091018c85106972b032194e23a6a26030a6 Mon Sep 17 00:00:00 2001 From: Tyler Benson Date: Tue, 11 Jun 2019 11:12:50 -0700 Subject: [PATCH 7/7] Review fixes. --- .../jdbc/DriverInstrumentation.java | 17 ++++++------ .../jdbc/JDBCConnectionUrlParser.java | 25 ++++++++--------- .../PreparedStatementInstrumentation.java | 27 +++++++++---------- .../jdbc/StatementInstrumentation.java | 27 +++++++++---------- .../groovy/JDBCConnectionUrlParserTest.groovy | 2 ++ 5 files changed, 49 insertions(+), 49 deletions(-) diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DriverInstrumentation.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DriverInstrumentation.java index 33c258284a..a5340ddbd3 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DriverInstrumentation.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DriverInstrumentation.java @@ -35,18 +35,17 @@ public final class DriverInstrumentation extends Instrumenter.Default { @Override public String[] helperClassNames() { - final JDBCConnectionUrlParser[] parsers = JDBCConnectionUrlParser.values(); - final List parserClasses = new ArrayList<>(parsers.length + 3); + final List helpers = new ArrayList<>(JDBCConnectionUrlParser.values().length + 4); - parserClasses.add(packageName + ".DBInfo"); - parserClasses.add(packageName + ".DBInfo$Builder"); - parserClasses.add(packageName + ".JDBCMaps"); - parserClasses.add(packageName + ".JDBCConnectionUrlParser"); + helpers.add(packageName + ".DBInfo"); + helpers.add(packageName + ".DBInfo$Builder"); + helpers.add(packageName + ".JDBCMaps"); + helpers.add(packageName + ".JDBCConnectionUrlParser"); - for (final JDBCConnectionUrlParser parser : parsers) { - parserClasses.add(parser.getClass().getName()); + for (final JDBCConnectionUrlParser parser : JDBCConnectionUrlParser.values()) { + helpers.add(parser.getClass().getName()); } - return parserClasses.toArray(new String[0]); + return helpers.toArray(new String[0]); } @Override diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCConnectionUrlParser.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCConnectionUrlParser.java index ba5cdf4a30..8f5124ad79 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCConnectionUrlParser.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCConnectionUrlParser.java @@ -618,36 +618,37 @@ public enum JDBCConnectionUrlParser { populateStandardProperties(builder, splitQuery(split[1], ";")); } - if (split[0].startsWith("memory:")) { + final String details = split[0]; + if (details.startsWith("memory:")) { builder.subtype("memory"); - final String urlInstance = split[0].substring("memory:".length()); + final String urlInstance = details.substring("memory:".length()); if (!urlInstance.isEmpty()) { instance = urlInstance; } - } else if (split[0].startsWith("directory:")) { + } else if (details.startsWith("directory:")) { builder.subtype("directory"); - final String urlInstance = split[0].substring("directory:".length()); + final String urlInstance = details.substring("directory:".length()); if (!urlInstance.isEmpty()) { instance = urlInstance; } - } else if (split[0].startsWith("classpath:")) { + } else if (details.startsWith("classpath:")) { builder.subtype("classpath"); - final String urlInstance = split[0].substring("classpath:".length()); + final String urlInstance = details.substring("classpath:".length()); if (!urlInstance.isEmpty()) { instance = urlInstance; } - } else if (split[0].startsWith("jar:")) { + } else if (details.startsWith("jar:")) { builder.subtype("jar"); - final String urlInstance = split[0].substring("jar:".length()); + final String urlInstance = details.substring("jar:".length()); if (!urlInstance.isEmpty()) { instance = urlInstance; } - } else if (split[0].startsWith("//")) { + } else if (details.startsWith("//")) { builder.subtype("network"); if (dbInfo.getPort() == null) { builder.port(DEFAULT_PORT); } - String url = split[0].substring("//".length()); + String url = details.substring("//".length()); final int instanceLoc = url.indexOf("/"); if (instanceLoc >= 0) { instance = url.substring(instanceLoc + 1); @@ -666,7 +667,7 @@ public enum JDBCConnectionUrlParser { } } else { builder.subtype("directory"); - final String urlInstance = split[0]; + final String urlInstance = details; if (!urlInstance.isEmpty()) { instance = urlInstance; } @@ -701,7 +702,7 @@ public enum JDBCConnectionUrlParser { if (connectionUrl == null) { return DEFAULT; } - // Make this easer and ignore case. + // Make this easier and ignore case. connectionUrl = connectionUrl.toLowerCase(); if (!connectionUrl.startsWith("jdbc:")) { diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/PreparedStatementInstrumentation.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/PreparedStatementInstrumentation.java index 1b4b0d7da6..2242387c1d 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/PreparedStatementInstrumentation.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/PreparedStatementInstrumentation.java @@ -42,24 +42,23 @@ public final class PreparedStatementInstrumentation extends Instrumenter.Default @Override public String[] helperClassNames() { - final JDBCConnectionUrlParser[] parsers = JDBCConnectionUrlParser.values(); - final List parserClasses = new ArrayList<>(parsers.length + 8); + final List helpers = new ArrayList<>(JDBCConnectionUrlParser.values().length + 9); - parserClasses.add(packageName + ".DBInfo"); - parserClasses.add(packageName + ".DBInfo$Builder"); - parserClasses.add(packageName + ".JDBCUtils"); - parserClasses.add(packageName + ".JDBCMaps"); - parserClasses.add(packageName + ".JDBCConnectionUrlParser"); + helpers.add(packageName + ".DBInfo"); + helpers.add(packageName + ".DBInfo$Builder"); + helpers.add(packageName + ".JDBCUtils"); + helpers.add(packageName + ".JDBCMaps"); + helpers.add(packageName + ".JDBCConnectionUrlParser"); - parserClasses.add("datadog.trace.agent.decorator.BaseDecorator"); - parserClasses.add("datadog.trace.agent.decorator.ClientDecorator"); - parserClasses.add("datadog.trace.agent.decorator.DatabaseClientDecorator"); - parserClasses.add(packageName + ".JDBCDecorator"); + helpers.add("datadog.trace.agent.decorator.BaseDecorator"); + helpers.add("datadog.trace.agent.decorator.ClientDecorator"); + helpers.add("datadog.trace.agent.decorator.DatabaseClientDecorator"); + helpers.add(packageName + ".JDBCDecorator"); - for (final JDBCConnectionUrlParser parser : parsers) { - parserClasses.add(parser.getClass().getName()); + for (final JDBCConnectionUrlParser parser : JDBCConnectionUrlParser.values()) { + helpers.add(parser.getClass().getName()); } - return parserClasses.toArray(new String[0]); + return helpers.toArray(new String[0]); } @Override diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/StatementInstrumentation.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/StatementInstrumentation.java index 9d513319e9..5c0fb81177 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/StatementInstrumentation.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/StatementInstrumentation.java @@ -42,24 +42,23 @@ public final class StatementInstrumentation extends Instrumenter.Default { @Override public String[] helperClassNames() { - final JDBCConnectionUrlParser[] parsers = JDBCConnectionUrlParser.values(); - final List parserClasses = new ArrayList<>(parsers.length + 8); + final List helpers = new ArrayList<>(JDBCConnectionUrlParser.values().length + 9); - parserClasses.add(packageName + ".DBInfo"); - parserClasses.add(packageName + ".DBInfo$Builder"); - parserClasses.add(packageName + ".JDBCUtils"); - parserClasses.add(packageName + ".JDBCMaps"); - parserClasses.add(packageName + ".JDBCConnectionUrlParser"); + helpers.add(packageName + ".DBInfo"); + helpers.add(packageName + ".DBInfo$Builder"); + helpers.add(packageName + ".JDBCUtils"); + helpers.add(packageName + ".JDBCMaps"); + helpers.add(packageName + ".JDBCConnectionUrlParser"); - parserClasses.add("datadog.trace.agent.decorator.BaseDecorator"); - parserClasses.add("datadog.trace.agent.decorator.ClientDecorator"); - parserClasses.add("datadog.trace.agent.decorator.DatabaseClientDecorator"); - parserClasses.add(packageName + ".JDBCDecorator"); + helpers.add("datadog.trace.agent.decorator.BaseDecorator"); + helpers.add("datadog.trace.agent.decorator.ClientDecorator"); + helpers.add("datadog.trace.agent.decorator.DatabaseClientDecorator"); + helpers.add(packageName + ".JDBCDecorator"); - for (final JDBCConnectionUrlParser parser : parsers) { - parserClasses.add(parser.getClass().getName()); + for (final JDBCConnectionUrlParser parser : JDBCConnectionUrlParser.values()) { + helpers.add(parser.getClass().getName()); } - return parserClasses.toArray(new String[0]); + return helpers.toArray(new String[0]); } @Override diff --git a/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCConnectionUrlParserTest.groovy b/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCConnectionUrlParserTest.groovy index 3e70935b54..e0fb31854a 100644 --- a/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCConnectionUrlParserTest.groovy +++ b/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCConnectionUrlParserTest.groovy @@ -30,6 +30,8 @@ class JDBCConnectionUrlParserTest extends Specification { url | _ null | _ "" | _ + "jdbc:" | _ + "jdbc::" | _ "bogus:string" | _ }