Merge pull request #382 from DataDog/gary/jdbc-cache-investigation
Fixes #379 proxy connection caching issue
This commit is contained in:
commit
77717d305b
|
@ -1,5 +1,13 @@
|
|||
apply from: "${rootDir}/gradle/java.gradle"
|
||||
|
||||
apply plugin: 'org.unbroken-dome.test-sets'
|
||||
|
||||
testSets {
|
||||
latestDepTest {
|
||||
dirName = 'test'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(':dd-java-agent:agent-tooling')
|
||||
|
||||
|
@ -12,7 +20,24 @@ dependencies {
|
|||
// jdbc unit testing
|
||||
testCompile group: 'com.h2database', name: 'h2', version: '1.4.197'
|
||||
testCompile group: 'org.apache.derby', name: 'derby', version: '10.12.1.1'
|
||||
// not using hsqldb 2.4 because org/hsqldb/jdbc/JDBCDriver : Unsupported major.minor version 52.0
|
||||
testCompile group: 'org.hsqldb', name: 'hsqldb', version: '2.3.+'
|
||||
|
||||
testCompile group: 'org.apache.tomcat', name: 'tomcat-jdbc', version: '7.0.19'
|
||||
// tomcat needs this to run
|
||||
testCompile group: 'org.apache.tomcat', name: 'tomcat-juli', version: '7.0.19'
|
||||
testCompile group: 'com.zaxxer', name: 'HikariCP', version: '2.4.0'
|
||||
testCompile group: 'com.mchange', name: 'c3p0', version: '0.9.5'
|
||||
}
|
||||
|
||||
configurations.latestDepTestCompile {
|
||||
resolutionStrategy {
|
||||
force group: 'com.h2database', name: 'h2', version: '+'
|
||||
force group: 'org.apache.derby', name: 'derby', version: '+'
|
||||
force group: 'org.hsqldb', name: 'hsqldb', version: '+'
|
||||
|
||||
force group: 'org.apache.tomcat', name: 'tomcat-jdbc', version: '+'
|
||||
force group: 'org.apache.tomcat', name: 'tomcat-juli', version: '+'
|
||||
force group: 'com.zaxxer', name: 'HikariCP', version: '+'
|
||||
force group: 'com.mchange', name: 'c3p0', version: '+'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,9 +56,13 @@ public final class PreparedStatementInstrumentation extends Instrumenter.Default
|
|||
return null;
|
||||
}
|
||||
final String sql = JDBCMaps.preparedStatements.get(statement);
|
||||
final Connection connection;
|
||||
Connection connection;
|
||||
try {
|
||||
connection = statement.getConnection();
|
||||
// unwrap the connection to cache the underlying actual connection and to not cache proxy objects
|
||||
if (connection.isWrapperFor(Connection.class)) {
|
||||
connection = connection.unwrap(Connection.class);
|
||||
}
|
||||
} catch (final Throwable e) {
|
||||
// Had some problem getting the connection.
|
||||
return NoopScope.INSTANCE;
|
||||
|
|
|
@ -57,9 +57,13 @@ public final class StatementInstrumentation extends Instrumenter.Default {
|
|||
if (callDepth > 0) {
|
||||
return null;
|
||||
}
|
||||
final Connection connection;
|
||||
Connection connection;
|
||||
try {
|
||||
connection = statement.getConnection();
|
||||
if (connection.isWrapperFor(Connection.class)) {
|
||||
// unwrap the connection to cache the underlying actual connection and to not cache proxy objects
|
||||
connection = connection.unwrap(Connection.class);
|
||||
}
|
||||
} catch (final Throwable e) {
|
||||
// Had some problem getting the connection.
|
||||
return NoopScope.INSTANCE;
|
||||
|
|
|
@ -1,42 +1,145 @@
|
|||
import com.mchange.v2.c3p0.ComboPooledDataSource
|
||||
import com.zaxxer.hikari.HikariConfig
|
||||
import com.zaxxer.hikari.HikariDataSource
|
||||
import datadog.trace.agent.test.AgentTestRunner
|
||||
import datadog.trace.api.DDSpanTypes
|
||||
import io.opentracing.tag.Tags
|
||||
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.Connection
|
||||
import java.sql.PreparedStatement
|
||||
import java.sql.ResultSet
|
||||
import java.sql.Statement
|
||||
|
||||
import static datadog.trace.agent.test.ListWriterAssert.assertTraces
|
||||
|
||||
class JDBCInstrumentationTest extends AgentTestRunner {
|
||||
|
||||
@Shared
|
||||
def dbName = "jdbcUnitTest"
|
||||
|
||||
@Shared
|
||||
private Map<String, Connection> connections
|
||||
private Map<String, String> jdbcUrls = [
|
||||
h2 : "jdbc:h2:mem:" + dbName,
|
||||
derby : "jdbc:derby:memory:" + dbName,
|
||||
hsqldb: "jdbc:hsqldb:mem:" + dbName
|
||||
]
|
||||
|
||||
@Shared
|
||||
private Map<String, String> jdbcDriverClassNames = [
|
||||
h2 : "org.h2.Driver",
|
||||
derby : "org.apache.derby.jdbc.EmbeddedDriver",
|
||||
hsqldb: "org.hsqldb.jdbc.JDBCDriver"
|
||||
]
|
||||
|
||||
@Shared
|
||||
private Map<String, String> jdbcUserNames = [
|
||||
h2 : null,
|
||||
derby : "APP",
|
||||
hsqldb: "SA"
|
||||
]
|
||||
|
||||
// JDBC Connection pool name (i.e. HikariCP) -> Map<dbName, Datasource>
|
||||
@Shared
|
||||
private Map<String, Map<String, DataSource>> cpDatasources = new HashMap<>()
|
||||
|
||||
def prepareConnectionPoolDatasources() {
|
||||
String[] connectionPoolNames = [
|
||||
"tomcat", "hikari", "c3p0"
|
||||
]
|
||||
connectionPoolNames.each {
|
||||
cpName ->
|
||||
Map<String, DataSource> dbDSMapping = new HashMap<>()
|
||||
jdbcUrls.each {
|
||||
dbType, jdbcUrl ->
|
||||
dbDSMapping.put(dbType, createDS(cpName, dbType, jdbcUrl))
|
||||
}
|
||||
cpDatasources.put(cpName, dbDSMapping)
|
||||
}
|
||||
}
|
||||
|
||||
def createTomcatDS(String dbType, String jdbcUrl) {
|
||||
DataSource ds = new org.apache.tomcat.jdbc.pool.DataSource()
|
||||
def jdbcUrlToSet = dbType == "derby" ? jdbcUrl + ";create=true" : jdbcUrl
|
||||
ds.setUrl(jdbcUrlToSet)
|
||||
ds.setDriverClassName(jdbcDriverClassNames.get(dbType))
|
||||
String username = jdbcUserNames.get(dbType)
|
||||
if (username != null) {
|
||||
ds.setUsername(username)
|
||||
}
|
||||
ds.setPassword("")
|
||||
ds.setMaxActive(1) // to test proper caching, having > 1 max active connection will be hard to
|
||||
// determine whether the connection is properly cached
|
||||
return ds
|
||||
}
|
||||
|
||||
def createHikariDS(String dbType, String jdbcUrl) {
|
||||
HikariConfig config = new HikariConfig()
|
||||
def jdbcUrlToSet = dbType == "derby" ? jdbcUrl + ";create=true" : jdbcUrl
|
||||
config.setJdbcUrl(jdbcUrlToSet)
|
||||
String username = jdbcUserNames.get(dbType)
|
||||
if (username != null) {
|
||||
config.setUsername(username)
|
||||
}
|
||||
config.setPassword("")
|
||||
config.addDataSourceProperty("cachePrepStmts", "true")
|
||||
config.addDataSourceProperty("prepStmtCacheSize", "250")
|
||||
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048")
|
||||
config.setMaximumPoolSize(1)
|
||||
|
||||
return new HikariDataSource(config)
|
||||
}
|
||||
|
||||
def createC3P0DS(String dbType, String jdbcUrl) {
|
||||
DataSource ds = new ComboPooledDataSource()
|
||||
ds.setDriverClass(jdbcDriverClassNames.get(dbType))
|
||||
def jdbcUrlToSet = dbType == "derby" ? jdbcUrl + ";create=true" : jdbcUrl
|
||||
ds.setJdbcUrl(jdbcUrlToSet)
|
||||
String username = jdbcUserNames.get(dbType)
|
||||
if (username != null) {
|
||||
ds.setUser(username)
|
||||
}
|
||||
ds.setPassword("")
|
||||
ds.setMaxPoolSize(1)
|
||||
return ds
|
||||
}
|
||||
|
||||
def createDS(String connectionPoolName, String dbType, String jdbcUrl) {
|
||||
DataSource ds = null
|
||||
if (connectionPoolName == "tomcat") {
|
||||
ds = createTomcatDS(dbType, jdbcUrl)
|
||||
}
|
||||
if (connectionPoolName == "hikari") {
|
||||
ds = createHikariDS(dbType, jdbcUrl)
|
||||
}
|
||||
if (connectionPoolName == "c3p0") {
|
||||
ds = createC3P0DS(dbType, jdbcUrl)
|
||||
}
|
||||
return ds
|
||||
}
|
||||
|
||||
def setupSpec() {
|
||||
Connection h2Connection = new Driver().connect("jdbc:h2:mem:" + dbName, null)
|
||||
Connection hsqlConnection = new JDBCDriver().connect("jdbc:hsqldb:mem:" + dbName, null)
|
||||
Connection derbyConnection = new EmbeddedDriver().connect("jdbc:derby:memory:" + dbName + ";create=true", null)
|
||||
|
||||
connections = [
|
||||
h2 : h2Connection,
|
||||
derby : derbyConnection,
|
||||
hsqldb: hsqlConnection,
|
||||
]
|
||||
prepareConnectionPoolDatasources()
|
||||
}
|
||||
|
||||
def cleanupSpec() {
|
||||
connections.values().each {
|
||||
it.close()
|
||||
cpDatasources.values().each {
|
||||
it.values().each {
|
||||
datasource ->
|
||||
if (datasource instanceof Closeable) {
|
||||
datasource.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Unroll
|
||||
def "basic statement on #driver generates spans"() {
|
||||
def "basic statement with #connection.getClass().getCanonicalName() on #driver generates spans"() {
|
||||
setup:
|
||||
Statement statement = connection.createStatement()
|
||||
ResultSet resultSet = statement.executeQuery(query)
|
||||
|
@ -44,45 +147,52 @@ class JDBCInstrumentationTest extends AgentTestRunner {
|
|||
expect:
|
||||
resultSet.next()
|
||||
resultSet.getInt(1) == 3
|
||||
TEST_WRITER.size() == 1
|
||||
|
||||
def trace = TEST_WRITER.firstTrace()
|
||||
trace.size() == 1
|
||||
def span = trace[0]
|
||||
|
||||
span.context().operationName == "${driver}.query"
|
||||
span.serviceName == driver
|
||||
span.resourceName == query
|
||||
span.type == "sql"
|
||||
!span.context().getErrorFlag()
|
||||
span.context().parentId == 0
|
||||
|
||||
|
||||
def tags = span.context().tags
|
||||
tags["db.type"] == driver
|
||||
tags["db.user"] == username
|
||||
tags["span.kind"] == "client"
|
||||
tags["component"] == "java-jdbc-statement"
|
||||
|
||||
tags["db.jdbc.url"].contains(driver)
|
||||
tags["span.origin.type"] != null
|
||||
|
||||
tags["thread.name"] != null
|
||||
tags["thread.id"] != null
|
||||
tags.size() == username == null ? 7 : 8
|
||||
assertTraces(TEST_WRITER, 1) {
|
||||
trace(0, 1) {
|
||||
span(0) {
|
||||
operationName "${driver}.query"
|
||||
serviceName driver
|
||||
resourceName query
|
||||
spanType DDSpanTypes.SQL
|
||||
errored false
|
||||
tags {
|
||||
"db.type" driver
|
||||
if (username != null) {
|
||||
"db.user" username
|
||||
}
|
||||
"span.kind" Tags.SPAN_KIND_CLIENT
|
||||
"span.type" DDSpanTypes.SQL
|
||||
"component" "java-jdbc-statement"
|
||||
"db.jdbc.url" jdbcUrls.get(driver)
|
||||
"span.origin.type" String
|
||||
defaultTags()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
statement.close()
|
||||
connection.close()
|
||||
|
||||
where:
|
||||
driver | connection | username | query
|
||||
"h2" | connections.get("h2") | null | "SELECT 3"
|
||||
"derby" | connections.get("derby") | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1"
|
||||
"hsqldb" | connections.get("hsqldb") | "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" | 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
|
||||
def "prepared statement execute on #driver generates a span"() {
|
||||
def "prepared statement execute on #driver with #connection.getClass().getCanonicalName() generates a span"() {
|
||||
setup:
|
||||
PreparedStatement statement = connection.prepareStatement(query)
|
||||
assert statement.execute()
|
||||
|
@ -91,45 +201,48 @@ class JDBCInstrumentationTest extends AgentTestRunner {
|
|||
expect:
|
||||
resultSet.next()
|
||||
resultSet.getInt(1) == 3
|
||||
TEST_WRITER.size() == 1
|
||||
|
||||
def trace = TEST_WRITER.firstTrace()
|
||||
trace.size() == 1
|
||||
def span = trace[0]
|
||||
|
||||
span.context().operationName == "${driver}.query"
|
||||
span.serviceName == driver
|
||||
span.resourceName == query
|
||||
span.type == "sql"
|
||||
!span.context().getErrorFlag()
|
||||
span.context().parentId == 0
|
||||
|
||||
|
||||
def tags = span.context().tags
|
||||
tags["db.type"] == driver
|
||||
tags["db.user"] == username
|
||||
tags["span.kind"] == "client"
|
||||
tags["component"] == "java-jdbc-prepared_statement"
|
||||
|
||||
tags["db.jdbc.url"].contains(driver)
|
||||
tags["span.origin.type"] != null
|
||||
|
||||
tags["thread.name"] != null
|
||||
tags["thread.id"] != null
|
||||
tags.size() == username == null ? 7 : 8
|
||||
assertTraces(TEST_WRITER, 1) {
|
||||
trace(0, 1) {
|
||||
span(0) {
|
||||
operationName "${driver}.query"
|
||||
serviceName driver
|
||||
resourceName query
|
||||
spanType DDSpanTypes.SQL
|
||||
errored false
|
||||
tags {
|
||||
"db.type" driver
|
||||
if (username != null) {
|
||||
"db.user" username
|
||||
}
|
||||
"span.kind" Tags.SPAN_KIND_CLIENT
|
||||
"span.type" DDSpanTypes.SQL
|
||||
"component" "java-jdbc-prepared_statement"
|
||||
"db.jdbc.url" jdbcUrls.get(driver)
|
||||
"span.origin.type" String
|
||||
defaultTags()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
statement.close()
|
||||
connection.close()
|
||||
|
||||
where:
|
||||
driver | connection | username | query
|
||||
"h2" | connections.get("h2") | null | "SELECT 3"
|
||||
"derby" | connections.get("derby") | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1"
|
||||
"hsqldb" | connections.get("hsqldb") | "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"
|
||||
"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
|
||||
def "prepared statement query on #driver generates a span"() {
|
||||
def "prepared statement query on #driver with #connection.getClass().getCanonicalName() generates a span"() {
|
||||
setup:
|
||||
PreparedStatement statement = connection.prepareStatement(query)
|
||||
ResultSet resultSet = statement.executeQuery()
|
||||
|
@ -137,45 +250,48 @@ class JDBCInstrumentationTest extends AgentTestRunner {
|
|||
expect:
|
||||
resultSet.next()
|
||||
resultSet.getInt(1) == 3
|
||||
TEST_WRITER.size() == 1
|
||||
|
||||
def trace = TEST_WRITER.firstTrace()
|
||||
trace.size() == 1
|
||||
def span = trace[0]
|
||||
|
||||
span.context().operationName == "${driver}.query"
|
||||
span.serviceName == driver
|
||||
span.resourceName == query
|
||||
span.type == "sql"
|
||||
!span.context().getErrorFlag()
|
||||
span.context().parentId == 0
|
||||
|
||||
|
||||
def tags = span.context().tags
|
||||
tags["db.type"] == driver
|
||||
tags["db.user"] == username
|
||||
tags["span.kind"] == "client"
|
||||
tags["component"] == "java-jdbc-prepared_statement"
|
||||
|
||||
tags["db.jdbc.url"].contains(driver)
|
||||
tags["span.origin.type"] != null
|
||||
|
||||
tags["thread.name"] != null
|
||||
tags["thread.id"] != null
|
||||
tags.size() == username == null ? 7 : 8
|
||||
assertTraces(TEST_WRITER, 1) {
|
||||
trace(0, 1) {
|
||||
span(0) {
|
||||
operationName "${driver}.query"
|
||||
serviceName driver
|
||||
resourceName query
|
||||
spanType DDSpanTypes.SQL
|
||||
errored false
|
||||
tags {
|
||||
"db.type" driver
|
||||
if (username != null) {
|
||||
"db.user" username
|
||||
}
|
||||
"span.kind" Tags.SPAN_KIND_CLIENT
|
||||
"span.type" DDSpanTypes.SQL
|
||||
"component" "java-jdbc-prepared_statement"
|
||||
"db.jdbc.url" jdbcUrls.get(driver)
|
||||
"span.origin.type" String
|
||||
defaultTags()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
statement.close()
|
||||
connection.close()
|
||||
|
||||
where:
|
||||
driver | connection | username | query
|
||||
"h2" | connections.get("h2") | null | "SELECT 3"
|
||||
"derby" | connections.get("derby") | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1"
|
||||
"hsqldb" | connections.get("hsqldb") | "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"
|
||||
"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
|
||||
def "statement update on #driver generates a span"() {
|
||||
def "statement update on #driver with #connection.getClass().getCanonicalName() generates a span"() {
|
||||
setup:
|
||||
Statement statement = connection.createStatement()
|
||||
def sql = connection.nativeSQL(query)
|
||||
|
@ -183,87 +299,97 @@ class JDBCInstrumentationTest extends AgentTestRunner {
|
|||
expect:
|
||||
!statement.execute(sql)
|
||||
statement.updateCount == 0
|
||||
|
||||
TEST_WRITER.size() == 1
|
||||
|
||||
def trace = TEST_WRITER.firstTrace()
|
||||
trace.size() == 1
|
||||
def span = trace[0]
|
||||
|
||||
span.context().operationName == "${driver}.query"
|
||||
span.serviceName == driver
|
||||
span.resourceName == query
|
||||
span.type == "sql"
|
||||
!span.context().getErrorFlag()
|
||||
span.context().parentId == 0
|
||||
|
||||
|
||||
def tags = span.context().tags
|
||||
tags["db.type"] == driver
|
||||
tags["db.user"] == username
|
||||
tags["span.kind"] == "client"
|
||||
tags["component"] == "java-jdbc-statement"
|
||||
|
||||
tags["db.jdbc.url"].contains(driver)
|
||||
tags["span.origin.type"] != null
|
||||
|
||||
tags["thread.name"] != null
|
||||
tags["thread.id"] != null
|
||||
tags.size() == username == null ? 7 : 8
|
||||
assertTraces(TEST_WRITER, 1) {
|
||||
trace(0, 1) {
|
||||
span(0) {
|
||||
operationName "${driver}.query"
|
||||
serviceName driver
|
||||
resourceName query
|
||||
spanType DDSpanTypes.SQL
|
||||
errored false
|
||||
tags {
|
||||
"db.type" driver
|
||||
if (username != null) {
|
||||
"db.user" username
|
||||
}
|
||||
"span.kind" Tags.SPAN_KIND_CLIENT
|
||||
"span.type" DDSpanTypes.SQL
|
||||
"component" "java-jdbc-statement"
|
||||
"db.jdbc.url" jdbcUrls.get(driver)
|
||||
"span.origin.type" String
|
||||
defaultTags()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
statement.close()
|
||||
connection.close()
|
||||
|
||||
where:
|
||||
driver | connection | username | query
|
||||
"h2" | connections.get("h2") | null | "CREATE TABLE S_H2 (id INTEGER not NULL, PRIMARY KEY ( id ))"
|
||||
"derby" | connections.get("derby") | "APP" | "CREATE TABLE S_DERBY (id INTEGER not NULL, PRIMARY KEY ( id ))"
|
||||
"hsqldb" | connections.get("hsqldb") | "SA" | "CREATE TABLE PUBLIC.S_HSQLDB (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
|
||||
def "prepared statement update on #driver generates a span"() {
|
||||
def "prepared statement update on #driver with #connection.getClass().getCanonicalName() generates a span"() {
|
||||
setup:
|
||||
def sql = connection.nativeSQL(query)
|
||||
PreparedStatement statement = connection.prepareStatement(sql)
|
||||
|
||||
expect:
|
||||
statement.executeUpdate() == 0
|
||||
TEST_WRITER.size() == 1
|
||||
|
||||
def trace = TEST_WRITER.firstTrace()
|
||||
trace.size() == 1
|
||||
def span = trace[0]
|
||||
|
||||
span.context().operationName == "${driver}.query"
|
||||
span.serviceName == driver
|
||||
span.resourceName == query
|
||||
span.type == "sql"
|
||||
!span.context().getErrorFlag()
|
||||
span.context().parentId == 0
|
||||
|
||||
|
||||
def tags = span.context().tags
|
||||
tags["db.type"] == driver
|
||||
tags["db.user"] == username
|
||||
tags["span.kind"] == "client"
|
||||
tags["component"] == "java-jdbc-prepared_statement"
|
||||
|
||||
tags["db.jdbc.url"].contains(driver)
|
||||
tags["span.origin.type"] != null
|
||||
|
||||
tags["thread.name"] != null
|
||||
tags["thread.id"] != null
|
||||
tags.size() == username == null ? 7 : 8
|
||||
assertTraces(TEST_WRITER, 1) {
|
||||
trace(0, 1) {
|
||||
span(0) {
|
||||
operationName "${driver}.query"
|
||||
serviceName driver
|
||||
resourceName query
|
||||
spanType DDSpanTypes.SQL
|
||||
errored false
|
||||
tags {
|
||||
"db.type" driver
|
||||
if (username != null) {
|
||||
"db.user" username
|
||||
}
|
||||
"span.kind" Tags.SPAN_KIND_CLIENT
|
||||
"span.type" DDSpanTypes.SQL
|
||||
"component" "java-jdbc-prepared_statement"
|
||||
"db.jdbc.url" jdbcUrls.get(driver)
|
||||
"span.origin.type" String
|
||||
defaultTags()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
statement.close()
|
||||
connection.close()
|
||||
|
||||
where:
|
||||
driver | connection | username | query
|
||||
"h2" | connections.get("h2") | null | "CREATE TABLE PS_H2 (id INTEGER not NULL, PRIMARY KEY ( id ))"
|
||||
"derby" | connections.get("derby") | "APP" | "CREATE TABLE PS_DERBY (id INTEGER not NULL, PRIMARY KEY ( id ))"
|
||||
"hsqldb" | connections.get("hsqldb") | "SA" | "CREATE TABLE PUBLIC.PS_HSQLDB (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 ))"
|
||||
|
||||
}
|
||||
|
||||
@Unroll
|
||||
|
@ -291,37 +417,34 @@ class JDBCInstrumentationTest extends AgentTestRunner {
|
|||
then:
|
||||
rs.next()
|
||||
rs.getInt(1) == 3
|
||||
TEST_WRITER.size() == 1
|
||||
|
||||
def trace = TEST_WRITER.firstTrace()
|
||||
trace.size() == 1
|
||||
|
||||
and:
|
||||
def span = trace[0]
|
||||
span.context().operationName == "${driver}.query"
|
||||
span.serviceName == driver
|
||||
span.resourceName == query
|
||||
span.type == "sql"
|
||||
!span.context().getErrorFlag()
|
||||
span.context().parentId == 0
|
||||
|
||||
def tags = span.context().tags
|
||||
tags["db.type"] == driver
|
||||
tags["db.user"] == user
|
||||
tags["span.kind"] == "client"
|
||||
if (prepareStatement) {
|
||||
tags["component"] == "java-jdbc-prepared_statement"
|
||||
} else {
|
||||
tags["component"] == "java-jdbc-statement"
|
||||
assertTraces(TEST_WRITER, 1) {
|
||||
trace(0, 1) {
|
||||
span(0) {
|
||||
operationName "${driver}.query"
|
||||
serviceName driver
|
||||
resourceName query
|
||||
spanType DDSpanTypes.SQL
|
||||
errored false
|
||||
tags {
|
||||
"db.type" driver
|
||||
if (username != null) {
|
||||
"db.user" username
|
||||
}
|
||||
if (prepareStatement) {
|
||||
"component" "java-jdbc-prepared_statement"
|
||||
} else {
|
||||
"component" "java-jdbc-statement"
|
||||
}
|
||||
"span.kind" Tags.SPAN_KIND_CLIENT
|
||||
"span.type" DDSpanTypes.SQL
|
||||
"db.jdbc.url" jdbcUrls.get(driver)
|
||||
"span.origin.type" String
|
||||
defaultTags()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tags["db.jdbc.url"].contains(driver)
|
||||
tags["span.origin.type"] != null
|
||||
|
||||
tags["thread.name"] != null
|
||||
tags["thread.id"] != null
|
||||
tags.size() == user == null ? 7 : 8
|
||||
|
||||
cleanup:
|
||||
if (statement != null) {
|
||||
statement.close()
|
||||
|
@ -331,11 +454,97 @@ class JDBCInstrumentationTest extends AgentTestRunner {
|
|||
}
|
||||
|
||||
where:
|
||||
prepareStatement | driver | driverClass | url | user | 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" | 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"
|
||||
DataSource ds = createDS(connectionPoolName, dbType, jdbcUrls.get(dbType))
|
||||
String query = "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS"
|
||||
int numQueries = 5
|
||||
Connection connection = null
|
||||
Statement statement = null
|
||||
ResultSet rs = null
|
||||
int[] res = new int[numQueries]
|
||||
|
||||
when:
|
||||
for (int i = 0; i < numQueries; ++i) {
|
||||
try {
|
||||
connection = ds.getConnection()
|
||||
statement = connection.prepareStatement(query)
|
||||
rs = statement.executeQuery()
|
||||
if (rs.next()) {
|
||||
res[i] = rs.getInt(1)
|
||||
} else {
|
||||
res[i] = 0
|
||||
}
|
||||
} finally {
|
||||
connection.close()
|
||||
}
|
||||
}
|
||||
|
||||
then:
|
||||
for (int i = 0; i < numQueries; ++i) {
|
||||
res[i] == 3
|
||||
}
|
||||
assertTraces(TEST_WRITER, 6) {
|
||||
trace(0, 1) {
|
||||
span(0) {
|
||||
operationName "${dbType}.query"
|
||||
serviceName dbType
|
||||
resourceName "CALL USER()"
|
||||
spanType DDSpanTypes.SQL
|
||||
errored false
|
||||
tags {
|
||||
"db.type" "hsqldb"
|
||||
"db.user" "SA"
|
||||
"component" "java-jdbc-statement"
|
||||
"span.kind" Tags.SPAN_KIND_CLIENT
|
||||
"span.type" DDSpanTypes.SQL
|
||||
"db.jdbc.url" jdbcUrls.get(dbType)
|
||||
"span.origin.type" String
|
||||
defaultTags()
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 1; i < numQueries + 1; ++i) {
|
||||
trace(i, 1) {
|
||||
span(0) {
|
||||
operationName "${dbType}.query"
|
||||
serviceName dbType
|
||||
resourceName query
|
||||
spanType DDSpanTypes.SQL
|
||||
errored false
|
||||
tags {
|
||||
"db.type" dbType
|
||||
"db.user" "SA"
|
||||
"component" "java-jdbc-prepared_statement"
|
||||
"span.kind" Tags.SPAN_KIND_CLIENT
|
||||
"span.type" DDSpanTypes.SQL
|
||||
"db.jdbc.url" jdbcUrls.get(dbType)
|
||||
"span.origin.type" String
|
||||
defaultTags()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (ds instanceof Closeable) {
|
||||
ds.close()
|
||||
}
|
||||
|
||||
where:
|
||||
connectionPoolName | _
|
||||
"hikari" | _
|
||||
"tomcat" | _
|
||||
"c3p0" | _
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue