8
votes

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.

6
The source code for NLogViewerTarget on Github shows that the Layout set {} is no-op so you cannot override the default which does not include exceptions.Shane Courtrille

6 Answers

4
votes

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>
2
votes

I had this problem, and just updated my NLog nuget package to 2.0.1.2

Now I have exceptions coming through to Log2Console just fine.

2
votes

A few years later and this is pretty trivial, try adding

includeSourceInfo="true"

to your target file, so it looks like;

 <target name="viewer"
            xsi:type="NLogViewer"
            includeSourceInfo="true"
            address="udp://127.0.0.1:9999" />

Gives you Source File, Line, Class and Method info.

1
votes

Have you tried the latest developer snapshot of Chainsaw? It will display stack traces and supports log4net/UDP appenders, and according to NLog you can use it as well: http://nlog-project.org/wiki/Chainsaw_target

Try the latest developer snapshot, has a ton of features: http://people.apache.org/~sdeboy

1
votes

Just download and build the latest (NLog-Build-2.0.0.2007-0-g72f6495) sources from GitHub: https://github.com/jkowalski/NLog/tree/ This issue is fixed there by NLog developer.

1
votes

In your NLog.config modify the target like the following.

<target name="file" xsi:type="File" fileName="log.txt" layout="${longdate}:${message} ${exception:format=message,stacktrace:separator=*}" /> 

The part that you are looking for is

${exception:format=message,stacktrace:separator=*}

For more information on this look here.