I manage an open source project in Java and have about 20 places in my code where I log exceptions using the following pattern (slf4j version 1.7.30)
private static final Logger logger = LoggerFactory.getLogger();
...
try {
interfaces = NetworkInterface.getNetworkInterfaces();
} catch (SocketException ex) {
logger.error("Socket exception when retrieving interfaces: {}", ex);
}
or similarly
try {
// stuff
} catch (IOException ioe) {
logger.error("Server error: {}", ioe);
}
Starting today, the SonarCloud automated code quality review has begun flagging these with rule java:S2275
(Printf-style format strings should not lead to unexpected behavior at runtime) with the specific message "Not enough arguments."
EDIT: Of note, this appears to consistently happen when an Exception
is the final argument. The following pattern does not flag:
try {
// Server connection code
} catch (IOException e) {
logger.error("Server Connection error: {}", e.getMessage());
}
A review of this other StackOverflow question indicates that perhaps an extra argument for the exception is optional and would result in different behavior, so I'm not clear how that would apply here and why it would suddenly change.
Is there something I can/should do to better translate these exceptions to log messages (e.g., use getMessage()
on all of them instead of relying on the automated toString()
parsing), or is this a false positive?
(Sonar's list of my 20 issues linked here.)
This is pure conjecture, but each of the issues points to a log line that can be generalized as:
LOG.something(format, custom_arguments, exception)
where format has {}
appearing count(custom_arguments) + 1
(the 1 reserved for exception).
As you've seen the linked answer, exceptions get treated specially by slf4j, so it's possible that due to some reason SonarCloud is doing the same thing. Unfortunately there's no documentation.
The "fix" would be to remove the final {}
intended for the exception, so e.g.
LOG.error("boom: {}", e);
LOG.error("boom2 {}: {}", something, e);
becomes
// exceptions handled in a special way
LOG.error("boom", e);
LOG.error("boom2 {}", something, e);