最近、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}")
その結果、名前空間とクラスがログに追加され、メソッドのみが欠落しています。
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
ロガー構成では、 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();
しかし、正直なところ、メソッド名をログに記録したかどうかは思い出せません。
組み込みのロガーファクトリを使用している場合、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メソッドがロガーで呼び出されると、プロパティはコンテキストから削除され、他のロギング呼び出しを汚染しません。