I have code that is logging Exception.Message. However, I read an article which states that it's better to use Exception.ToString(). With the latter, you retain more crucial information about the error.

Is this true, and is it safe to go ahead and replace all code logging Exception.Message?

I'm also using an XML based layout for log4net. Is it possible that Exception.ToString() may contain invalid XML characters, which may cause issues?

7 Answers
7

Exception.Message contains only the message (doh) associated with the exception. Example:

Object reference not set to an instance of an object

The Exception.ToString() method will give a much more verbose output, containing the exception type, the message (from before), a stack trace, and all of these things again for nested/inner exceptions. More precisely, the method returns the following:

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 a null reference (Nothing in Visual Basic), its value is not included in the returned string.

If there is no error message or if it is an empty string (""), then no error message is returned. The name of the inner exception and the stack trace are returned only if they are not a null reference (Nothing in Visual Basic).

+1 Its very painful to see ONLY that "Object reference not set to an instance of an object" in the logs. You feel really helpless. :-)
– Ashish GuptaJun 4 '11 at 11:51

1

For the last part, there are Exceptions that don't come with Exception.Message. In function of what you do in the error handling part, you can get to have problems because of the Exception.Message.
– Coral DoeAug 20 '12 at 8:48

37

It is very painful to see that I wrote code that essentially does the exact same thing that ToString() does.
– Preston McCormickApr 29 '14 at 20:31

1

@KunalGoel If the log comes from prod and you have no indication what the input was, then no, you can't just "debug through by turning on the CLR exception".
– jpmc26Apr 26 '17 at 21:32

1

Note, it is the "default implementation of ToString"...(emphasis on "default")..it does not mean that everyone has followed that practice with any custom exceptions. #learnedTheHardWay
– granadaCoderApr 24 at 15:12

In addition to what's already been said, don't use ToString() on the exception object for displaying to the user. Just the Message property should suffice, or a higher level custom message.

In terms of logging purposes, definitely use ToString() on the Exception, not just the Message property, as in most scenarios, you will be left scratching your head where specifically this exception occurred, and what the call stack was. The stacktrace would have told you all that.

As @JornSchouRode points out, doing a exception.ToString() gives you more information than just using the exception.Message property. However, even this still leaves out lots of information, including:

The Data collection property found on all exceptions.

Any other custom properties added to the exception.

There are times when you want to capture this extra information. The code below handles the above scenarios. It also writes out the properties of the exceptions in a nice order. It's using C# 6.0 but should be very easy for you to convert to older versions if necessary. See also this related answer.

Top Tip - Logging Exceptions

Most people will be using this code for logging. Consider using Serilog with my Serilog.Exceptions NuGet package which also logs all properties of an exception but does it faster and without reflection in the majority of cases. Serilog is a very advanced logging framework which is all the rage at the time of writing.

I'd say @Wim is right. You should use ToString() for logfiles - assuming a technical audience - and Message, if at all, to display to the user. One could argue that even that is not suitable for a user, for every exception type and occurance out there (think of ArgumentExceptions, etc.).

Also, in addition to the StackTrace, ToString() will include information you will not get otherwise. For example the output of fusion, if enabled to include log messages in exception "messages".

Some exception types even include additional information (for example from custom properties) in ToString(), but not in the Message.

@Matt: Constructing an instance of StringBuilder in this scenario may well be more expensive than two new string allocations, it's highly debatable it would be more efficient here. It's not like we're dealing with iterations. Horses for courses.
– Wim HollebrandseFeb 1 '10 at 13:28

5

Just use ex.ToString. It gets you all the details.
– John SaundersFeb 1 '10 at 15:13

3

@Christian: The compiler is sane with multiple +s. See for example "The + operator is easy to use and makes for intuitive code. Even if you use several + operators in one statement, the string content is copied only once." from msdn.microsoft.com/en-us/library/ms228504.aspx
– David EisonSep 25 '12 at 18:06

In terms of the XML format for log4net, you need not worry about ex.ToString() for the logs. Simply pass the exception object itself and log4net does the rest do give you all of the details in its pre-configured XML format. The only thing I run into on occasion is new line formatting, but that's when I'm reading the files raw. Otherwise parsing the XML works great.