65.9K
CodeProject 正在变化。 阅读更多。
Home

构建 Windows 事件日志监视器服务进程以将事件日志条目导出为 RSS Feed

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.70/5 (22投票s)

2007年11月5日

CPOL

3分钟阅读

viewsIcon

96222

构建 Windows 事件日志监视器服务进程以将事件日志条目导出为 RSS feed。

引言

本文介绍了如何开发和设置一个进程来监视 Windows 事件日志(应用程序、系统等)的更改,并将它们导出为 RSS 源。
之前,我写了一篇文章关于如何设置一个进程,通过/使用 TCP 监听器来监视事件日志更改 - 远程事件日志监视器/观察器(在 .NET 中使用 TCP) (在 Code Project 上 - 如何构建简单的事件日志监视器/观察器(在 .NET 中使用 TCP)
(参阅其他 Siccolo 关于使用 .NET、Windows 事件日志、C# 和 VB.NET 的文章

还有一些关于如何使用 ASP.NET 将事件日志条目“导出”到 RSS 源的想法 - 例如,事件日志 RSS 源生成器,或 使用 RSS 监视事件日志。 然而,在这个应用程序中,我使用 Windows 服务来监视 Windows 事件日志中与特定事件源相关的事件。

所以这个想法与 远程事件日志监视器/观察器(在 .NET 中使用 TCP) 非常相似 - 在一台机器上运行 Windows 服务,监视特定的事件日志条目并将它们导出到 RSS 源文件。 之后,任何支持 UNC 文件名的 Feed 阅读器和 RSS 聚合器都能够将这些事件日志条目显示为 RSS 源。 例如,我正在使用 用于 Outlook 的 intraVnews Feed 阅读器和 RSS 聚合器

Click to enlarge image

如你所知,.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

或者,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
        }
    }

这种方法的唯一问题是 - 它不允许监视远程机器上的事件日志更改。 请参阅 Microsoft 支持文章 815314

1. 创建事件日志监视器服务

首先,让我们构建一个服务组件 - Windows 服务应用程序 - 负责“密切关注”机器上的事件日志。 要创建一个服务应用程序(即作为服务运行的应用程序)

作为服务运行的应用程序具有一些事件(继承自 System.ServiceProcess.ServiceBase

  • OnStart() - 服务收到 Start 命令时发生
  • OnStop() - 服务收到 Stop 命令时发生
  • OnPause()OnContinue() - 服务收到 Pause/Resume 命令时发生

对于事件日志监视器服务,我们只需要 OnStart()OnStop() 事件。
onStart() 过程说明了当事件日志监视器服务开始运行时应采取的操作 - 加载配置设置(例如,RSS 源的输出位置;要监视的事件日志;是否需要过滤某些事件源和过滤某些事件类型 - 例如,我们可能只需要“注意”来自 Microsoft SQL Server 服务的错误事件类型)然后实际开始工作并监视事件日志更改!

例如,config 文件可能如下所示...

...其中配置设置是使用 ConfigurationManager 类加载的。 为了从配置文件中加载/读取设置,我使用了以下简单的类 LogWatcherSettings(仅显示一个设置的一个方法)

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
            }
        }
        ...
        ...
    }
}

现在,回到日志监视器主类 log_watch_rss

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();
        }
    }
}

因此,正如你所看到的,日志监视器服务主类 log_watch_rss 并没有做很多工作 - 加载设置并创建 EventLogRSS 的实例。 EventLogRSS 类是监视 Windows 事件日志更改并将它们“导出”到 RSS 源文件的类。

2. 构建事件日志监视器/观察器

让我们看看 EventLogRSS 类。 首先,在类构造函数中

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();
        }
    }

因此,如果并且当一个新的条目被添加到 Windows 事件日志时

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

应用程序将调用 EventLog_OnEntryWritten() 过程

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);
            }
    }

并且,如果事件日志条目是针对给定的事件源和指定的事件类型,则调用 AddEntryToRSSFeed() 过程

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>";
                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);
            }
    }

就是这样。 我们刚刚开发了自己的 Windows 事件日志监视器/监控工具。 与 MOM 相比,你刚刚节省了,呃-h,大约 500 美元 .

Click to enlarge image

历史

  • 到目前为止没有改进,几乎完美
© . All rights reserved.