Logging exceptions with NLog

A feature of my nice WPF application is to log exceptions that bring it down when running standalone. Of course this never happens but still, if such an event occurs I want to understand the cause. Why exceptions in plural? Because an exception might have an InnerException and this InnerException might have another InnerException and so forth.

I use NLog as logging framework. Nice and slick. Here is my really simple configuration:

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target name="file" xsi:type="File" fileName="log.txt" layout="${longdate}:${message} ${exception:format=message,stacktrace:separator=*}" />
<target name="ds" xsi:type="Debugger"/>
</targets>
<rules>
<logger name="*" writeTo="file" minLevel="Warn"/>
<logger name="*" writeTo="ds" />
</rules>
</nlog>

Basically I log exceptions to log.txt file (as well as pretty much everything to debugger’s output). The layout to write the exception is this: layout="${longdate}:${message} ${exception:format=message,stacktrace:separator=*}". It is a pretty much standard NLog’s format for exceptions. However, the problem with it is that it won’t log InnerExceptions at all.

Hence I need to use the following code:

private bool showingFatal;
private void Application_DispatcherUnhandledException(object sender, 
    DispatcherUnhandledExceptionEventArgs e)
{
    if (showingFatal)
    {
        e.Handled = true;
        return;
    }
    showingFatal = true;
    logger.Error(LogCategory.Engine, "Fatal exception start ********************** ");
    try
    {
        int level = 0;
        Exception ex = e.Exception;
        while (ex != null)
        {
            logger.Error(LogCategory.Engine, 
                string.Format("Fatal exception level {0}: ", level++), ex);
            ex = ex.InnerException;
        }
    }
    finally
    {
        logger.Error(LogCategory.Engine, "Fatal exception end ********************** ");
    }
    Shutdown();
}

I use the flag showingFatal to prevent duplicate entry into the method (not sure why it happens but it happens) and a loop to log all, really all, exceptions and callstacks there are.

This way I have a good information about the exception that caused the crash. If it happens someday…