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" />
