C#事件日志EntryWrittenEventHandler不仅加载最后一个事件

时间:2018-07-12 10:17:14

标签: c# event-log

我已经创建了一个小程序(服务或控制台,对它们进行了相同的测试,以观察它们的结果),仅在Windows安全事件日志中查找某些事件ID,然后在该ID通过的最后一次事件上执行操作。

这可以正常工作一段时间,然后突然,一天几次,程序运行并获取整个日志中具有指定事件ID的所有事件(而不仅仅是最后一个)。

这是我的代码:

class Program
{   // These are the events I want to listen to
    public static string[] eventsToListen = { "4727", "4730", "5136", "5139" };

    static void Main(string[] args)
    {
        EventLog eventLog = new EventLog("Security", Environment.MachineName);

        eventLog.EntryWritten += new EntryWrittenEventHandler(OnEntryWrittenAsync);
        eventLog.EnableRaisingEvents = true;

        Console.ReadLine();
    }

    private static void OnEntryWrittenAsync(object sender, EntryWrittenEventArgs e)
    {
        if (eventsToListen.Contains(e.Entry.InstanceId.ToString()))
        {
            Task.Factory.StartNew(() => writeToRemoteLog(e.Entry));
        }
    }

    private static void writeToRemoteLog(EventLogEntry entry)
    {
        string logMessage = null;

        if (EventLog.Exists("DCGroupEvents", "targetMachineName"))
        {
            try
            {
                var log = new EventLog("DCGroupEvents", "targetMachineName");
                log.Source = "DCGroupEvents";
                String strMessage = entry.Index.ToString();
                log.WriteEntry(strMessage);
                log.Close();
                logMessage = entry.InstanceId.ToString() + "/" + entry.TimeWritten.ToString() + "/" + entry.Index.ToString() + " written to eventlog";
            }
            catch (Exception e)
            {
                logMessage = e.Message;
            }
        }
        else
        {
            logMessage = "Log does not exist";
        }
        Console.WriteLine(logMessage);
        logMessage = null;

    }
}

如何每天避免多次下载所有符合标准的事件?

在此先感谢所有知道这一点的人,此刻我有些困惑。

2 个答案:

答案 0 :(得分:0)

  

仅当上一次写入事件至少在六秒钟之前发生时,系统才对WriteEntry作出响应。这意味着即使发生了多个事件日志更改,您也只会在六秒钟的间隔内收到一个EntryWritten事件通知。如果您在两次调用WriteEntry之间插入足够长的睡眠间隔(大约10秒),则不太可能错过事件。但是,如果写入事件发生的频率更高,则可能要等到下一个时间间隔,才能收到事件通知。通常,错过的事件通知不会丢失,而是会延迟。

来源:https://social.msdn.microsoft.com/Forums/vstudio/en-US/b0314be2-3b75-4a21-aabc-4777cd8ba100/eventlogentrywritten-firing-for-events-in-the-past?forum=netfxbcl

答案 1 :(得分:0)

虽然不是理想的解决方案,可以尝试并使用映射表通过实现字典来解决这个问题,其存储所述事件属性和事件的索引ID。创建一个将验证和更新映射表并返回布尔结果的方法。然后,而不是执行时的事件被触发的活性,通过调用ValidatedUpdate(PARAMS)并基于该结果来执行的活性进行验证。 ValidatedUpdate(params)方法检查1;如果事件是在当日的第二天写的;如果索引ID已经存在于映射表3;如果事件ID与您需要过滤的ID相同。

当这些条件匹配时,则仅将其确定为当天的“新”事件。然后将该条目添加到字典中,并且可以返回布尔结果以供将来跟踪。为了减少臃肿,定时器可通过刷新值来实现每天将要“干净”的映射表。像下面这样

    private ConcurrentDictionary<int, DateTime> mappingTable;

    private bool ValidateAndUpdate(int id, DateTime entry)
    {
        try
        {
            if(!mappingTable.ContainsKey(id) && entry.TimeStamp > DateTime.Today.Date)
            {
                mappingTable.TryAdd(id, entry);

                return true;
            }
            else
            {
                return false;
            }
        }
        catch(Exception exception)
        {
            //handle exception event
        }
    }

    private void OnEntryWritten(object sender, EntryWrittenEventArgs e)
    {
        //preceding code here

        if(ValidateAndUpdate(e.Entry.Index, entry) == true)
        {
            //perform operation
        }
        catch(Exception exception)
        {
            //handle exception event
        }
    }