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.
Started my career as an electronics engineer.
Started software development in 4004 assembler.
Progressed to 8080, Z80 and 6802 assembler in the days when you built your own computer from discrete components.
Dabbled in Macro-11 and Coral66 by way of a small digression.
Moved on to C, first on Z80s and then on PCs when they were invented.
Continued to C++ and then C#
Now working mostly in C# and XAML while maintaining about half a million lines of C++