6

ロギングに関するアドバイスを探しています。Microsoft Enterprise Library 5.0Logger を内部的に使用するというラッパーを作成しました。現在、次の方法でログインできます。

Logger.Error(LogCategory.Server, "Some message with some state {0}", state);

私が直面している問題は、EventViewer のすべてのログが無関係であるように見えることです。たとえば、特定のクライアントからの要求の処理に由来するものなど、何らかの形で関連しているものもあります。

問題について詳しく説明しましょう。複数のクライアントからのリクエストを同時に処理し、それぞれが異なるパラメータ セットをサービス メソッドに渡す必要があるサービスに取り組んでいるとします。どのクライアントがどの種類のリクエストをどの一意に識別可能なパラメータで行っているかなど、リクエストを識別するために使用できるパラメータはほとんどありません。これらのパラメータは次のとおりです(コンテキスト情報を呼び出します):

  • サーバープロファイル ID
  • WebProfileId
  • リクエストID
  • セッション情報

これで、サービスはリクエストの処理を開始し、(ワークフローのように) 次々と処理を行いました。その過程で、 「file not found」「entry not found in DB」などのローカル1メッセージをログに記録していますが、すべてのログで上記の情報 (コンテキスト情報)を手動でログに記録したくはありません。ロガーは、ローカル メッセージをログに記録するたびにそれらを自動的にログに記録します。

Logger.Error(LogCategory.Server, "requested file not found");

そして、上記の呼び出しで「要求されたファイルが見つかりません」というメッセージとともにコンテキスト情報をログに記録して、メッセージをそのコンテキストに関連付けることができるようにします。

問題は、コンテキストを自動的にログに記録するロガー ラッパーをどのように設計すればよいかということです。すべての重要な情報がリクエストの最初に利用できるとは限らないため、サービスがリクエストを処理する過程でより具体的なコンテキスト情報を追加できるように、十分な柔軟性を持たせたいと考えています!

また、構成可能にしたいので、コンテキスト情報をログに記録せずにローカル メッセージをログに記録できます。:-)


1.ローカルメッセージとは、より具体的で、本質的にローカルなメッセージを意味します。対照的に、コンテキスト情報はグローバルメッセージであり、リクエストを処理するフロー全体にとって意味があると言えます。

4

2 に答える 2

4

これは、セットアップがかなり簡単な Enterprise Library を使用する 1 つのアプローチです。アクティビティ トレースを使用してグローバル コンテキストを保存し、拡張プロパティを使用してローカル コンテキストを保存できます。

例として、ラッパー クラスを使用せずにサービス ロケーターを使用してアプローチを示します。

var traceManager = EnterpriseLibraryContainer.Current.GetInstance<TraceManager>();

using (var tracer1 = traceManager.StartTrace("MyRequestId=" + GetRequestId().ToString()))
using (var tracer2 = traceManager.StartTrace("ClientID=" + clientId))
{
    DoSomething();
}

static void DoSomething()
{
    var logWriter = EnterpriseLibraryContainer.Current.GetInstance<LogWriter>();
    logWriter.Write("doing something", "General");

    DoSomethingElse("ABC.txt");
}

static void DoSomethingElse(string fileName)
{
    var logWriter = EnterpriseLibraryContainer.Current.GetInstance<LogWriter>();

    // Oops need to log
    LogEntry logEntry = new LogEntry()
    {
        Categories = new string[] { "General" },
        Message = "requested file not found",
        ExtendedProperties = new Dictionary<string, object>() { { "filename", fileName } }
    };

    logWriter.Write(logEntry);
}

構成は次のようになります。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
    </configSections>
    <loggingConfiguration name="" tracingEnabled="true" defaultCategory="General"
        logWarningsWhenNoCategoriesMatch="false">
        <listeners>
            <add name="Flat File Trace Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                fileName="trace.log" formatter="Text Formatter" traceOutputOptions="LogicalOperationStack" />
        </listeners>
        <formatters>
            <add type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                template="Timestamp: {timestamp}&#xA;Message: {message}&#xA;ActivityID: {activity}&#xA;Context: {category}&#xA;Priority: {priority}&#xA;EventId: {eventid}&#xA;Severity: {severity}&#xA;Title:{title}&#xA;Machine: {localMachine}&#xA;App Domain: {localAppDomain}&#xA;ProcessId: {localProcessId}&#xA;Process Name: {localProcessName}&#xA;Thread Name: {threadName}&#xA;Win32 ThreadId:{win32ThreadId}&#xA;Local Context: {dictionary({key} - {value}{newline})}"
                name="Text Formatter" />
        </formatters>
        <categorySources>
            <add switchValue="All" name="General">
                <listeners>
                    <add name="Flat File Trace Listener" />
                </listeners>
            </add>
        </categorySources>
        <specialSources>
            <allEvents switchValue="All" name="All Events" />
            <notProcessed switchValue="All" name="Unprocessed Category" />
            <errors switchValue="All" name="Logging Errors &amp; Warnings" />
        </specialSources>
    </loggingConfiguration>
