The AWS Documentation for AWS X-Ray currently doesn't give any solutions for Java projects that do not use Tomcat JDBC.
In order to instrument database queries using spring-boot-data-jpa
, you need to also include Tomcat JDBC as a dependency, and set up a Tomcat DataSource object along with your Hikari one, and include the XRay interceptor as a JDBC interceptor by either:
dataSource.setJdbcInterceptors("com.amazonaws.xray.sql.postgres.TracingInterceptor;");
spring.datasource.jdbc-interceptors=com.amazonaws.xray.sql.postgres.TracingInterceptor
Gradle:
dependencies {
...
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation "com.amazonaws:aws-java-sdk-core"
implementation "com.amazonaws:aws-xray-recorder-sdk-core" // Required for core xray features
implementation "com.amazonaws:aws-xray-recorder-sdk-spring" // Required for spring annotations
implementation "com.amazonaws:aws-xray-recorder-sdk-sql-postgres" // required for db callouts
implementation 'org.apache.tomcat:tomcat-jdbc:9.0.31'
...
}
Database Configuration (Spring):
@Bean(name = "dataSource")
@Primary
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
final org.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource();
dataSource.setUsername(getUsername());
dataSource.setPassword(getPassword());
dataSource.setUrl(POSTGRES_URL_PREFIX
+ getHost()
+ ":" + getPort()
+ "/" + getName()
+ "?stringtype=unspecified");
dataSource.setDriverClassName(getDriver());
dataSource.setJdbcInterceptors("com.amazonaws.xray.sql.postgres.TracingInterceptor;");
final HikariDataSource hikariDataSource = new HikariDataSource();
hikariDataSource.setDataSource(dataSource);
return hikariDataSource;
}
I find this quite clunky, and I would rather not have to have Tomcat JDBC as an additional dependency if possible.
Is there no way around this without using Tomcat?
Other notes:
Spring Boot 2.1.7
Gradle 6.0.1
AWS SDK for Java 2.4.0
It turns out that someone else had this question. The AWS developers have been working on this in a feature branch that got merged in Novemeber 2019 for SDK version 2.3.0
.
I am yet to find any documentation for this new feature, so after some digging into the PR code, I managed to find that it's even more simple than the previous implementation.
Simply add the following dependency instead of the postgres specific one to your build.gradle
file (or similar):
implementation "com.amazonaws:aws-java-sdk-core:2.4.0"
implementation "com.amazonaws:aws-xray-recorder-sdk-core:2.4.0"
implementation "com.amazonaws:aws-xray-recorder-sdk-sql:2.4.0"
Then simply create a TracingDataSource
object in your DataSource configuration, and pass it your original javax.sql.DataSource
object. This should be done in whatever @Configuration
annotated class you use to create your DataSource
bean.
@Bean(name = "dataSource")
@Primary
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
final DataSource dataSource = DataSourceBuilder
.create()
.username(getUsername())
.password(getPassword())
.url(POSTGRES_URL_PREFIX
+ getHost()
+ ":" + getPort()
+ "/" + getName()
+ "?stringtype=unspecified")
.driverClassName(getDriver())
.build();
final TracingDataSource tracingDataSource = new TracingDataSource(dataSource);
return tracingDataSource;
}
That's all there is to it. I really hope this helps someone as I spent many hours trying to get this to work without Tomcat, plus the AWS documentation doesn't help here either.