ログ出力規則の一環でLogger束縛の種類を考察しました。サンプルコードではlog4netを使っていますが、どのようなロギングフレームワークにも通用する分類だと思います。
考察の結果、Loggerが関連付くのは識別子, スレッド, インスタンス, コード(ネームスペース, クラス, 関数, ブロック等)のいずれかになりそうです。それぞれ、識別子束縛Logger, スレッド束縛Logger, インスタンス束縛Logger, コード束縛Loggerと呼ぶことにします。
Loggerを生成する際にはLoggerが何に関連付いているかを明確にすることが重要です。最適なLogger生成のために参考にしてください。
以下に各Logger束縛の特徴,用途,サンプルコードを示します。
識別子束縛Logger
- 特徴
- システムで定めた識別子に束縛されるLoggerです。識別子とLoggerの対応をMapなどでとる必要があります。log4j, log4netにおいてはLogger名に識別子の機能をもたせることもできます。ただし、生成処理がいたるところで発生する傾向があるため、コードが煩雑になりがちです。できるだけ利用しないほうがよいでしょう。ジョブやタスクがスレッドに束縛される場合はスレッド束縛Loggerの利用を、インスタンスに束縛される場合はインスタンス束縛Loggerの利用をお勧めします。
- 用途
- ジョブやタスクといったシステム上意味のある単位でログを収集したい場合に利用します。
- サンプルコード
-
ILog tLog = LogManager.GetLogger("Job." + tJob.Id); // Logger名を識別子とした例
スレッド束縛Logger
- 特徴
- スレッドに束縛されるLoggerです。寿命の管理が難しく、ASP.NETでの利用は注意が必要です。
- 用途
- ジョブやタスクといった処理の流れ単位でログを収集したい場合に利用します。
- サンプルコード
-
public class HogeHoge { [ThreadStatic] private static ILog LOG_THREAD; public static ILog LOG { get { if(LOG_THREAD == null) // なければ生成する戦略 { LOG_THREAD = LogManager.GetLogger(Thread.CurrentThread.Name); } return LOG_THREAD; } } }
インスタンス束縛Logger
- 特徴
- インスタンスに束縛されるLoggerです。ログ収集単位(Jobクラスなど)を表すインスタンスからLoggerが取得できるようにすると利用が楽です。
- 用途
- ジョブやタスクといったシステム上意味のある単位でログを収集したい場合に利用します。
- サンプルコード
-
- 宣言コード例
-
public class Job { public readonly ILog Log; public Job(string aId) { Log = LogManager(LogManager.GetLogger("Job." + aId)); } }
- 利用コード例
-
tJob.Log.Info("ジョブにかかわる何かをした。");
コード束縛Logger
- 特徴
- ネームスペース束縛Logger, クラス束縛Logger, 関数束縛Logger, ブロック束縛Loggerの総称です。C#やJavaを使う限り、コード束縛Loggerは結局クラスにスタティック宣言することになるため、できるだけクラス束縛Loggerのみを利用したほうがよいでしょう。
- 用途
- あるコードのまとまり単位でログを収集したい場合に利用します。
- サンプルコード
-
public class HogeHoge { private static readonly ILog LOG_NamespaceA = LogManager.GetLogger("NamespaceA"); // ネームスペース束縛Logger宣言 private static readonly ILog LOG_FuncB = LogManager.GetLogger("FuncB"); // 関数束縛Logger宣言 private static readonly ILog LOG_FuncB_BlockC = LogManager.GetLogger("FuncB.BlockC"); // ブロック束縛Logger宣言 }
クラス束縛Logger
- 特徴
- クラスに束縛されるLoggerです。コード束縛Loggerの一種ですが、使い勝手がよいため一番よく使われています。C#やJavaではクラス宣言内でprivateクラス束縛変数に代入して初期化します。
- 用途
- クラス単位でログを収集したい場合に利用します。
- サンプルコード
-
public class HogeHoge { private static readonly ILog LOG = LogManager.GetLogger(typeof(HogeHoge)); }
参考URL
- ThreadStaticAttributeクラス
ThreadStaticAttribute でマークしたフィールドの初期値を指定しないでください。このような初期化は、クラスのコンストラクタの実行時に一度だけ行われるもので、関係するスレッドは 1 つだけです。初期値を指定しなければ、フィールドが、値型の場合はその既定値に、参照型の場合は null参照 (Visual Basic では Nothing) に初期化されることを前提にできます。
- ThreadStatic, CallContext and HttpContext in ASP.Net
The problems with [ThreadStatic] are well documented, but to summarize:
* Field initalizers only fire on the first thread
* ThreadStatic data needs explicit cleaning up (eg in EndRequest), because whilst the Thread’s reachable, the ThreadStatic data won’t be GC’d so you might be leaking resources.
* ThreadStatic data is only any good within a request, because the next request might come in on a different thread, and get someone else’s data.