1

一定期間にイベントがイベント ログに記録されているかどうかを確認する最も簡単な方法は何ですか?

一連の自動化されたテスト手順を実行し、関心のないいくつかのソースを無視して、アプリケーション イベント ログにエラーが記録されたかどうかを確認したいと考えています。 System.Diagnostics.EventLog を使用して、エントリを確認できます。コレクションですが、このシナリオではあまり役に立たないようです。たとえば、イベント ログが古いエントリを削除している場合、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.
  // ...
}
4

5 に答える 5

5

良き Wiki 市民であり、完成に向けて努力するためだけに、他の方法があります。テストスイートの一部として社内でのみ実行されるものにとっては完全にやり過ぎなので、以前は提案しませんでした.タイトルで簡単なものが欲しいと言っていました.

ただし、出荷コードで発生するイベントを確認する必要がある場合は、読み進めてください。信じられないかもしれませんが、この時点で3 つの異なる Windows API が存在します。

NotifyChangeEventLog()

この種の元の API はNotifyChangeEventLog()と呼ばれ、Windows 2000 以降でサポートされていました。基本的には、WIN32 イベント ログ APIを使用してイベント ログを開き、他の API から提供されたハンドルを使用してこの API を呼び出します。 API とイベント ハンドル。確認する新しいイベント ログ エントリがあると、Windows はイベントを通知します。

私自身、この API を使用したことはありません。私の関心のほとんどはリモート イベント ログ アクセスであり、この API は明示的にリモート ログをサポートしていないためです。ただし、これが属する残りの API セットでは、適切な権限があれば、リモート ログを順番に読み取ることができます

Windows 管理インストルメンテーション

2 番目の方法は、Windows Management Instrumentation APIを使用することです。これは、ローカル ログとリモート ログの両方をサポートします。これは、Windows に数年前から存在する COM/DCOM ベースの API であり、.NET Framework ではSystem.Management名前空間に適切に実装されています。基本的に行うことは、 Win32_NTLogEventの型 (WMI 型システム内の意味) の新しい WMI オブジェクトの出現を探すEventQueryを作成することです。これらの外観は、新しいイベント ログ エントリを示し、ほぼリアルタイムで表示されます。これらのオブジェクトの属性には、ログ エントリの詳細がすべて含まれています。MSDNマガジンの記事ですそれは、Visual Studio でこのようなものをいじることについて話しています。

繰り返しますが、これはテスト アプリケーションにとってはやり過ぎであり、既存のソリューションよりもはるかに多くのコードが必要になります。しかし、何年も前に、この API の DCOM フレーバーを使用してネットワーク上のすべてのサーバーからイベント ログを収集し、特定のサーバーにアラートを出すことができるネットワーク管理アプリケーション用のサブシステムを作成しました。それはかなり滑らかで、ほぼリアルタイムでした。これを DCOM を使用して C++ で実装する場合は、マルチスレッド アパートメントと、リモート サーバーへの接続がアップまたはダウンしたかどうかを検出するための多くの毛むくじゃらのロジックに対処する準備をしてください。

Windows Vista イベント ログ

Windows Vista (および Server 2008) には、イベント ログとトレースに関連するまったく新しい API スイートがあります。新しいイベント ログは、ここに記載されています。イベントをサブスクライブできる EvtSubscribe という API があるようです。私はこの API を使用したことがないので、その長所と短所についてコメントすることはできません。

于 2008-10-08T16:08:49.353 に答える
3

そうは言っても、実際にはテスト アプリケーションでも非常に簡単で、.NET Framework 固有の答えがあります。

テストを開始する前に EventLog を開き、イベント ハンドラーをEventLog.EntryWrittenイベントにサブスクライブする必要があります。これは、.NET が NotifyChangeEventLog() Win32 API を公開する方法です。

現在のロジックをGetEventLogEntriesSince()イベント ハンドラーに移動しますが、イベントをリストに追加して返すのではなく、実行の最後にどこかから取得できるリストにイベントを保存します。Entryプロパティを介して、渡された EntryWrittenEventArgs 引数からログ エントリの内容を取得できます。

于 2008-10-08T16:53:38.293 に答える
1

System.Diagnostics.EventLogクラスは、これを行う正しい方法です。

あなたの主な異議は、場合によってはログが古いエントリを削除できるということです。しかし、これはソフトウェア テストのシナリオだとおっしゃっています。ログにすべてのエントリを含めるのに十分な大きさがあり、テスト中に古いエントリが削除されないように、テスト システムを構成できませんか?

于 2008-10-08T12:56:52.203 に答える
0

この 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 クエリにあります。

于 2008-10-08T17:02:30.617 に答える
0

私が思いついた解決策は、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.");
于 2008-10-08T13:21:34.447 に答える