Visual Studio 2015 IntelliTrace – We have all been there. You get given a legacy project that has an error and you need to find it and fix it. Perhaps it is an old project you worked on several months or years ago. If the project was written by someone else who has perhaps left the company, understanding the code in order to find the bug is a huge challenge. Learn how Historical Debugging can speed through common tedious debugging tasks to get to the root of the problem fast!
Visual Studio 2015 IntelliTrace Saves The Day
Before I go on, I have to mention that IntelliTrace is only offered in Visual Studio 2015 Enterprise. (Compare the Visual Studio 2015 editions). If you haven’t worked with IntelliTrace before, it’s worth mentioning that it isn’t a new feature. IntelliTrace has been part of the Visual Studio offering since 2010. While its main set of features have been growing over time, the main experience has remained unchanged. That is until Visual Studio 2015 came along and integrated IntelliTrace into the new Diagnostic Tools window. Let’s expand on the scenario above to illustrate the power of IntelliTrace and Historical Debugging.
A Point In Time
So a legacy application you have never laid eyes on (or even seen the code) is starting to throw exceptions and isn’t working properly. It isn’t logging some calculated results to a log table and nobody knows why. What would the first thought be for a developer? Find out what action more or less is causing the exceptions to be exhibited and then go into the source code, place a few breakpoints and start debugging. This method of finding bugs, especially in unknown code makes the learning curve so much steeper.
Visual Studio 2015 has enhanced the breakpoints now to include the settings and enable/disable options right there inline with the code. No more modal dialog.
So you could go and set a bunch of breakpoints and specify conditions or actions in all the places in code you think the problem could be in. This is however a very hit and miss way of debugging.
With IntelliTrace and Historical Debugging, you simply run your application in debug mode and without setting any breakpoints leave it to run. It is important to note that IntelliTrace is a recorder for your debugging session and is on by default. When you are ready to inspect the data collected, hit the Break All button. The button will become inactive and the Diagnostic Tools windows will be available with a rich set of information.
Right off the bat, I can see that there are two red diamond icons in my events timeline. The team that developed IntelliTrace decided to keep errors in your code execution flagged as red icons making them easier to pick out from the rest. You will see other diamond icons for events such as loading certain resources, clicking on buttons and so on. The tool tip on the errors already tell me what the problem is too.
Using your mouse, left click in the area just before the first error and drag to the right just after the second red icon. The area will highlight to white which you can now right-click and select ‘Zoom To Selection’ from the context menu. You can keep doing this until you zoom in to where you want to be. This is particularly helpful if you have a cluster of events you want to inspect because in this view, you are viewing your timeline from an eagle’s viewpoint.
When you have zoomed in closer, you can click on the events you want to inspect. I clicked on the first error icon and I immediately see that the error is expanded in the events grid below the diagnostic timeline. We have a classic divide by zero exception being thrown (sorry, I could not think of anything else). Below the expanded exception event you will notice a link ‘Activate Historical Debugging’.
If you click on this, you will be taken to the piece of code that threw that error at that point in time (you can return to live debugging by clicking the relevant link to the top of the code window). From this code view I can see that I have a value being divided by another value that is coming in to my method as a parameter. Unfortunately, this parameter was equal to zero. Immediately I can see where the problem lies and I can start to address this immediately. I can now set a regular break point to see why the calling method is passing a zero as a parameter. In my example it is hard coded in Method3(), but assume something funky happened and a zero was passed. Perhaps as a result from a database insert that had failed and din’t return a value, so the failed insert returned a zero instead.
So the above Historical Debugging window showed me why the error is happening and where to find it but it didn’t tell me why my log table is empty and no results are logged. Clicking on the second error icon paints a different picture all together. You can see that from Method4() the result is initialized to -1 and the call to Method5() is outside the try. This means that the result is passed to Method5() as -1 in the event of an error. Method5() now does a check to see if the result is not -1 and if not, writes the result to the log table. Otherwise it throws an exception.
While I am aware that the code above is rather silly and not very complex, it illustrates the functioning of IntelliTrace and Historical Debugging. Keep in mind that these errors were discovered without setting a single break point or stepping through hundreds or thousands of lines of code.
Being able to pinpoint issues in code as they happen is a very powerful feature. Why must developers be spending time trying to understand unfamiliar code and looking for bugs. I’d rather be writing new and exciting features. Visual Studio 2015 IntelliTrace is an absolute life saver!