Coder Social home page Coder Social logo

java-jdbc's Introduction

Build Status Coverage Status Released Version Apache-2.0 license

OpenTracing JDBC Instrumentation

OpenTracing instrumentation for JDBC.

Installation

pom.xml

<dependency>
    <groupId>io.opentracing.contrib</groupId>
    <artifactId>opentracing-jdbc</artifactId>
    <version>VERSION</version>
</dependency>

Usage

Non-interceptor

Tracing for JDBC connections of URLs starting with "jdbc:tracing:".

  1. Activate tracing for JDBC connections by adding tracing to the JDBC url:

    jdbc:tracing:h2:mem:test

    To trace calls with active Spans only, set property traceWithActiveSpanOnly=true.

    jdbc:tracing:h2:mem:test?traceWithActiveSpanOnly=true

    To ignore specific queries (such as health checks), use the property ignoreForTracing="SELECT 1". Double quotes can be escaped with \.

    SELECT * FROM \"TEST\"
    The property can be repeated for multiple statements.

  2. Set driver class to io.opentracing.contrib.jdbc.TracingDriver.

    Class.forName("io.opentracing.contrib.jdbc.TracingDriver");

    or

    io.opentracing.contrib.jdbc.TracingDriver.load();
  3. Instantiate tracer and register it with GlobalTracer.

    // Instantiate tracer
    Tracer tracer = ...
    
    // Register tracer with GlobalTracer
    GlobalTracer.register(tracer);

Interceptor

Tracing for all JDBC connections without modifying the URL.

In "interceptor mode", the TracingDriver will intercept calls to DriverManager.getConnection(url,...) for all URLs. The TracingDriver provides connections to the DriverManager that are instrumented. Please note that the TracingDriver must be registered before the underlying driver, It's recommended to turn on "interceptor mode" in the first place.

For standalone applications:

public static void main(String[] args) {
   io.opentracing.contrib.jdbc.TracingDriver.setInterceptorMode(true);
   // some jdbc operation here
}

For web applications:

public void contextInitialized(ServletContextEvent event) {
   io.opentracing.contrib.jdbc.TracingDriver.setInterceptorMode(true);
}

Or call TracingDriver.ensureRegisteredAsTheFirstDriver() along with TracingDriver.setInterceptorMode(true) at any place, Please note driver like Oracle JDBC may fail since it's destroyed forever after deregistration.

The withActiveSpanOnly and ignoreStatements properties for "interceptor mode" can be configured with the TracingDriver via:

// Set withActiveSpanOnly=true
TracingDriver.setInterceptorProperty(true);

and

// Set ignoreStatements={"CREATE TABLE ignored (id INTEGER, TEST VARCHAR)"}
TracingDriver.setInterceptorProperty(Collections.singleton("CREATE TABLE ignored (id INTEGER, TEST VARCHAR)"));

Hibernate

<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">io.opentracing.contrib.jdbc.TracingDriver</property>
        <property name="hibernate.connection.url">jdbc:tracing:mysql://localhost:3306/test</property>
        ...
    </session-factory>
    ...
</hibernate-configuration>

JPA

<persistence-unit name="jpa">
    <properties>
        <property name="javax.persistence.jdbc.driver" value="io.opentracing.contrib.jdbc.TracingDriver"/>
        <property name="javax.persistence.jdbc.url" value="jdbc:tracing:mysql://localhost:3306/test"/>
        ...
    </properties>
</persistence-unit>

Spring

For dbcp2:

<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp2.BasicDataSource">
    <property name="driverClassName" value="io.opentracing.contrib.jdbc.TracingDriver"/>
    <property name="url" value="jdbc:tracing:mysql://localhost:3306/test"/>
    ...
</bean>

Spring Boot 2

For Hikari (Postgresl):

### Spring JPA Datasource Connection
spring.datasource.username=postgres
spring.datasource.password=XXXXX
spring.datasource.hikari.driverClassName=io.opentracing.contrib.jdbc.TracingDriver
spring.datasource.hikari.jdbcUrl=jdbc:tracing:postgresql://localhost:5432/my_app_db

Configuration Bean:

@Component
public class OpenTracingConfig {

  @Bean
  public io.opentracing.Tracer jaegerTracer() {
    io.opentracing.contrib.jdbc.TracingDriver.load();
    return new Configuration("my_app").getTracer();
  }
}

Slow Query

Span is marked by tag slow=true if duration exceed slowQueryThresholdMs. slowQueryThresholdMs defaults to 0 which means disabled, can be enabled in two ways:

  1. Passing system property, E.g. -Dio.opentracing.contrib.jdbc.slowQueryThresholdMs=100
  2. Modify value by code, E.g. io.opentracing.contrib.jdbc.JdbcTracing.setSlowQueryThresholdMs(100)

Fast Query

Spans that complete faster than the optional excludeFastQueryThresholdMs flag will be not be reported. excludeFastQueryThresholdMs defaults to 0 which means disabled, can be enabled in two ways:

  1. Passing system property, E.g. -Dio.opentracing.contrib.jdbc.excludeFastQueryThresholdMs=100
  2. Modify value by code, E.g. io.opentracing.contrib.jdbc.JdbcTracing.setExcludeFastQueryThresholdMs(100)

Troubleshooting

In case of Unable to find a driver error the database driver should be registered before configuring the datasource. E.g. Class.forName("com.mysql.jdbc.Driver");

License

Apache 2.0 License.

java-jdbc's People

Contributors

