Nothing in progress right now. Contributions would be gratefully accepted.
Possibly we could go down to the driver level (and get support for JPA as well that way) as well. Zipkin (and Brave) already have some MySQL driver support for instance.
I will more look Zipkin and Brave support for Driver or atleast Datasource level.
BTW, off-topic from JDBC support, Sleuth also doesn't provide support for STOMP messages over websockets using Spring websocket. I have written interceptor to provide support in case of STOMP messages and will create Pull Request when I am fully sure it is correctly doing its work.
@dsyer
In recent weeks, I have looked into many JDBC drivers and connection pool libraries, None is supporting elegant way of adding hooks for intercepting database calls. MySQL provide StatementInterceptorV2. MongoDB has some event support but at connection level. Apache Tomcat connectionpool has JDBCInterceptor, not sure if anyone will use Apache Tomcat JDBC pool.
Any pointers/suggestions how to proceed with this or initial support for MySQL and Apache Tomcat JDBC pool is nice to have for now.
Will doing similar to p6spy a nice to have or it is just over kill for tracing db calls?
my2p
StatementInterceptorV2 is tough, iirc, as it needs to be supplied in the
JDBC url. This means it needs to look up static state, if I'm not mistaken.
Here's an example:
https://github.com/openzipkin/brave/blob/master/brave-mysql/src/main/java/com/github/kristofa/brave/mysql/MySQLStatementInterceptor.java
Another choice is to instrument at a higher level, such as JOOQ. Here's an
example of that:
https://github.com/openzipkin/zipkin-java/blob/master/zipkin-java-server/src/main/java/io/zipkin/server/brave/JDBCTracerConfiguration.java
Both of the above are modeled after finagle-mysql, which is a
protocol-level driver
https://github.com/twitter/finagle/blob/develop/finagle-mysql/src/main/scala/com/twitter/finagle/Mysql.scala#L48
All of the above are logging relatively high-level data, such as the type
of statement and whether or not it finished. These are a good start for
latency analysis.
@adriancole Thanks for the pointer. Does that mean instrument most of the libraries will be the solution for JDBC tracing viz. JOOQ, Dalesbred, Spring JDBC etc.(written support for last two though :)) like wrapping up these libraries or connection pools which have this kind of support.
there are tradeoffs to each decision.
Picking integrations explicitly is less magical code, albeit repetitive.
Using JOOQ (or anything with a nice interceptor abstraction), you can write
succinct (usually <100loc) integration. I'll call this the library approach.
Seeking out a single portable solution across all the libraries (and
versions therein) is its own problem space. I'll call this the agent
approach.
For example, pinpoint has a sophisticated JDBC library plugin thing which
other things extend. This is substantially more harder to test and higher
maintenance code, but the end effect is a black-box which drops in
anywhere:
https://github.com/naver/pinpoint/tree/master/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc
I guess we can close this one...
FYI this is hard to hook into (as it deals at JDBC driver level), but might be a way-out
https://github.com/p6spy/p6spy
It has a implementation in Brave folks could take a look at.
https://github.com/openzipkin/brave/tree/master/brave-p6spy
What would you think about an aspect based approach on JDBCTemplate method invocations? Could name the span something like jdbc:/jdbcTemplateMethodName. While it wouldn't be able to distinguish between two calls, it would be useful for applications where an http call has a small number of db requests attached.
Any thoughts before I spend some time working on this?
ok, simplest pass first, ill need to change up the injection strategy but i just dropped this into a sample app:
package sample;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.util.SpanNameUtil;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class JdbcTemplateSleuthAspect {
Tracer tracer;
@Autowired
public JdbcTemplateSleuthAspect(Tracer tracer) {
this.tracer = tracer;
}
@Around("execution (* org.springframework.jdbc.core.JdbcTemplate.*(..))")
public Object traceJdbcCall(final ProceedingJoinPoint pjp) throws Throwable {
String spanName = SpanNameUtil.toLowerHyphen(pjp.getSignature().getName());
Span span = this.tracer.createSpan("jdbc:/" + spanName);
try {
return pjp.proceed();
}
finally {
this.tracer.close(span);
}
}
}
@jmcshane , can you please tell me how you wired Tracer, we are planning to implement DT (Distributed Tracing) for Non boot ( Spring MVC) application. trying for help on how to ingest Tracer and invoke sleuth framework.
This issue relates to https://github.com/spring-cloud/spring-cloud-sleuth/issues/693
Most helpful comment
What would you think about an aspect based approach on
JDBCTemplatemethod invocations? Could name the span something like jdbc:/jdbcTemplateMethodName. While it wouldn't be able to distinguish between two calls, it would be useful for applications where an http call has a small number of db requests attached.Any thoughts before I spend some time working on this?