27

What is the best practice for logging complete exception details including all possible inner exceptions?

Currently, I use the following code:

try
{
    //some code that throws an exception
}
catch(Exception ex)
{
    do
    {
        Console.WriteLine(ex.Message+ex.StackTrace);
        ex=ex.InnerException;
    }while(ex!=null)
}

Are there any scenarios where this code may fail?

Cœur
  • 37,241
  • 25
  • 195
  • 267
CodeWarrior
  • 1,239
  • 1
  • 14
  • 19
  • 3
    Yes, you might want to also handle [AggregateException](http://msdn.microsoft.com/en-us/library/system.aggregateexception.aspx) since they have an [InnerExceptions](http://msdn.microsoft.com/en-us/library/system.aggregateexception.innerexceptions.aspx) property which you will otherwise miss. – Matthew Watson Aug 28 '13 at 13:34
  • Your logger doesn't handle the entire exception or are you writing a logger? – Dustin Kingen Aug 28 '13 at 13:39
  • I'm assuming you actually use some utility (either third party logger, or your own class/implementation) so you aren't repeating the logging code itself wherever you need to try/catch/log? Also, I personally update it so it increases the initial tab indent (or you can use another mechanism) for each successive inner exception so when I read the logs I can distinguish the `InnerException` parent/child relationships rather than just getting a flat list of exceptions and trying to figure out where one stops and another starts. EDIT: _And_ I prefix it with "INNER-EXCEPTION: " – Chris Sinclair Aug 28 '13 at 13:40
  • @MatthewWatson I didn't know about AggregateException until now! Thanks – CodeWarrior Aug 28 '13 at 13:44
  • 4
    Using ex.ToString() would be the better practice. – Hans Passant Aug 28 '13 at 13:52
  • Maybe useful ***http://www.extensionmethod.net/csharp/exception*** – Kiquenet Dec 03 '15 at 14:26

2 Answers2

48

Have you tried just using ex.ToString()? It gives most (if not all) of the data you need to diagnose - including the message details, stack trace, and inner exceptions:

From MSDN:

ToString returns a representation of the current exception that is intended to be understood by humans. Where the exception contains culture-sensitive data, the string representation returned by ToString is required to take into account the current system culture. Although there are no exact requirements for the format of the returned string, it should attempt to reflect the value of the object as perceived by the user. The default implementation of ToString obtains the name of the class that threw the current exception, the message, the result of calling ToString on the inner exception, and the result of calling Environment.StackTrace. If any of these members is null, its value is not included in the returned string.

D Stanley
  • 149,601
  • 11
  • 178
  • 240
  • 1
    I'm logging `ReflectionTypeLoadException` using this method and it does not output the details from the nested `LoaderException` entries. I have to write a special case. – Gusdor Jul 05 '16 at 12:39
  • JetBrains complains .ToSring() is not required on ex. Not sure why – Sandeep Dec 07 '16 at 17:55
  • 1
    Some methods (like `Console.WriteLine()`) will implicitly call `ToString` when an object is passed in. There's no harm in removing it if it's not needed. – D Stanley Dec 07 '16 at 18:00
30

I have this extension method which suits my purposes just fine.

public static class ExceptionExtensions {
    public static string ToMessageAndCompleteStacktrace(this Exception exception) {
        Exception e = exception;
        StringBuilder s = new StringBuilder();
        while (e != null) {
            s.AppendLine("Exception type: " + e.GetType().FullName);
            s.AppendLine("Message       : " + e.Message);
            s.AppendLine("Stacktrace:");
            s.AppendLine(e.StackTrace);
            s.AppendLine();
            e = e.InnerException;
        }
        return s.ToString();
    }
}

And use it like this:

using SomeNameSpaceWhereYouStoreExtensionMethods;
try {
    // Some code that throws an exception
}
catch(Exception ex) {
    Console.WriteLine(ex.ToMessageAndCompleteStacktrace());
}

Update

Since I'm receiving upvotes for this answer I want to add that I stopped using this extension method, and now I'm just using exception.ToString(). It gives more information. So please, stop using this method, and just use .ToString(). See the answer above.

Maarten
  • 22,527
  • 3
  • 47
  • 68
  • 12
    Up-voted because of your update! – H.Wolper Oct 05 '16 at 08:02
  • 2
    I up-voted @H.Wolper because he up-voted (approved) the "Update" of old up-voted user. – Lost_In_Library Mar 27 '17 at 13:44
  • Exception.ToString is useless. I adapted the source code of AggregateException.Flatten to actually flatten all exceptions, not just AggregateExceptions, using the same basic non-recursive algorithm. This returns a flat list of Exceptions, which includes every exception, including AggrgateExceptions themselves and the individual exceptions therin, and their children, etc. This gives you the ability to filter out exceptions, by type, by message, etc. and finally construct a string with useful information. For example, you could filter out messages like "See the inner exception for details." – Triynko Oct 12 '18 at 22:52
  • @Maarten - Doesn't `ex.ToString()` *not* include any special attributes that the exception might have? Perhaps a `FooException` has an `int FooSize` and a `string FooCode`. These wouldn't be included in `ToString();` – Matthew Sep 27 '20 at 13:51
  • @Matthew You could be right. But the extension method in my answer *also* does not include that information either. – Maarten Sep 28 '20 at 06:00