apemost avatar asvanberg avatar backjo avatar bhs avatar brocchini avatar dengliming avatar dependabot[bot] avatar dimovelev avatar dleischnig avatar farukciber avatar ivan-slavchev avatar jayeve avatar jpkrohling avatar lake-of-dreams avatar malafeev avatar megdesko avatar naveedyahyazadeh avatar oburgosm avatar osvaldopina avatar pikkapikkachu avatar quaff avatar qudongfang avatar rnorth avatar safris avatar slowteetoe avatar wcarmon avatar will-gtv avatar wuyupengwoaini avatar xehonk avatar yisheng-liang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

java-jdbc's Issues

URLParser not happy with tnsnames.ora logging 'error occurs when paring jdbc url'

You have a small issue here in version 0.0.12 when using external tnsnames.ora wuth URL's of the from ''jdbc:oracle:thin:@tns_entry":

java.lang.StringIndexOutOfBoundsException: String index out of range: -2
	at java.lang.String.substring(String.java:1967)
	at io.opentracing.contrib.jdbc.parser.AbstractURLParser.fetchDatabaseHostsFromURL(AbstractURLParser.java:39)
	at io.opentracing.contrib.jdbc.parser.OracleURLParser.commonsURLParse(OracleURLParser.java:72)
	at io.opentracing.contrib.jdbc.parser.OracleURLParser.parse(OracleURLParser.java:67)

Details:
https://docs.oracle.com/en/database/oracle/oracle-database/19/jjdbc/data-sources-and-URLs.html
Section 8.2.6

Consequences: Minor

  • warning in the log
  • ConnectionInfo on spans not set

Fix in fetchDatabaseHostsFromURL:

		if (hostsLocation.startIndex() > hostsLocation.endIndex()) {
			final String unknownPortPostfix = ":0"; // need to load tnsnames.ora otherwise
			return url.substring(hostsLocation.startIndex()) + unknownPortPostfix;
		}

No big deal, but you might want to improve it.

java.lang.IllegalArgumentException: object is not an instance of declaring class

When i integrated alibaba's druid and java-jdbc, somtimes there is an error was thrown,sometimes is ok. the error message is the follow content:
java.lang.IllegalArgumentException: object is not an instance of declaring class at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_211] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_211] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_211] at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_211] at io.opentracing.contrib.jdbc.DynamicProxy$1.invoke(DynamicProxy.java:68) ~[opentracing-jdbc-0.2.7-SNAPSHOT.jar:na] at com.sun.proxy.$Proxy39.isReadOnly(Unknown Source) ~[na:na] at com.alibaba.druid.pool.DruidConnectionHolder.<init>(DruidConnectionHolder.java:137) ~[druid-1.1.18.jar:1.1.18] at com.alibaba.druid.pool.DruidConnectionHolder.<init>(DruidConnectionHolder.java:77) ~[druid-1.1.18.jar:1.1.18] at com.alibaba.druid.pool.DruidDataSource.init(DruidDataSource.java:933) ~[druid-1.1.18.jar:1.1.18] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_211] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_211] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_211] at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_211] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(AbstractAutowireCapableBeanFactory.java:1897) [spring-beans-5.1.12.RELEASE.jar:5.1.12.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1839) [spring-beans-5.1.12.RELEASE.jar:5.1.12.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1767) [spring-beans-5.1.12.RELEASE.jar:5.1.12.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593) [spring-beans-5.1.12.RELEASE.jar:5.1.12.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) [spring-beans-5.1.12.RELEASE.jar:5.1.12.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) [spring-beans-5.1.12.RELEASE.jar:5.1.12.RELEASE] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.12.RELEASE.jar:5.1.12.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) [spring-beans-5.1.12.RELEASE.jar:5.1.12.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) [spring-beans-5.1.12.RELEASE.jar:5.1.12.RELEASE] at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277) ~[spring-beans-5.1.12.RELEASE.jar:5.1.12.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1255) ~[spring-beans-5.1.12.RELEASE.jar:5.1.12.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1175) ~[spring-beans-5.1.12.RELEASE.jar:5.1.12.RELEASE] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:595) ~[spring-beans-5.1.12.RELEASE.jar:5.1.12.RELEASE] at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90) ~[spring-beans-5.1.12.RELEASE.jar:5.1.12.RELEASE] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:376) ~[spring-beans-5.1.12.RELEASE.jar:5.1.12.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1404) [spring-beans-5.1.12.RELEASE.jar:5.1.12.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:592) [spring-beans-5.1.12.RELEASE.jar:5.1.12.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) [spring-beans-5.1.12.RELEASE.jar:5.1.12.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) [spring-beans-5.1.12.RELEASE.jar:5.1.12.RELEASE] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.12.RELEASE.jar:5.1.12.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) [spring-beans-5.1.12.RELEASE.jar:5.1.12.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) [spring-beans-5.1.12.RELEASE.jar:5.1.12.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:847) ~[spring-beans-5.1.12.RELEASE.jar:5.1.12.RELEASE] at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877) ~[spring-context-5.1.12.RELEASE.jar:5.1.12.RELEASE] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549) ~[spring-context-5.1.12.RELEASE.jar:5.1.12.RELEASE] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:744) ~[spring-boot-2.1.11.RELEASE.jar:2.1.11.RELEASE] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:391) ~[spring-boot-2.1.11.RELEASE.jar:2.1.11.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:312) ~[spring-boot-2.1.11.RELEASE.jar:2.1.11.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215) ~[spring-boot-2.1.11.RELEASE.jar:2.1.11.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1204) ~[spring-boot-2.1.11.RELEASE.jar:2.1.11.RELEASE] at com.example.druidopentracejdbc.DruidOpentracejdbcApplication.main(DruidOpentracejdbcApplication.java:19) ~[classes/:na]
my pom.xml:
`

org.springframework.boot
spring-boot-starter

	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>
	<dependency>
		<groupId>com.alibaba</groupId>
		<artifactId>druid-spring-boot-starter</artifactId>
		<version>1.1.18</version>
	</dependency>
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-jdbc</artifactId>
		<version>5.1.6.RELEASE</version>
	</dependency>
	<dependency>
		<groupId>io.opentracing.contrib</groupId>
		<artifactId>opentracing-jdbc</artifactId>
		<version>0.2.7-SNAPSHOT</version>
	</dependency>
	<dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
		<version>5.1.47</version>
	</dependency>
</dependencies>`

