I needed an extension to NLog to buffer log output for a
MailTarget
and only send it when an event with
Fatal
level arrives. In other words, it will email me the whole buffer when the program crashes so that I get some context with the crash event.
I wrote a
LevelTriggeredBufferingWrapper
to achieve that. Here's the significant bit:
using System.ComponentModel;
using NLog;
using NLog.Common;
using NLog.Targets;
using NLog.Targets.Wrappers;
namespace LevelTriggeredBufferingWrapper
{
[Target("LevelTriggeredBufferingWrapper", IsWrapper = true)]
public class LevelTriggeredBufferingWrapper : WrapperTargetBase
{
LogLevel triggerLevel = LogLevel.Fatal;
LogEventInfoBuffer buffer;
public LevelTriggeredBufferingWrapper()
: this(null)
{
}
public LevelTriggeredBufferingWrapper(Target wrappedTarget)
: this(wrappedTarget, 100)
{
}
public LevelTriggeredBufferingWrapper(Target wrappedTarget,
int bufferSize,
string triggerLevel = "Fatal")
{
try
{
this.triggerLevel = LogLevel.FromString(triggerLevel);
}
catch { }
WrappedTarget = wrappedTarget;
BufferSize = bufferSize;
}
[DefaultValue(100)]
public int BufferSize { get; set; }
[DefaultValue("Fatal")]
public string TriggerLevel
{
get { return triggerLevel.ToString(); }
set { triggerLevel = LogLevel.FromString(value); }
}
protected override void FlushAsync(NLog.Common.AsyncContinuation asyncContinuation)
{
}
protected override void InitializeTarget()
{
base.InitializeTarget();
this.buffer = new LogEventInfoBuffer(this.BufferSize, false, 0);
}
protected override void Write(NLog.Common.AsyncLogEventInfo logEvent)
{
WrappedTarget.PrecalculateVolatileLayouts(logEvent.LogEvent);
buffer.Append(logEvent);
if (logEvent.LogEvent.Level >= triggerLevel)
{
AsyncLogEventInfo[] events = buffer.GetEventsAndClear();
WrappedTarget.WriteAsyncLogEvents(events);
}
}
}
}
You can use it to wrap any target you like but I think it's most useful for an email target.
You need to modify the
NLog.config file.
First add a reference to the assembly with the wrapper:
<extensions>
<add assembly="LevelTriggeredBufferingWrapper"/>
</extensions>
Second, use the wrapper:
<target name="gmailwrapper" xsi:type="LevelTriggeredBufferingWrapper">
<BufferSize>100</BufferSize>
<TriggerLevel>Fatal</TriggerLevel>
<target name="mail" xsi:type="Mail" >
</target>
</target>
Those
BufferSize
and
TriggerLevel
parameters are not really necessary - they are the default values, but you can change the values if you want.