Navigating in Exception Stack Traces in Visual C-Sharp

From eqqon

(Difference between revisions)
Jump to: navigation, search
m
m
 
(9 intermediate revisions not shown)
Line 1: Line 1:
[[Category:CSharp]]
[[Category:CSharp]]
-
Today I wrote a nice little debug helper function called '''PrintException''' in C#. It prints all available information about an exception in a very structured way to the output. The clue is, that it does this in a format that is understood by the error parser of Microsoft Visual Studio. So if one gets an exception one can easily navigate to the source locations by clicking on the lines in the printed stacktrace. It also prints inner exceptions recursively with increasing indent, which is extremely useful!
 
-
Here is a simple example of usage of '''Debug.PrintException''':
+
<div style="margin-left:100px; margin-right:200px;">
-
<pre>
+
= Navigating in Exception Stack Traces in Visual C# =
-
public static class PrintExceptionTest  
+
Today I wrote a nice little debug helper function called '''PrintException'''. It prints the relevant informations about an exception and its inner exceptions to the output recursively. The clue is, that it does this in a format that is understood by the '''error parser of Microsoft Visual Studio'''. So if you get an exception you can '''easily navigate''' to the source locations by clicking on the lines in the printed stacktrace. It also prints inner exceptions recursively with increasing indent for better readability.
-
{
+
 
-
static void test()  
+
Note: Error parser formatting works, of course, only when the exception is raised in an assembly that has been compiled in debug mode. Also the redirection of standard out to Visual Studio's output window is only activated by default for a Windows Forms application not for a Console application.
-
{
+
 
-
try { test1(); }
+
== A Simple Example of Usage ==
-
catch( Exception e) { throw new Exception("outer exception message", e); }
+
<br>
-
}
+
<span><span class="S5">public</span><span class="S0"> </span><span class="S5">static</span><span class="S0"> </span><span class="S5">class</span><span class="S0"> </span>PrintExceptionTest<br />
-
+
<span class="S10">{</span><br />
-
static void test1()
+
<span class="S0">&nbsp; &nbsp; </span><span class="S5">static</span><span class="S0"> </span><span class="S5">void</span><span class="S0"> </span>test<span class="S10">()</span><br />
-
{
+
<span class="S0">&nbsp; &nbsp; </span><span class="S10">{</span><br />
-
throw new InvalidOperationException("inner exception message");
+
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="S5">try</span><span class="S0"> </span><span class="S10">{</span><span class="S0"> </span>test1<span class="S10">();</span><span class="S0"> </span><span class="S10">}</span><br />
-
}
+
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="S5">catch</span><span class="S0"> </span><span class="S10">(</span>Exception<span class="S0"> </span>e<span class="S10">)</span><span class="S0"> </span><span class="S10">{</span><span class="S0"> </span><span class="S5">throw</span><span class="S0"> </span><span class="S5">new</span><span class="S0"> </span>Exception<span class="S10">(</span><span class="S6">"outer exception message"</span><span class="S10">,</span><span class="S0"> </span>e<span class="S10">);</span><span class="S0"> </span><span class="S10">}</span><br />
-
+
<span class="S0">&nbsp; &nbsp; </span><span class="S10">}</span><br />
-
public static void Main()  
+
<br />
-
{
+
<span class="S0">&nbsp; &nbsp; </span><span class="S5">static</span><span class="S0"> </span><span class="S5">void</span><span class="S0"> </span>test1<span class="S10">()</span><br />
-
try { test(); }
+
<span class="S0">&nbsp; &nbsp; </span><span class="S10">{</span><br />
-
catch(Exception e) { Debug.PrintException(e); }
+
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="S5">throw</span><span class="S0"> </span><span class="S5">new</span><span class="S0"> </span>InvalidOperationException<span class="S10">(</span><span class="S6">"inner exception message"</span><span class="S10">);</span><br />
-
}
+
<span class="S0">&nbsp; &nbsp; </span><span class="S10">}</span><br />
-
}
+
<br />
-
</pre>
+
<span class="S0">&nbsp; &nbsp; </span><span class="S5">public</span><span class="S0"> </span><span class="S5">static</span><span class="S0"> </span><span class="S5">void</span><span class="S0"> </span>Main<span class="S10">()</span><br />
-
Here is the output generated by the above exanple. Links to source files are recognized by Visual Studio's error parser. Works also in some other IDEs and editors like Scite:
+
<span class="S0">&nbsp; &nbsp; </span><span class="S10">{</span><br />
 +
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="S5">try</span><span class="S0"> </span><span class="S10">{</span><span class="S0"> </span>test<span class="S10">();</span><span class="S0"> </span><span class="S10">}</span><br />
 +
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="S5">catch</span><span class="S0"> </span><span class="S10">(</span>Exception<span class="S0"> </span>e<span class="S10">)</span><span class="S0"> </span><span class="S10">{</span><span class="S0"> </span>Debug<span class="S10">.</span>PrintException<span class="S10">(</span>e<span class="S10">);</span><span class="S0"> </span><span class="S10">}</span><br />
 +
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; </span>Console<span class="S10">.</span>ReadLine<span class="S10">();</span><br />
 +
<span class="S0">&nbsp; &nbsp; </span><span class="S10">}</span><br />
 +
<span class="S10">}</span></span>
 +
