How to log exceptions with network targets in NLog

angularsen picture angularsen · Apr 3, 2012 · Viewed 8.6k times · Source

I am using the NLog logging framework and am trying to get exception and stacktrace information showing up in any UDP logger appliaction, such as Sentinel and Log2Console, but can only get the log message part displayed. Outputting to a file works well as most examples do just that, so the problem revolves around using network targets with NLog.

Bonus if a custom format can be applied on inner exceptions and stacktrace, but this is not required. Exception.ToString() would go a long way.

Note on the example code: With Log2Console I found an article on how to send exception as a separate log entry. Although this worked, I was not happy with the solution.

Example exception logging code:

Logger Log = LogManager.GetCurrentClassLogger();

try
{
    throw new InvalidOperationException("My ex", new FileNotFoundException("My inner ex1", new AccessViolationException("Innermost ex")));
}
catch (Exception e)
{
    Log.ErrorException("TEST", e);
}

Example NLog.config:

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<targets async="true">

    <!-- Send by UDP to Sentinel with NLogViewer protocol -->
    <target name="network" xsi:type="NLogViewer" address="udp://192.168.1.3:9999" layout="${message}${onexception:inner=${newline}${exception:format=tostring}}" />

    <!-- Send message by UDP to Log2Console with Chainsaw protocol -->
    <target name="network2" xsi:type="Chainsaw" address="udp://192.168.1.3:9998" appinfo="Grocelist"/>

    <!-- Send exception/stacktrace by UDP to Log2Console with generic network protocol -->
    <target name="network2ex" xsi:type="Network" address="udp4://192.168.1.3:9998" layout="${exception:format=ToString}" />

    <target name="logfile" xsi:type="File" layout="${longdate}|${level:uppercase=true}|${logger}|${message}|${exception:format=tostring}"
                createDirs="true"
                fileName="${basedir}/logs/${shortdate}.log"
                />
</targets>

  <rules>
    <logger name="*" minlevel="Debug" writeTo="logfile" />
    <logger name="*" minlevel="Debug" writeTo="network" />
    <logger name="*" minlevel="Debug" writeTo="network2" />
    <logger name="*" minlevel="Warn" writeTo="network2ex" />
  </rules>
</nlog>

Some links:

Edit: After searching some more this seems to be a limitation on NLog's end. A recent patch is apparently out there: log4jxmlevent does not render Exception

Edit2: I rebuilt NLog with patch, but it did not seem to help in Sentinel or Log2Console apps. I might have to try log4net to make sure those apps really do support what I am trying to achieve.

Edit3: I currently use string.Format() to join and format message and exception text myself. This works well, but is not what I'm looking for here.

Answer

alex picture alex · Mar 20, 2013

You can also extend NLog to include exceptions for network logging.

Create an extended layout:

[Layout("Log4JXmlEventLayoutEx")]    
public class Log4JXmlEventLayoutEx : Log4JXmlEventLayout
{
    protected override string GetFormattedMessage(LogEventInfo logEvent)
    {
        string msg = logEvent.Message + " ${exception:format=Message,Type,ToString,StackTrace}";
        msg = SimpleLayout.Evaluate(msg, logEvent);    
        LogEventInfo updatedInfo;
        if (msg == logEvent.Message) { 
            updatedInfo = logEvent;
        } else {
            updatedInfo = new LogEventInfo(
                logEvent.Level, logEvent.LoggerName, 
                logEvent.FormatProvider, msg, 
                logEvent.Parameters, logEvent.Exception);
        }    
        return base.GetFormattedMessage(updatedInfo);
    }
}

Create a target that uses that layout

[Target("NLogViewerEx")]
public class NLogViewerTargetEx : NLogViewerTarget
{
    private readonly Log4JXmlEventLayoutEx layout = new Log4JXmlEventLayoutEx();    
    public override Layout Layout { get { return layout; } set {} }
}

Update NLog.config:

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <extensions>
    <add assembly="Assembly.Name.That.Contains.Extended.Target"/>
  </extensions>
  <targets>
    <target name="logViewer" 
            xsi:type="NLogViewerEx" 
            address="udp://localhost:7071">
  </targets>
 ...
</nlog>