Picking a Logging Framework
A couple of years back, I inherited maintenance of a pretty big java application (a couple of thousand classes). Logging was a mess:
- Several logging frameworks were in general use (most of the ones listed below were actively used)
- All log messages went to stdout, some even directly, using the evil exception.printStackTrace()
- No standard, explicit or implicit, existed concerning what the severities (Fatal/Error/Warn/etc.) of the various frameworks meant - apparently, people just used whichever framework and message priority felt right on the day.
- Exceptions were frequently wrapped and rethrown - I found several cases of exceptions nested many layers deep!
- The antipattern "log, wrap and rethrow" was applied in places were it wasn't warranted, generating confusing and repetitive logs ("Were there really 50 NullPointerExceptions within 50ms or was it the same one?" - sometimes the answer was 1, sometimes more)
Conclusion: I found myself maintaining an application which with light traffic generated several 100MBs of logs every day, with an estimated 5-6000 messages with priority "Error" or worse. Many of these were actual problems in the application, most were unimportant.
If I could throw the whole thing away and start from scratch, what would I do?
Loads of logging frameworks exist. Some are optional, several are likely to be available at runtime whether you want them or not. On this project, when all dependencies and transitive dependencies have been considered, the we're-here-and-that's-that logging options are:
- stdout/stderr
- Something always seems to end up being written here, no matter how hard you try not to.
- Application server vendor logging
- The advantage of this solution is unbeatable integration with the application server administration and monitoring tools. The main disadvantage is vendor lock-in: If you ever want to switch to another vendor, deploy part of your application outside of a JEE context, or simply upgrade to another major version of the product, you are up the creek without a paddle.
- Java logging
- My only problem with this framework is that when SUN added it to java, log4j was already mature and widely used in the community. It didn't really seem necessary to add yet another logging framework, but I guess SUN can do what they want. java.util.logging is simpler than log4j, but log4j isn't all that complicated.
- Commons logging
- If you are writing code which might be reused by projects which might want to pick their own logging framework, commons logging makes sense (those are pretty big "mights"!). Otherwise, the potential classloader problems and general added complexity makes me prefer picking a concrete logging framework and using it directly.
- Log4j
- This is the one I know best, and it works so well I don't really need to explore other options. There hasn't been a new major version in many, many years (1.3 branch abandoned, 2.0 branch doesn't seem to be going anywhere). IMHO, this is a good thing - log4j is easy to extend, so if you need more than what's there, just do it!
What do I want?
- I want log messages coming from different application layers to be easily distinguishable. I do not want one log file which contains everything. For example, the application server should have it's own log - that way, I can easily ignore it when I want to.
- All application code should use the same logging framework, and there should be a standard for what the different message priorities mean.
- I want an application in production which only writes error messages when something is wrong (e.g. subsystem down, illegal application state). Each error should produce at least one, but as few and concise log messages as possible.
- On a perfect day, there should be NO ERROR MESSAGES in the log!
- On a good day, there should be few enough error messages for a serious person to bother reading (with thousands of error messages and no users complaining, you might as well not have a log).
How do you ensure that all your logging is done using the framework you picked?
You could just send out an email informing your team about the framework you have decided to use, and in a perfect world, this would be enough. Unfortunately, with geographically remote teams, developers who come and go, and other priorities on the project, logging has little chance of getting people's attention unless it takes very little time and effort.
Checkstyle has a great rule, GenericIllegalRegexp, which lets you flag any regular expression in the source as illegal. This comes in very handy for automating the logging framework adherence - here is a sample file which prohibits all the above-mentioned logging frameworks: checkstyle-logging.xml. Obviously, you should remove the rule which forbids the framework of your choice.
Checkstyle cannot check hacks like using reflection to avoid referencing another logging framework directly, but if that is likely to happen on your project, you have bigger problems.
Taking the time to bug your team about logging will pay off further down the road, when the only person still around might turn out to be... You!