It is a good practice to add logging capabilities to applications as they are built. There are a lot of good tutorials on how to setup logging within various applications and software frameworks. It is also instructive to discuss why something is a good practice since understanding why can lead to new insight in how, when, and where to apply said ’thing.’ The point of today’s post is to discuss some scenarios for why application logging is important. This post will be mostly non-technical because the how of logging can be learned with some decent web searches and there is already a wealth of information on logging software on the web.
In a few minutes of searching I didn’t come across a formal definition for application logging. With that in mind, let’s define a couple terms for this post:
- Logging is the exposure of internal application state via a representation which can be converted to text
- A log is a description of some state of the application which generated the log.
A couple interesting points can be made on these, hopefully, intuitive formalizations. A log statement as simple as I GOT HERE!
counts as a description of
the application’s state. It requires context to understand what “HERE” is, but it is still a description. Also the information generated by logging logic
and the method of getting it out doesn’t necessarily have to be text based. One example of a non-text logging component is
journald which accepts text and binary input and stores those inputs in a binary file. The importance of adding logging capabilities to an application
is question of why are we (or other applications that we write!) are interested in the state of a running application.
Being reactive
At least in my case I’m often interested in the state of a running application because it has done something it is not supposed to do. The Baker test, pictured above, did a number of unexpected things, including blanketing ships with radioactive water. Not understanding the effects of the underwater explosion may have lead to the tragic shorting of US service members lives.
Thankfully software development is not so dangerous.
The hypothetical horror story here though is some support engineering being woken at 03:00 in the morning by an alarm and then needing to review an application’s logs in order to determine how to quickly fix the issue. Later in the day, a developer perhaps will also review application logs from the night in order to understand why and where a failure occurred.
In short, logs are needed in order to respond to failures. A log can be generated from an error thrown within frameworks that the application relies on or generated from logic added by the application developer to indicate the application has reached an inappropriate state. The important thing for a log to do in this scenario is to capture the state the application reached. An Java based example of the full application state is capturing a full stacktrace, error message, and arguments to the current function call. More generally speaking, logging the full call stack is important in most language and frameworks since reactive log use involves trying to understand why and how and application reached a particular state.
Without a developer survey, I cannot say with complete confidence that this is most common use case for logs, but it certainly seems like it. A less common but nonetheless very use reason for logging is to provide non-error information about the application.
Being proactive
Proactive logging means putting log statements into an application to expose state information which might be useful at some point in the future. Logging when certain methods are called, when the application started, stopped, and when certain external inputs are received are all valid forms of proactive logging. The point here is not to track the full call stack of the application as much as tracking the application over time.
Adding these kinds of log statements to an application enables us to determine if the application is behaving nominally. There’s a common joke amongst developers about an application being done “when it compiles.” The point of the joke is that code compiling is only a minimal requirement for something being done and doesn’t, by itself, indicate completeness. Similarly, it’s possible for an application to be usable by a customer but misbehave in other ways, such as making 10s of API calls instead of one to service a client’s request. Poor design may result in a minimally working application, but being slower than desired or using too many hardware resources. These kinds of problems are not (easily) discoverable via logging for reactive reasons, but instead can be found of via logs written for proactive reasons.
Logging proactively can also enable feature analysis. Logs generated when a user uses a certain application feature can be analyzed in order to determine which areas of an application need more or less development. A common example of this is Google Analytics which can be used to analyze how users interact with a web site. The concept, however, is applicable to all types of software application. For example, it’s equally important to understand what features of a company’s public APIs are used by third party developers.
Being…aware? (collecting status)
Logs that expose basic application status are a subset of being proactive, but worth mentioning separately. Status logging consists of logs that contain information about the application’s operational state. Useful examples of status logging include logging that the application has started, that it’s stopping, and what version of the application has started.
These kinds of logs are particularly useful for engineering environments that employ automated CI and continuous delivery. With status logs in place it is possible to see an application’s automated tests pass, get deployed, and then log that the latest version has started. Additionally, in continuous delivery systems status logs can help show what times updates are common and how frequently new software is being released.
I hope today’s post was insightful or at least useful. Understanding why I need to do something has often lead to personal insight in how to better execute on that ‘something’. In the case of logging, it is vital for any sizable application and the lack of it can really hurt when it comes time to support the system in production.