NLogのドキュメントによると:
ほとんどのアプリケーションは、クラスごとに1つのロガーを使用します。ここで、ロガーの名前はクラスの名前と同じです。
これは、log4netが動作するのと同じ方法です。なぜこれが良い習慣なのですか?
回答:
log4netでは、クラスごとに1つのロガーを使用すると、ログメッセージのソース(つまり、クラスがログに書き込む)を簡単にキャプチャできます。クラスごとに1つのロガーがなく、代わりにアプリ全体に1つのロガーがある場合は、ログメッセージの送信元を知るために、より多くのリフレクショントリックに頼る必要があります。
以下を比較してください。
using System.Reflection;
private static readonly ILog _logger =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public void SomeMethod()
{
_logger.DebugFormat("File not found: {0}", _filename);
}
Logger.DebugFormat("File not found: {0}", _filename); // Logger determines caller
-- or --
Logger.DebugFormat(this, "File not found: {0}", _filename); // Pass in the caller
2番目の例を使用すると、ロガーはスタックトレースを作成して、誰が呼び出しているかを確認する必要があります。そうしないと、コードは常に呼び出し元に渡される必要があります。クラスごとのロガースタイルでもこれを行うことができますが、呼び出しごとに1回ではなく、クラスごとに1回行うことができ、深刻なパフォーマンスの問題を排除できます。
NLogで「ファイルごとのロガー」を使用する利点:名前空間とクラス名でログを管理/フィルタリングできる可能性があります。例:
<logger name="A.NameSpace.MyClass" minlevel="Debug" writeTo="ImportantLogs" />
<logger name="A.NameSpace.MyOtherClass" minlevel="Trace" writeTo="ImportantLogs" />
<logger name="StupidLibrary.*" minlevel="Error" writeTo="StupidLibraryLogs" />
<!-- Hide other messages from StupidLibrary -->
<logger name="StupidLibrary.*" final="true" />
<!-- Log all but hidden messages -->
<logger name="*" writeTo="AllLogs" />
NLoggerには、これを行うための非常に便利なコードスニペットがあります。nlogger
スニペットは、次のコードを作成します。
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
したがって、キーストロークはわずかで、クラスごとにロガーがあります。ロガーの名前として名前空間とクラス名を使用します。クラスロガーに別の名前を設定するには、次を使用できます。
private static NLog.Logger logger = NLog.LogManager.GetLogger("MyLib.MyName");
また、@ JeremyWiebeが言ったように、メッセージをログに記録しようとしているクラスの名前を取得するためにトリックを使用する必要はありません。ロガーの名前(通常はクラスの名前)をファイルに簡単に記録できます。 (または他のターゲット)${logger}
レイアウトで使用する。
開発の観点からは、毎回ロガーオブジェクトを作成する必要がない場合が最も簡単です。一方、そうではなく、リフレクションを使用して動的に作成すると、パフォーマンスが低下します。これを解決するには、ロガーを動的に非同期で作成する次のコードを使用できます。
using NLog;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WinForms
{
class log
{
public static async void Log(int severity, string message)
{
await Task.Run(() => LogIt(severity, message));
}
private static void LogIt(int severity, string message)
{
StackTrace st = new StackTrace();
StackFrame x = st.GetFrame(2); //the third one goes back to the original caller
Type t = x.GetMethod().DeclaringType;
Logger theLogger = LogManager.GetLogger(t.FullName);
//https://github.com/NLog/NLog/wiki/Log-levels
string[] levels = { "Off", "Trace", "Debug", "Info", "Warn", "Error", "Fatal" };
int level = Math.Min(levels.Length, severity);
theLogger.Log(LogLevel.FromOrdinal(level), message);
}
}
}
おそらく、カプセル化を壊すことなくクラスにのみ表示されるメソッドをログに記録できるようにしたいため、これにより、ログ機能を壊すことなく、別のアプリケーションでクラスを簡単に使用できるようになります。
NLOGを使用している場合は、構成でcallsiteを指定できます。これにより、ロギングステートメントが配置されたクラス名とメソッドが記録されます。
<property name="CallSite" value="${callsite}" />
次に、ロガー名またはアセンブリ名に定数を使用できます。
免責事項:NLOGがこの情報を収集する方法がわかりません。私の推測は反映であるため、パフォーマンスを考慮する必要がある場合があります。NLOG v4.4以降を使用していない場合、非同期メソッドにはいくつかの問題があります。