Custom log4net raising application-level events Use Case: I have a form application in which I log events to a file/database and have a need to also raise those events to the application itself (for display purposes).  Think old school updating status bar with the same content that you will log to a file.

The solution I put in place is a custom log4net class (since we're already using that for the actual file and databases logging).  This simple class just raises an event when the message payload of the caller.  This way I can use a single call to the log instead of multiple calls to different loggers.

This is a working class, I'm just looking for input on pitfalls on the code or potential performance issues that might be found (and to also share the idea for others that need it).  I'm also wondering missing some best practices or something simple that I've overlooked.

I the case of my requirements, this event may be called 30 times/sec across multiple different threads. 

MemoryQueueEventArgs isn't the actual final class name, it was another direction I was going to go, I just haven't renamed it yet. 

public class MemoryQueueEventArgs : EventArgs
{
  // Customize to your business requirements
  public DateTime CreateDate { get; set; }
  public string Message { get; set; }
  public string Level { get; set; }
  public string LoggerName { get; set; }
  internal int Count { get; set; }
}

public class MemoryQueueAppender : AppenderSkeleton
{
  private object objectLock = new Object();

  #region Public Methods
  public static MemoryQueueAppender GetActiveAppender(Type type)
  {
    IAppender[] appenders = log4net.LogManager.GetLogger(type).Logger.Repository.GetAppenders();
    return (appenders
     .FirstOrDefault(a =&gt; a.GetType().Name == "MemoryQueueAppender") as MemoryQueueAppender)
    ;
  }

  protected event EventHandler&lt;MemoryQueueEventArgs&gt; _LogUpdate;
  public event EventHandler&lt;MemoryQueueEventArgs&gt; LogUpdate
  {
    add
    {
      lock (objectLock)
      {
        _LogUpdate += value;
      }
    }
    remove
    {
      lock (objectLock)
      {
        _LogUpdate -= value;
      }
    }

  }
  #endregion Public Methods

  protected override void Append(log4net.Core.LoggingEvent loggingEvent)
  {
    MemoryQueueEventArgs mqea = _CreateMemoryQueueEventArgs(loggingEvent);
    this.OnLogUpdate(mqea);
  }

  protected override void Append(log4net.Core.LoggingEvent[] loggingEvents)
  {
    base.Append(loggingEvents);
  }


  #region Private Methods

  private MemoryQueueEventArgs _CreateMemoryQueueEventArgs(log4net.Core.LoggingEvent loggingEvent)
  {
    return new MemoryQueueEventArgs
    {
      CreateDate = DateTime.Now,
      Level = loggingEvent.Level.Name,
      LoggerName = loggingEvent.LoggerName,
      Message = RenderLoggingEvent(loggingEvent),
    };
  }

  protected virtual void OnLogUpdate(MemoryQueueEventArgs e)
  {
    EventHandler&lt;MemoryQueueEventArgs&gt; handler = _LogUpdate;
    if (handler != null)
    {
      handler(this, e);
    }
  }

  #endregion Private Methods

}


Calling Code:

public TestDevelopment()
{
  MemoryQueueAppender appender = MemoryQueueAppender.GetActiveAppender(this.GetType());
  appender.LogUpdate += appender_LogUpdateEvent;
}

void appender_LogUpdateEvent(object sender, MemoryQueueEventArgs e)
{
  System.Diagnostics.Debug.WriteLine(string.Format("[{0}] {1}", e.Level, e.Message));
}
I log events to a file/database and have a need to also raise those events to the application itself (for display purposes).


Generally this is not a bad idea but...


  I the case of my requirements, this event may be called 30 times/sec across multiple different threads.


with this many log events per second it is. No human can read it anymore unless you are writing applications for Jedis.

Use a custom named logger and send to the UI only those messages that have some value to the user not just everything that gets logged.

Or create some kind of a filter that reduces the number of messages to a reasonable count.