Skip to content

Instantly share code, notes, and snippets.

@oleksabor
Last active October 5, 2017 08:30
Show Gist options
  • Save oleksabor/aa0fc3b20f7a5e5641ab94c1376f34de to your computer and use it in GitHub Desktop.
Save oleksabor/aa0fc3b20f7a5e5641ab94c1376f34de to your computer and use it in GitHub Desktop.
sample exception generator to test NLog exception logging
using NLog;
using NLog.LayoutRenderers;
using System;
using System.Linq;
using System.Text;
using System.Collections.Concurrent;
namespace NLogTest
{
/// <summary>
/// renders exception starting from new line
/// with short type exception name followed by message
/// and stacktrace (optionally)
/// if exception is logged more than once (catched, logged and re-thrown as inner), stack trace is not written
/// </summary>
[LayoutRenderer("IndentException")]
public class IndentExceptionLayoutRenderer : LayoutRenderer
{
/// <summary>
/// indent before exception type (default is tab)
/// </summary>
public string Indent { get; set; }
/// <summary>
/// indent between each stack trace line (default is two tab characters)
/// </summary>
public string StackTraceIndent { get; set; }
/// <summary>
/// is written before exception type name (default [)
/// </summary>
public string BeforeType { get; set; }
/// <summary>
/// is written after exception type name (default ])
/// </summary>
public string AfterType { get; set; }
/// <summary>
/// separator between exception type and message
/// </summary>
public string Separator { get; set; }
/// <summary>
/// log stack trace or not (for console logger e.g.)
/// </summary>
public bool LogStack { get; set; }
/// <summary>
/// holds logged already exceptions just to skip surplus stack logging
/// </summary>
static ConcurrentQueue<Exception> _loggedErrors = new ConcurrentQueue<Exception>();
public IndentExceptionLayoutRenderer()
{
Indent = "\t";
StackTraceIndent = "\t\t";
BeforeType = "[";
AfterType = "]";
LogStack = true;
Separator = " ";
}
protected override void Append(StringBuilder builder, LogEventInfo logEvent)
{
var e = logEvent.Exception;
while (e != null)
{
builder.AppendFormat("{1}{2}{0}{3}{4}", e.GetType().Name, Indent, BeforeType, AfterType, Separator);
builder.Append(e.Message);
if (LogStack)
{
var stackTraceWasLogged = _loggedErrors.Contains(e);
if (!stackTraceWasLogged)
{
builder.AppendLine();
_loggedErrors.Enqueue(e);
builder.AppendFormat("{0}", e.StackTrace.Replace(" ", StackTraceIndent));
}
if (_loggedErrors.Count > 50)
{
_loggedErrors.TryDequeue(out Exception ex1);
_loggedErrors.TryDequeue(out Exception ex2);
}
}
e = e.InnerException;
if (e != null)
builder.AppendLine();
}
}
}
}
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"
autoReload="true"
throwExceptions="false"
internalLogLevel="Off" internalLogFile="%temp%\nlog-internal.log">
<!-- optional, add some variables
https://github.com/nlog/NLog/wiki/Configuration-file#variables
-->
<variable name="logfilename" value="NLogTest"/>
<targets>
<target xsi:type="ColoredConsole"
name="console"
useDefaultRowHighlightingRules="true"
detectConsoleAvailable="true"
layout="${message}${onexception:${newline}${exception:maxInnerExceptionLevel=10:format=shortType,message}}" />
<target name="file" xsi:type="File"
fileName="${basedir}/${logfilename}.log"
keepFileOpen="false"
layout="${longdate} ${logger} ${message}${onexception:${newline}${exception:maxInnerExceptionLevel=10:format=shortType,message,stacktrace:separator=*:innerExceptionSeparator=&#xD;&#xA;&#x9;}}" />
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="file" />
<logger name="*" minlevel="Trace" writeTo="Console" />
</rules>
</nlog>
<target xsi:type="ColoredConsole"
name="console"
useDefaultRowHighlightingRules="true"
detectConsoleAvailable="true"
layout="${level} ${message}${onexception:${newline}${IndentException:LogStack=false:separator=&#x9;:beforeType=:aftertype=}}" />
<target name="file" xsi:type="File"
fileName="${basedir}/${logfilename}.log"
keepFileOpen="false"
layout="[${threadid}] ${longdate} ${level} ${logger} ${message}${onexception:${newline}${IndentException}}" />
using NLog;
using NLogTest.Classes;
using System;
using System.Collections.Generic;
namespace NLogTest
{
class Program
{
static ILogger Log = LogManager.GetCurrentClassLogger();
static void Main(string[] args)
{
Log.Debug("starting");
try
{
new UnitOfWork().tryException();
}
catch (Exception e)
{
Log.Error(e, "failed to start NLogTest");
Console.ReadKey();
}
Log.Debug("the end");
}
}
}
namespace NLogTest.Classes
{
class UnitOfWork
{
static ILogger Log = LogManager.GetCurrentClassLogger();
public void innerException()
{
throw new KeyNotFoundException("innerException");
}
public void outerException()
{
try
{
innerException();
}
catch (Exception e)
{
throw new ArgumentException("outer exception", e);
}
}
public void tryException()
{
try
{
outerException();
}
catch (Exception e)
{
Log.Error(e, "tryException failure");
throw new ArgumentException("bad try", e);
}
}
}
}
@oleksabor
Copy link
Author

I've asked a question about exception layout renderer at SO
However seems that writing custom layout renderer is not so complex
So here i will keep IndentExceptionLayoutRenderer.cs source code
This renderer allows to show exception using readable format (from my point of view) in the log (file or console)
NLog.exceptionIndent.config is a sample configuration that shows how layout can be parameterized for console and file logging

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment