Как проще всего использовать .net, чтобы проверить, были ли события зарегистрированы в журнале событий? - PullRequest
1 голос
/ 08 октября 2008

Какой самый простой способ проверить, регистрировались ли события в журнале событий за определенный период времени?

Я хочу выполнить серию автоматизированных тестовых шагов, а затем проверить, были ли какие-либо ошибки зарегистрированы в журнале событий приложений, игнорируя несколько источников, которые мне не интересны. Я могу использовать System.Diagnostics.EventLog и затем посмотреть в коллекции Entries, но она не кажется очень полезной для этого сценария. Например, Entries.Count может со временем уменьшиться, если журнал событий удаляет старые записи. Я бы предпочел какой-либо способ либо запросить журнал, либо отслеживать его на предмет изменений в течение определенного периода времени. например

DateTime start = DateTime.Now;
// do some stuff...
foreach(EventLogEntry entry in CleverSolution.EventLogEntriesSince(start, "Application"))
{ 
  // Now I can do stuff with entry, or ignore if its Source is one
  // that I don't care about.
  // ...
}

Ответы [ 5 ]

5 голосов
/ 08 октября 2008

Просто чтобы быть хорошим гражданином вики и стремиться к завершению, есть и другие способы. Я не предлагал этого раньше, потому что это полностью излишне для чего-то, что будет запускаться только в составе набора тестов, и вы прямо в заголовке сказали, что хотите чего-то легкого.

Но если вам нужно увидеть события, как они происходят, в коде доставки, читайте дальше. Верьте или нет, на данный момент для этой вещи есть три различных API-интерфейса Windows.

NotifyChangeEventLog ()

Исходный API для такого рода вещей называется NotifyChangeEventLog () , и он поддерживается начиная с Windows 2000. По сути, вы используете API журнала событий WIN32 , чтобы открыть журнал событий. Затем вы вызываете этот API с дескриптором, который вы дали другому API, и с дескриптором события. Windows сообщит о вашем событии, когда появятся новые записи в журнале событий.

Я никогда не использовал этот API сам, потому что больше всего меня интересовал удаленный доступ к журналу событий, и этот API явно не поддерживает удаленные журналы. Однако остальная часть набора API, к которой относится , делает , позволяя вам последовательно читать удаленные журналы, если у вас есть необходимые разрешения.

Инструментарий управления Windows

Второй способ - использовать API инструментария управления Windows , и он поддерживает как локальные, так и удаленные журналы. Это API, основанный на COM / DCOM, который существует уже несколько лет в Windows, и .NET Framework имеет хорошую реализацию его в пространстве имен System.Management . По сути, вы создаете EventQuery , который ищет появление новых объектов WMI типа (то есть в системе типов WMI) Win32_NTLogEvent . Их появление будет указывать на новые записи в журнале событий, и они будут представлены в реальном времени. Атрибуты этих объектов содержат все детали записи журнала. В журнале MSDN есть статья , в которой рассказывается об игре с этим материалом в Visual Studio.

Опять же, это было бы полным перерасходом для тестового приложения, для этого потребовалось бы гораздо больше кода, чем в существующем решении. Но много лет назад я написал подсистему для приложения управления сетью, которая использовала DCOM-версию этого API для сбора журналов событий со всех серверов в сети, чтобы мы могли предупреждать о конкретных из них. Это было довольно гладко и чертовски близко к реальному времени. Если вы реализуете это в C ++ с DCOM, будьте готовы иметь дело с Multithreaded Apartments и множеством хитрой логики, чтобы определить, когда / когда ваше соединение с удаленным сервером увеличивается или уменьшается.

Журнал событий Windows Vista

Windows Vista (и Server 2008) имеют совершенно новый набор API, относящийся к регистрации и отслеживанию событий. новый журнал событий документирован здесь . Похоже, есть API под названием EvtSubscribe, который позволяет подписываться на события . Я не использовал этот API, поэтому не могу комментировать его плюсы и минусы.

3 голосов
/ 08 октября 2008

Как уже было сказано, вот ответ, который на самом деле должен быть довольно простым даже для вашего тестового приложения и является специфическим для .NET Framework.

Вам нужно открыть EventLog перед началом теста и подписать обработчик событий на событие EventLog.EntryWritten . Это способ, которым .NET предоставляет Win32 API NotifyChangeEventLog ().

Переместите текущую логику из GetEventLogEntriesSince() в обработчик событий, но вместо добавления событий в список для возврата сохраните их в списке, который можно получить откуда-то в конце цикла. Вы можете извлечь содержимое записи журнала из аргумента EntryWrittenEventArgs, который передается через его свойство Entry .

1 голос
/ 08 октября 2008

Класс System.Diagnostics.EventLog действительно является правильным способом сделать это.

Ваше основное возражение заключается в том, что в некоторых случаях журнал может удалять старые записи. Но вы говорите, что это в сценарии тестирования программного обеспечения. Разве вы не можете настроить свои тестовые системы так, чтобы журналы были достаточно большими, чтобы содержать все записи, и удаление старых записей не будет происходить во время ваших тестов?

0 голосов
/ 08 октября 2008

Я использую этот Powershell для сканирования журнала событий на предмет соответствующих записей за последние 7 дней:

$d=Get-Date
$recent=[System.Management.ManagementDateTimeConverter]::ToDMTFDateTime($d.AddDays(-7))

get-wmiobject -computer HOSTNAME -class Win32_NTLogEvent `
    -filter "logfile = 'Application' and (sourcename = 'SOURCENAME' or sourcename like 'OTHERSOURCENAME%') and (type = 'error' or type = 'warning') AND (TimeGenerated >='$recent')" | 
sort-object @{ expression = {$_.TimeWritten} } -descending |
select SourceName, Message | 
format-table @{Expression = { $_.SourceName};Width = 20;Label="SourceName"}, Message

Если вы используете C # (помеченный, но не упомянутый в вопросе), магия заключается в запросе get-wmiobject.

0 голосов
/ 08 октября 2008

Хорошо, решение, которое я придумал, использует System.Diagnostics.EventLog и просто перебирает все события, чтобы отфильтровать те, которые мне нужны. Я думаю, это просто, я просто подумал, что был бы более эффективный интерфейс для этого. Любые предложения или улучшения очень приветствуются!

Я создал метод для возврата записей журнала событий с определенного времени:

/// <summary>
/// Steps through each of the entries in the specified event log and returns any that were written 
/// after the given point in time. 
/// </summary>
/// <param name="logName">The event log to inspect, eg "Application"</param>
/// <param name="writtenSince">The point in time to return entries from</param>
/// <param name="type">The type of entry to return, or null for all entry types</param>
/// <returns>A list of all entries of interest, which may be empty if there were none in the event log.</returns>
public List<EventLogEntry> GetEventLogEntriesSince(string logName, DateTime writtenSince, EventLogEntryType type)
{
    List<EventLogEntry> results = new List<EventLogEntry>();
    EventLog eventLog = new System.Diagnostics.EventLog(logName);
    foreach (EventLogEntry entry in eventLog.Entries)
    {
        if (entry.TimeWritten > writtenSince && (type==null || entry.EntryType == type))
            results.Add(entry);
    }
    return results;
}

В моем тестовом классе я храню метку времени:

private DateTime whenLastEventLogEntryWritten;

и во время настройки теста я установил метку времени, когда была записана последняя запись в журнале событий:

EventLog eventLog = new EventLog("Application");
whenLastEventLogEntryWritten = eventLog.Entries.Count > 0 ? 
     eventLog.Entries[eventLog.Entries.Count - 1] : DateTime.Now;

В конце теста я проверяю, не было ли ошибок в журнале событий:

Assert.IsEmpty(GetEventLogEntriesSince("Application",
                                       whenLastEventLogEntryWritten,  
                                       EventLogEntryType.Error), 
               "Application Event Log errors occurred during test execution.");
...