Log4Net - ELMAH style

Problem: I wanted a simple way of configuring log4net so I can view the log details via a url - not having to log into the server to view a log file, or having to query a table in a database. I wanted a simple setup, and I was inspired by ELMAH - incredibly easy to configure and get up and running.

My solution: Create an in-memory appender to log to a fixed-length buffer and an http handler to view the buffer.

So, to start off, the appender. Couldn't be easier, create a class thus:

public class InMemoryAppender : IAppender

And the append implementation:

public void DoAppend(LoggingEvent loggingEvent)
{
  InMemoryBuffer.Instance.AppendEvent(loggingEvent);
}

That's the appender, now for the InMemoryBuffer - some snippets from this class:

public class InMemoryBuffer
{
  public static readonly InMemoryBuffer Instance = new InMemoryBuffer();
  private readonly LinkedList<LogEventInfo> logBuffer = new LinkedList<LogEventInfo>();

  public void AsyncAppendEvent(LoggingEvent loggingEvent)
  {
    var timestamp = loggingEvent.TimeStamp;
    var loggingLevel = loggingEvent.Level;
    var name = loggingEvent.LoggerName;
    var message = loggingEvent.RenderedMessage;
    this.logBuffer.AddLast(new LogEventInfo(timestamp, loggingLevel.DisplayName, name, message));
    while (this.logBuffer.Count > InMemoryBuffer.MaxBufferSize) this.logBuffer.RemoveFirst();
  }
}

And for the HttpHandler to enable viewing the log messages via a url:

public class Log4NetDisplayHttpHandler : IHttpHandler
{
  public void ProcessRequest(HttpContext context)
  {
    var templateFile = Resources.Template;
    var rows = new StringBuilder();
    foreach (var logEventInfo in InMemoryBuffer.Instance.LogEvents)
      rows.AppendFormat(@"
        <tr>
          <td>{0}</td>
          <td>{1}</td>
          <td>{2}</td>
          <td>{3}</td>
        </tr>",
        logEventInfo.Timestamp.ToString("u"), logEventInfo.Level,
        logEventInfo.Class, logEventInfo.Message);

      var replaced = templateFile.Replace("${LOGGINGROWS}", rows.ToString());
      context.Response.Write(replaced);
  }
}

The project contains the Template resource which contains the html page into which the logging rows are inserted. I then use jquery-based flexigrid to turn the table into a fancy grid!

Finally, the web.config configuration. Add the appender to the log4net section:

<appender name="InMemory" type="InMemoryAppender, MyLog4Net" />

And to the httpHandler section:

<add verb="POST,GET,HEAD" path="inmemorylogging.axd" type="Log4NetDisplayHttpHandler, MyLog4Net" />

Comments:

Uploaded to Git: http://github.com/andywhitfield/Whitfield.Log4Net.

Good point. At the time I didn't really have anywhere public to put it, but now I've signed up to GitHub, I can upload this code there. Will update the post with a link to the GitHub project once I've put it together in a nice project and uploaded.

Why didn't you post the project for users to download?


Comment Guidelines
See the FAQ for details on the full rules and guidelines. No Spam. Write clearly and thoughtfully - no bad language.