-
-
Notifications
You must be signed in to change notification settings - Fork 4.1k
jdbcdslog is now enabled at the connection pool / data source level #6150
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| /** | ||
| * Wraps a data source in a org.jdbcdslog.LogSqlDataSource if the logSql configuration property is set to true. | ||
| */ | ||
| def maybeWrapDataSource(dataSource: DataSource, configuration: Config): DataSource = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these methods could be private[db].
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, maybe the signature could be something like:
private[db] def wrapToLogSql(dataSource: DataSource, wrap: Boolean): DataSourceThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @marcospereira,
thanks for reviewing the PR. I agree with the reduced visibility of the methods and the name change, but not sure about replacing Configuration with a Boolean. That would just mean the logSql property needs to be extracted in each connection pool implementation?
Would the following changes be acceptable?
/**
* Wraps a data source in a org.jdbcdslog.LogSqlDataSource if the logSql configuration property is set to true.
*/
private[db] def wrapToLogSql(dataSource: DataSource, configuration: Config): DataSource = {
if (configuration.getBoolean("logSql")) {
val proxyDataSource = new LogSqlDataSource()
proxyDataSource.setTargetDSDirect(dataSource)
proxyDataSource
} else {
dataSource
}
}
/**
* Unwraps a data source if it has been previously wrapped in a org.jdbcdslog.LogSqlDataSource.
*/
private[db] def unwrap(dataSource: DataSource): DataSource = {
dataSource match {
case ds: LogSqlDataSource => ds.getTargetDatasource
case _ => dataSource
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that using a logSql: Boolean parameter is more explicit than passing the whole configuration. Also, getting is pretty straightforward.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I see your point about passing around the whole configuration, but wouldn't it makes sense then to leave the parameter out of the method altogether and just do the check in each ConnectionPool implementation:
/**
* Wraps a data source in a org.jdbcdslog.LogSqlDataSource.
*/
private[db] def wrapToLogSql(dataSource: DataSource): DataSource = {
val proxyDataSource = new LogSqlDataSource()
proxyDataSource.setTargetDSDirect(dataSource)
proxyDataSource
}
Then in HikariCPModule (for example):
val wrappedDataSource = configuration.getBoolean("logSql") match {
case true => ConnectionPool.wrapToLogSql(datasource)
case _ => datasource
}
or (not sure which is more idiomatic to be honest):
val wrappedDataSource = if (configuration.getBoolean("logSql")) {
ConnectionPool.wrapToLogSql(datasource)
} else {
datasource
}
I say that because the Boolean parameter just controls whether the method has any effect at all it feels to me more natural to do the check outside the method itself, whereas passing the whole configuration at least leaves it up to ConnectionPool to control which configuration property is used to decide whether logging is enabled or not?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm ok with you passing the configuration instead of a boolean. This is just a small detail. Also, I would go with the if/else instead of the match/case.
|
Is this PR ready to merge? |
Updated data source wrapper method names
|
I have updated data source wrapper method visibility and names as suggested by @marcospereira, so from my point of view the PR can be merged. |
…6150) * jdbcdslog is now enabled at the connection pool / data source level * Added tests for the logSql configuration property * Reduced data source wrapper method visibility Updated data source wrapper method names
Pull Request Checklist
Fixes
Fixes #6149
Purpose
To enable SQL logging with jdbcdslog the data source needs to be wrapped in a org.jdbcdslog.LogSqlDataSource. This was previously done at the database API level (in Databases.scala) before data sources were registered with JNDI. This causes database operations that use JPA to not be logged as their data source is not wrapped in a org.jdbcdslog.LogSqlDataSource. Now each supported connection pool wraps its own data sources when they are created and unwraps them before they are closed.
Background Context
The data sources are already registered with JNDI in the implementation classes for both supported connection pools, so I modified both to also automatically wrap the data source in a org.jdbcdslog.LogSqlDataSource if logSql is set to true. I have also moved the code that unwraps a data source when it needs to be closed. Since the functionality is the same for both connection pool implementations I placed the two methods (wrap data source and unwrap data source) in the ConnectionPool object.
It seems that registering any new data sources with JNDI is left up to the implementation of each connection pool at the moment, so it seemed appropriate that wrapping and unwrapping their data sources to support logging would be done there as well. Although I am not a huge fan of this as it makes implementing a new connection pool more difficult (have to remember to bind its data sources to JNDI and to wrap / unwrap the data sources to enable logging).
The code that actually wraps / unwraps the data sources could be copied into both implementations directly and removed from ConnectionPool to match what is done with JNDI registration code at the moment if that is preferable.
Apologies for not writing any test cases for this, not sure how I would go about that unfortunately. Maybe someone can direct me? But I can confirm I have tested the changes with both Java and Scala versions of Play.
Edit: I have now added a few tests to check whether the logSql configuration property is applied correctly and whether the right data source class is used both using the Database API and the JPA API.
References
Here's the original post about this issue on the Google group:
https://groups.google.com/d/msgid/play-framework/bd37c292-60b7-457c-a01c-018e824c8c70%40googlegroups.com?utm_medium=email&utm_source=footer