What makes a good log message?

What makes a good log message?

Logging can provide important information about the behaviour of software applications. It allows operations staff to monitor application performance and gives developers a trail to follow when trying to diagnose the cause of errors.

With this in mind, it is worth considering what is good information to record in a log file and what format it should be recorded in. Below is a list of the general guidelines I follow when writing log messages.

Use log levels to indicate severity

There are 6 log levels included in the logging abstraction provided in .NET Core. These can be used to indicate how severe a problem is (or that the message is just for information or other purposes).

Trace
Commonly used for debugging and may contain sensitive application data. This should never be used in production.
Debug
Used for debugging and can be temporarily used in production to help diagnose issues.
Information
Provides details about the flow of the application. This can be used to record messages with long-term value.
Warning
Used to record events which are unexpected, but don’t cause the application execution to fail.
Error
Indicates events which cause the application execution to stop before completing.
Critical
These events cause the application to fail in such a way it cannot be recovered. These usually require urgent attention.

Selecting the right log level is important, it can help to surface information about the application which indicate a problem may develop in the future (such as a warning about limited remaining free disk space) or that

Do not include sensitive data

Logging personal or sensitive data is not a good idea. This information is often stored in an unencrypted format and has been the source of data breaches in the past. Ensuring that this doesn’t happen is also an important part of ensuring GDPR compliance.

Some examples of these can include:

  • Application, database or API authentication information
  • Names, usernames, emails and passwords
  • Phone numbers

Add parameters to the end of messages

Including information about a request can help when determining the cause of an issue. For example, if a problem is encountered processing a file you may want to include an identifier for that file.

Processing file 128 failed.

Arranging the information in the form of a sentence makes it easy for humans to accidentally skim over the information and almost impossible to devise a simple way for automated tools to extract information from log files.

An improved approach to this is to include additional information at the end of the message. I would recommend using a format which is easily understood and parsed by machines (such as JSON).

Processing file failed. { fileId: 128 }

Include context in log messages

It is easy to write log messages with the context of the code surrounding them. After all, that is what you as the developer can see. But when these messages are output, they do not have that additional context. This can make log messages hard to understand.

Let’s take the example of an application which is attempting to read a user’s record from a database but can’t establish a database connection the message. You might add the following message to the log.

Could not read user record.

This might be okay in the context of the code, but if you are reading this message in a log file you don’t have that context. You have no idea what record the application was trying to access. To improve this you need to add more context to your log messages.

Could not read user record. A database connection could not be established. Please check the database is accessible. { userId: 36 }

In the above example, the complete context is included along with the ID of the user record which is attempted to retrieve. The message also includes a potential remediation step, which an individual can use to check for any common causes of issues.

Don’t log everything

It can be tempting but, adding log messages everywhere you possibly can, only results in adding noise to your logs. In the best-case scenario, this causes your logs to become bloated with unnecessary information, and in the worst-case scenario this can obscure useful information.

It is important to consider who will read your logs and what they will actually be looking for. Adding messages for successfully reading database records has little benefit in most cases. However, if you were expecting a database record to be there which isn’t that might be worth a log message which can be followed up on.

Conclusion

Hopefully some of these guidelines help you write more informative log messages. Hopefully this will cut down on logging noise and improve the quality of your logging. I am sure your future self (or someone else) will thank you!