How to generate error log from nested exceptions.

Working on error logging for my new application I’ve realized that I always use the same pattern when it comes to converting actual exceptions into a text form. And since I started posting rare code snippets that I write down all the time on Gist recently, there will be a number of ‘sharing code’ blog posts in the foreseeable future.

The code is rather simple, it traverses down the entire nested exception hierarchy and populates StringBuilder with the appropriate error information. There is a slightly different workflow for AggregateException – we want to flatten its InnerExceptions collection.

public string GetExceptionLog(Exception exception)
{
    return UnwrapExceptionTextLoop(new StringBuilder(), 0, exception);
}

private string UnwrapExceptionTextLoop(StringBuilder sb, int level, Exception e)
{
    if (e == null)
    {
        return sb.ToString();
    }

    for (int i = 0; i < level; i++)
    {
        sb.Append(">>");
    }

    var aggregate = e as AggregateException;

    sb.AppendFormat("{0} - {1} [{2}] {3}", e.GetType(), aggregate == null ? e.Message : String.Empty, e.StackTrace, Environment.NewLine);

    if (aggregate != null)
    {
        return String.Join(Environment.NewLine,
            aggregate.InnerExceptions.Select(inner => UnwrapExceptionTextLoop(sb, level + 1, inner)));
    }

    return UnwrapExceptionTextLoop(sb, level + 1, e.InnerException);
}

Let’s put on a simple method that throws several exceptions:

public void TestMethod()
{
    try
    {
        try
        {
            throw new Exception("Inner exception");
        }
        catch (Exception ex)
        {
            throw new Exception("Outer exception");
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(ErrorHelper.GetExceptionLog(ex));
    }
}

And here is the result (I’ve omitted the large stack trace information):

System.Exception - Outer exception [   at Client.App.TestMethod()..] 
>>System.Exception - Inner exception [   at Client.App.TestMethod()..]