When talking about logging practices, you could segment the topic into three main areas of concern. Those would include, in chronological order, application logging, log aggregation, and log consumption. In plain English, you set up logging in your source code, collect the results in production, and then monitor or search those results as needed.
For aggregation and consumption, you will almost certainly rely on third-party tools (an advisable course of action). But the first concern, application logging, is really up to you as an application developer. Sure, logging frameworks exist. But, ultimately, you’re writing the code that uses them, and you’re dictating what goes into the log files.
And not all logging code is created equal. Your logging code can make everyone’s lives easier, or it can really make a mess. Let’s take a look at some techniques for avoiding the mess situation.
What Do You Mean by Application Logging Practices?
Before diving into the practices themselves, let’s briefly clarify what application logging practices are. In the context of this post, I’m talking specifically about things that you do in your application’s source code.
So this means how you go about using the API. How do you fit the logging API into your source code? How do you use that API? And what kinds of messages do you log?
Use a Framework for Application Logging
A moment ago, I said that logging frameworks exist. Let me build on that by also saying that you should use them.
Logging frameworks handle the standard parts of application logging for you. They also generally offer you ready-made options for the logging medium. So basically, you add a logging package to your application’s source code, and then you just start making calls to an API. All of the details of file I/O or database drivers or whatever become the framework’s problem.
Why do I recommend this? Well, first of all, it helps a lot with standardization. And secondly, this is a well-solved problem. You’ll find your life much easier if you rely on the solutions of those who have put a lot of time and thought into it, rather than reinventing that wheel. You specialize in writing software for your problem domain — not in writing loggers.
Avoid Side Effects and Logging Code in the Critical Path
Next up, let’s consider the effect that your logging code has on the rest of your application. The relationship here is rather interesting.
Logging, as a practice, is critically important. But the execution of any given logging logic generally takes a backseat to your code fulfilling its primary purpose. In other words, when your e-commerce platform (for instance) is logging a sale, the financial transaction itself is a whole lot more important than writing information about the transaction to a log file. You can live with a missing entry in your log file. You’ll lose a customer if you bill them without shipping them a product.
So make sure your logging logic doesn’t interfere with critical application activities. Don’t let some kind of exception generated in a logging statement, for instance, throw you out of your application’s normal execution flow. And definitely don’t involve the logger in the logic flow of your application. Logging should have almost no impact on your application. Logging frameworks can help a lot with this, but they won’t entirely prevent you from shooting yourself in the foot.
Know And Consider Your Audience
When you’re creating writes to your log, think through who (or what) will consume it. In the broadest terms, there are two types of consumers: humans and machines. If humans will consume the log, then it’s important to create human-readable log messages through the API. On the other hand, if machines will consume it, then you want to emphasize writing entries that those machines can parse (e.g. with key value pairs or JSON).
But you can take this even a bit further. Will operations people read it? Or, if you’re writing code for a small startup, perhaps non-technical people will pitch in for troubleshooting. I can’t enumerate all possible cases, but you should have a good idea for your codebase. Generally speaking, bear your audience in mind, the same way you might when writing documentation or code comments.
This is a related point to keeping your audience in mind, particularly when your audience consists of humans. Make sure you supply context to the entries you write to the log file.
In other words, give those reading enough relevant information to make sense of the entry. As an extreme example, imagine an entry in a log file that just said, “error” and listed a timestamp. Would that help you? Would it help anyone at all, ever? Probably not.
What sort of error was it? An exception? A validation error? And where did it happen? What inputs and outputs triggered it? What are the possible implications?
Again, I can’t take you through everything that someone might find relevant in your situation. But if you give it some thought, you should be able to help those reading the log.
Think of Your Log as Data
The point about context slants toward humans consuming the log file, whereas this point focuses more on machine parsing. Still, the best scenario involves creating log files that either can consume. So think of your logs as data no matter who might consume them.
What do I mean by this? Quite simply, don’t think of your logs as free form text. You’re not writing a short story through this medium. Instead, at a fundamental level, your logs capture data about your application’s runtime behavior. Give your entries relevant data such as time stamps, call stacks, and values of variables in your application.
Think of your logs, in general terms, as key-value stores that others want to use for data mining purposes. Get the best of all worlds by thinking of your log entries this way and then endeavoring to make them human readable as well.
Strive for Consistency
This is another area where your logging framework can help a lot, but you still have some work to do. Go for consistency in how you structure entries to the log file.
Don’t add time stamps for some entries but not others. Don’t have a hodgepodge of formats that people might use, depending on mood.
Instead, have a standard for log messages in your application, the same way that you have a coding standard. You don’t need to go overboard, but it should establish a basic template for log messages, as well as some guidance on what sorts of information to capture and when.
This consistency adds up to a log file that’s easy to consume and that you can rely on to provide information to you in a predictable way.
Err on the Side of Too Much
I’ll close with a philosophical recommendation. When in doubt, log it. If you’re not sure, err on the side of logging too much.
I get it. Logging historically has a pretty low signal to noise ratio. Most techies have, at some time or another, found themselves staring at gigantic log files, looking for needles in haystacks. It’s headache inducing and frustrating, but you shouldn’t let it stop you from logging as much as you possibly can.
The world of application development has come a long way and solved a lot of problems. When it comes to noise in logs, efficient aggregation and search capabilities let you sift through all of that information without the headaches. So capture as much of it as you possibly can during the application logging phase of development. Aggregation and search have your back.