Skip to content

Commit

Permalink
Fix sqlite-jdbc insrumentation for > 3.32.3.2 kamon-io#1008
Browse files Browse the repository at this point in the history
This is more of a temporary workaround than a fix. It disables
instrumentation on the non-prepared statement versions of queries
  • Loading branch information
David Knapp committed Apr 30, 2021
1 parent a6ebaca commit c10bfd2
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 39 deletions.
3 changes: 2 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,8 @@ lazy val `kamon-jdbc` = (project in file("instrumentation/kamon-jdbc"))
logbackClassic % "test",
"com.typesafe.slick" %% "slick-hikaricp" % "3.3.2" % "test",
"com.h2database" % "h2" % "1.4.182" % "test",
"org.xerial" % "sqlite-jdbc" % "3.27.2.1" % "test",
"org.xerial" % "sqlite-jdbc" % "3.34.0" % "test",
"org.apache.commons" % "commons-lang3" % "3.12.0" % "test",
"ch.vorburger.mariaDB4j" % "mariaDB4j" % "2.4.0" % "test"
)
).dependsOn(`kamon-core`, `kamon-executors`, `kamon-testkit` % "test")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@ import kamon.trace.Hooks
import kanela.agent.api.instrumentation.InstrumentationBuilder
import kanela.agent.api.instrumentation.bridge.FieldBridge
import kanela.agent.libs.net.bytebuddy.asm.Advice

import scala.util.Try

import kamon.instrumentation.jdbc.utils.LoggingSupport
import kanela.agent.libs.net.bytebuddy.matcher.ElementMatchers._