My application.properties:
spring.datasource.druid.url=jdbc:tracing:mysql://***?useUnicode=true&characterEncoding=utf8&useSSL=true spring.datasource.druid.username=*** spring.datasource.druid.password=*** spring.datasource.druid.driver-class-name=io.opentracing.contrib.jdbc.TracingDriver spring.datasource.druid.initial-size=10 spring.datasource.druid.max-active=50 spring.datasource.druid.min-idle=5 spring.datasource.druid.max-wait=1800000 spring.datasource.druid.pool-prepared-statements=false spring.datasource.druid.max-pool-prepared-statement-per-connection-size=-1 spring.datasource.druid.validation-query=select 1 spring.datasource.druid.validation-query-timeout=60 spring.datasource.druid.test-while-idle=true spring.datasource.druid.time-between-eviction-runs-millis=180000
My Test Code:
`package com.example.druidopentracejdbc;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import javax.sql.DataSource;
import java.io.Serializable;
import java.sql.Connection;

@SpringBootApplication
public class DruidOpentracejdbcApplication implements CommandLineRunner {

@Autowired
DataSource dataSource;

public static void main(String[] args) {
	SpringApplication.run(DruidOpentracejdbcApplication.class, args);
}

@Override
public void run(String... args) throws Exception {
  Connection connection = dataSource.getConnection();
	System.out.println(connection.isReadOnly());;
  connection.close();
	System.out.println();
}

}'
It's happen at:
image
Simetimes the method declareinglcass is com.mysql.jdbc.MySQLConnection, and it's will cause the errors above.

Instrumentation does not add span to existing span context

Hi there,

I'm relatively new to OpenTracing, and started using this library to instrument JDBC calls in our application. The way our application works is that it consumes an event from Kafka, and makes a database call to insert a new row in our database.

Consuming an event from Kafka successfully creates a span, and I would expect the JDBC call to create a follows_from reference to the previous span. However, it looks like this library does not cater for adding follows_from or child_of references whatsoever, and assumes that a database call is always a completely new trace in isolation.

Am I misunderstanding this?

Cheers,
Danny

In interceptor mode, TracingDriver#acceptsURL should accept URLs without "tracing:"

Interceptor mode may not work in some cases. For instance, if another wrapper driver calls Driver#acceptsURL for each registered driver in order to find an underlying driver, it won't see TracingDriver unless the JDBC URL has been rewritten to have the jdbc:tracing: prefix.

Simple fix is to change TracingDriver#acceptsURL to be:

  @Override
  public boolean acceptsURL(String url) throws SQLException {
    return url != null && (
        url.startsWith(getUrlPrefix()) || 
        (interceptorMode && url.startsWith("jdbc:"))
    );
  }

Not compatible with native image since version 0.2.5

Since version 0.2.5, the library uses a dynamic proxy (via WrapperProxy) on top of the JDBC connection.
Dynamic proxy didn't work OOTB on GraalVM native image, they need to be configured explicitly.

However, to configure native image dynamic proxy capability, we must configure the list of interface of the proxy, in the right order ! WrapperProxy generates a list of interfaces in no order, so we must register all possible combinations which can be huge, see the following experiment with an underlying Postgres driver: https://gist.github.com/luneo7/453ea0bd0d51a48c6c4377237e8ad831

Imagine native support where we want to support multiple database drivers, this becomes challenging.

Be also aware that with such configuration time to build the native image incrase a lot.

I don't know if it' easily feasable to switch back to not using any proxy, or if at least the WrapperProxy can be updated to generate a list of interfaces in a reproducible manner so we don't have to configure all possible combinations.

TracingDriver deregisterDriver and registerDriver will cause oracle ojdbc8 driver not work

com.oracle.ojdbc ojdbc8 19.3.0.0 io.opentracing.contrib opentracing-jdbc 0.2.9

When project startup, we will see error message: (even I add TracingDriver.load() at first line of main, still same error)
Caused by: com.zaxxer.hikari.pool.HikariPool$PoolInitializationException: Failed to initialize pool: Timer already cancelled.
at com.zaxxer.hikari.pool.HikariPool.throwPoolInitializationException(HikariPool.java:597)
at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:576)
at com.zaxxer.hikari.pool.HikariPool.(HikariPool.java:115)
at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112)
at com.zaxxer.hikari.HikariDataSource$$FastClassBySpringCGLIB$$eeb1ae86.invoke()
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:769)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:136)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)
at com.zaxxer.hikari.HikariDataSource$$EnhancerBySpringCGLIB$$5297385d.getConnection()
at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:180)
at org.hibernate.hql.spi.id.IdTableHelper.executeIdTableCreationStatements(IdTableHelper.java:67)
at org.hibernate.hql.spi.id.global.GlobalTemporaryTableBulkIdStrategy.finishPreparation(GlobalTemporaryTableBulkIdStrategy.java:125)
at org.hibernate.hql.spi.id.global.GlobalTemporaryTableBulkIdStrategy.finishPreparation(GlobalTemporaryTableBulkIdStrategy.java:42)
at org.hibernate.hql.spi.id.AbstractMultiTableBulkIdStrategyImpl.prepare(AbstractMultiTableBulkIdStrategyImpl.java:88)
at org.hibernate.internal.SessionFactoryImpl.(SessionFactoryImpl.java:313)
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:462)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1237)
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:58)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:391)
... 18 common frames omitted
Caused by: java.lang.IllegalStateException: Timer already cancelled.
at java.util.Timer.sched(Timer.java:397)
at java.util.Timer.schedule(Timer.java:193)
at oracle.net.nt.TimeoutInterruptHandler.scheduleInterrupt(TimeoutInterruptHandler.java:90)
at oracle.net.nt.TimeoutInterruptHandler.scheduleInterrupt(TimeoutInterruptHandler.java:103)
at oracle.net.nt.TimeoutSocketChannel.scheduleInterrupt(TimeoutSocketChannel.java:235)
at oracle.net.nt.TimeoutSocketChannel.connect(TimeoutSocketChannel.java:97)
at oracle.net.nt.TimeoutSocketChannel.(TimeoutSocketChannel.java:85)
at oracle.net.nt.TcpsNTAdapter.connect(TcpsNTAdapter.java:229)
at oracle.net.nt.ConnOption.connect(ConnOption.java:174)
at oracle.net.nt.ConnStrategy.execute(ConnStrategy.java:510)
at oracle.net.resolver.AddrResolution.resolveAndExecute(AddrResolution.java:548)
at oracle.net.ns.NSProtocol.establishConnection(NSProtocol.java:682)
at oracle.net.ns.NSProtocol.connect(NSProtocol.java:309)
at oracle.jdbc.driver.T4CConnection.connect(T4CConnection.java:1596)
at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:588)
at oracle.jdbc.driver.PhysicalConnection.connect(PhysicalConnection.java:793)
at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:57)
at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:747)
at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:562)
at io.opentracing.contrib.jdbc.TracingDriver.connect(TracingDriver.java:174)
at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:138)
at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:353)
at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:201)
at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:473)
at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:562)
... 43 common frames omitted

But if I change to ojdbc6 , it will not meet error.

com.oracle
ojdbc6
11.2.0.4.0

So can we enhance tracing driver to support oracle ojdbc8 ? Thanks!

H2 URL with implicit file mode does not work

H2 does not require that 'file:' is explicitly stated, but the H2URLParser does.

Example that worked with 0.0.8: jdbc:tracing:h2:~/db;AUTO_SERVER=TRUE;MODE=Oracle;MVCC=TRUE;LOCK_TIMEOUT=10000?traceWithActiveSpanOnly=true

Invoking by code to change slowQueryThresholdMs

It's well documented that it's possible to change slowQueryThresholdMs value by code, as it's public static variable.
For example as in the below example:
io.opentracing.contrib.jdbc.JdbcTracingUtils.slowQueryThresholdMs = 100
Unfortunately, the class containing this static variable has a package scope (JdbcTracingUtils), so I'm afraid it's not possible to do so.
The only way of setting this value is just via setting environment variable, but didn't find any way to do it dynamically.
Maybe I'm missing here something?

Postgres url parser fails to parse IPv6 hosts

every database connection will cause a new log message to be printed and the host and port of the server are not properly logged.
i.o.contrib.jdbc.parser.URLParser : error occurs when parsing jdbc url

example that fails:
jdbc:postgresql://[::1]:5432/db

WildFly 19 configuration

Hello,
is there any tutorial or guide to configure the jdbc trace for WildfFly or any other application server without touching the application or the JPA persistent unit?
Our application is in JTA mode so we configure the datasource in the application server but we don't instantiate it directly.

In the source folder I have not seen any class specific for MSSQL, could it be an issue?

Thanks for your attention.

DynamicProxy ClassCastException when using JPA

This appears related to #59 as if I rollback to 0.2.4, the error does not occur.

Error (sorry, it's a long one):

	at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:857)
	at org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate.getAbstractSession(EntityManagerFactoryDelegate.java:222)
	at org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate.createEntityManagerImpl(EntityManagerFactoryDelegate.java:330)
	at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:350)
	at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:313)
	at com.oracle.coherence.demo.application.Utilities.<clinit>(Utilities.java:126)
	at com.oracle.coherence.demo.application.BootstrapInterceptor.onEvent(BootstrapInterceptor.java:50)
	at com.oracle.coherence.demo.application.BootstrapInterceptor.onEvent(BootstrapInterceptor.java:36)
	at com.tangosol.net.events.internal.NamedEventInterceptor.onEvent(NamedEventInterceptor.java:261)
	at com.tangosol.net.events.internal.AbstractEvent.nextInterceptor(AbstractEvent.java:122)
	at com.tangosol.net.events.internal.AbstractEvent.dispatch(AbstractEvent.java:167)
	at com.tangosol.net.events.internal.ConfigurableCacheFactoryDispatcher.dispatchEvent(ConfigurableCacheFactoryDispatcher.java:78)
	at com.tangosol.net.events.internal.ConfigurableCacheFactoryDispatcher.dispatchActivated(ConfigurableCacheFactoryDispatcher.java:54)
	at com.tangosol.net.ExtensibleConfigurableCacheFactory.activate(ExtensibleConfigurableCacheFactory.java:630)
	at com.tangosol.net.DefaultCacheServer.startServicesInternal(DefaultCacheServer.java:565)
	at com.tangosol.net.DefaultCacheServer.initialStartServices(DefaultCacheServer.java:503)
	at com.tangosol.net.DefaultCacheServer.lambda$startAndMonitor$0(DefaultCacheServer.java:87)
	at java.security.AccessController.doPrivileged(Native Method)
	at com.tangosol.net.DefaultCacheServer.startAndMonitor(DefaultCacheServer.java:84)
	at com.tangosol.net.DefaultCacheServer.main(DefaultCacheServer.java:430)
	at com.oracle.coherence.demo.application.Launcher.main(Launcher.java:190)
Caused by: java.lang.reflect.UndeclaredThrowableException
	at com.sun.proxy.$Proxy48.prepareStatement(Unknown Source)
	at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.prepareStatement(DatabaseAccessor.java:1595)
	at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.prepareStatement(DatabaseAccessor.java:1544)
	at org.eclipse.persistence.internal.databaseaccess.DatabaseCall.prepareStatement(DatabaseCall.java:807)
	at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:628)
	at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:567)
	at org.eclipse.persistence.internal.sessions.AbstractSession.basicExecuteCall(AbstractSession.java:2099)
	at org.eclipse.persistence.sessions.server.ServerSession.executeCall(ServerSession.java:603)
	at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:275)
	at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:261)
	at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeNoSelectCall(DatasourceCallQueryMechanism.java:304)
	at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeNoSelect(DatasourceCallQueryMechanism.java:284)
	at org.eclipse.persistence.queries.DataModifyQuery.executeDatabaseQuery(DataModifyQuery.java:87)
	at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:911)
	at org.eclipse.persistence.internal.sessions.AbstractSession.internalExecuteQuery(AbstractSession.java:3356)
	at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1898)
	at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1880)
	at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1830)
	at org.eclipse.persistence.internal.sessions.AbstractSession.priviledgedExecuteNonSelectingCall(AbstractSession.java:5223)
	at org.eclipse.persistence.tools.schemaframework.DatabaseObjectDefinition.createOnDatabase(DatabaseObjectDefinition.java:204)
	at org.eclipse.persistence.tools.schemaframework.SchemaManager.createObject(SchemaManager.java:223)
	at org.eclipse.persistence.tools.schemaframework.TableCreator.createTables(TableCreator.java:173)
	at org.eclipse.persistence.tools.schemaframework.TableCreator.createTables(TableCreator.java:150)
	at org.eclipse.persistence.tools.schemaframework.TableCreator.createTables(TableCreator.java:142)
	at org.eclipse.persistence.tools.schemaframework.SchemaManager.createDefaultTables(SchemaManager.java:1030)
	at org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider.generateDefaultTables(EntityManagerFactoryProvider.java:110)
	at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.writeDDLToDatabase(EntityManagerSetupImpl.java:4436)
	at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.writeDDL(EntityManagerSetupImpl.java:4364)
	at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.writeDDL(EntityManagerSetupImpl.java:4264)
	at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:819)
	... 20 more
Caused by: java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at io.opentracing.contrib.jdbc.DynamicProxy$1.invoke(DynamicProxy.java:32)
	... 50 more
Caused by: java.lang.ClassCastException: com.sun.proxy.$Proxy49 cannot be cast to java.sql.PreparedStatement
	at io.opentracing.contrib.jdbc.TracingConnection.prepareStatement(TracingConnection.java:65)
	... 55 more

My persistence.xml is defined as:

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
             version="1.0">
  <persistence-unit name="demo" transaction-type="RESOURCE_LOCAL">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <class>model.Price</class>
    <class>model.Trade</class>
    <properties>
      <property name="javax.persistence.jdbc.driver" value="io.opentracing.contrib.jdbc.TracingDriver"/>
      <property name="javax.persistence.jdbc.url"
                value="jdbc:tracing:derby:memory;create=true;traceWithActiveSpanOnly=true"/>
      <property name="eclipselink.ddl-generation" value="create-tables"/>
      <property name="eclipselink.ddl-generation.output-mode" value="database"/>
      <property name="eclipselink.weaving" value="false"/>
      <property name="eclipselink.logging.level.sql" value="FINE"/>
    </properties>
  </persistence-unit>
</persistence>

TracingPreparedStatement.executeUpdate NPE

In TracingCallableStatement:69, for tracer null is being forwarded.

That causes NPE when calling TracingPreparedStatement.executeUpdate(), since in JdbcTracingUtils line 41 and 47 accesses tracer.

TracingConnection improvement

When i use OpenTracing Spring Cloud project to trace jdbc,and i find the problem
JdbcAspect.getConnectionwill executeSELECT USER()` every time

