5

私の API は、さまざまなタイプのコンシューマーによってアクセスされます。外部アプリケーションと Web インターフェイス経由のユーザーがあります。

例を挙げて説明します。つまり、メソッド呼び出しで、誰が、または何がアクセスしたかをログに記録したいと思います。

外部アプリケーションの場合、次のようにログに記録したいと思います (テンプレートを使用):

"[{Caller}] {Timestamp:HH:mm:ss} [{Level}] (RequestId:{RequestId} | Key:{Key} | AppVersion:{Version}) {Message}{NewLine}{Exception}"

ユーザーがトリガーしたアクションの場合、次のようなログを記録したいと思います。

"[{Caller}] {Timestamp:HH:mm:ss} [{Level}] FullName:{FullName} | Organization:{Organization} | AppVersion:{Version}) {Message}{NewLine}{Exception}"

両方のタイプのメソッド呼び出し元が からアクセスされますがThread.CurrentPrincipal.Identity、それぞれが異なるカスタム プロパティを使用して、異なるタイプの ID を実装します。

私のコードは次のようになります。

public void DoSomething()
{
    Log.Information("DoSomething called");
}

ロガーを次のように構成した場合:

var logger = new LoggerConfiguration()
                   .Enrich.WithProperty("Version", appVersion)
                   .Enrich.WithProperty("Caller", caller)
                   .Enrich.With(new MyEnricher())
                   .WriteTo.ColoredConsole(outputTemplate: "[{Caller}] {Timestamp:HH:mm:ss} [{Level}] FullName:{FullName} | Organization:{Organization} | AppVersion:{Version}) {Message}{NewLine}{Exception}")
                   .CreateLogger();

外部アプリケーション (スレッド ID) によってトリガーされて呼び出された場合、Key と RequestId は表示されません。

MyEnricher私はロガーに追加しましたが、次のようなものです:

public class MyEnricher : ILogEventEnricher
{
    public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
    {
        var identity = Thread.CurrentPrincipal.Identity;
        if (identity is ExternalIdentity)
        {
            var externalIdentity = Thread.CurrentPrincipal.Identity as ExternalIdentity;
            logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("Key", externalIdentity.Key));
            logEvent.AddOrUpdateProperty(propertyFactory.CreateProperty("RequestId", externalIdentity.RequestId));
        }
        else
        {
            var userIdentity = Thread.CurrentPrincipal.Identity as UserIdentity;

            logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("FullName", userIdentity.FullName));
            logEvent.AddOrUpdateProperty(propertyFactory.CreateProperty("Organization", userIdentity.OrganizationName));
        }
}

オンラインのドキュメントと例から把握できる限り、ロギング テンプレートは、実際に作成される前の、ロガーを構成する瞬間にのみ設定されます。エンリッチャーは読み取り専用 (getter のみ) であるため、LogEvent 経由でエンリッチャーにアクセスして変更できませんでした。

メッセージのフォーマットの可能性は認識していますが、これはこの特定のケースで探しているものではありません。

外部アプリへのアクセスについて、ログに表示したい最終結果は次のようなものです。

2016 年 1 月 17 日 10:11:42.524 [API] 10:11:40 [情報] (RequestId: 123 | キー: XXX-1 | AppVersion:1.2.1) DoSomething が呼び出されました

そして、ユーザーのためにログに記録されたとき:

2016 年 1 月 17 日 11:12:42.524 [WEB] 11:12:40 [情報] (FullName: Anonymous | Organization: MyOrg | AppVersion:1.2.1) DoSomething と呼ばれる

私の質問は、テンプレートにログインするために、さまざまなプロパティを持つさまざまな種類のイベントを (可能であれば) ログに記録 (およびログで確認) するにはどうすればよいですか? その場で実行時にテンプレートを操作することは可能ですか? 両方または他の多くの可能なイベント タイプからのすべての可能なトークンと、それらのプロパティが 1 か所で定義されたテンプレートを持ちたくありません (いずれかのケースでそれらの多くが空白になっています)。

4

1 に答える 1

6

例とはわずかに異なるフォーマットを受け入れることができる場合は、ここで分解を使用できます。

"[{Caller}] {Timestamp:HH:mm:ss} [{Level}] ({Principal}) {Message}{NewLine}{Exception}"

次に、エンリッチャーで:

public class MyEnricher : ILogEventEnricher
{
    public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
    {
        var identity = Thread.CurrentPrincipal.Identity;
        if (identity is ExternalIdentity)
        {
            var externalIdentity = Thread.CurrentPrincipal.Identity as ExternalIdentity;
            logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("Principal", new {
                externalIdentity.Key,
                externalIdentity.RequestId
            }, true));
        }
        else
        {
            var userIdentity = Thread.CurrentPrincipal.Identity as UserIdentity;
            logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("Principal", new {
                userIdentity.FullName,
                userIdentity.OrganizationName
            }, true));
        }
    }
}

true(匿名オブジェクトのシリアル化をトリガーすることに注意してください。)

これにより、プリンシパルのさまざまなプロパティがキーと値のペアの構文で出力されます。

それ以外の場合は、カスタムITextFormatterを使用して (Serilog のコードに基づいてDisplayFormatter) 実行する方法です。ColoredConsoleカスタム テキスト フォーマッタは受け入れませんが、次のようになります。

WriteTo.Sink(new RollingFileSink(@"Logs\app-{Date}.txt", formatter))

通過できるようになります。

于 2016-01-19T11:05:27.853 に答える