class StatementInstrumentation extends InstrumentationBuilder {
class StatementInstrumentation extends InstrumentationBuilder with LoggingSupport {

private val withOneStringArgument = withArgument(0, classOf[String])

Expand Down Expand Up @@ -78,11 +79,30 @@ class StatementInstrumentation extends InstrumentationBuilder {
.advise(method("executeQuery"), classOf[PreparedStatementExecuteQueryMethodAdvisor])
.advise(method("executeUpdate"), classOf[PreparedStatementExecuteUpdateMethodAdvisor])

onType("org.sqlite.jdbc3.JDBC3Statement")
.advise(method("execute").and(withOneStringArgument), classOf[StatementExecuteMethodAdvisor])
.advise(method("executeQuery").and(withOneStringArgument), classOf[StatementExecuteQueryMethodAdvisor])
.advise(method("executeUpdate").and(withOneStringArgument), classOf[StatementExecuteUpdateMethodAdvisor])
.advise(anyMethods("executeBatch", "executeLargeBatch"), classOf[StatementExecuteBatchMethodAdvisor])

try {
val prop = new Properties()
prop.load(this.getClass().getResourceAsStream("sqlite-jdbc.properties"))
val sqliteVersion = prop.getProperty("version", "0").split('.').map(_.toInt).toList

sqliteVersion match {
case epoch :: maj :: _ if epoch <= 3 && maj < 32 =>
onType("org.sqlite.jdbc3.JDBC3Statement")
.advise(method("execute").and(withOneStringArgument), classOf[StatementExecuteMethodAdvisor])
.advise(method("executeQuery").and(withOneStringArgument), classOf[StatementExecuteQueryMethodAdvisor])
.advise(method("executeUpdate").and(withOneStringArgument), classOf[StatementExecuteUpdateMethodAdvisor])
.advise(anyMethods("executeBatch", "executeLargeBatch"), classOf[StatementExecuteBatchMethodAdvisor])
case 3 :: 32 :: 3 :: p :: _ if p < 3 =>
onType("org.sqlite.jdbc3.JDBC3Statement")
.advise(method("execute").and(withOneStringArgument), classOf[StatementExecuteMethodAdvisor])
.advise(method("executeQuery").and(withOneStringArgument), classOf[StatementExecuteQueryMethodAdvisor])
.advise(method("executeUpdate").and(withOneStringArgument), classOf[StatementExecuteUpdateMethodAdvisor])
.advise(anyMethods("executeBatch", "executeLargeBatch"), classOf[StatementExecuteBatchMethodAdvisor])
case _ =>
logWarn("Could not instrument org.sqlite.jdbc3.JDBC3Statement. Prepared statements will be instrumented, but direct SQL calls will not")
}

}

/**
* Since Postgres is reusing the same statement in the implementation if isAlive, we need to "refresh" the
Expand Down Expand Up @@ -198,4 +218,4 @@ object PgConnectionIsAliveAdvice {
}
}
}
}
}
2 changes: 1 addition & 1 deletion instrumentation/kamon-jdbc/src/test/resources/logback.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@
<root level="OFF">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
</configuration>
Original file line number Diff line number Diff line change
Expand Up @@ -86,17 +86,19 @@ class StatementInstrumentationSpec extends WordSpec
}
}

"generate Spans on calls to .execute(sql) in statements" in {
val select = s"SELECT * FROM Address where Nr = 2"
val statement = connection.createStatement()
statement.execute(select)
validateNextRow(statement.getResultSet, valueNr = 2, valueName = "foo")


eventually(timeout(scaled(5 seconds)), interval(200 millis)) {
val span = commonSpanValidations(testSpanReporter(), driver)
validateQuery(span, StatementTypes.GenericExecute, select)
validateNextSpanIsEmpty(testSpanReporter())
if (driver != DriverSuite.SQLite) {
"generate Spans on calls to .execute(sql) in statements" in {
val select = s"SELECT * FROM Address where Nr = 2"
val statement = connection.createStatement()
statement.execute(select)
validateNextRow(statement.getResultSet, valueNr = 2, valueName = "foo")


eventually(timeout(scaled(5 seconds)), interval(200 millis)) {
val span = commonSpanValidations(testSpanReporter(), driver)
validateQuery(span, StatementTypes.GenericExecute, select)
validateNextSpanIsEmpty(testSpanReporter())
}
}
}

Expand All @@ -113,16 +115,18 @@ class StatementInstrumentationSpec extends WordSpec
}
}

"generate Spans on calls to .executeQuery(sql) in statements" in {
val select = s"SELECT * FROM Address where Nr = 4"
val statement = connection.createStatement()
val rs = statement.executeQuery(select)
validateNextRow(rs, valueNr = 4, valueName = "foo")

eventually(timeout(5 seconds), interval(100 millis)) {
val span = commonSpanValidations(testSpanReporter(), driver)
validateQuery(span, StatementTypes.Query, select)
validateNextSpanIsEmpty(testSpanReporter())
if (driver != DriverSuite.SQLite) {
"generate Spans on calls to .executeQuery(sql) in statements" in {
val select = s"SELECT * FROM Address where Nr = 4"
val statement = connection.createStatement()
val rs = statement.executeQuery(select)
validateNextRow(rs, valueNr = 4, valueName = "foo")

eventually(timeout(5 seconds), interval(100 millis)) {
val span = commonSpanValidations(testSpanReporter(), driver)
validateQuery(span, StatementTypes.Query, select)
validateNextSpanIsEmpty(testSpanReporter())
}
}
}

Expand All @@ -138,15 +142,17 @@ class StatementInstrumentationSpec extends WordSpec
}
}

"generate Spans on calls to .executeUpdate(sql) in statements" in {
val insert = s"INSERT INTO Address (Nr, Name) VALUES(6, 'foo')"
val affectedRows = connection.createStatement().executeUpdate(insert)
affectedRows shouldBe 1
if (driver != DriverSuite.SQLite) {
"generate Spans on calls to .executeUpdate(sql) in statements" in {
val insert = s"INSERT INTO Address (Nr, Name) VALUES(6, 'foo')"
val affectedRows = connection.createStatement().executeUpdate(insert)
affectedRows shouldBe 1

eventually(timeout(5 seconds), interval(100 millis)) {
val span = commonSpanValidations(testSpanReporter(), driver)
validateQuery(span, StatementTypes.Update, insert)
validateNextSpanIsEmpty(testSpanReporter())
eventually(timeout(5 seconds), interval(100 millis)) {
val span = commonSpanValidations(testSpanReporter(), driver)
validateQuery(span, StatementTypes.Update, insert)
validateNextSpanIsEmpty(testSpanReporter())
}
}
}

Expand Down

0 comments on commit c10bfd2

Please sign in to comment.