But i also think it is so hard to opentracing-spring-cloud-jdbc-starter to fix this issue,beacause the java class
TracingConnnection's Construction method must need username.So could TracingConnnection's Construction method receive the object containing all the database info.and The JdbcTracingUtils convert the object to the k-v tags

URLParser unable to handle replication keyword

Hi,

first of all, thanks for the great implementation of Jaeger integration for Spring Boot. It is very easy to integrate and useful for our project.

I noticed for one Spring Boot based service that connects to a cluster of database instances that the URLParser of Jdbc is not able to handle the following JDBC URL format:

jdbc:mysql:replication://primary.db:3306,replica.db:3306/database

If the :replicationpart of the URL is omitted, the tag peer.address is set correctly, if not, it has a value like **internally_generated**1598275417336**:3306, which messes up the System Architecture view in the Jaeger frontend because the peer address is not unique any more (the number 1598... is a timestamp).

Is it possible to fix the parser or somehow override the peer.address or ConnectionInfo data from the application?

Error while creating mysql connection using non-interceptor mode

When we add libraries and follow the steps mentioned in the non-interceptor mode as per the ReadMe file, we are getting the below connection error. Please advice. Also, does it work for JDBC connection pool?

java.sql.SQLException: Driver:com.mysql.jdbc.Driver@20124626 returned null for URL:jdbc:tracing:mysql://localhost:3306/db_test?traceWithActiveSpanOnly=true
	at org.apache.tomcat.jdbc.pool.PooledConnection.connectUsingDriver(PooledConnection.java:338) ~[tomcat-jdbc-8.5.54.jar:?]
	at org.apache.tomcat.jdbc.pool.PooledConnection.connect(PooledConnection.java:212) ~[tomcat-jdbc-8.5.54.jar:?]
	at org.apache.tomcat.jdbc.pool.ConnectionPool.createConnection(ConnectionPool.java:739) ~[tomcat-jdbc-8.5.54.jar:?]
	at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:671) ~[tomcat-jdbc-8.5.54.jar:?]
	at org.apache.tomcat.jdbc.pool.ConnectionPool.init(ConnectionPool.java:483) ~[tomcat-jdbc-8.5.54.jar:?]
	at org.apache.tomcat.jdbc.pool.ConnectionPool.<init>(ConnectionPool.java:154) ~[tomcat-jdbc-8.5.54.jar:?]
	at org.apache.tomcat.jdbc.pool.DataSourceProxy.pCreatePool(DataSourceProxy.java:118) ~[tomcat-jdbc-8.5.54.jar:?]
	at org.apache.tomcat.jdbc.pool.DataSourceProxy.createPool(DataSourceProxy.java:107) ~[tomcat-jdbc-8.5.54.jar:?]
	at org.apache.tomcat.jdbc.pool.DataSourceProxy.getConnection(DataSourceProxy.java:131) ~[tomcat-jdbc-8.5.54.jar:?]
	at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:111) ~[spring-jdbc-4.3.25.RELEASE.jar:4.3.25.RELEASE]
	at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77) ~[spring-jdbc-4.3.25.RELEASE.jar:4.3.25.RELEASE]
	at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:341) ~[spring-jdbc-4.3.25.RELEASE.jar:4.3.25.RELEASE]
	at org.springframework.boot.actuate.health.DataSourceHealthIndicator.getProduct(DataSourceHealthIndicator.java:120) ~[spring-boot-actuator-1.5.22.RELEASE.jar:1.5.22.RELEASE]
	at org.springframework.boot.actuate.health.DataSourceHealthIndicator.doDataSourceHealthCheck(DataSourceHealthIndicator.java:103) ~[spring-boot-actuator-1.5.22.RELEASE.jar:1.5.22.RELEASE]
	at org.springframework.boot.actuate.health.DataSourceHealthIndicator.doHealthCheck(DataSourceHealthIndicator.java:98) ~[spring-boot-actuator-1.5.22.RELEASE.jar:1.5.22.RELEASE]
	at org.springframework.boot.actuate.health.AbstractHealthIndicator.health(AbstractHealthIndicator.java:43) ~[spring-boot-actuator-1.5.22.RELEASE.jar:1.5.22.RELEASE]
	at org.springframework.boot.actuate.health.CompositeHealthIndicator.health(CompositeHealthIndicator.java:67) ~[spring-boot-actuator-1.5.22.RELEASE.jar:1.5.22.RELEASE]
	at org.springframework.boot.actuate.endpoint.HealthEndpoint.invoke(HealthEndpoint.java:85) ~[spring-boot-actuator-1.5.22.RELEASE.jar:1.5.22.RELEASE]
	at org.springframework.boot.actuate.endpoint.HealthEndpoint.invoke(HealthEndpoint.java:37) ~[spring-boot-actuator-1.5.22.RELEASE.jar:1.5.22.RELEASE]
	at org.springframework.boot.actuate.endpoint.jmx.DataEndpointMBean.getData(DataEndpointMBean.java:46) ~[spring-boot-actuator-1.5.22.RELEASE.jar:1.5.22.RELEASE]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_71]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_71]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_71]
	at java.lang.reflect.Method.invoke(Method.java:497) ~[?:1.8.0_71]
	at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71) ~[?:1.8.0_71]
	at sun.reflect.GeneratedMethodAccessor91.invoke(Unknown Source) ~[?:?]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_71]
	at java.lang.reflect.Method.invoke(Method.java:497) ~[?:1.8.0_71]
	at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:275) ~[?:1.8.0_71]
	at javax.management.modelmbean.RequiredModelMBean$4.run(RequiredModelMBean.java:1252) ~[?:1.8.0_71]
	at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_71]
	at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76) ~[?:1.8.0_71]
	at javax.management.modelmbean.RequiredModelMBean.invokeMethod(RequiredModelMBean.java:1246) ~[?:1.8.0_71]
	at javax.management.modelmbean.RequiredModelMBean.invoke(RequiredModelMBean.java:1085) ~[?:1.8.0_71]
	at org.springframework.jmx.export.SpringModelMBean.invoke(SpringModelMBean.java:90) ~[spring-context-4.3.25.RELEASE.jar:4.3.25.RELEASE]
	at javax.management.modelmbean.RequiredModelMBean.getAttribute(RequiredModelMBean.java:1562) ~[?:1.8.0_71]
	at org.springframework.jmx.export.SpringModelMBean.getAttribute(SpringModelMBean.java:109) ~[spring-context-4.3.25.RELEASE.jar:4.3.25.RELEASE]
	at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.getAttribute(DefaultMBeanServerInterceptor.java:647) ~[?:1.8.0_71]
	at com.sun.jmx.mbeanserver.JmxMBeanServer.getAttribute(JmxMBeanServer.java:678) ~[?:1.8.0_71]
	at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1445) ~[?:1.8.0_71]
	at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:76) ~[?:1.8.0_71]
	at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1309) ~[?:1.8.0_71]
	at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1401) ~[?:1.8.0_71]
	at javax.management.remote.rmi.RMIConnectionImpl.getAttribute(RMIConnectionImpl.java:639) ~[?:1.8.0_71]
	at sun.reflect.GeneratedMethodAccessor88.invoke(Unknown Source) ~[?:?]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_71]
	at java.lang.reflect.Method.invoke(Method.java:497) ~[?:1.8.0_71]
	at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:323) ~[?:1.8.0_71]
	at sun.rmi.transport.Transport$1.run(Transport.java:200) ~[?:1.8.0_71]
	at sun.rmi.transport.Transport$1.run(Transport.java:197) ~[?:1.8.0_71]
	at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_71]
	at sun.rmi.transport.Transport.serviceCall(Transport.java:196) ~[?:1.8.0_71]
	at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:568) ~[?:1.8.0_71]
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826) ~[?:1.8.0_71]
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$256(TCPTransport.java:683) ~[?:1.8.0_71]
	at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_71]
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682) [?:1.8.0_71]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [?:1.8.0_71]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [?:1.8.0_71]
	at java.lang.Thread.run(Thread.java:745) [?:1.8.0_71]

