65.9K
CodeProject is changing. Read more.
Home

NLog email buffering wrapper

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1 vote)

Dec 2, 2010

CPOL
viewsIcon

22969

An NLog target wrapper to pass on log events when triggered by an event with a specified log level

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 { /* use default trigger level */ }

      WrappedTarget = wrappedTarget;
      BufferSize = bufferSize;
      }

    /// <summary>
    /// Gets or sets the number of log events to be buffered.
    /// </summary>
    [DefaultValue(100)]
    public int BufferSize { get; set; }

    /// <summary>
    /// Gets or sets the trigger level. Any event with a level equal to
    /// or greater than the trigger level will cause the whole buffer of
    /// events to be passed to the wrapped target
    /// </summary>
    /// <value>The trigger level.</value>
    [DefaultValue("Fatal")]
    public string TriggerLevel
      {
      get { return triggerLevel.ToString(); }
      set { triggerLevel = LogLevel.FromString(value); }
      }

    protected override void FlushAsync(NLog.Common.AsyncContinuation asyncContinuation)
      {
      // do nothing
      }

    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" >
    <!-- whatever else you need to configure the mail target -->
  </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.
NLog email buffering wrapper - CodeProject