fficient software debugging is definitely an acquired talent. Most programmers have some ideas on how to do it when they first get started but typically can’t handle a large complex program that doesn’t work. Add multithreading to a complex program and you’re sure to lose most junior software developers.
In the “old days” the only way to debug a program was to put in a bunch of print statements, or the language appropriate equivalent, interspersed with the rest of the code to dump out variables and let you know where the program got to before it crashed. This method still works well for any language without a suitable debugger.
SmartInspect from Gurock Software uses a mixture of old-fashioned techniques with tight Visual Studio integration to help ease the pain of debugging multithreaded applications. Today’s version of the old print statements writes messages into a log file. The advantage of a log file is that you can typically put enough information there to help you find out what’s going on?and you can make logging a feature that can be turned on or off via configuration in a production deployment of your application.
Installation and Setup
Installing SmartInspect takes only a few minutes and adds a single icon to your desktop to access the console program. To use the product with your projects, you’ll need to perform this three-step process.
|Figure 1. The Project Property Pages: This is where you add the Gurock.SmartInspect namespace as an import for your project.|
- You must add a reference to the SmartInspect.dll. To do that, right click the References item in the Solution Explorer, browse to the folder where you installed the program, and select the SmartInspect.dll file.
- Add SmartInspect to the import list by right-clicking on your root project item in Solution Explorer and selecting Properties. From the Properties page, select “Imports,” and then enter “Gurock.SmartInspect” in the namespace edit box (see Figure 1).
- Enabling SmartInspect in your project requires a single line of code in the form load method. In VB.NET, this line should look like:
SiAuto.Si.Enabled = True
After enabling SmartInspect, you have two choices for debugging code?you can debug through the SmartInspect console or exclusively through log files. The console is great for initial development and testing but it isn’t something you’d want to leave in a production program. During development however, using the console for debugging sessions is much easier than wading through log files.
You can use either the TCP/IP protocol for real-time logging (the default) or specify a log file, for example:
SiAuto.Si.Connections = @"file(filename=c:log.sil)";
The console can load a specified log file or receive the logging information via TCP/IP. For production use it’s better to use log files, especially for a commercial app where support is likely to be offsite.
The best way to enable debugging for a production application is to use the LoadConnections method of the SmartInspect class. With this method, support staff can send a preconfigured connections file to the customer to enable logging. Here’s an example of using the LoadConnections method:
In the example above, if you had deployed an application with a customer that was having problems, you could have the customer place a preconfigured connections file called connections.sic in the c: folder, thus enabling logging and directing the log output to a destination specified in the connections file. You can then use the log contents to debug the deployed application. Logging will remain disabled if SmartInspect can’t find the specified connections file, or if the file doesn’t contain a valid connection string.
The code that logs a message works with both the console and log file output. SmartInspect provides two additional methods, EnterMethod and LeaveMethod, that let you know when a program enters or leaves a method. The console also provides a button so you can display the call stack to trace program execution paths easily. Here’s a code snippet from the downloadable TimeServer sample program showing several different log methods:
SiAuto.Main.LogMessage("Calculating minutes/seconds"); int minutes = DateTime.Now.Minute; int seconds = DateTime.Now.Second; SiAuto.Main.LogValue("seconds", seconds); SiAuto.Main.LogDateTime("System Time", System.DateTime.Now); int index = minutes / seconds; SiAuto.Main.LogMessage("Sending date to client."); w.WriteLine(DateTime.Now.ToString()); for( int j = 0; j<1024; j++) buffer[j] = (byte) (j * 431); SiAuto.Main.LogBinary("Byte Array",buffer,0,1024);
Debugging with SmartInspect
Finding a bug frequently resembles the "needle in a haystack" drill. Multithreaded programs simply add more haystacks that you have to look in. The SmartInspect product provides several tools that let you quickly find where programs are having trouble.
|Figure 2. The Navigate Menu: The Navigate menu lets you jump right to an item of interest such as an error.|
Using the SmartInspect console is similar to the Visual Studio debugger but with some added features to help with tracking things down in multiple threads. Creating different views with filters makes it possible to examine just the information you need to see. A Navigate menu item lets you select from a list of possible log items to search for, as shown in Figure 2. Stepping through these items happens by either clicking on a small icon that resembles a play button or by pressing the Ctrl and Right arrow buttons at the same time.
It can be useful to examine some piece of data as it passes through your program, depending on the nature of the bug you're trying to track down. You can log values at any point by sending a packet of information to either a log file or to the SmartInspect console for viewing.
SmartInspect divides program information into categories represented by classes. For example, the Session class contains a number of different methods including the generic Session.LogMessage, Session.LogObject and Session.LogSQL for logging generic information. Session is fully thread safe and returns data only when there is an active session.
|Figure 3. Data Viewer: The Data Viewer displays almost any type of logged information.|
The product also includes a host of more specific methods such as LogDecimal, LogHtml, LogDataTable and others for logging specific types of data. One thing that's a little lacking from a documentation perspective at this point is a good set of examples showing how each of the different methods could be used. There are some examples but just not enough.
After logging some data, you use the Data Viewer (see Figure 3) from the console application to view it. The Data Viewer tool lets you examine any type of data your program has sent to the logger. There's also a floppy disk icon in the viewer that lets you save a copy of the data to disk should you need to.
When you try to evaluate whether a product is worth the cost, it's important to consider not just the price tag but how much your time is worth. A single-user license copy of SmartInspect will set you back $229. If you are writing software with multithreading, you will no doubt have to debug it at some point. Saving a few hours over the course of a week with this product will justify the cost in a short period of time. An added benefit to this product is the ability to embed logging capabilities that can be enabled with a configuration change or by setting an option on a menu. Very few complex programs are 100% error free. Having the ability to turn on a logging feature with deployed software will make tracking those bugs you didn't catch during development and testing a whole lot easier.
SmartInspect isn't limited to .NET debugging; it also ships with libraries that work with Java or Delphi. You can try a fully-functional time-limited (45 days) trial version of SmartInspectto help you decide whether to buy.