Logging Strategies

Maintaining logs during development can help you quickly analyze problems pre- and post-delivery.

Even the best-designed software doesn't always perform as well in the field as it may on your development machine. Collecting information is critical when the customer is having a problem. In this column, I'll look at some of the strategies for collecting and analyzing runtime information both before and after you deploy your applications.

Logging During Development
When you're developing software you have the comparative luxury of dropping into the debugger when something goes wrong. This means that you can usually analyze any crash based on the actual state of the application, rather than whatever history information you might have recorded. But there are still some circumstances where maintaining a log file during development can be very helpful:

  • If you have colleagues helping you to test the application, a log file can help you understand their actions when they do manage to provoke a crash.
  • If the application depends on asynchronous input (such as financial data from an external Web service, or events from an analog-to-digital converter), a log can help clarify the order of events.
  • If a bug is extremely rare, happening only after hundreds or thousands of calls to a particular function, a log can let you search for patterns after automated testing.
  • Some bugs can't be tracked in the debugger because the very act of going into debug mode changes the state of the application. Bugs involving the focus of controls on the screen often fall into this category.

The main goal of logging during development is to collect information that you can't get by running the code in the debugger. If you're logging during development, you usually want the logging to be turned on full-time, because you won't generally be concerned about too many log files cluttering up your hard drive or a minor loss of performance. It's far better to collect too much information than too little when you're hunting bugs.

Logging After Development
Logging grows in importance after you've shipped your application. That's because the chance of getting back a good bug report goes way down after the code leaves the hands of the customers and lands on those of end users, who may have never had to write a bug report in their life. After a few rounds of "it just crashed" and "I didn't do anything special" you'll learn how useful a log file can be. Giving users the ability to send you a log file lets them give you more information with less effort—a definite win for both of you.

On the other hand, end users do care about performance, even if you don't. If you collect a lot of information in a log file, you can add substantial overhead to your application, as well as a substantial load to the user's hard drive. This leads to a simple rule: In a shipping application, it should be easy for the end user to turn logging on or off.

There are many ways to implement this switch for end users, including:

  • Use a menu item or button in an out-of-the-way spot, such as the About box.
  • Save a flag in a registry key. The easiest way to do this for end users is to give them reg files to turn the flag on and off.
  • Use an XML file that can be edited to turn logging on an off. In this case, you'll want to include instructional comments in the file.

