Skip to main content

Clean code, clean logs: log method arguments and return values (7/10)

When you find a bug during development, you typically run a debugger trying to track down the potential cause*. Now imagine for a while you can’t use a debugger. For example, because the bug manifested itself on a customer environment few days ago and everything you have are logs. Would be able to find anything in them?

If you follow the simple rule of logging each method input and output (arguments and return values), you don’t even need debugger any more. Of course, you must be reasonable but every method that: accesses external system (including database), blocks, waits, etc. should be considered. Simply follow this pattern:

public String printDocument(Document doc, Mode mode) {
log.debug("Entering printDocument(doc={}, mode={})", doc, mode);
String id = //Lengthy printing operation
log.debug("Leaving printDocument(): {}", id);
return id;

Because you are logging both the beginning and the end of method invocation, you can manually discover inefficient code and even detect possible causes of deadlocks and starvation – simply by looking after "entering" without corresponding "leaving". If your methods have meaningful names, reading logs would be a pleasure. Also analyzing what went wrong is much simpler as on each step you know exactly what has been processed. You can even use a simple AOP aspect to log a wide range of methods in your code. This reduces code duplication, but be careful, since it may lead to enormous amount of huge logs (do you know what you are logging?)

You should consider DEBUG or TRACE levels as best suited for these types of logs. And if you discover some method are called too often and logging might harm performance, simply decrease logging level for that class or remove the log completely (maybe leaving just one for the whole method invocation?) But it is always better to have too much rather than too few logging statements. Treat logging statements with same respect as unit tests – your code should be covered with logging routines as it is with unit tests. No part of the system should stay with no logs at all. Remember, sometimes observing logs rolling by is the only way to tell whether your application is working properly or hangs forever.

* If you start by writing failing test case exposing the bug, my congratulations, I am proud of you!


  1. A much better approach for method begin / end logs are aspects. You can define so-called pointcuts to non-linear mix java statements.

    "If you start by writing failing test case exposing the bug, my congratulations, I am proud of you!" - I thought everybody already got the idea from eXtreme Programming. Are there non-unit-testing programmers still around ? ;-)

  2. Thank you for Your comment. As for AOP, I mentioned this approach in the article. The problem is with an unknown amount of data to be logged. We can access both arguments and return values of a method from within an aspect. But if the argument is a collection, should we log its whole contents or only size? It depends on the collection contents and aspect can't determine which approach to use. That's why I linked to this article. Could You explain "pointcuts to non-linear mix java statements" - never heard this term.

    It's sad, but You would be surprised how many "deploy -> run -> forget" programmers are still around :-(.


Post a Comment