For developers, one of the most onerous jobs can be tracking down errors that are reported by the users of a live application. This is especially true if the error is difficult to re-create or the user can’t remember the steps he or she took to originally cause it. Stop me if you’ve had a conversation like this before:
User: It just blew up again.
Developer: Okay, what was the error message?
User: It said something about… a special aerial foundry?
Developer: Can you read me the full error message?
User: Oh, well we got a bunch more after that one.
Developer: [sigh] Okay… what were you doing when it crashed?
User: I was on the customer info screen and I clicked the Save button.
Developer: Was this a new customer or did you search for an existing one?
User: I searched… but then I cancelled it.
Well, you get the point. This is exactly the sort of situation where a product by the name of TraceBack, from InCert Software, can come in very handy. InCert made a name for itself with its TraceBack tool for OS/390, and it has recently begun porting it to other platforms, including Windows and Solaris. Table A summarizes the TraceBack product information.
When I first heard about TraceBack, I thought that the product would turn out to be simply a code library for generating error logs. In reality, however, TraceBack is much more sophisticated than that, and using it in an application requires no additional code. The product attaches itself to compiled application files through a process called “instrumentation,” records some debugging information about the files, and then inserts some code that monitors them for a variety of faults, including exceptions and errors. InCert has gone to great lengths to make the code inserted by TraceBack as unobtrusive as possible so that it doesn’t prevent the function of debuggers on instrumented code. If an error occurs in an instrumented application, TraceBack generates a “trace” that includes information about the state of the application immediately before the error occurred.
You can use TraceBack throughout all phases of an application’s life, from initial testing through release and into maintenance. In fact, it would appear that maintenance-mode applications would derive the most benefit from TraceBack’s instrumentation. As applications mature and evolve, they usually become more and more complex, until even a simple error can take some time to isolate. A developer who has access to TraceBack trace information will have a much easier time tracking down the error.
How does it work?
I took a look at a prerelease copy of the C/C++ and Visual Basic version of TraceBack for Windows. Using the product is straightforward; it’s usable as a command-line program, an IDE add-in for Visual Basic, or a custom build rule or NMAKE file for Visual C++. The included documentation does a very good job of walking you through the task of instrumenting your code. The whole process takes just a few minutes.
Once instrumented, if an application fails due to an unhandled exception or error, a trace is generated that lists all events that occurred in the code leading up to the crash. It’s also possible to take “snap” traces of your application programmatically by using TraceBack’s runtime library. Once you have a set of trace files, you can actually step through the application’s source code line-by-line, checking out variable contents and stack information as they existed just before the error. Here is TraceBack’s trace viewer, shown debugging a division by zero error in Figure A.
|Okay, so that’s a rather obvious problem.|
The viewer can also provide information about the state of the system on which an instrumented application was running at the time of a crash, including:
- The user and machine name.
- The command line used to launch the app.
- The operating system version.
- Hardware information such as the type and number of processors.
TraceBack is very configurable through its Runtime Options Editor. Developers can configure its behavior on an exception-by-exception basis (for C/C++) or an error-code-by-error-code basis (for Visual Basic) and add user-defined error codes and exceptions to its library. TraceBack can also be made to automatically e-mail or FTP trace files to a developer when errors occur.
No, I mean how well does it work?
I built and instrumented a few simple (and deliberately buggy) VB and C++ programs while testing TraceBack for this review. After some initial confusion on my part over where trace files are saved, everything went smoothly. My programs crashed as expected, and by viewing the trace files, I could watch things unfold and determine exactly where the error occurred and what led up to it.
Some other things I noticed:
- Instrumented executables are somewhat larger than their uninstrumented equivalents. My unscientific results showed a size increase of around 25 percent for Visual Basic and 50 percent for C/C++. I should stress that these may not be accurate numbers, since I’m sure there is a minimum footprint size for the instrumentation code, and my test files were all relatively small (19–204kb).
- There is a performance hit associated with instrumentation as well. My once again not-entirely-scientific numbers showed about a 4 percent performance hit, which is not far off from information provided by InCert showing a performance impact ranging from 5–15 percent, depending on the runtime options selected.
- Some runtime options carry a bigger performance hit than others. The option to capture module and thread data, for example, seems to extract a big price.
- In order to get the most from viewing the trace files, it’s important to have debug symbol files for the appropriate runtime environment installed on the viewing machine. Otherwise, memory contents and stack traces may not be viewable. This is especially true for Visual Basic.
- The default configuration generates memory dumps for only a handful of C/C++ exception types and for none of the VB error codes. This may or may not be what you want, so be sure to check the configuration.
All in all, I’d have to say that TraceBack is definitely worth a look if you find yourself having trouble tracking down errors in your applications. It becomes especially attractive for those applications that lack any error-reporting functionality, where instrumentation becomes ridiculously trivial compared with the time and cost of retrofitting such a system into an existing app.
With TraceBack, that conversation at the top of this article could be reduced to:
User: It just blew up again.
Developer: I know; I’m already looking into it.
What debugging tips do you have?
What debugging tools do you use? Are there any debugging tips you think other developers should know about? Send us an e-mail with your comments and experiences or post a comment below.