人々が依存性注入プラットフォームを使用してログを注入する方法についてもっと知りたいと思っています。以下のリンクと私の例は log4net と Unity を参照していますが、必ずしもこれらのいずれかを使用するわけではありません。依存性注入/IOC については、プロジェクトの残りの部分 (大規模) が落ち着いている標準であるため、おそらく MEF を使用します。
私は依存性注入/ioc に非常に慣れておらず、C# と .NET にもかなり慣れていません (過去 10 年ほど VC6 と VB6 を使用した後、C#/.NET でプロダクション コードをほとんど作成していません)。さまざまなロギング ソリューションについて多くの調査を行ってきたので、それらの機能セットについては十分に理解できていると思います。私は、1 つの依存関係を注入する (または、より「正しく」、1 つの依存関係の抽象化されたバージョンを注入する) 実際のメカニズムに十分に精通していません。
ロギングおよび/または依存性注入に関連する他の投稿を見たことがあります: 依存性注入およびロギング インターフェイス
私の質問は、「ioc ツール yyy を使用してロギング プラットフォーム xxx を挿入するにはどうすればよいですか?」とは特に関係ありません。むしろ、ロギング プラットフォームのラッピング (常に推奨されているわけではありませんが、よくあることです) と構成 (つまり app.config) を人々がどのように処理しているかに興味があります。たとえば、log4net を例として使用すると、(app.config で) 多数のロガーを構成し、次のようなコードを使用する標準的な方法でそれらのロガーを (依存性注入なしで) 取得できます。
private static readonly ILog logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
別の方法として、ロガーの名前がクラスではなく機能領域である場合は、次のようにすることができます。
private static readonly ILog logger = LogManager.GetLogger("Login");
private static readonly ILog logger = LogManager.GetLogger("Query");
private static readonly ILog logger = LogManager.GetLogger("Report");
したがって、私の「要件」は次のようなものになると思います。
製品のソースをロギング プラットフォームに直接依存しないようにしたいと考えています。
特定の名前付きロガー インスタンス (おそらく、同じ名前付きインスタンスのすべてのリクエスター間で同じインスタンスを共有する) を、何らかの依存性注入 (おそらく MEF) によって直接的または間接的に解決できるようにしたいと考えています。
これを難しい要件と呼ぶかどうかはわかりませんが、必要に応じて名前付きロガー (クラス ロガーとは異なる) を取得できるようにしたいと考えています。たとえば、クラス名に基づいてクラスのロガーを作成する場合がありますが、1 つのメソッドには、個別に制御したい特に重い診断が必要です。言い換えれば、1 つのクラスを 2 つの個別のロガー インスタンスに「依存」させたいと思うかもしれません。
番号 1 から始めましょう。ラップするのが良いかどうかについて、主にここでスタックオーバーフローに関する多くの記事を読みました。上記の「ベスト プラクティス」リンクを参照し、jeffrey hantinのコメントにアクセスして、log4net をラップすることがなぜ悪いのかについての 1 つのビューを参照してください。ラップした場合 (そして効果的にラップできた場合) は、直接依存性の注入/除去の目的で厳密にラップしますか? それとも、log4net app.config 情報の一部またはすべてを抽象化しようとしますか?
System.Diagnostics を使用したいとしましょう。おそらく、TraceSource に基づいて、インターフェイス ベースのロガーを実装したいと思います (「共通の」ILogger/ILog インターフェイスを使用することもあるでしょう)。インターフェイスを実装し、たとえば TraceSource を使用して、System.Diagnostics の app.config 情報をそのまま使用しますか?
このようなもの:
public class MyLogger : ILogger
{
private TraceSource ts;
public MyLogger(string name)
{
ts = new TraceSource(name);
}
public void ILogger.Log(string msg)
{
ts.TraceEvent(msg);
}
}
そして、次のように使用します。
private static readonly ILogger logger = new MyLogger("stackoverflow");
logger.Info("Hello world!")
番号 2 に移ります ... 特定の名前付きロガー インスタンスを解決するにはどうすればよいですか? 選択したロギング プラットフォームの app.config 情報をそのまま利用する必要がありますか (つまり、app.config の命名スキームに基づいてロガーを解決します)? では、log4net の場合、LogManager を「注入」する方がよいでしょうか (これは静的オブジェクトであるため、これは不可能であることに注意してください)。LogManager (これを MyLogManager と呼びます) をラップし、それに ILogManager インターフェイスを与えてから、MyLogManager.ILogManager インターフェイスを解決することができます。私の他のオブジェクトは、ILogManager (実装されているアセンブリからのエクスポート) に依存関係 (MEF 用語でのインポート) を持つことができます。これで、次のようなオブジェクトを持つことができます。
public class MyClass
{
private ILogger logger;
public MyClass([Import(typeof(ILogManager))] logManager)
{
logger = logManager.GetLogger("MyClass");
}
}
ILogManager が呼び出されるたびに、log4net の LogManager に直接委任されます。または、ラップされた LogManager は、app.config に基づいて取得した ILogger インスタンスを取得し、それらを (?) MEF コンテナーに名前で追加できます。その後、同じ名前のロガーが要求されると、ラップされた LogManager に対してその名前が照会されます。ILogger が存在する場合は、その方法で解決されます。これが MEF で可能である場合、そうするメリットはありますか?
この場合、実際には ILogManager だけが「注入」され、log4net が通常行う方法で ILogger インスタンスを配布できます。このタイプの (本質的にはファクトリの) インジェクションは、名前付きロガー インスタンスのインジェクションと比べてどうですか? これにより、log4net (または他のロギング プラットフォーム) の app.config ファイルをより簡単に活用できます。
次のように、MEF コンテナーから名前付きインスタンスを取得できることを知っています。
var container = new CompositionContainer(<catalogs and other stuff>);
ILogger logger = container.GetExportedValue<ILogger>("ThisLogger");
しかし、名前付きインスタンスをコンテナーに入れるにはどうすればよいでしょうか? ILogger のさまざまな実装を持つことができる属性ベースのモデルについては知っていますが、それぞれに (MEF 属性を介して) 名前が付けられていますが、それは実際には役に立ちません。ロガー (すべて同じ実装) を名前でリストし、MEF が読み取ることができる app.config (またはその中のセクション) のようなものを作成する方法はありますか? 基礎となるapp.configを介して名前付きロガーを解決し、解決されたロガーをMEFコンテナーに挿入する中央の「マネージャー」(MyLogManagerなど)が存在する可能性がありますか? このようにして、同じ MEF コンテナーにアクセスできる他の誰かが利用できるようになります (ただし、log4net の app.config 情報の使用方法に関する MyLogManager の知識がなくても、
これはすでにかなり長くなりました。首尾一貫していることを願っています。ロギング プラットフォーム (log4net、NLog、または System.Diagnostics 上に構築されたもの (できれば薄い) を検討している可能性が最も高い) をアプリケーションにどのように依存関係に注入したかについて、具体的な情報を自由に共有してください。
「マネージャー」を注入して、ロガーインスタンスを返すようにしましたか?
独自の構成セクションまたは DI プラットフォームの構成セクションに独自の構成情報の一部を追加して、ロガー インスタンスを直接注入することを容易/可能にしましたか (つまり、依存関係を ILogManager ではなく ILogger にします)。
ILogManager インターフェイスまたは名前付きの ILogger インスタンスのセットを含む静的またはグローバル コンテナーを使用する場合はどうでしょうか。そのため、従来の意味で (コンストラクター、プロパティ、またはメンバー データを介して) 注入するのではなく、ログの依存関係はオンデマンドで明示的に解決されます。これは、依存性を注入するための良い方法ですか、それとも悪い方法ですか。
明確な答えがある質問のようには見えないため、これをコミュニティ wiki としてマークします。違うと感じた人は遠慮なく変更してください。
助けてくれてありがとう!