It is pretty easy to forget about logging when writing code, and even if you think about it most often you will just log any exceptions. While logging exceptions will tell you when something went wrong, and where it went wrong it will not tell you what was the actual cause of it. In other cases there will not be any exceptions at all, but the problem will be caused by a bug in the program.
When trying to figure out the cause of the problem it is essential you can see the actions leading to it. To allow this you should log a lot more than just the exception, but logging everything that happens will lead to a log file that will easily blow up and become impossible to handle. A log file that is too big to read or to hard to understand is just as bad as having no log file at all. So what are some good practices to have decent logging?
There are couple of considerations to make:
- Use one or multiple log files.
- What log rotation should be used, if any at all.
- What information should be logged.
- How should the information be logged.
Having one log file makes it easier to understand and read what is going on, as all the information is in the same file. As the application grows, and more and more will be logged, you will find having it all in one file to be harder to read, because there will be a lot of noise. Even when all the information that gets logged is important, it may not be important at that time when you are looking for something specific. Having separate log files overcomes this, as you can more easily focus on something specific and see what was going on in that component.
When you however need to see the full picture and need to know the full state of different components are at a certain time, there is no other option than opening multiple files and ‘merging’ them yourself. In a multi-threaded application timing can be tricky if you use one logger for each file which may lead to you have the cause-effect wrong. If you have a log aggregator that allows filtering, this will not be a problem. If the aggregator has knowledge about the application, it may even help you with finding connections.
Whether you are writing to just one file or to multiple files, your logs will keep growing over time. Depending on the type of application you may want or need to keep the logs for a certain period. Just letting them grow in their own file may lead to log files of a couple of gigabytes. This is not something you want as opening them will become painful. A rollover can be based on different things: date, reboot, size, … I usually prefer to combine both date and size as this allows you to easily see the period of the logs (by mentioning the week or day the logs tells you about) and prevents logs from becoming too big if for some reason your log gets spammed with errors.
Probably the most important, but most difficult topic is what information must be logged. It is obvious that you want to log any exception with the complete stacktrace. But this is not enough, as it only shows you the problem and not the real cause. At the same time you can not log every method call as this will blow up your log file and slow down your application. In general it is a good idea to just log every ‘decision’ that the application makes. Normally this should be enough to follow the flow of the program and pinpoint the error. Other things that must be logged are events and input signals that arrive, either caused by human interaction, external programs or time-based.
It is advised to have a consistent way of logging data, as you are interested in the content and not the structure. The most appropriate format is up to you to decide, it is however essential to have an easy to read date of when the message was logged. You should also make sure your log messages contain all important details, and that it is easy to understand. A log message with just numbers, but that does not explain each number will be much harder to understand than a sentence saying what is happening.
It is clear that logging is important, it is however not that easy to find the right balance of what and how to log. Logs are written to find the cause of a problem that has occurred, while it is much better to prevent problems this will be impossible. In the end a system that never has any problem does not need any logging at all, but unfortunately such a system does not exist.