We have following three logging best practices:
- All loggers should be final variables. So, we prefer
private final Logger logger = LoggerFactory
.getLogger(MyService.class); // good
Instead of
private static final Logger LOGGER = LoggerFactory
.getLogger(MyService.class); // bad
Using constant based syntax makes code look ugly and require developers to use shift key for typing upper case variable name. This breaks the flow so we prefer to use field variable naming.
- All logs should have description and context So, we prefer
logger.info("Event is alreay processed so not
processing it again [eventId={}, eventDbId={},
eventType={}]",
eventId, event.getId(), eventType); // good
instead of
logger.info("Event is already processed
so not processing"); // bad
We want logger statement to have enough context so that we can debug problems. The bad logging statement does not help you understand for which event this log statement was logged. All of these statements look similar.
- All error logs should have the exception in the context So, we prefer
logger.error("Exception while processing event
[eventId={}]", eventId, exception); // good
instead of
logger.error("Exception while processing event
[eventId={}]", eventId); // bad
To help developers discover these before raising their pull requests we have written ArchUnit tests for enforcing these practices. So, local build fails in case they violate these best practices. You can read my earlier post on ArchUnit[1] in case you are new to it.
Continue reading “Enforcing Logging best practices by writing ArchUnit tests”