Click here to Skip to main content
Click here to Skip to main content

NLog email buffering wrapper

, 19 Dec 2010
Rate this:
Please Sign up or sign in to vote.
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.

License

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

About the Author

Phil J Pearson
Software Developer (Senior)
England England
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# while maintaining about half a million lines of C++

Comments and Discussions

 
GeneralReason for my vote of 5 Just what I was looking for. Perfect... PinmemberSimon Hughes11-Mar-11 23:50 
Reason for my vote of 5
Just what I was looking for. Perfect thanks.
GeneralGood work PinmemberAbdul Quader Mamun16-Dec-10 9:38 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140721.1 | Last Updated 19 Dec 2010
Article Copyright 2010 by Phil J Pearson
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid