Spring Boot integration with p6spy, datasource-proxy, flexy-pool and spring-cloud-sleuth
Spring Boot auto-configuration for integration with
Connection
, Statement
and ResultSet
methods invocationsConnection
, Statement
and ResultSet
method callsInstead of using the library you can manually wrap your DataSource
, but this library also provides
@ConfigurationProperties
provided by Spring Boot (spring.datasource.hikari.*
, spring.datasource.dbcp2.*
)decorator.datasource.enabled=true/false
application.properties/yml
and customize proxies by defining beans in the spring contextAdd one of the starters to the classpath of a Spring Boot 3 application and your datasources (auto-configured or custom) will be wrapped into one of a datasource proxy providers below.
[!NOTE]
For Spring Boot 2 applications, the latest compatible version is 1.8.1.
If you want to use P6Spy
implementation("com.github.gavlyukovskiy:p6spy-spring-boot-starter:${version}")
<dependency>
<groupId>com.github.gavlyukovskiy</groupId>
<artifactId>p6spy-spring-boot-starter</artifactId>
<version>${version}</version>
</dependency>
or Datasource Proxy:
implementation("com.github.gavlyukovskiy:datasource-proxy-spring-boot-starter:${version}")
<dependency>
<groupId>com.github.gavlyukovskiy</groupId>
<artifactId>datasource-proxy-spring-boot-starter</artifactId>
<version>${version}</version>
</dependency>
or FlexyPool
To use FlexyPool with connection pool other than HikariCP you must add
PoolAdapter
for your particular connection pool.
implementation("com.github.gavlyukovskiy:flexy-pool-spring-boot-starter:${version}")
<dependency>
<groupId>com.github.gavlyukovskiy</groupId>
<artifactId>flexy-pool-spring-boot-starter</artifactId>
<version>${version}</version>
</dependency>
You can use all decorators at the same time if you need, if so decorating order will be:
P6DataSource -> ProxyDataSource -> FlexyPoolDataSource -> DataSource
After adding p6spy starter you’ll start getting all sql queries in the logs:
2017-06-07 21:42:08 INFO p6spy: #1496860928120 | took 0ms | statement | connection 0|SELECT NOW()
;
2017-06-07 21:51:07 INFO p6spy: #1496861467802 | took 0ms | statement | connection 1|SELECT NOW()
;
2017-06-07 21:51:07 INFO p6spy: #1496861467803 | took 0ms | statement | connection 2|SELECT NOW()
;
2017-06-07 21:51:08 INFO p6spy: #1496861468806 | took 0ms | statement | connection 3|SELECT NOW()
;
All beans of type JdbcEventListener
are registered in P6Spy:
@Bean
public JdbcEventListener myListener() {
return new JdbcEventListener() {
@Override
public void onAfterGetConnection(ConnectionInformation connectionInformation, SQLException e) {
System.out.println("got connection");
}
@Override
public void onAfterConnectionClose(ConnectionInformation connectionInformation, SQLException e) {
System.out.println("connection closed");
}
};
}
This done by adding RuntimeListenerSupportFactory
into P6Spy modulelist
, overriding this property will cause to not registering factory thus listeners will not be applied
You can configure small set of parameters in your application.properties
:
[!NOTE]
Configuration below indicates al possible parameters together with their default values and does not need to be set explicitly
# Register P6LogFactory to log JDBC events
decorator.datasource.p6spy.enable-logging=true
# Use com.p6spy.engine.spy.appender.MultiLineFormat instead of com.p6spy.engine.spy.appender.SingleLineFormat
decorator.datasource.p6spy.multiline=true
# Use logging for default listeners [slf4j, sysout, file, custom]
decorator.datasource.p6spy.logging=slf4j
# Log file to use (only with logging=file)
decorator.datasource.p6spy.log-file=spy.log
# Class file to use (only with logging=custom). The class must implement com.p6spy.engine.spy.appender.FormattedLogger
decorator.datasource.p6spy.custom-appender-class=my.custom.LoggerClass
# Custom log format, if specified com.p6spy.engine.spy.appender.CustomLineFormat will be used with this log format
# see https://p6spy.readthedocs.io/en/latest/configandusage.html#customlogmessageformat
decorator.datasource.p6spy.log-format=
# Use regex pattern to filter log messages. If specified only matched messages will be logged.
decorator.datasource.p6spy.log-filter.pattern=
# Exclude certain categories from logging. If specified only matched messages will be logged.
# see https://p6spy.readthedocs.io/en/latest/configandusage.html#excludecategories
decorator.datasource.p6spy.exclude-categories=
Also you can configure P6Spy manually using one of available configuration methods. For more information please refer to the P6Spy Configuration Guide
After adding datasource-proxy starter you’ll start getting all sql queries in the logs with level DEBUG
and slow sql queries with level WARN
:
2017-06-07 21:58:06 DEBUG n.t.d.l.l.SLF4JQueryLoggingListener:
Name:, Time:0, Success:True
Type:Statement, Batch:False, QuerySize:1, BatchSize:0
Query:["SELECT NOW()"]
Params:[]
2017-06-07 21:58:06 DEBUG n.t.d.l.l.SLF4JQueryLoggingListener:
Name:, Time:0, Success:True
Type:Statement, Batch:False, QuerySize:1, BatchSize:0
Query:["SELECT NOW()"]
Params:[]
2017-06-07 21:58:06.630 DEBUG 8492 --- [ool-1-worker-50] n.t.d.l.l.SLF4JQueryLoggingListener :
Name:, Time:0, Success:True
Type:Statement, Batch:False, QuerySize:1, BatchSize:0
Query:["SELECT NOW()"]
Params:[]
2017-06-07 22:10:50 WARN n.t.d.l.logging.SLF4JSlowQueryListener:
Name:, Time:0, Success:False
Type:Statement, Batch:False, QuerySize:1, BatchSize:0
Query:["SELECT SLEEP(301000)"]
Params:[]
You can add custom QueryExecutionListener
by registering them in the context, as well you can override ParameterTransformer
, QueryTransformer
and ConnectionIdManager
:
@Bean
public QueryExecutionListener queryExecutionListener() {
return new QueryExecutionListener() {
@Override
public void beforeQuery(ExecutionInfo execInfo, List<QueryInfo> queryInfoList) {
System.out.println("beforeQuery");
}
@Override
public void afterQuery(ExecutionInfo execInfo, List<QueryInfo> queryInfoList) {
System.out.println("afterQuery");
}
};
}
@Bean
public ParameterTransformer parameterTransformer() {
return new MyParameterTransformer();
}
@Bean
public QueryTransformer queryTransformer() {
return new MyQueryTransformer();
}
@Bean
public ConnectionIdManagerProvider connectionIdManagerProvider() {
return MyConnectionIdManager::new;
}
You can configure logging, query/slow query listeners and more using your application.properties
:
[!NOTE]
Configuration below indicates al possible parameters together with their default values and does not need to be set explicitly
```propertiesOne of logging libraries (slf4j, jul, common, sysout)
decorator.datasource.datasource-proxy.logging=slf4j
decorator.datasource.datasource-proxy.query.enable-logging=true
decorator.datasource.datasource-proxy.query.log-level=debug
decorator.datasource.datasource-proxy.query.logger-name=
decorator.datasource.datasource-proxy.slow-query.enable-logging=true
decorator.datasource.datasource-proxy.slow-query.log-level=warn
decorator.datasource.datasource-proxy.slow-query.logger-name=
decorator.datasource.datasource-proxy.slow-query.threshold=300
decorator.datasource.datasource-proxy.multiline=true
decorator.datasource.datasource-proxy.format-sql=false
decorator.datasource.datasource-proxy.json-format=false
decorator.datasource.datasource-proxy.count-query=false
#### Flexy Pool
If the `flexy-pool-spring-boot-starter` is added to the classpath your datasource will be wrapped to the `FlexyPoolDataSource`.
> [!IMPORTANT]
> If you are not relying on Spring Boot autoconfiguration and instead declare a custom `DataSource` bean, you need to use
> a concrete `DataSource` type as the return value (e.g., `@Bean HikariDataSource dataSource()`) to match the FlexyPool adapter.
With default setting you will start getting messages about acquiring and leasing connections:
```text
2017-07-13 01:31:02 INFO c.v.flexypool.FlexyPoolDataSource: Connection leased for 1500 millis, while threshold is set to 1000 in dataSource FlexyPoolDataSource
2017-07-13 01:31:03 WARN PoolOnTimeoutConnectionAcquisitionStrategy: Connection was acquired in 1502 millis, timeoutMillis is set to 500
2017-07-13 01:31:03 INFO PoolOnTimeoutConnectionAcquisitionStrategy: Pool size changed from previous value 10 to 11
All beans of type ConnectionAcquisitionStrategyFactory
are used to provide ConnectionAcquisitionStrategy
for the pool.
MetricsFactory
and ConnectionProxyFactory
beans can be used to customize metrics and connection decorators.
EventListener<? extends Event>
beans can be registered to subscribe on events of flexy-pool (e.g. ConnectionAcquisitionTimeThresholdExceededEvent
, ConnectionLeaseTimeThresholdExceededEvent
).
You can configure your FlexyPoolDataSource
by using bean FlexyPoolConfigurationBuilderCustomizer
or properties:
[!NOTE]
Configuration below indicates al possible parameters together with their default values and does not need to be set explicitly
```propertiesIncrements pool size if connection acquisition request has timed out
decorator.datasource.flexy-pool.acquisition-strategy.increment-pool.max-overgrow-pool-size=15
decorator.datasource.flexy-pool.acquisition-strategy.increment-pool.timeout-millis=500
decorator.datasource.flexy-pool.acquisition-strategy.retry.attempts=2
decorator.datasource.flexy-pool.metrics.reporter.jmx.enabled=true
decorator.datasource.flexy-pool.metrics.reporter.jmx.auto-start=false
decorator.datasource.flexy-pool.metrics.reporter.log.millis=300000
decorator.datasource.flexy-pool.threshold.connection.acquisition=50
decorator.datasource.flexy-pool.threshold.connection.lease=1000
#### Spring Cloud Sleuth (removed since 1.9.0)
##### For Spring Boot users, that DO NOT use Spring Cloud Sleuth
Nothing has changed, this project is continued to be supported and maintained, and can be used to enable JDBC logging
and provide auto-configuration of P6Spy, Datasource-Proxy and FlexyPool.
##### For Spring Cloud Sleuth users
As of release 1.8.0 Spring Cloud Sleuth integration was deprecated in favor of [Spring Cloud Sleuth: Spring JDBC](https://docs.spring.io/spring-cloud-sleuth/docs/3.1.0/reference/html/integrations.html#sleuth-jdbc-integration)
which provides JDBC instrumentation out of the box.
As of release 1.9.0 Spring Cloud Sleuth integration was removed.
Spring Cloud Sleuth JDBC was based on this project and keeps all functionality including logging, tracing, configuration and customizations.
##### Migration process:
1. If you are using Spring Cloud Sleuth you can migrate all properties from `decorator.datasource.*` to `spring.sleuth.jdbc.*` with minimal changes.
2. If you have query logging enabled (default state) then you need to explicitly enable logging using:
- P6Spy: `spring.sleuth.jdbc.p6spy.enable-logging=true`
- Datasource-Proxy: `spring.sleuth.jdbc.datasource-proxy.query.enable-logging=true`
3. If you were using decoration customizers please consult with Spring Cloud Sleuth documentation and migrate usage of those to appropriate alternatives in Spring Cloud Sleuth
4. _(Optional)_ Replace dependency on this starter with the particular library
- P6Spy: replace `com.github.gavlyukovskiy:p6spy-spring-boot-starter` with `p6spy:p6spy`
- Datasource-Proxy: replace `com.github.gavlyukovskiy:datasource-proxy-spring-boot-starter` with `net.ttddyy:datasource-proxy`
5. Any issues can be raised in Spring Cloud Sleuth project on GitHub, you may tag me (@gavlyukovskiy) and I'll try to help.
6. Enjoy using JDBC instrumentation, and thank you for using this library :)
Due to similarities in implementation, using starters from this library together with Spring Cloud Sleuth 3.1.0 is possible, although decoration will be automatically disabled in favor of Spring Cloud Sleuth to avoid duplicated logging, tracing or any other potential issues.
#### Custom Decorators
Custom data source decorators are supported through declaring beans of type `DataSourceDecorator`
```java
@Bean
public DataSourceDecorator customDecorator() {
return (beanName, dataSource) -> new DataSourceWrapper(dataSource);
}
If you want to disable decorating set decorator.datasource.exclude-beans
with bean names you want to exclude.
Also, you can disable decorating for AbstractRoutingDataSource
setting property decorator.datasource.ignore-routing-data-sources
to true
Set decorator.datasource.enabled
to false
if you want to disable all decorators for all datasources.