aboutsummaryrefslogblamecommitdiff
path: root/kamon-jdbc/src/test/scala/kamon/jdbc/instrumentation/StatementInstrumentationSpec.scala
blob: a778144722665b9d37391f3c3df66eaa208edf14 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
















                                                                                             
                                               
 
                                        
                                                                                             
                                  
                                              

                                                                       
                                                                                 











                                                                         

                                         
                                                        
                                                           
                               




                                                                           
                                      
       
 

                                                                              
 

                                                                                   




                                                                           
                                                         

                                                                                       
     
 
                                                        
                                                           
                               




                                                              
                                      
       
 

                                                                             
 

                                                                                   




                                                                           
                                                         

                                                                                       
     
 
                                                        
                                                           

                                                                           



                                                                   
                                      
       
 

                                                                              
 

                                                                                   




                                                                           
                                                         

                                                                                       
     
 
                                                        
                                                           

                                                            

                                                            

         
                                      
       
 

                                                                              
 

                                                                                   




                                                                           
                                                         

                                                                                       
 
     
 
                                                                                                 
                                                         
                             




                                                                
                                      
       
 

                                                                             
 
     
 
                               
                                                           
                             
                                   
                                                         



                                                             
 
                                      
       
 

                                                                             
     
   

 
                                                         
                                                                                                                            

 
                                                       


                                                                                


                                                                                       
/* =========================================================================================
 * Copyright © 2013-2014 the kamon project <http://kamon.io/>
 *
 * Licensed under the Apache License, Version 2.0 (the "License") you may not use this file
 * except in compliance with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the
 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language governing permissions
 * and limitations under the License.
 * =========================================================================================
 */

package kamon.jdbc.instrumentation

import java.sql.{ DriverManager, SQLException }

import com.typesafe.config.ConfigFactory
import kamon.jdbc.{ JdbcExtension, JdbcNameGenerator, SqlErrorProcessor, SlowQueryProcessor }
import kamon.testkit.BaseKamonSpec
import kamon.trace.{ Tracer, SegmentCategory }

class StatementInstrumentationSpec extends BaseKamonSpec("jdbc-spec") {
  val connection = DriverManager.getConnection("jdbc:h2:mem:jdbc-spec", "SA", "")

  override protected def beforeAll(): Unit = {
    connection should not be null

    val create = "CREATE TABLE Address (Nr INTEGER, Name VARCHAR(128));"
    val createStatement = connection.createStatement()
    createStatement.executeUpdate(create)

    val sleep = "CREATE ALIAS SLEEP FOR \"java.lang.Thread.sleep(long)\""
    val sleepStatement = connection.createStatement()
    sleepStatement.executeUpdate(sleep)
  }

  "the StatementInstrumentation" should {
    "record the execution time of INSERT operation" in {
      Tracer.withContext(newContext("jdbc-trace-insert")) {
        for (id  1 to 100) {
          val insert = s"INSERT INTO Address (Nr, Name) VALUES($id, 'foo')"
          val insertStatement = connection.prepareStatement(insert)
          insertStatement.execute()
        }

        Tracer.currentContext.finish()
      }

      val jdbcSnapshot = takeSnapshotOf("jdbc-statements", "jdbc-statements")
      jdbcSnapshot.histogram("writes").get.numberOfMeasurements should be(100)

      val traceSnapshot = takeSnapshotOf("jdbc-trace-insert", "trace")
      traceSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1)

      val segmentSnapshot = takeSnapshotOf("Jdbc[Insert]", "trace-segment",
        tags = Map(
          "trace" -> "jdbc-trace-insert",
          "category" -> SegmentCategory.Database,
          "library" -> JdbcExtension.SegmentLibraryName))

      segmentSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(100)
    }

    "record the execution time of SELECT operation" in {
      Tracer.withContext(newContext("jdbc-trace-select")) {
        for (id  1 to 100) {
          val select = s"SELECT * FROM Address where Nr = $id"
          val selectStatement = connection.createStatement()
          selectStatement.execute(select)
        }

        Tracer.currentContext.finish()
      }

      val jdbcSnapshot = takeSnapshotOf("jdbc-statements", "jdbc-statements")
      jdbcSnapshot.histogram("reads").get.numberOfMeasurements should be(100)

      val traceSnapshot = takeSnapshotOf("jdbc-trace-select", "trace")
      traceSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1)