Mark the JAX-RS dependency as `provided`

The JAX-RS dependency should be marked as provided, as the party consuming the OT instrumentation has a concrete implementation as dependency already.

This is what's shown as mvn dependency:tree for a Wildfly Swarm application when requiring io.opentracing.contrib:opentracing-jaxrs2:0.0.8:

[INFO] +- io.opentracing.contrib:opentracing-jaxrs2:jar:0.0.8:compile
[INFO] |  +- io.opentracing.contrib:opentracing-concurrent:jar:0.0.1:compile
[INFO] |  \- javax.ws.rs:javax.ws.rs-api:jar:2.0.1:compile

memory leak using c3p0 pooling library

I am using a custom fork of the Java Special Agent. We have a service that relies on the Quartz scheduler, which uses c3p0 (v0.9.1.1). With the tracing agent applied, the service leaks memory until it throws an OOM error.

A heap dump showed that TracingPreparedStatements were being leaked. I tracked this to the use of the WrapperProxy and the fact that, given a Proxy instance of TracingConnection or TracingStatement, a call to obj.equals(obj) will always return false. This is because the WrapperProxy is delegating all method calls to the wrapper or the original object, but these don't know how to handle the added Proxy/WrapperProxy layers for the equals method. This leads to c3p0 not being able to clean up its collections for the connections/statements.

