Reputation: 8644
In our code, there are quite a lot of logging fragments like this:
if(logger.isDebugEnabled()) {
logger.debug("...")
}
Is it possible to configure SonarQube so that such code blocks are not included in the code coverage analysis? Writing tests to cover such debug statements does not seem to make much sense...
I found out how to:
But I did not find a way of excluding a code block from the coverage analysis only.
Upvotes: 16
Views: 5295
Reputation: 1328342
Since Sonarqube can import JaCoCo coverage report, you could use an annotation containing "Generated
" in its name, as explained here by nineninesevenfour.
In your case, you would replace your log calls with logDebug()
calls, and:
@Generated
void logDebug(String message) {
if(logger.isDebugEnabled()) {
logger.debug("...")
}
}
fbastien adds in the comments:
Using
@Generated
is a nice trick.
Beware though not to use this when logging a message whose parameters are costly to retrieve, since encapsulating this in a method would require the parameters to be always computed, thus defeating the purpose of checkingisDebugEnabled()
before retrieving and logging them.
That is a valid concern regarding the performance implications of encapsulating the logging statement inside a separate method.
In Java, method arguments are evaluated before the method is called. So, if you encapsulate the logging call inside a method, any expensive computation required to produce the log message will always be executed, regardless of whether logger.isDebugEnabled()
returns true or false.
For example, consider the following:
@Generated
void logDebug(String message) {
if (logger.isDebugEnabled()) {
logger.debug(message);
}
}
// Calling the method
logDebug(expensiveComputation()); // expensiveComputation() will always execute
The expensiveComputation()
method would execute irrespective of the logging level, which would potentially cause performance issues.
A possible alternative would be to lazily evaluate parameters.
Instead of passing the message directly, you could pass a supplier function that generates the message.
@Generated
void logDebug(Supplier<String> messageSupplier) {
if (logger.isDebugEnabled()) {
logger.debug(messageSupplier.get());
}
}
Then, call the function like this:
logDebug(() -> expensiveComputation());
That alternative using Supplier<String>
aligns well with the comment's concern by making sure the expensive computation only occurs when debugging is enabled, and preserving the performance benefits of the original isDebugEnabled()
check.
@Generated
void logDebug(Supplier<String> messageSupplier) {
if (logger.isDebugEnabled()) {
logger.debug(messageSupplier.get());
}
}
The logDebug
method is annotated with @Generated
to be excluded from code coverage analysis.
It accepts a Supplier<String>
to delay the potentially expensive computation of the log message until it is confirmed that debug logging is enabled. So the performance optimization of the original isDebugEnabled()
check is preserved.
Upvotes: 4
Reputation: 3806
for files:
sonar-project.properties
sonar.exclusions=**/someglobalfolder*/** , **/someotherglobalfolder/*.js
For commenting out blocks:
See article: Turning Sonar off for certain code
Upvotes: -2
Reputation: 2302
I have also faced same problem.Rather ignoring it I used following two techniques
1)Mock These Logger Using any Mocking Framework example Mockito,Powermockito,PowerMock etc.Use same Mocking Code Across Test Classes wherever Applicable
2) Keep logback-test.xml(or logging config file for whatever logging framework you using) in class path and set Lower Log Level Like Trace.So let test classes to load logger to print these statements.
This will help in showing details about how test cases executing statement statement
Upvotes: -3