      val segmentSnapshot = takeSnapshotOf("Jdbc[Select]", "trace-segment",
        tags = Map(
          "trace" -> "jdbc-trace-select",
          "category" -> SegmentCategory.Database,
          "library" -> JdbcExtension.SegmentLibraryName))

      segmentSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(100)
    }

    "record the execution time of UPDATE operation" in {
      Tracer.withContext(newContext("jdbc-trace-update")) {
        for (id  1 to 100) {
          val update = s"UPDATE Address SET Name = 'bar$id' where Nr = $id"
          val updateStatement = connection.prepareStatement(update)
          updateStatement.execute()
        }

        Tracer.currentContext.finish()
      }

      val jdbcSnapshot = takeSnapshotOf("jdbc-statements", "jdbc-statements")
      jdbcSnapshot.histogram("writes").get.numberOfMeasurements should be(100)

      val traceSnapshot = takeSnapshotOf("jdbc-trace-update", "trace")
      traceSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1)

      val segmentSnapshot = takeSnapshotOf("Jdbc[Update]", "trace-segment",
        tags = Map(
          "trace" -> "jdbc-trace-update",
          "category" -> SegmentCategory.Database,
          "library" -> JdbcExtension.SegmentLibraryName))

      segmentSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(100)
    }

    "record the execution time of DELETE operation" in {
      Tracer.withContext(newContext("jdbc-trace-delete")) {
        for (id  1 to 100) {
          val delete = s"DELETE FROM Address where Nr = $id"
          val deleteStatement = connection.createStatement()
          deleteStatement.execute(delete)
        }

        Tracer.currentContext.finish()
      }

      val jdbcSnapshot = takeSnapshotOf("jdbc-statements", "jdbc-statements")
      jdbcSnapshot.histogram("writes").get.numberOfMeasurements should be(100)

      val traceSnapshot = takeSnapshotOf("jdbc-trace-delete", "trace")
      traceSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1)

      val segmentSnapshot = takeSnapshotOf("Jdbc[Delete]", "trace-segment",
        tags = Map(
          "trace" -> "jdbc-trace-delete",
          "category" -> SegmentCategory.Database,
          "library" -> JdbcExtension.SegmentLibraryName))

      segmentSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(100)

    }

    "record the execution time of SLOW QUERIES based on the kamon.jdbc.slow-query-threshold" in {
      Tracer.withContext(newContext("jdbc-trace-slow")) {
        for (id  1 to 2) {
          val select = s"SELECT * FROM Address; CALL SLEEP(100)"
          val selectStatement = connection.createStatement()
          selectStatement.execute(select)
        }

        Tracer.currentContext.finish()
      }

      val jdbcSnapshot = takeSnapshotOf("jdbc-statements", "jdbc-statements")
      jdbcSnapshot.counter("slows").get.count should be(2)

    }

    "count all SQL ERRORS" in {
      Tracer.withContext(newContext("jdbc-trace-errors")) {
        for (_  1 to 10) {
          intercept[SQLException] {
            val error = "SELECT * FROM NO_EXISTENT_TABLE"
            val errorStatement = connection.createStatement()
            errorStatement.execute(error)
          }
        }

        Tracer.currentContext.finish()
      }

      val jdbcSnapshot = takeSnapshotOf("jdbc-statements", "jdbc-statements")
      jdbcSnapshot.counter("errors").get.count should be(10)
    }
  }
}

class NoOpSlowQueryProcessor extends SlowQueryProcessor {
  override def process(sql: String, executionTimeInMillis: Long, queryThresholdInMillis: Long): Unit = { /*do nothing!!!*/ }
}

class NoOpSqlErrorProcessor extends SqlErrorProcessor {
  override def process(sql: String, ex: Throwable): Unit = { /*do nothing!!!*/ }
}

class NoOpJdbcNameGenerator extends JdbcNameGenerator {
  override def generateJdbcSegmentName(statement: String): String = s"Jdbc[$statement]"
}