If you’ve spent any amount of time in the software industry, you’ve probably bumped up against logging. Maybe you first encountered it as a way to debug your program as you worked, printing “you are here” messages. Go much beyond that, especially in 2017, and your logging efforts likely graduate to the use of a logging framework.
What Is a Logging Framework? Let’s Get Precise.
So what marks this distinction? When do you go from newbie printing out “got into the Calculate() method” to user of a logging framework? To understand that, let’s define logging framework.
A logging framework is a utility specifically designed to standardize the process of logging in your application. This can come in the form of a third party tool, such as log4j or its .NET cousin, log4net. But a lot of organizations also roll their own.
You have to go beyond just standardizing, however, to qualify as a framework. After all, you could simply “standardize” that logging meant invoking the file system API to write to a file called log.txt. A logging framework has to standardize the solution by taking it care of the logging for you, exposing a standard API.
To get more specific, we can conceive of a logging framework encapsulating three main concerns: recording, formatting, and appending. When you want to capture runtime information about your application, you start by signaling what to record. Then, you determine how to format that information. And, finally, you append it to something. Classically, this is a file, but you can also append to RDBMS tables, document databases, or really anywhere capable of receiving data.
If you have a piece of code dedicated to solving these problems, you have yourself a logging framework.
Should You Use an Existing Logging Framework or Build Your Own?
Now that we have precision around the definition, let’s examine your options for making use of a logging framework. Notice that I frame the question in terms of which one you should pick, rather than whether or not you should use one. I do that because production applications should most definitely make use of logging frameworks. Without them, you’re flying blind about what your application does in the wild.
The question then becomes whether you should use an existing one or write your own. Use an existing one — full stop. It’s 2017, and this is a well solved problem in every tech stack. You shouldn’t write a logging framework any more than you should write your own source control tool or build a bug tracker. Others have built these, and you can have them cheaply or freely. Stick with solving problems in your own domain, rather than reinventing wheels.
So you need a logging framework, and you should use an existing one. The question then becomes “which one?” Which logging framework should you use? I won’t answer that outright, since it will depend on your stack and your needs. Instead, I’ll offer guidance for how to choose.
Ease of Use and Community Support
As you examine your options, I’d consider ease of use before anything else. Logging has a massive surface area inside of your application code. In other words, every developer in the group will use the logger and use it often. You want to make sure that’s a pleasant experience, rather than a convoluted nightmare.
Look for a logging framework with a simple, intuitive API. As a measuring stick, a relatively inexperienced team member should be able to glance at an existing common use or two and understand how to use it himself. Setup should also be easy. An experienced team member should have no trouble figuring out how to configure application level settings.
But look beyond calls in the code and configuration. Does the tool have people that support it? Does it have a robust presence on Q&A sites like Stack Overflow? You want to make sure that if you hit snags, you have a way to resolve them. If you pick an obscure tool and encounter a bug, you might waste a lot of time troubleshooting someone else’s issues.
Impact on Your Application’s Runtime
Another critical consideration has to do with how your application behaves and performs. As I’ve already mentioned, you’re going to call the logger a lot. In fact, you’ll call it so much that it might top your list of most common invocations.
This means it can have an outsize impact on your application’s performance. Imagine, for instance, a logging framework that blocked and performed file I/O at every single invocation. Gearing up for some mission critical tight loop, your app needs every possible cycle… but then it stops the presses to open a file, write “data processed after 8 microseconds” to it, and then close the file. Ouch.
So when evaluating your logging framework options, consider its behavior and reported performance. Look for sites or articles that benchmark and compare the different frameworks. You can even run some comparative experiments yourself.
Impact on Your Codebase
By now, I’ve hopefully made the point about ubiquity of logging calls. And just as these can affect runtime performance, they can also affect maintenance concerns in your source code. Say you’re diligently logging in as many as 50% of the methods in your codebase. That describes a pretty large footprint.
Logging, from an application perspective, is awkward. You do your best to isolate dependencies, provide good abstractions, and minimize coupling. You program with the single responsibility principle in mind. And then logging comes along and creates a deafening record-skipping sound.
Logging runs counter to all of these good design principles. It gets everywhere, has nothing to do with the code around it, and triggers an awkward and expensive construct: file (or other) I/O. It’s a cross cutting concern, and cross cutting application concerns are so confounding that they’ve created an entire category of software architecture called aspect oriented programming (AOP).
Look for a logging framework with an elegant solution to this problem (or at least an elegant option). Of particular concern, from a codebase cleanliness perspective, are the impact on code noise and ease of unit test writing. Make sure that the framework you choose has guidance on how to handle these concerns.
Complete Solutions for Recording, Formatting, and Appending
The last major point involves completeness. Earlier in the post, I categorized the functionality of a logger in three main buckets: recording, formatting, and appending. You want to make sure that your logging framework of choice thoroughly addresses all three concerns.
Recording is relatively trivial. I can’t recall ever seeing a logging framework that didn’t record messages. The only real concern here is whether it neatly captures a variety of data types. Do you have to convert everything to a string, or is the thing smart enough to understand a rich variety of types?
You also don’t see solutions without some kind of appender concept (or, again, you wouldn’t be logging). But here you want to make sure of a couple of things. First, the framework should neatly decouple appending from recording. And, secondly, you should have a variety of options for where to append (and ideally be able to define custom appenders).
I saved formatting for last because that’s where these frameworks can really distinguish themselves. Historically, formatting log files often involved making them neatly aligned and scannable by human eyes. But as we find ourselves firmly in the modern world of DevOps, you need something more. Specifically, you need to format your log files as parseable data. By treating log output as data, you can aggregate, search, and visualize logs in ways that give you a huge leg up in production support. So make sure that your logging framework gives you this ability and, hopefully, even defaults to doing it.
The Future Is Bright
There’s no getting around it — choosing a logging framework is an important architectural decision. Your code will use it a lot, creating enormous impact on both performance and code maintainability. Anyone supporting your application in production will consume its output. You want to make the right call.
But, as much pressure as that might seem to create, your prospects are good. The move toward DevOps and toward treating runtime artifacts as first class data means that we’re getting better and better at this stuff. Application developers are getting better at logging. Anyone supporting the application is getting better at troubleshooting. And logging framework authors are getting better at supporting both.
So do your research, make your decision, and then feel good about the future of your application. We’ve come a long way since the days of hard-coding obtuse text dumps to files. And the coming years will see us progress even more.