Friday, October 27, 2006

Show source file and line number information in your Stack traces

A while ago I wrote a blog-post about not breaking the stack trace while throwing an exception up the call stack. Stack traces are the very first place you look when finding the cause of an unexpected exception. Today I was once again saved by a stack trace. A project I am currently working on is starting a pilot in Cairo next week and had some trouble with a NullRefrenceException that was blocking one of the main scenarios. The entire pilot should be called-off, if this didn't get fixed right away.
Luckily the application's crash screen did not only allow me to view the exceptions stack trace (which is pretty common), but we had also deployed the compilers .PDB files along with the application's assemblies. PDB files contain (among other things) information about which IL-instruction corresponds to which source file and line number. The Visual Studio debugger uses this to place the yellow arrow at the next line of code that will be executed. Because most people don't debug on their production environment why should you deploy these files? By default Visual Studio doesn't even generate them for a Release build.
Besides assisting the debugger, the information in the .PDB files are also used at runtime when you call the Exception.ToString() method. At each level in the stack trace after the name of the executing method, the source file and the line number of the executing statement are added, if a PDB file is present for the assempley containing the method. This looks something like this.
System.NullReferenceException: Object reference not set to an instance of an object.
   at Demo.Class1.Foo(Object parameter) in c:\projects\Demo\class1.cs:line 48 
   at Demo.Class1.Main(String[] args) in c:\projects\Demo\class1.cs:line 21


With this information I retrieved the correct version of the source file from source control (of course we label the sources with the build-number in our build cycle) and scrolled to the line number I had found in the stack trace. This showed me the exact statement that caused the NullReferenceException in less than five minutes, without having to reproduce the error in the development environment (which would have been quite tricky in this case). By only looking at the code I was able to see that someone had made a configuration error while installing the pilot environment. Correcting the configuration error fixed the problem and the pilot was ready to go. So unless you have good reasons to hide information about your source code from your end users, you should always set the compilers 'Generate Debugging Information' option to true for Release builds and keep the PDB files along side the assemblies wherever they go.