Choosing the Right Log Level in Java
Fast recall
Quick revision
Core answer
Interview-ready guide
Interview answer
When I add a log statement, I decide the level by asking who needs to see this and how urgently.
My first question is: did this situation actually stop the operation from completing? If the database is down and I can't save an order, that's ERROR, because the operation failed and someone needs to act. But if a user typed an invalid email and validation caught it, that's not an error at all — that's expected behavior, so it's INFO or even DEBUG.
The user will just fix it and resubmit. My second question is about production visibility. Significant business events like an order being placed or a user registering go at INFO, because that's the narrative operations teams follow.
Something unexpected that I handled — say I retried a slow call and it eventually worked, or I fell back to a default config — that's WARN. It's worth noticing, but the app kept working. Anything that's purely developer diagnostics, like the exact SQL or a cache hit, goes at DEBUG and stays off in production.
The biggest mistake I see freshers make is logging every caught exception at ERROR. Not every exception is a failure. A declined card or a wrong password is normal user behavior.
If you log those at ERROR, you get alerts constantly, and that's alert fatigue — eventually people ignore the alerts, and when a real database outage happens, it gets missed in the noise. So my rule is simple: ERROR for things that broke and need attention, WARN for handled surprises, INFO for normal business activity, DEBUG for developer detail.
Choosing the Right Log Level in Java
Direct Answer
Choose a level by the meaning of the event and the team's monitoring policy. ERROR is a failed operation worth investigation, WARN is an unexpected or degraded condition the system handled, INFO is a selected normal lifecycle or business event, and DEBUG/TRACE are progressively finer diagnostic detail. Expected client mistakes usually should not create ERROR alerts.
Code Example
try {
paymentGateway.charge(order);
} catch (CardDeclinedException e) {
// Expected business outcome — the user will try another card
log.info("Card declined for order {}: {}", order.id(), e.reasonCode());
} catch (GatewayTimeoutException e) {
// Unexpected but we recovered via retry
log.warn("Gateway slow for order {}, retrying", order.id());
} catch (GatewayDownException e) {
// System failure — the order cannot be placed
log.error("Payment gateway unavailable for order {}", order.id(), e);
throw e;
}
Three exceptions, three very different levels — because the consequence differs, not because they are all 'errors'.
Common Mistakes & Pitfalls
- Every exception is ERROR: catching a validation or authentication failure and logging it at ERROR, paging people for normal user behavior.
- Detail at INFO: putting cache hits or query timings at INFO, making production logs unreadable. That's DEBUG.
- Choosing for local dev: picking levels by what's convenient on your laptop instead of what production observability needs.
Check your understanding
Answer these without looking back at the article.
- What is alert fatigue and how does incorrect log levels contribute to it?
- How do you review and clean up log levels in a codebase?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.