</configuration>

これにより、次のような出力が得られます。

----------------------------------------
Timestamp: 1/16/2013 3:50:11 PM
Message: doing something
ActivityID: 5b765d8c-935a-445c-b9fb-bde4db73124f
Context: General, ClientID=123456, MyRequestId=8f2828be-44bf-436c-9e24-9641963db09a
Priority: -1
EventId: 1
Severity: Information
Title:
Machine: MACHINE
App Domain: LoggingTracerNDC.exe
ProcessId: 5320
Process Name: LoggingTracerNDC.exe
Thread Name: 
Win32 ThreadId:8472
Local Context: 
----------------------------------------
----------------------------------------
Timestamp: 1/16/2013 3:50:11 PM
Message: requested file not found
ActivityID: 5b765d8c-935a-445c-b9fb-bde4db73124f
Context: General, ClientID=123456, MyRequestId=8f2828be-44bf-436c-9e24-9641963db09a
Priority: -1
EventId: 0
Severity: Information
Title:
Machine: MACHINE
App Domain: LoggingTracerNDC.exe
ProcessId: 5320
Process Name: LoggingTracerNDC.exe
Thread Name: 
Win32 ThreadId:8472
Local Context: filename - ABC.txt

----------------------------------------

注意事項:

  • トレースを使用しているため、アクティビティの関連付けに使用できる .NET アクティビティ ID を無料で取得できます。もちろん、独自のコンテキスト情報 (カスタム リクエスト ID、クライアント ID など) も使用できます。
  • Enterprise Library はトレースの「操作名」をカテゴリとして使用するため、logWarningsWhenNoCategoriesMatch="false" を設定する必要があります。そうしないと、警告メッセージが次々と表示されます。
  • このアプローチの欠点は、パフォーマンスかもしれません (しかし、私は測定していません)。

グローバル コンテキスト (この実装ではトレース) を無効にする場合は、構成ファイルを編集して、tracingEnabled="false" を設定するだけです。

これは、組み込みの Enterprise Library 機能を使用して目的を達成するためのかなり簡単な方法のようです。

考慮すべき他のアプローチは、非常に洗練された何らかのインターセプト (カスタム LogCallHandler) を潜在的に使用することです (ただし、それは既存の設計に依存する可能性があります)。

カスタム実装を使用してコンテキストを収集および管理する場合は、スレッド コンテキストごとにTrace.CorrelationManagerを使用することを検討できます。IExtraInformationProviderを作成して拡張プロパティ ディクショナリ を作成することも検討できます(例については、 Enterprise Library 3.1 Logging Formatter Template - Include URL Requestを参照してください)。

于 2013-01-16T16:02:42.267 に答える
1

免責事項: Microsoft の技術スタックの詳細はわかりません。

この場合に私がすることは、次のようなものです。

基本的に「キー」がリクエストの一意に意味のある識別子である一種のハッシュマップであるシングルトンを実装します(サーバーインスタンスレベルでは、アプリがクラスターにデプロイされている場合はグローバルシングルトンである必要はありません)処理。Java では、thread-id を使用します (スレッド プールからスレッドをディスパッチしてリクエストを処理すると仮定します)。これが不可能な場合/あなたのケースでは意味がない場合は、リクエスト ID を使用する必要があります (ただし、この場合、ログ マネージャーに浸透させる必要がありますが、私の考えでは、本質的に利用可能なものを使用することです)スレッド自体)。

Hashmap の「値」は一連のデータになります。あなたの場合は、ServerProfileId、WebProfileId、RequestId (すでにキーでない限り)、SessionInfo です。これにより、logmanager は条件付きでこれらを取得し、重要な部分を取得できます。特定のログ イベント。

そのため、リクエスト管理の開始時にリクエスト状態へのグローバルに使用可能な参照を作成し、必要に応じてロギング マネージャーがリクエスト状態を取得できるようにします

もちろん、ハッシュマップが正しく管理されていることを確認する必要があります (リクエストが破棄された後に状態を削除することによって)。

于 2013-01-16T15:03:10.483 に答える