I was able to fix this by adding a custom equals method to TracingStatement:

  @Override
  public boolean equals(Object obj) {
	if (this == obj) {
		return true;
	} else if (obj == null) {
		return false;
	} else if (WrapperProxy.isWrapper(obj, getClass())) {
		return obj.equals(this); // trick to get through the WrapperProxy/Proxy instances
	} else if (getClass() != obj.getClass()) {
		return false;
	} else {
		TracingStatement other = (TracingStatement) obj;
		if (statement == null) {
			if (other.statement != null) {
				return false;
			}
		} else if (statement != other.statement && !statement.equals(other.statement)) {
			return false;
		}
	}
	return true;
  }

and to TracingConnection:

  @Override
  public boolean equals(Object obj) {
	if (this == obj) {
		return true;
	} else if (obj == null) {
		return false;
	} else if (WrapperProxy.isWrapper(obj, getClass())) {
		return obj.equals(this); // trick to get through the WrapperProxy/Proxy instances
	} else if (getClass() != obj.getClass()) {
		return false;
	} else {
		TracingConnection other = (TracingConnection) obj;
		if (connection == null) {
			if (other.connection != null) {
				return false;
			}
		} else if (connection != other.connection && !connection.equals(other.connection)) {
			return false;
		}
	}
	return true;
  }

