3

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.)

1 Answer 1

10

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);
Sign up to request clarification or add additional context in comments.

7 Comments

I thought of that, but then it looked like adding the exception as a +1 argument actually threw the exception, which is not the behaviour I want. Also, in the first example, I extract a String from the exception...
@DanielWiddis it's pretty weird, as I don't see logger.error("Server Connection error: {}", e.getMessage()); in any of the 20 issues linked; absolutely surprised by the throwing behaviour though
Hmm, you're right... I opened one of the flagged files and grabbed one as an example pattern, but it's fine. It's only the ones leading to the exceptions that are the issue. I'll edit my post.
OK, did some testing and while it's not obvious/documented, the behavior is identical when the {} is removed as per your examples. Seems Sonar may have recently changed their checking to be more strict.
OK, not "identical". The brackets are output unnecessarily... so in fact it is an error and your solution is spot on.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.