有没有办法在C#中确定是哪个EventLog引起了EntryWritten事件?

6

我正在开发一个类似于事件查看器的Web应用程序,用于展示事件日志数据。该应用程序还需要提供一种方式让用户订阅事件日志,当被订阅的日志有新条目时,利用Web服务接收通知。

我使用以下代码在Web服务中订阅事件日志:

EventLog eventLog = new EventLog(observer.logName, observer.machineName);
eventLog.EnableRaisingEvents = true;
eventLog.EntryWritten += new EntryWrittenEventHandler(eventLog_EntryWritten);
eventList.Add(eventLog);

我试图将观察者作为事件日志的订阅者,并在处理EventWritten事件时调用一个观察者的Update方法。问题是,我不知道如何区分事件日志,因为它们都使用相同的事件处理程序。我这样做是因为每台计算机上的事件日志数量不同。此外,我希望观察者仅处理一种类型的EventLog,即一个观察者在将事件写入应用程序日志时发送电子邮件。
我使用以下代码行在当前计算机上获取所有日志:
remoteEventLogs = EventLog.GetEventLogs(machineName);

EventWritten事件处理程序有一个名为sender的对象参数,但是Visual Studio显示其类型为EventLogInternal,我无法使用它,也无法将sender强制转换为EventLog以获取EventLog.Log属性。如果我尝试像这样进行强制转换:

void eventLog_EntryWritten(object sender, EntryWrittenEventArgs e)
    {
        var log = (EventLog)sender;
    }

我收到一个异常,说我无法将EventLogInternal强制转换为EventLog。

有没有办法知道是哪个EventLog触发了事件?

谢谢

5个回答

4
我认为问题在于,EventLog类的整个概念是它假定它只适用于单个日志 - 这确实是这样。因此,既不是EventWrittenEventArgs类,也不是EventEntry类支持包含日志名称的成员,因为它是由关联的EventLog实例隐含给出的。当然不好的是,在EventWritten处理程序中无法访问它。
您可以创建一个System.Diagnostics.EventLog的包装器,如下所示:
class MyEventLog : EventLog
{
    public MyEventLog(string logName, string machineName)
        : base(logName, machineName)
    {
        base.EnableRaisingEvents = true;
        base.EntryWritten += MyEventLog_EntryWritten;
    }

    void MyEventLog_EntryWritten(object sender, EntryWrittenEventArgs e)
    {
        Console.WriteLine("Entry in {0} log.", base.Log);

        // Your code
    }
}

然后在通常使用EventLog的地方使用MyEventLog。不过可能需要给它一个更好的名字。

您还可以通过提供一个Action<string, EntryWrittenEventArgs>属性来分离“您的代码”部分,该属性从MyEventLog_EntryWritten内部调用,并且可以设置为您的“外部”处理程序函数。


还没有考虑过在EventLog周围创建一个包装器,我会尝试一下。非常感谢。 - markhan777
这不允许您从事件处理程序中访问日志名称,或者我漏掉了什么。 - driverobject
base.Log 会返回日志的名称。或者你可以将它存储在构造函数的成员变量中,并从事件处理程序(也是成员函数)中访问它。 - Christian.K

3

另一种选项是沿着这些线使用反射:

string log = (string)sender.GetType().GetProperty("Log").GetValue(sender, null);

在这种情况下,sender 实际上具有 Log 属性。


不错的临时解决方案。可能与新的 .Net 框架有问题。 - Zam

2
我认为你要找的东西可以在EntryWrittenEventArgs中找到。
MSDN显示有一个名为Entry的属性,它会向您显示有关刚刚记录的所有信息。 EventLogEntry类中有一些属性可能对您有所帮助,例如MachineName或UserName。
这是Args类的链接 http://msdn.microsoft.com/en-us/library/system.diagnostics.entrywritteneventargs.aspx 这是Entry类的链接 http://msdn.microsoft.com/en-us/library/system.diagnostics.eventlogentry.aspx 我没有看到特定事件日志的直接链接,但是如果您使用调试器在该类中浏览Entry对象,可能会提供足够的信息来查找它。
希望这可以帮到你。

是的,问题在于Entry属性没有以任何方式显示正在写入日志的信息。 - markhan777

0

我同意Christian提出的将EventLog类包装在另一个类中的想法。最近我也在这样的需求上工作过。

这是我创建的类

 public class EventLogWatcher : EventLog
{
    Action<string, EntryWrittenEventArgs> _changeHandler;
    public EventLogWatcher(string logName, Action<string, EntryWrittenEventArgs> changeHandler)
        : base(logName)
    {
        _changeHandler = changeHandler;
    }

    public void EnableCapture()
    {
        base.EnableRaisingEvents = true;
        base.EntryWritten += EventLogChangeHandler;
    }

    public void DisableCapture()
    {
        base.EnableRaisingEvents = false;
        base.EntryWritten -= EventLogChangeHandler;
    }

    private void EventLogChangeHandler(object sender, EntryWrittenEventArgs e)
    {
        _changeHandler(base.Log, e);
    }
}

这是一个用法示例

 foreach (string eventlogType in LogTypes)
            logWatchers.Add(new EventLogWatcher(eventlogType, EventLogChangeHandler));

        foreach (EventLogWatcher localLog in logWatchers)
        {
            try
            {
                localLog.EnableCapture();
            }
            catch(Exception ex)
            {
                EventManager.PublishExceptionLogMessage(ex);
            }
        }
        EventManager.PublishInfoLogMessage($"Started EventLog listeners for {string.Join(",", LogTypes)} logs");

 private void EventLogChangeHandler(string eventLogType, EntryWrittenEventArgs e)
    {
        try
        {
            if (UploadAllowed(eventLogType, e))
            {

                Dm.EventLog model = _eventLogEntryMapper.MapEntryToModel(e);
                Task.Factory.StartNew(
                       () => _eventLogUploadService.UploadEventLog(model),
                       _cancellationTokenProvider.Token,
                       TaskCreationOptions.None,
                       TaskScheduler.Default);
            }
        }
        catch(Exception ex)
        {
            EventManager.PublishExceptionLogMessage(ex);
        }

    }

0

另外一种选择是像这样改变事件注册:

eventLog.EntryWritten += (sender, e) => eventLog_EntryWritten(eventLog, e);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接