These may not be 100% hardened, but they got me past the memory leak with c3p0. I thought I should be a good citizen and open an issue regarding this.

Benchmarks - overhead of instrumented code without a tracer

See opentracing/opentracing-java#295

Similar to the linked issue, this task is about measuring the overhead of traced JDBC calls when compared to their non-traced counter-parts.

Scenarios to test:

  • Using an in-memory database, execute as many simple queries as possible (like select 1). Run it by time (X statements per minute) and by a fixed number of statements (task took N seconds to complete). Run twice, one with a traced JDBC driver and one without.

JdbcTracingUtils.decorate can set empty tag values which can break tracers

I am using the Java SpecialAgent 1.3.2 with a Wavefront Tracer. The Wavefront Tracer does not support empty tag values (an empty String) and throws an exception when processing the span. The OpenTracing spec seems to imply that empty tag values should not be used, but doesn't specifically say they are disallowed:

From https://opentracing.io/specification/ :

Set a Span tag
Required parameters

The tag key, which must be a string
The tag value, which must be either a string, a boolean value, or a numeric type
Note that the OpenTracing project documents certain “standard tags” that have prescribed semantic meanings.

The code checks for null, but allows the empty String. This should be fixed:

private static void decorate(Span span,
      String sql,
      ConnectionInfo connectionInfo) {
    Tags.COMPONENT.set(span, COMPONENT_NAME);
    Tags.DB_STATEMENT.set(span, sql);
    if (connectionInfo.getDbType() != null) {
      Tags.DB_TYPE.set(span, connectionInfo.getDbType());
    }
    if (connectionInfo.getDbPeer() != null) {
      PEER_ADDRESS.set(span, connectionInfo.getDbPeer());
    }
    if (connectionInfo.getDbInstance() != null) {
      Tags.DB_INSTANCE.set(span, connectionInfo.getDbInstance());
    }
    if (connectionInfo.getDbUser() != null) {
      Tags.DB_USER.set(span, connectionInfo.getDbUser());
    }
  }

TracerPreparedStatement.executeBatch() is failing.

First, let’s revisit the interface/class hierarchy:

  1. java.sql.PreparedStatement extends java.sql.Statement
  2. io.opentracing.contrib.jdbc.TracingStatement implements java.sql.Statement
  3. io.opentracing.contrib.jdbc.TracingPreparedStatement implements java.sql.PreparedStatement
  4. io.opentracing.contrib.jdbc.TracingPreparedStatement extends io.opentracing.contrib.jdbc.TracingStatement

