If you’re a software developer, then you understand how vital application logging is in software development and a critical part of logging is something called logging levels.
Log entries generally contain essential information—such as a timestamp, a message, and sometimes additional stuff like an exception’s stack trace. Those pieces of information are useful because they allow someone reading the log entry to understand how the application behaved in production.
How do logging levels fit into this picture? How are they useful to the reader performing a post-mortem debug on an application? What are logging levels anyway? How many of them are there?
Before we dive into the logging levels specifically, let’s do a quick review of the concept of application logging itself. Feel free to skip this section if you’re already well acquainted with logging.
I’d define logging as the practice of recording information about an application’s behavior in production and storing it into some target—text file or database—so it can be reviewed later.
It’s one thing to debug software from the comfort and safety of your IDE, with things under your control. But when you build this very complicated thing and release it into the wild… that’s a different animal entirely. Sure, I know your team writes code to the highest standards and has a robust quality assurance approach in place. But even then, your software will fail in production. When it does, how are you going to know what went wrong? And how exactly it went wrong? And what you need to do to prevent it from happening again?
That’s why you need to be able to perform a post-mortem debug on your application. And that’s why you need logging.
Now that we know what application logging is and why it matters, let’s turn our focus to logging levels.
Think about a document folder. An old-fashioned physical folder, storing actual documents made of dead trees. Now imagine that you have a lot of labels on those documents, categorizing them according to some criteria. With those labels in place, you can easily find your tax documents or the rent contract for your apartment.
Those labels are pretty much what logging levels are for your entry logs. By giving each entry a level, according to its severity, you become able to do lots of interesting and useful things with your logs.
The first thing that comes to mind is filtering. Once you have lots and lots of log entries, finding the information you need can be like searching for a needle in a haystack. It doesn’t have to be this way, though. And it won’t be if you have logging levels in place that allow you to quickly filter and easily distinguish between the fatal error that caused your app to crash and a routine usage statistic.
Logging levels also allow you to configure your logging process so that it behaves differently according to each level. These are some of the things you can adjust:
Now that you’ve learned about the general concept of logging levels and what they’re good for, let’s see the actual existing logging levels.
What follows are the most common logging levels you’re likely to see and use.
This is basically the union of all of the other levels. Everything is going to be logged. And this includes custom logging levels that you may have defined.
The debug level is not a lot of mystery. It’s probably what you’d be thinking anyway, given its name. It includes information in a very granular way so developers—and other IT professionals—can then use that information to perform diagnostics on the application.
You use the INFO logging level to record messages about routine application operation. Those are entries you usually don’t care that much about, to be honest. If things go bad during development, you’ll be looking at DEBUG entries. When things go bad in production, ERROR entries are what you’re looking for. Finally, when things go really bad in production, you’ll spend time looking at entries with the FATAL logging level.
So INFO log entries inhabit this kind of grey area between the more sought-after levels. But they’re far from being useless. Since they represent the mundane, everyday usage of the application, those entries might offer a valuable window through which you can better understand user behavior and gather usage statistics.
The WARN level designates potentially harmful occurrences. What “potentially harmful” means will, of course, vary in each situation. Those are situations that don’t cause harm per se, but they could indicate that something is not quite right. Do you know the “code smell” metaphor? While a code smell is not necessarily a problem in itself, it’s a sign of a possible problem that deserves investigation. The same is true when talking about logs marked with the WARN logging level.
The ERROR level denotes a serious problem that has to be dealt with. Not as serious as FATAL, which you’ll see next, but still a problem. Think about a desktop app failing to connect to the internet to synchronize some data. Sure, that’s not good and it’s definitely not the desired behavior, but it’s not the end of the world. It still needs to be recorded, though, so someone can take care of the issue.
The fatal level, like ERROR, designates a problem. But unlike ERROR, it designates a really serious error event. “Catastrophic” wouldn’t be too far-fetched an adjective to describe these kinds of problems. What “very serious” means will vary, of course, and you’ll have to decide what that is in the context of your application. But to illustrate, think about serious data loss or financial losses. In most situations, when a fatal event happens, the application should be aborted immediately in order to prevent more serious damage from happening.
With this level, nothing gets logged at all.
Think of this like DEBUG, but on steroids. This level logs information in a very fine-grained way. You probably wouldn’t want to use it in production scenarios, under penalty of high consumption of resources.
Now you know the main logging levels you’re likely to use. But how do they actually work in practice? That’s what we’re—briefly—answering in this section.
It’s actually very simple. During runtime, the application code will make logging requests, which will have a level. At the same, the logging framework has a log level configured, which acts as a threshold. If the request level is at the configured level or higher, it gets logged to the configured target. If not, it’s denied. It’s simple as that.
Consider that as the following rank order for the levels:
ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF
So if, for instance, the logging framework level is set to WARN, requests with any of the levels WARN, FATAL, and ERROR will be accepted, while the rest will be denied.
By understanding the value and applications of logging levels, you take one more step in the direction of using logging to its full potential and leveraging its benefits in your applications.
This post covered just the tip of the iceberg, though, so make sure you keep checking Stackify’s blog in order to learn more about logging and other topics. Also, take a look at Stackify’s Retrace and give it a try. It’s a tool that, among other features, will allow you to extract a whole lot more value from your logs.