Click here to Skip to main content
15,880,905 members
Articles / Programming Languages / C#
Article

Build Windows Event Log Watcher Service Process to Export Event Log Entries as RSS Feed

Rate me:
Please Sign up or sign in to vote.
4.70/5 (22 votes)
5 Nov 2007CPOL3 min read 94.5K   62   7
Build Windows Event Log Watcher Service Process to Export Event Log Entries as RSS feed

Introduction

The article presented below shows how to develop and setup a process to monitor for Windows Event Log (Application, System etc.) changes and export them as RSS feeds.
Previously, I wrote an article on how to setup a process to monitor Event Log Changes via/with TCP Listener - Remote Event Log Monitor/Watcher (Using TCP in .NET) (on The Code Project - How to Build Simple Event Log Monitor/Watcher (Using TCP in .NET)
(see other Siccolo articles about working with .NET, Windows Event Log, C# and VB.NET)

There're some other ideas on how to "export" Event Log entries into RSS Feeds using ASP.NET - for example, Event Log RSS Feed Generator, or Event Log Monitoring with RSS. In this application, however, I'm using Windows service to monitor Windows Event Log for an event associated with a certain Event source.

So the idea is very similar to Remote Event Log Monitor/Watcher (Using TCP in .NET) - have a Windows service on a machine monitoring for certain Event Log entries and export them into RSS feed file. After that, any Feed Reader & RSS Aggregator supporting UNC file names will be able to display those Event Log entries as RSS feeds. For example, I'm using intraVnews Feed Reader & RSS Aggregator for Outlook.

Click to enlarge image

As you may know, .NET allows a developer to attach a "handler" to monitor for event log changes (VB.NET):

VB.NET
        ...
    Dim objLog As EventLog = New EventLog("Application")
    AddHandler objLog.EntryWritten, AddressOf ApplicationLog_OnEntryWritten
    objLog.EnableRaisingEvents = True
        ...

Public Sub ApplicationLog_OnEntryWritten(ByVal [source] As Object, _
    ByVal e As EntryWrittenEventArgs)
        Try

               'handle event log change here

        Catch err As Exception
        'oops
        End Try
    End Sub

or, C#:

C#
EventLog eLog = new EventLog("Application");
eLog.EntryWritten += new EntryWrittenEventHandler(EventLog_OnEntryWritten);
eLog.EnableRaisingEvents = true;
...
public void EventLog_OnEntryWritten(object source, EntryWrittenEventArgs e)
    {
       try
        {
           //handle event log change here
        }
        catch (Exception ex)
        {
            //oops
        }
    }

The only problem with this approach - it does not allow to monitor for event log changes on a remote machine. See Microsoft support article 815314.

Image 2

1. Creating Event Log Watcher Service

First, let's build a service component - Windows Service application - responsible for "keep an eye on" event log on a machine. To create a service application (i.e. application that runs as a service):

Image 3

An application that runs as a service has few events (inherited from System.ServiceProcess.ServiceBase)

  • OnStart() - Occurs when the service receives a Start command
  • OnStop() - Occurs when the service receives a Stop command
  • OnPause() and OnContinue() - Occurs when the service receives a Pause/Resume command

For Event Log Watcher service, we'll only need OnStart() and OnStop() events.
onStart() procedure tells what actions should be taken when Event Log Watcher service starts running - load configuration settings (such as where to output RSS feeds; which Event Logs to monitor; if there is a need to filter certain event sources and filter certain Event Types - for example, we may need to only "watch out" for Error event types from Microsoft SQL Server service) and after that actually start working and monitor for Event Log changes!

For example, config file may look like this...

Image 4

... where configuration settings are loaded using ConfigurationManager class. To load/read settings from the configuration file, I'm using the following simple class LogWatcherSettings (showing just one method for just one configuration setting):

C#
using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;

namespace LogWatcher_RSS
{
    class LogWatcherSettings
    {
        ...
        ...
    public static string RssFeedsOutputFoler()
        {
            try
            {
                Configuration config = ConfigurationManager.OpenExeConfiguration
                                       (ConfigurationUserLevel.None);
                return ConfigurationManager.AppSettings["RssOutputFolder"].ToString();
            }
            catch
            {
                return "c:\\";   // by default log file
            }
        }
        ...
        ...
    }
}

Now, back to Log Watcher main class log_watch_rss:

C#
public partial class log_watch_rss : ServiceBase
{
    bool m_ToDebug = false;
    string m_DebugFileName = "";

    string m_RSSFeedsFolder = "";                //where to put RSS feed files

    //keep a list of Event Logs to monitor
    ArrayList m_EventLogsToMonitor = new ArrayList();
                            //for example, Application and System
    ...
       ...

    protected override void OnStart(string[] args)
    {
        //load settings:
        m_ToDebug = LogWatcherSettings.ToDebug();
        m_DebugFileName = LogWatcherSettings.DebugFile();
        m_RSSFeedsFolder = LogWatcherSettings.RssFeedsOutputFoler();

        //first - load list of event logs to monitor:
        string[] eventLogList = LogWatcherSettings.Filter_LogName().Split(',') ;
        if (m_ToDebug)
        {
            AddDebugMessage("LogWatcher_RSS monitors logs {" +
                           LogWatcherSettings.Filter_LogName() + "}");
        }

        //for each Event Log - create instances of :
        for (int i = 0; i < eventLogList.Length; i++)
        {
            string logName = eventLogList[i];
            //one instance of EventLogRSS per log:
            EventLogRSS eventLog =
                            new EventLogRSS(logName,
                                            m_ToDebug,
                                            m_DebugFileName,
                                            m_RSSFeedsFolder,
                                            LogWatcherSettings.Filter_LogSource(),
                                            LogWatcherSettings.Filter_LogEvent(),
                                            LogWatcherSettings.HowManyRecordsPull() );
            m_EventLogsToMonitor.Add(eventLog);
        }
    }

      ...
...

protected override void OnStop()
    {
        foreach (EventLogRSS log in m_EventLogsToMonitor)
        {
            log.CloseLog();
        }
    }
}

So, as you can see, Log Watcher service main class log_watch_rss is not doing a whole lot of work - loading settings and creating instances of EventLogRSS. EventLogRSS class is the one monitoring for Windows Event Log changes and "exporting" them to RSS Feed files.

2. Building Event Log Watcher/Monitor

Let's look at EventLogRSS class. First, in the class constructor:

C#
class EventLogRSS
    {
    //class variables:
        private EventLog m_EventLog = null;    //Event log to monitor

        bool m_ToDebug = false;
        string m_DebugFileName = "";

        string m_RSSFeedsFolder = "";
        string m_RSSFeedFileName = "";

        string m_EventLogName = "";        //actual name of Event log to monitor

        string m_FilterEventSource="";        //filter by Source name
        ArrayList m_FilterEventSourceList = new ArrayList();

        string m_FilterEventType="";        //filter by event type
        ArrayList m_FilterEventTypeList = new ArrayList();

        //how many records before creating a new RSS file
        int m_RecordsToPull=250;

        int m_CurrentRecordCount = 0;

        //machine where Event Log Watcher service is running
        string m_LocalIP = System.Net.Dns.GetHostName();


        public EventLogRSS(string logName,
                            bool toDebug,
                            string debugFileName,
                            string rssFeedsPath,
                            string filterEventSource,
                            string filterEventType,
                            int recordsToPull)
        {
            m_EventLogName = logName;
            m_ToDebug = toDebug;
            m_DebugFileName = debugFileName;
            m_RSSFeedsFolder = rssFeedsPath;
            //construct RSS Feed File Name:
            m_RSSFeedFileName = Path.Combine
                        (m_RSSFeedsFolder, m_EventLogName + "_eventlog_rss.xml");

            //filters
            m_FilterEventSource = filterEventSource;
            m_FilterEventType = filterEventType;

            if (m_FilterEventSource != String.Empty)
            { m_FilterEventSourceList.AddRange(m_FilterEventSource.Split(',')); }

            if (m_FilterEventType != String.Empty)
            { m_FilterEventTypeList.AddRange(m_FilterEventType.Split(',')); }


            //how many records in a RSS file, before a new file is created
            m_RecordsToPull = recordsToPull;

            //initialize log...
            m_EventLog = new EventLog(logName);
            m_EventLog.EntryWritten +=
                new EntryWrittenEventHandler(EventLog_OnEntryWritten);
            m_EventLog.EnableRaisingEvents = true;

            //create new RSS file
            StartRSSFeed();
        }
    }

So, if and when a new entry is being added to Windows Event Log:

C#
m_EventLog.EntryWritten += new EntryWrittenEventHandler(EventLog_OnEntryWritten);
m_EventLog.EnableRaisingEvents = true;

The application will call the EventLog_OnEntryWritten() procedure:

C#
public void EventLog_OnEntryWritten(object source, EntryWrittenEventArgs e)
    {
            try
            {
                if (m_ToDebug)
                {
                    //or use m_EventLogName
                    string eventLogName = ((EventLog)source).LogDisplayName;

                    AddDebugMessage(eventLogName + " - " + e.Entry.Source + ":" +
                        e.Entry.Message);
                }
                //filter it?
                if ((m_FilterEventSource == String.Empty ||
                m_FilterEventSourceList.Contains(e.Entry.Source)) &&
                            m_FilterEventTypeList.Contains
                            (e.Entry.EntryType.ToString()))
                {
                    if (m_CurrentRecordCount > m_RecordsToPull)
                    {
                        StartRSSFeed();
                    }
                    //create entry in RSS file...
                    AddEntryToRSSFeed((EventLogEntry)e.Entry);
                    m_CurrentRecordCount += 1;
                }
                else
                {
                    if (m_ToDebug)
                    { AddDebugMessage("not in filter --> " +
                e.Entry.Source + ":" + e.Entry.EntryType.ToString());}
                }
            }
            catch (Exception ex_on_entry_written)
            {
                //oh-ho...
                AddDebugMessage("Failed to EventLog_OnEntryWritten() for
                   [" + m_EventLog + "] event log\n" + ex_on_entry_written.Message);
            }
    }

And if, Event Log Entry is for a given Event source and of a specified Event Type, then call to AddEntryToRSSFeed() procedure follows:

C#
public void AddEntryToRSSFeed(EventLogEntry entry)
    {
            try
            {
                XmlDocument rssFeedXMLDoc = new XmlDocument();
                rssFeedXMLDoc.Load(m_RSSFeedFileName);
                XmlElement rssFeedItemElement =
                rssFeedXMLDoc.CreateElement("item");
                //
                rssFeedItemElement.InnerXml =
                "<title></title><link></link><description></description><pubdate /></pubdate />";
                rssFeedItemElement["title"].InnerText =
                entry.Source + "-" + entry.EntryType.ToString();
                rssFeedItemElement["link"].InnerText = "";
                rssFeedItemElement["description"].InnerText = entry.Message;
                rssFeedItemElement["pubDate"].InnerText =
                entry.TimeGenerated.ToString("r");

                rssFeedXMLDoc.DocumentElement.SelectNodes
                ("/rss/channel")[0].AppendChild(rssFeedItemElement);
                rssFeedXMLDoc.Save(m_RSSFeedFileName);
            }

            catch (Exception ex_add_entry_to_rss_fee)
            {
                AddDebugMessage("Failed to AddEntryToRSSFeed() for
                    [" + m_EventLog + "] event log\n" +
                    ex_add_entry_to_rss_fee.Message);
            }
    }

And that's it. We just developed our own Windows Event Log watcher/monitoring tool. And you just saved, eh-h, about 500 US dollars compared to MOM Image 5.

Click to enlarge image

History

  • No improvements so far, nearly perfect

License

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


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralWMI Pin
AnthonyLloyd305-Nov-07 21:58
AnthonyLloyd305-Nov-07 21:58 
Have you looked at WMI? Its very easy to subscribe to event log events on remote machines.

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

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