Some fact:

  1. executeBatch() method is defined in java.sql.Statement interface. And io.opentracing.contrib.jdbc.TracingStatement class has implemented this method.
  2. Both TracingPreparedStatement and TracingStatement class have their independent Tracer variable (instance level).

Now, let’s look at the below piece of code. It adds 10 records to a batch and send all 10 records to the database at one go. (Read the inline comments for better understanding) :

// Get the Connection object, which already has the Tracer object in it.
// getConnection() object is an utility method to return a TracingConnection with a valid Tracer object in it. (I have not given the implementation here).
// This connection (conn) is of type io.opentracing.contrib.jdbc.TracingConnection.
Connection conn = getConnection();

// The same Tracer object will be passed internally to the newly created PreparedStatement (pstmt) object.
// This PreparedStatement is nothing but of type io.opentracing.contrib.jdbc.TracingPreparedStatement.
PreparedStatement pstmt = conn.prepareStatement(“”);

// Start the batch operation.
for (int i = 0; i < 10; i ++) {
pstmt.setXXX(…);
pstmt.setXXX(…);
pstmt.setXXX(…);

pstmt.addBatch();

}
// It calls io.opentracing.contrib.jdbc.TracingStatement.executeBatch() [note fact #1].
// Because TracingStatement has its own copy of Tracer object [note fact #2], which is
// still in uninitialized state, the call fails.
int[] count = pstmt.executeBatch();

The last line pstmt.executeBatch() is failing, because it's Tracer object is null.


Because TracingPreparedStatement is extending TracingStatement, I feel they should share the same Tracer object defined in the TracingStatement. Having a separate Tracer object in the child class (TracingPreparedStatement) is causing the issue.

Database span not contained in the parent span

Database span details:

"traceID": "b770ba1c4dac9785",
"spans": [
{
"traceID": "b770ba1c4dac9785",
"spanID": "b770ba1c4dac9785",
"flags": 1,
"operationName": "Query",
"references": [],
"startTime": 1676462594032760,
"duration": 553479,
"tags": [

Other span details from the same request:

{
"traceID": "78101819be2e1ac9",
"spanID": "245cf9f59edac042",
"flags": 1,
"operationName": "Rest Call",
"references": [
{
"refType": "CHILD_OF",
"traceID": "78101819be2e1ac9",
"spanID": "586d9760ad1c6cf8"
}
],

Expected behavior: the Query operation should be a child of the parent span, as we see on Rest Call references.
If I will add parameter withActiveSpanOnly=true then the Query operation will not appear at all.
Environment:
quarkus: 2.15.3.Final
opentracing-jdbc: 0.2.15
database: db2

Properties:
quarkus.datasource.jdbc.tracing=true
quarkus.datasource.jdbc.driver=io.opentracing.contrib.jdbc.TracingDriver

Support for XA datasources

I have several applications configured to use XA datasources and would like to have tracing added to these applications. As far as I can see this requires an implementation of java.sql.XADatasource in order to work (it certainly fails if a add tracing to an XA connection url). Is there any plans for supporting XA datasources?

Control whether jdbc traces will be enabled or not.

I'm new to this library and I could not find a way to turn it on and off depending on a global configuration. My need is to control wheter I'm going to trace jdbc calls or not and chage this behavior without the need to restart de application. Is it possible?

hard coded JdbcTracingUtils

New option to exclude spans faster than a latency threshold

Similar to slowQueryThresholdMs, another beneficial optional setting would be a flag to omit spans that are faster than some latency threshold (i.e: excludeSpansBelowQueryThreshold=100ms). This can be implemented identically to the existing flag, but will reduce the number of spans produced by the Driver.

This change will have significant performance benefits on systems that produce high numbers of JDBC spans. It will also keep spans whose latencies are small (fast requests) enough to be considered non-negligible.

I think I have a solution in mind, and if you all are ok, I can spin up a PR!

Using Oracle oci driver causes NPE, because of OracleURLParser "thin" expectations

When using "oci" driver instead of "thin" the OracleURLParser is not capable of recognizing the pattern and returns null. This causes NPE later. At the same time the prefix that is expected for the OracleURLParser to pick up the connection string is "jdbc:oracle" and not "jdbc:oracle:thin". This makes it impossible to register custom parser specifically for oci.

Unable to find a driver that accepts

dataSource is DruidDataSource

String realUrl = this.extractRealUrl(url);
String dbType = this.extractDbType(realUrl);
String dbUser = info.getProperty("user");
Driver wrappedDriver = this.findDriver(realUrl);

this.findDriver(url) need using url not realUrl
this version will throw Excetpion
Caused by: java.sql.SQLException: Unable to find a driver that accepts jdbc:mysql://172.16.71.2:3306/tradecenter?useUnicode=true&characterEncoding=utf-8

URLParser reports "error occurs when paring jdbc url" for valid mysql url

The URLParser is emitting a large amount of WARN level messages about 'error occurs when paring jdbc url'

I added some debugging and discovered that the url it is complaining about is jdbc:mysql://mysql_db

This is actually a valid syntax for a mysql JDBC connection url (see the section about database in https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-jdbc-url-format.html)

Ideally, the MysqlURLParser should parse this URL correctly. I can turn down logging for that package, but it will still return ConnectionInfo.UNKNOWN_CONNECTION_INFO which isn't quite right.

Error span when record doesn't exist in database.

My database has a customer table with ID as a primary key.

Expected behavior: When I search for a record that doesn't exist in the database, I should see an error span in the Jaeger UI.

Actual behavior: When I search for a record that doesn't exist in the database, there is no error span created.

Code:

I'm calling JPA repository from a service using:
Customer customer = customerRepository.findByid(customerID);

findByid signature is like this:
Customer findByid(long id);

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.