Tuesday, February 2, 2010

EventLog based Error Logging using ELMAH

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml;
using System.IO;
using System.Text;
using Elmah;
using System.Diagnostics;


namespace Sample.SampleSystems.Sales.Web.Helpers
{
/// <summary>
/// This class extends Elmah ErrorLog class to log errors to EventLog.
/// </summary>
public class EventLogErrorLog : Elmah.ErrorLog
{
string _eventLog = string.Empty;
string _eventSource = string.Empty;

public string EventLogName
{
get
{
return _eventLog;
}
set
{
_eventLog = value;
}
}

public string EventSourceName
{
get
{
return _eventSource;
}
set
{
_eventSource = value;
}
}

public EventLogErrorLog(string eventLog, string eventSource)
{
_eventLog = eventLog;
_eventSource = eventSource;
}


public EventLogErrorLog(System.Collections.IDictionary config)
{
string eventLog = Mask.NullString(config["eventLog"] as string);

if (eventLog.Length == 0)
{
eventLog = Mask.NullString(config["EventLog"] as string);

if (eventLog.Length == 0)
throw new Elmah.ApplicationException("EventLog is missing for the EventLog-based error log.");
}

string eventSource = Mask.NullString(config["eventSource"] as string);

if (eventSource.Length == 0)
{
eventSource = Mask.NullString(config["EventSource"] as string);

if (eventSource.Length == 0)
throw new Elmah.ApplicationException("EventLog is missing for the EventLog-based error log.");
}
_eventLog = eventLog;
_eventSource = eventSource;
}

public override string Name
{
get { return "iMAD EventLog Error Log"; }
}

public override ErrorLogEntry GetError(string id)
{
ErrorLogEntry logEntry = null;
if (EventLog.SourceExists(_eventSource))
{
// Create an EventLog instance and assign its source.
EventLog imadLog = new EventLog(_eventLog);
foreach (EventLogEntry entry in imadLog.Entries)
{
XmlTextReader reader = new XmlTextReader(new StringReader(entry.Message));
while (reader.IsStartElement("error"))
{
string errorid = reader.GetAttribute("errorId");

if (errorid == id)
{
Error error = ErrorXml.Decode(reader);
logEntry = new ErrorLogEntry(this, errorid, error);
break;
}

reader.Read();

}
reader.Close();
if (logEntry != null)
break;
}
}
return logEntry;

}

public override int GetErrors(int pageIndex, int pageSize, System.Collections.IList errorEntryList)
{
if (EventLog.SourceExists(_eventSource))
{
// Create an EventLog instance and assign its source.
EventLog imadLog = new EventLog(_eventLog);

if (imadLog.Entries.Count > 0)
{
for (int counter = pageIndex; counter < pageSize; counter++)
{
if (counter >= imadLog.Entries.Count)
{
break;
}
EventLogEntry entry = imadLog.Entries[counter];
XmlTextReader reader = new XmlTextReader(new StringReader(entry.Message));

while (reader.IsStartElement("error"))
{
string id = reader.GetAttribute("errorId");
Error error = ErrorXml.Decode(reader);
errorEntryList.Add(new ErrorLogEntry(this, id, error));
}

reader.Close();
}
}
return errorEntryList.Count;
}

return default(int);
}

public override string Log(Error error)
{
string errorId = Guid.NewGuid().ToString();
StringWriter swritter = new StringWriter();
XmlTextWriter xwriter = new XmlTextWriter(swritter);
xwriter.Formatting = Formatting.Indented;
xwriter.WriteStartDocument();
xwriter.WriteStartElement("error");
xwriter.WriteAttributeString("errorId", errorId.ToString());
ErrorXml.Encode(error, xwriter);
xwriter.WriteEndElement();
xwriter.Flush();
xwriter.Close();

// Make sure the Eventlog Exists
if (EventLog.SourceExists(_eventSource))
{
// Create an EventLog instance and assign its source.
EventLog imadLog = new EventLog(_eventLog);
imadLog.Source = _eventSource;
string messageString = swritter.ToString();
if (messageString.Length > 32765)
{
////Max limit of characters that EventLog allows for an event is 32766.
messageString = messageString.Substring(0, 32765);
}
// Write the error entry to the event log.
imadLog.WriteEntry(messageString, EventLogEntryType.Error);
}

return errorId;

}
}

internal sealed class Mask
{
public static string NullString(string s)
{
return s == null ? string.Empty : s;
}

public static string EmptyString(string s, string filler)
{
return Mask.NullString(s).Length == 0 ? filler : s;
}

private Mask() { }
}
}

1 comment:

  1. Hello Deba,

    Thank you very much for this article! It's very helpful for me!

    But I have a question: how to register, configure and use this module? Can i use this module and standard Elmah module (XmlFileErrorLog for example) together?

    Best Regards,
    Aleksandrs

    ReplyDelete