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 番目の例を使用すると、Logger はスタック トレースを作成して呼び出し元を確認する必要があります。そうしないと、コードは常に呼び出し元を渡す必要があります。クラスごとのロガー スタイルでもこれを行うことができますが、呼び出しごとに 1 回ではなく、クラスごとに 1 回実行することで、深刻なパフォーマンスの問題を解消できます。
この選択にはいくつかの理由があります。
NLog の場合、パフォーマンス上の利点もあります。ほとんどのユーザーが使用します
Logger logger = LogManager.GetCurrentClassLogger()
スタック トレースから現在のクラスを検索すると、ある程度の (ただしそれほどではない) パフォーマンスが必要になります。
ほとんどの場合、クラスの名前がロガーの適切な名前になります。ログ ファイルをスキャンすると、ログ メッセージが表示され、それをコード行に直接関連付けることができます。
これが最善の方法ではない良い例は、Hibernate の SQL ログです。「Hibernate.SQL」などの名前の共有ロガーがあり、多くの異なるクラスが生の SQL を単一のロガー カテゴリに書き込みます。
2 つの理由がすぐに思い浮かびます。
開発の観点からは、毎回ロガー オブジェクトを作成する必要がない場合が最も簡単です。一方、そうせずにリフレクションを使用して動的に作成すると、パフォーマンスが低下します。これを解決するには、動的に非同期でロガーを作成する次のコードを使用できます。
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);
}
}
}
おそらく、カプセル化を壊さずにクラスにのみ表示されるメソッドをログに記録できるようにしたいため、これにより、ログ機能を壊さずに別のアプリケーションでクラスを簡単に使用できるようになります。
名前空間またはクラスごとにアペンダーを簡単に構成できます。