Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

NLog email buffering wrapper

5.00/5 (1 vote)
19 Dec 2010CPOL 22.8K  
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:

XML
<extensions>
  <add assembly="LevelTriggeredBufferingWrapper"/>
</extensions>


Second, use the wrapper:

XML
<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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)