The point of any of these schemes is to let the logging code remain hidden in your application in a dormant state until it's needed. That way, it doesn't affect the performance of the rest of your code. If a problem turns up, you (or if you're lucky, your support staff) can walk the end user through the steps needed turn on logging. They can then recreate the problem, send you the log file and turn logging back off.

What Should You Log?
The next question is what you should put in the log file. Remember, the log file is supposed to be a diagnostic tool. You should save enough information to let you tell what went wrong. A few things that might make sense to save, depending on your application, include:

  • Error messages and information, including a stack trace of the error.
  • The state of internal data structures at key points in the application.
  • User actions, such as button clicks and menu item selections.
  • The time that significant actions were performed.
  • Important information about the environment, such as variable settings and available memory.

If you think about how you debug your application when it's running on your computer, you should be able to come up with a good list of important information to log. The simplest rule of thumb is to log the information that you use when debugging interactively.

Logging for .NET
If you've been reading my column for any length of time, you know I'm spending most of my coding day in the .NET universe now. So I'm going to round out this column by listing some of the alternatives you can use for logging in .NET. This isn't an exhaustive list; there are undoubtedly .NET products that I'm unaware of, and there are many, many products for other environments. But it will, I hope, serve to give you some ideas of how you can implement logging.

For starters, you can simply use the System.Diagnostics.Trace and System.Diagnostics.Debug classes from the .NET Framework. These classes let you send string output to an array of TraceListeners, which can include disk files. There's built-in support for configuring the tracing level via switches in an XML configuration file, which can be handy.

There's another logging option in the System.Diagnostics namespace: You can use the EventLog class to write directly to the Windows event logs. This has the advantage that most users already know how to use the Event Log Viewer to look at event log entries. It also puts your logging messages into a repository that's not likely to be accidentally damaged or deleted accidentally. Keep in mind, though, that there is no event log on Windows 95 or Windows 98, so you'll need to find a different solution if your target market includes those operating systems.

If the basic facilities provided in the System.Diagnostics namespace aren't sufficient, you can turn to some more comprehensive tracing software from Microsoft. Start with the Enterprise Information Framework (EIF), which you can download from www.microsoft.com/downloads/details.aspx?
FamilyId=80DF04BC-267D-4919-8BB4-1F84B7EB1368&displaylang=en
. EIF is designed to manage tracing for applications that include more than one component. Its features include:

  • A single model for raising and recording tracing and diagnostic events across all parts of a distributed application
  • Windows Management Instrumentation (WMI) compatibility for integration with existing enterprise monitoring tools
  • A flexible runtime configuration layer that's that's designed to be modified by simple scripting code for "on the fly" changes to your monitoring configuration
  • Windows Event Tracing, a new service for high-speed, kernel-mode tracing that's capable of recording hundreds or thousands of events in rapid succession
  • Event correlation across distributed applications

EIF is good for distributed tracing, but it still lacks some features such as levels of tracing. You can go that next step by downloading the Logging Application Block from www.microsoft.com/downloads/details.aspx?
FamilyId=24F61845-E56C-42D6-BBD5-29F0D5CD7F65&displaylang=en
. The Logging Application Block adds a bunch of features to EIF, including:

  • Support for a set of logging levels similar to those that the Trace class defines.
  • Asynchronous logging via MSMQ
  • Logging to a SQL Server database.
  • An event transformation engine that can add information to events (for instance, common settings that apply to all events in a class), delete unwanted information, and flexibly format the results using Extensible Stylesheet Language Transformations (XSLT). There's also an interface to that allows you to write your own formatting classes.

Of course, you're not limited to Microsoft when searching for logging software. The best alternative I know of is log4net, an open-source project available from http://logging.apache.org/log4net (and based on a popular Java logging package). It has a ton of features, including:

  • Support for the Microsoft .NET Framework 1.0 and 1.1, as well as the .NET Compact Framework, Microsoft's shared-source implementation ("Rotor"), and the open-source Mono implementation.
  • Output to an extremely wide variety of targets, including databases, the ASP.NET trace context, console windows, event logs, disk files, the debugger, a remoting sink, e-mail, UDP datagrams, and more.
  • Multiple targets for a single log entry.
  • Level-based logging to pare events down.
  • As many different loggers as you like, arranged in a hierarchy for configuration purposes.
  • Dynamic runtime configuration via XML files.
  • Static configuration via assembly attributes.
  • Filtering on a per-target basis, so a target can decide which events it wants to log.
  • Flexible layout and rendering classes.
  • A plug-in architecture for easy extension.

If log4net won't do the logging job for you, you're in trouble.

A Final Cautionary Note
So, a bug rears its ugly head in the field, and the customer sends back a log file. Before you do anything else, take a mental step backwards and just think for a minute. Don't start with the details of log files and diagnostic information. Instead, take at least a few minutes to think about what happened (or what might have happened) before opening the logs.

Can you deduce the cause of the error simply by realizing what you've done wrong, or at least narrow down the portion of the code where it's likely to be? Does the error message tell you exactly what happened? Did the user try something that you never considered during testing? It's good to have logging available as a way to collect information when a truly mysterious bug occurs. But don't forget to look at the forest before you focus in on the individual trees.

Are you using logging innovatively in your applications? Or is your code so great that logging is a waste of time? You can get hold of me at MikeG1@larkfarm.com. I'll use the most interesting comments in a future issue of Developer Central.