From c10bfd20e962faa7d5d4cdcb5fe73acb83970a80 Mon Sep 17 00:00:00 2001 From: David Knapp Date: Mon, 26 Apr 2021 16:08:39 -0700 Subject: [PATCH] Fix sqlite-jdbc insrumentation for > 3.32.3.2 #1008 This is more of a temporary workaround than a fix. It disables instrumentation on the non-prepared statement versions of queries --- build.sbt | 3 +- .../jdbc/StatementInstrumentation.scala | 36 ++++++++--- .../kamon-jdbc/src/test/resources/logback.xml | 2 +- .../jdbc/StatementInstrumentationSpec.scala | 64 ++++++++++--------- 4 files changed, 66 insertions(+), 39 deletions(-) diff --git a/build.sbt b/build.sbt index e1162f587..19e3005ba 100644 --- a/build.sbt +++ b/build.sbt @@ -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") diff --git a/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/StatementInstrumentation.scala b/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/StatementInstrumentation.scala index f86081fd9..169d5ca38 100644 --- a/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/StatementInstrumentation.scala +++ b/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/StatementInstrumentation.scala @@ -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]) @@ -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 @@ -198,4 +218,4 @@ object PgConnectionIsAliveAdvice { } } } -} \ No newline at end of file +} diff --git a/instrumentation/kamon-jdbc/src/test/resources/logback.xml b/instrumentation/kamon-jdbc/src/test/resources/logback.xml index c336bbfe4..0f6936605 100644 --- a/instrumentation/kamon-jdbc/src/test/resources/logback.xml +++ b/instrumentation/kamon-jdbc/src/test/resources/logback.xml @@ -9,4 +9,4 @@ - \ No newline at end of file + diff --git a/instrumentation/kamon-jdbc/src/test/scala/kamon/instrumentation/jdbc/StatementInstrumentationSpec.scala b/instrumentation/kamon-jdbc/src/test/scala/kamon/instrumentation/jdbc/StatementInstrumentationSpec.scala index 7d317e762..a31d7841e 100644 --- a/instrumentation/kamon-jdbc/src/test/scala/kamon/instrumentation/jdbc/StatementInstrumentationSpec.scala +++ b/instrumentation/kamon-jdbc/src/test/scala/kamon/instrumentation/jdbc/StatementInstrumentationSpec.scala @@ -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()) + } } } @@ -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()) + } } } @@ -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()) + } } }