<br>
 +
 
 +
The output generated by the above example follows. Links to source files are recognized by Visual Studio's error parser. Works also in some other IDEs and editors like Scite:
 +
 
<pre>
<pre>
********************************************************************************
********************************************************************************
Line 41: Line 49:
</pre>
</pre>
-
And here is the class:
 
-
<pre>
 
-
public static class Debug
 
-
{
 
-
public static void PrintException(Exception exception)
 
-
{
 
-
PrintException(exception, "");
 
-
}
 
-
public static void PrintException(Exception exception, string indent)
+
== The Implementation of PrintException ==
-
{
+
<br>
-
string stars = new string('*', 80);
+
<span><span class="S0"></span><br />
-
Console.WriteLine(indent + stars);
+
<span class="S5">using</span><span class="S0"> </span>System<span class="S10">;</span><br />
-
Console.WriteLine(indent + "{0}: \"{1}\"", exception.GetType().Name, exception.Message);
+
<br />
-
Console.WriteLine(indent + new string('-', 80));
+
<span class="S5">public</span><span class="S0"> </span><span class="S5">static</span><span class="S0"> </span><span class="S5">class</span><span class="S0"> </span>Debug<br />
-
if (exception.InnerException != null)
+
<span class="S10">{</span><br />
-
{
+
<span class="S0">&nbsp; &nbsp; </span><span class="S5">public</span><span class="S0"> </span><span class="S5">static</span><span class="S0"> </span><span class="S5">void</span><span class="S0"> </span>PrintException<span class="S10">(</span>Exception<span class="S0"> </span>exception<span class="S10">)</span><br />
-
Console.WriteLine(indent + "InnerException:");
+
<span class="S0">&nbsp; &nbsp; </span><span class="S10">{</span><br />
-
PrintException(exception.InnerException, indent + "   ");
+
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; </span>PrintException<span class="S10">(</span>exception<span class="S10">,</span><span class="S0"> </span><span class="S6">""</span><span class="S10">);</span><br />
-
}
+
<span class="S0">&nbsp; &nbsp; </span><span class="S10">}</span><br />
-
foreach (string line in exception.StackTrace.Split(new string[] { " at " }, StringSplitOptions.RemoveEmptyEntries))
+
<br />
-
{
+
<span class="S0">&nbsp; &nbsp; </span><span class="S5">public</span><span class="S0"> </span><span class="S5">static</span><span class="S0"> </span><span class="S5">void</span><span class="S0"> </span>PrintException<span class="S10">(</span>Exception<span class="S0"> </span>exception<span class="S10">,</span><span class="S0"> </span><span class="S5">string</span><span class="S0"> </span>indent<span class="S10">)</span><br />
-
if (string.IsNullOrEmpty(line.Trim())) continue;
+
<span class="S0">&nbsp; &nbsp; </span><span class="S10">{</span><br />
-
string[] parts;
+
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="S5">string</span><span class="S0"> </span>stars<span class="S0"> </span><span class="S10">=</span><span class="S0"> </span><span class="S5">new</span><span class="S0"> </span><span class="S5">string</span><span class="S10">(</span><span class="S7">'*'</span><span class="S10">,</span><span class="S0"> </span><span class="S4">80</span><span class="S10">);</span><br />
-
parts = line.Trim().Split(new string[] { " in " }, StringSplitOptions.RemoveEmptyEntries);
+
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; </span>Console<span class="S10">.</span>WriteLine<span class="S10">(</span>indent<span class="S0"> </span><span class="S10">+</span><span class="S0"> </span>stars<span class="S10">);</span><br />
-
string class_info = parts[0];
+
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; </span>Console<span class="S10">.</span>WriteLine<span class="S10">(</span>indent<span class="S0"> </span><span class="S10">+</span><span class="S0"> </span><span class="S6">"{0}: \"{1}\""</span><span class="S10">,</span><span class="S0"> </span>exception<span class="S10">.</span>GetType<span class="S10">().</span>Name<span class="S10">,</span><span class="S0"> </span>exception<span class="S10">.</span>Message<span class="S10">);</span><br />
-
if (parts.Length == 2)
+
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; </span>Console<span class="S10">.</span>WriteLine<span class="S10">(</span>indent<span class="S0"> </span><span class="S10">+</span><span class="S0"> </span><span class="S5">new</span><span class="S0"> </span><span class="S5">string</span><span class="S10">(</span><span class="S7">'-'</span><span class="S10">,</span><span class="S0"> </span><span class="S4">80</span><span class="S10">));</span><br />
-
{
+
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="S5">if</span><span class="S0"> </span><span class="S10">(</span>exception<span class="S10">.</span>InnerException<span class="S0"> </span><span class="S10">!=</span><span class="S0"> </span><span class="S5">null</span><span class="S10">)</span><br />
-
parts = parts[1].Trim().Split(new string[] { "line" }, StringSplitOptions.RemoveEmptyEntries);
+
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="S10">{</span><br />
-
string src_file = parts[0];
+
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span>Console<span class="S10">.</span>WriteLine<span class="S10">(</span>indent<span class="S0"> </span><span class="S10">+</span><span class="S0"> </span><span class="S6">"InnerException:"</span><span class="S10">);</span><br />
-
int line_nr = int.Parse(parts[1]);
+
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span>PrintException<span class="S10">(</span>exception<span class="S10">.</span>InnerException<span class="S10">,</span><span class="S0"> </span>indent<span class="S0"> </span><span class="S10">+</span><span class="S0"> </span><span class="S6">" &nbsp;&nbsp;"</span><span class="S10">);</span><br />
-
Console.WriteLine(indent + " {0}({1},1):   {2}", src_file.TrimEnd(':'), line_nr, class_info);
+
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="S10">}</span><br />
-
}
+
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="S5">foreach</span><span class="S0"> </span><span class="S10">(</span><span class="S5">string</span><span class="S0"> </span>line<span class="S0"> </span><span class="S5">in</span><span class="S0"> </span>exception<span class="S10">.</span>StackTrace<span class="S10">.</span>Split<span class="S10">(</span><span class="S5">new</span><span class="S0"> </span><span class="S5">string</span><span class="S10">[]</span><span class="S0"> </span><span class="S10">{</span><span class="S0"> </span><span class="S6">" at "</span><span class="S0"> </span><span class="S10">},</span><span class="S0"> </span>StringSplitOptions<span class="S10">.</span>RemoveEmptyEntries<span class="S10">))</span><br />
-
else
+
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="S10">{</span><br />
-
Console.WriteLine(indent + " " + class_info);
+
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="S5">if</span><span class="S0"> </span><span class="S10">(</span><span class="S5">string</span><span class="S10">.</span>IsNullOrEmpty<span class="S10">(</span>line<span class="S10">.</span>Trim<span class="S10">()))</span><span class="S0"> </span><span class="S5">continue</span><span class="S10">;</span><br />
-
}
+
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="S5">string</span><span class="S10">[]</span><span class="S0"> </span>parts<span class="S10">;</span><br />
-
Console.WriteLine(indent + stars);
+
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span>parts<span class="S0"> </span><span class="S10">=</span><span class="S0"> </span>line<span class="S10">.</span>Trim<span class="S10">().</span>Split<span class="S10">(</span><span class="S5">new</span><span class="S0"> </span><span class="S5">string</span><span class="S10">[]</span><span class="S0"> </span><span class="S10">{</span><span class="S0"> </span><span class="S6">" in "</span><span class="S0"> </span><span class="S10">},</span><span class="S0"> </span>StringSplitOptions<span class="S10">.</span>RemoveEmptyEntries<span class="S10">);</span><br />
-
}
+
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="S5">string</span><span class="S0"> </span>class_info<span class="S0"> </span><span class="S10">=</span><span class="S0"> </span>parts<span class="S10">[</span><span class="S4">0</span><span class="S10">];</span><br />
-
}
+
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="S5">if</span><span class="S0"> </span><span class="S10">(</span>parts<span class="S10">.</span>Length<span class="S0"> </span><span class="S10">==</span><span class="S0"> </span><span class="S4">2</span><span class="S10">)</span><br />
-
</pre>
+
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="S10">{</span><br />
 +
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span>parts<span class="S0"> </span><span class="S10">=</span><span class="S0"> </span>parts<span class="S10">[</span><span class="S4">1</span><span class="S10">].</span>Trim<span class="S10">().</span>Split<span class="S10">(</span><span class="S5">new</span><span class="S0"> </span><span class="S5">string</span><span class="S10">[]</span><span class="S0"> </span><span class="S10">{</span><span class="S0"> </span><span class="S6">"line"</span><span class="S0"> </span><span class="S10">},</span><span class="S0"> </span>StringSplitOptions<span class="S10">.</span>RemoveEmptyEntries<span class="S10">);</span><br />
 +
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="S5">string</span><span class="S0"> </span>src_file<span class="S0"> </span><span class="S10">=</span><span class="S0"> </span>parts<span class="S10">[</span><span class="S4">0</span><span class="S10">];</span><br />
 +
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="S5">int</span><span class="S0"> </span>line_nr<span class="S0"> </span><span class="S10">=</span><span class="S0"> </span><span class="S5">int</span><span class="S10">.</span>Parse<span class="S10">(</span>parts<span class="S10">[</span><span class="S4">1</span><span class="S10">]);</span><br />
 +
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span>Console<span class="S10">.</span>WriteLine<span class="S10">(</span>indent<span class="S0"> </span><span class="S10">+</span><span class="S0"> </span><span class="S6">" &nbsp;{0}({1},1): &nbsp;&nbsp;{2}"</span><span class="S10">,</span><span class="S0"> </span>src_file<span class="S10">.</span>TrimEnd<span class="S10">(</span><span class="S7">':'</span><span class="S10">),</span><span class="S0"> </span>line_nr<span class="S10">,</span><span class="S0"> </span>class_info<span class="S10">);</span><br />
 +
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="S10">}</span><br />
 +
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="S5">else</span><br />
 +
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span>Console<span class="S10">.</span>WriteLine<span class="S10">(</span>indent<span class="S0"> </span><span class="S10">+</span><span class="S0"> </span><span class="S6">" &nbsp;"</span><span class="S0"> </span><span class="S10">+</span><span class="S0"> </span>class_info<span class="S10">);</span><br />
 +
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="S10">}</span><br />
 +
<span class="S0">&nbsp; &nbsp; &nbsp; &nbsp; </span>Console<span class="S10">.</span>WriteLine<span class="S10">(</span>indent<span class="S0"> </span><span class="S10">+</span><span class="S0"> </span>stars<span class="S10">);</span><br />
 +
<span class="S0">&nbsp; &nbsp; </span><span class="S10">}</span><br />
 +
<span class="S10">}</span><br />
 +
