What Should I Log In My Application?
No matter what logging API you use or whether you’re in .NET, Java, or something else - here’s a list of common situations you should log in your application to be sure you’re ready to support it in production.
Useful Information to Log
- Application Session start/stop. We recommend including a log statement as early and as late as possible in your application’s run time. Also, if your program has complex setup or teardown logic, include additional messages at the start and end of these sections.
- User Session start/stop. For many applications such as services and web apps, there may be many user sessions within a single application session. Log distinctive messages at the start and end of each of these logical sessions.
- Unhandled Exceptions. Loupe will log unhandled exceptions by default. But, if you write your own exception handler, be sure to log each exception to Loupe - passing the exception object as well as what context you have.
- Handled Exceptions. We strongly recommend that in all cases where an exception is consumed within a catch block that you log the exception with an Informational severity rather than silently swallowing the error. Bonus prize for including what your code is going to do in the face of this handled exception (in other words, how you’re handling it!)
Process Entrance and Exit. Each time your code gets called from another process (like an incoming web request to your web application) or you call out to another process (like a database query or remote web request) log the request, generally with significant detail. If the request fails, log that as well. These statements serve as “bookmarks” for understanding why your software worked or didn’t. Compared to the cost of calling to another process, particularly across a network, these log statements are practically free.
Significant User Actions. We recommend that you log each significant action taken by the user and that you use a specific category for these log messages. This makes it easy to reconstruct reproduction steps for defect reports. Some examples of this include:
- Button actions - describe what the button means (Save, cancel, add, delete, etc.)
- Navigating to a new context - Switching tabs in a large application, opening views, etc.
- Any message box / modal prompt displayed.
- Expensive operations like recalculating data sets, visualizations, or others.
- Display Help requests. From a usability perspective, every time a user opens your help documentation is a hint that something could be made clearer in the user interface.
- Cancelled Actions. When a user begins an action then abandons it without completing, it may also point to usability issues.
- Log Thread start/stop. If your application creates background threads, consider creating a helper class to create threads that will automatically log thread start/stop.
- Asynchronous request start/stop. We recommend logging the start and stop of most asynchronous requests – possibly excluding high frequency activities such as loading the individual elements of a web page.
What Not to Log
- Avoid logging simple routine actions. While judicious logging can be extremely helpful, do not blindly log every method entry/exit. Apply judgment and include logging only where it provides useful information to help you understand application flow.
- Avoid logging in tight loops that will be executed many times a second. While Loupe can easily sustain logging rates of over 1000 messages a second, such long logs are unwieldy. You can get a very good sense of what an application is doing with relatively few well-placed log messages. You and your support staff will be thankful later.
- Think carefully about sensitive information. Be sensitive to privacy and intellectual property considerations when adding log messages to your application. For example, passwords and sensitive information such as social-security numbers should never be logged.
Tips & Tricks
Log What and Why, not Where. A log message should indicate what the application is doing in its chain of logic and why, not focus on where the execution is. Loupe automatically records the class & method where the log message was, but it needs you to say what your code believes it should do next and why. For example: “Starting to process new batch file found in queue” is more useful than “In Batch Start”.
Use Severities. Reserve Error for things that should indicate either a coding, hosting, or data problem. Even if you can’t complete a task, it’s not an error if it’s the intended outcome (e.g. canceling by request). Use Informational for tracking big picture state - like starting and completing user requests - and Verbose/Debug for fine point details of execution. Filtering by severity is the simplest way to get a quick overview of an app’s behavior so set your self up for success!
Differentiate Caption/Description. Loupe treats the first line of a multi-line message as its caption and the remaining lines as a description. You can use this to your advantage. For example, if you have a variety of messages that share the same caption with differing details, the Loupe Session Viewer will let you group these messages together.
Use the same default logging in Debug and Release builds. If logging is used judiciously (following the guidelines above) there is no need to disable logging for release builds which reduces the risk of different behaviors in release builds. If some logging is selectively disabled, have it disabled by default in both Debug and Release builds.
Avoid side-effects. Be careful not to pass arguments to log statements whose evaluation will change object state.