web-dev-qa-db-ja.com

C#ASP.NET Core Serilogがログにクラス名とメソッドを追加

最近、ASP.Net Coreプロジェクトにロギングを追加しました。現在、ログは次の形式で.txtファイルに書き込みます。

{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] {Message} {NewLine} {Exception}

例えば:

2017-11-30 13:58:22.229 +01:00【お知らせ】データベースにアイテムを作成しました。

これは問題ありませんが、ログに記録するクラスの名前と、この.txtファイルに対して実行されているメソッドが必要です。たとえば、クラスAがメソッドBを使用してデータベースに何かを書き込み、これをログに記録する場合、次のようなものを見たいと思います

ClassA.MethodB:データベースに作成されたアイテム

ログを記録するすべてのクラスのLoggerがコンストラクターに挿入されます

public class ClassA
{
    private readonly ILogger _log;

    public ClassA(ILogger<ClassA> log){
        _log = log;
    }

    public void AddItemToDb(Item item){
        //Add item
        //On success: 
        _log.LogInfo("Added item to db.");
    }
}

私は現在Serilogを使用しており、次のLoggerConfigurationを使用しています:

var logger = new LoggerConfiguration()
    .MinimumLevel.Verbose()
    .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
    .WriteTo.RollingFile(Configuration.GetValue<string>("LogFilePath") + "-{Date}.txt", LogEventLevel.Information)
    .CreateLogger();

クラスとメソッドをログに追加するにはどうすればよいですか?

編集

次のように、.WriteTo.Rollingfile()メソッドにカスタムoutputTemplateを追加しました。

"{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}) {Message}{NewLine}{Exception}")

その結果、名前空間とクラスがログに追加され、メソッドのみが欠落しています。

9
Jeroen

Jordan's 回答と this 回答の組み合わせを使用して、この問題を解決しました。

enrichment を介してlogcontextを追加することでLogger構成を変更し、プロパティ 'method'を出力テンプレートに追加しました:

var logger = new LoggerConfiguration()
    .MinimumLevel.Verbose()
    .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
    .Enrich.FromLogContext()
    .WriteTo.RollingFile(Configuration.GetValue<string>("LogFilePath") + "-{Date}.txt", LogEventLevel.Information, 
        outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{Method}) {Message}{NewLine}{Exception}")
    .CreateLogger();

Enrich.FromLogContextでは、LogContext.PushProperty()メソッドを使用して、プロパティをoutputTemplateにプッシュできます。この場合は 'method'プロパティ(outputTemplateの{Method}に注意)。

asyncメソッドの例:

using (LogContext.PushProperty("Method", new LogAsyncMethods().GetActualAsyncMethodName()))
{
    _log.LogInformation("Log message.");
}

GetActualAsyncMethodName()は次のように記述されています。

public static string GetActualAsyncMethodName([CallerMemberName]string name = null) => name;

これは、asyncメソッドでは正常に機能します。

non-asyncメソッドの場合、これは正常に機能します。

using (LogContext.PushProperty("Method", System.Reflection.MethodBase.GetCurrentMethod().Name))
{
    _log.LogInformation("Changing of customer name succeeded");
}

これで、メソッド名がログに表示されます。 SourceContextは名前空間とクラスを追加し、「。{Method}」を追加することで次の結果になります。

Namespace.ClassName.MethodName

8
Jeroen

ロガー構成では、 LogContextでエンリッチ する必要があります。

var logger = new LoggerConfiguration()
    .MinimumLevel.Verbose()
    .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
    .Enrich.FromLogContext()
    .WriteTo.RollingFile(
        Configuration.GetValue<string>("LogFilePath") + "-{Date}.txt", 
        LogEventLevel.Information)
    .CreateLogger();

しかし、正直なところ、メソッド名をログに記録したかどうかは思い出せません。

0
Jordan S. Jones

組み込みのロガーファクトリを使用している場合、SeriLogをASP.NET Coreで使用すると、完全な.NET F/Wよりも少し遅れます。これを解決するには、次のような一連の拡張メソッドを記述します。

    public static class LoggerExtensions
    {
        public static void LogAppError<T>(this ILogger<T> logger, EventId eventId, Exception exception, string message,
            [CallerMemberName] string memberName = "",
            [CallerFilePath] string sourceFilePath = "",
            [CallerLineNumber] int sourceLineNumber = 0)
        {
            using (var prop = LogContext.PushProperty("MemberName", memberName))
            {
                LogContext.PushProperty("FilePath", sourceFilePath);
                LogContext.PushProperty("LineNumber", sourceLineNumber);
                logger.LogError(eventId, exception, message);
            }
        }
}

あなたからの呼び出しは次のようなコードです:

public PeopleController(ILogger<PeopleController> logger)
{
    _logger.LogAppError("Ctor");
}

これは、次のような出力テンプレートがあることを前提としています。

private static string outputTemplate =
    @"[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}Message:{Message}{NewLine}in method {MemberName} at {FilePath}:{LineNumber}{NewLine}{Exception}{NewLine}";

拡張メソッドを呼び出すと、メソッド、ファイル、および行番号がそれぞれの属性によって取得されます。プロパティをLogContextにプッシュすると、そのプロパティとその後に追加されたプロパティを削除するIDisposableが返されます。したがって、usingステートメントで呼び出しをラップすることにより、LogErrorメソッドがロガーで呼び出されると、プロパティはコンテキストから削除され、他のロギング呼び出しを汚染しません。

0
Skimedic