<span class="S0"></span></span>
 +
<br>
 +
 
 +
Blogged by --[[User:Henon|Henon]] 12:07, 9 November 2007 (CET)
 +
 
 +
 
 +
This article has also been posted on [http://www.codeproject.com/useritems/NavigatingExceptions.asp The Code Project]
 +
</div>

Latest revision as of 11:05, 22 November 2007


Navigating in Exception Stack Traces in Visual C#

Today I wrote a nice little debug helper function called PrintException. It prints the relevant informations about an exception and its inner exceptions to the output recursively. The clue is, that it does this in a format that is understood by the error parser of Microsoft Visual Studio. So if you get an exception you can easily navigate to the source locations by clicking on the lines in the printed stacktrace. It also prints inner exceptions recursively with increasing indent for better readability.

Note: Error parser formatting works, of course, only when the exception is raised in an assembly that has been compiled in debug mode. Also the redirection of standard out to Visual Studio's output window is only activated by default for a Windows Forms application not for a Console application.

A Simple Example of Usage


public static class PrintExceptionTest
{
    static void test()
    {
        try { test1(); }
        catch (Exception e) { throw new Exception("outer exception message", e); }
    }

    static void test1()
    {
        throw new InvalidOperationException("inner exception message");
    }

    public static void Main()
    {
        try { test(); }
        catch (Exception e) { Debug.PrintException(e); }
        Console.ReadLine();
    }
}

The output generated by the above example follows. Links to source files are recognized by Visual Studio's error parser. Works also in some other IDEs and editors like Scite:

********************************************************************************
Exception: "outer exception message"
--------------------------------------------------------------------------------
InnerException:
   ********************************************************************************
   InvalidOperationException: "inner exception message"
   --------------------------------------------------------------------------------
     c:\C#\snippets\print_exception.cs(58,1):   PrintExceptionTest.test1()
     c:\C#\snippets\print_exception.cs(48,1):   PrintExceptionTest.test()
   ********************************************************************************
  c:\C#\snippets\print_exception.cs(52,1):   PrintExceptionTest.test()
  c:\C#\snippets\print_exception.cs(65,1):   PrintExceptionTest.Main()
********************************************************************************


The Implementation of PrintException



using System;

public static class Debug
{
    public static void PrintException(Exception exception)
    {
        PrintException(exception, "");
    }

    public static void PrintException(Exception exception, string indent)
    {
        string stars = new string('*', 80);
        Console.WriteLine(indent + stars);
        Console.WriteLine(indent + "{0}: \"{1}\"", exception.GetType().Name, exception.Message);
        Console.WriteLine(indent + new string('-', 80));
        if (exception.InnerException != null)
        {
            Console.WriteLine(indent + "InnerException:");
            PrintException(exception.InnerException, indent + "   ");
        }
        foreach (string line in exception.StackTrace.Split(new string[] { " at " }, StringSplitOptions.RemoveEmptyEntries))
        {
            if (string.IsNullOrEmpty(line.Trim())) continue;
            string[] parts;
            parts = line.Trim().Split(new string[] { " in " }, StringSplitOptions.RemoveEmptyEntries);
            string class_info = parts[0];
            if (parts.Length == 2)
            {
                parts = parts[1].Trim().Split(new string[] { "line" }, StringSplitOptions.RemoveEmptyEntries);
                string src_file = parts[0];
                int line_nr = int.Parse(parts[1]);
                Console.WriteLine(indent + "  {0}({1},1):   {2}", src_file.TrimEnd(':'), line_nr, class_info);
            }
            else
                Console.WriteLine(indent + "  " + class_info);
        }
        Console.WriteLine(indent + stars);
    }
}

Blogged by --Henon 12:07, 9 November 2007 (CET)


This article has also been posted on The Code Project