5

だから私はこれについて多くの研究をしましたが、「はい、それ」と言った答えは見つかりませんでした. 知識豊富な StackOverflow の皆さんが私を助けてくれることを願っています。

いくつかの異なるシナリオでこの問題に遭遇しました。C# アプリがあり、ログに記録したい重要なものがあるとします。

public class MyClass
{
    ... 

    public void ImportantMethod()
    {
        DoInterestingThing();

        var result = SomethingElseImportant();
        if (result == null)
        {
            logger.Log("I wasn't expecting that. No biggie.");
            return;
        }

        MoreInterestingStuff(); 
}

私が興味を持っているのは、どこloggerから取得するかです。

私が見ているように、私にはいくつかのオプションがあります。

  1. コンストラクターで MyClass に注入します。
  2. グローバルに利用可能なサービス ロケーターを使用して取得します。
  3. メソッド デコレーターと AOP を使用して、ログを記録します。

これらはどれも素晴らしいオプションのようには見えません。#3 は、メソッド呼び出し、入力パラメーター、および/またはスローされた例外の単純なトレースを行うだけでなく、ビジネス ロジックの途中でログを記録しているため、不可能に見えます。#2、単純に思えますが、単体テストは本当に難しいようです。もちろん、すべてを単体テストしたいと思います。#1 は問題なく動作しますが、ビジネス オブジェクト自体とは関係のないログ オブジェクトですべてのビジネス ロジックがごちゃごちゃになります。

上記のオプションのいずれかについて、代替案や考えはありますか? どうもありがとう!

編集:明確にするために、私はすでにDIの方法を知っており(Unityを使用しています)、優れたロギングフレームワークをすでに知っています(log4netを使用しています)。アプリケーション全体でアーキテクチャの意味でロギングを最もスマートな方法で使用する方法を考えてみてください。


* 編集 *

Mark Seeman の回答を解決策としてマークしました。アプリケーションを調べてみたところ、ロギング呼び出しのほとんどがデコレータと同じことを行っていることがわかりました。つまり、メソッドへのエントリ、スローされた例外をログに記録し、戻り値を終了します。

メソッド内で直接ログを記録する必要がある場合もありました。例は、何も返さないがException をスローしないメソッドで高速に失敗したい場合です。LogProviderそのような場合、名前付きログ インスタンスを取得する参照 a を保持するシングルトンがあります。コードは次のようになります。

private ILog logger = LogProviderFactory.Instance.GetLogger(typeof(Foo));

LogProviderFactory にはSetProvider、シングルトンを交換できるメソッドがあります。したがって、単体テストでは次のことができます。

// LogProviderFactory.Instance now is our mock
LogProviderFactory.SetProvider(MockLogProvider);

ロギング デコレータはシングルトンと同じ LogProvider (インジェクションによって取得) を使用するため、ロギングはシステム全体で統一されます。

したがって、最終的な解決策はほとんどがオプション 3 であり、ハイブリッド 2 でした (サービス ロケーター パターンですが、サービスはロケーターに「注入」されます)。

AOP

「アスペクト指向プログラミング」に関する限り、私は言語の限界に少しがっかりしました。AOP が将来のリリースで第一級市民として扱われることを願っています。

  • PostSharp を試しましたが、自分のマシンで正しく実行できませんでした。さらに、システムに PostSharp をインストールして使用する必要があるという大きな制限がありました (ソリューションに付属の dll などを呼び出すだけではありません)。
  • 私は LinFu を使用し、部分的に機能させることができました。ただし、いくつかの例で爆発しました。新しい 2.0 リリースはほとんど文書化されていないため、それがハードルでした。
  • ただし、Unity とのインターフェイス インターセプトは、そのままで問題なく機能するようです。ログに記録したいもののほとんどがインターフェイスを実装するクラスにあったことは幸運でした。
4

3 に答える 3

4

ロギング Decoratorを使用します。

于 2011-07-15T00:12:03.387 に答える
2

2 ビット:

(1) - 事前構築済みのロギング フレームワーク。

Log4Net が好きな人もいますが、私は EntLibs のファンです。これは、実際のロギングに関して大変な作業を行います。EntLibs のようなツールを使用すると、さまざまな種類のログ リポジトリ (データベース、メッセージ キュー、ローリング テキスト ファイルなど) にログを記録できます。また、カテゴリなどに基づいてさまざまなインスタンスにログを記録することもできます。それらは通常、高度に構成可能です。

(2) - ロギング フレームワークをラップするカスタム クラス。

したがって、「ロガー」はユーザーが作成するものであり、ロギング フレームワークを呼び出して実際のロギングを行います。

私がこのアプローチを気に入っている理由はいくつかあります。

  • カスタム ラッパーが別のアセンブリに入るときに、ロギング フレームワーク (#1) をアプリケーションの残りの部分から分離します。
  • 独自の Logging API を作成することで、ニーズに合ったメソッド シグネチャを定義し、それらを拡張することができます。
  • チームで作業している場合は、メソッド シグネチャを非常に使いやすくすることができます。これにより、ロギングの使用が難しすぎると言う根拠がなくなります。
  • ロギングの一貫性を保ちます。また、ログの一部として何も存在しないため、ファイル、コンソール、またはイベントログに書き込む「違法な」コードのコード検索を簡単に実行できます (すべてフレームワーク内にあります)。
  • 層ごとに特定のカスタム クラスを作成することで、実際のアプリケーション コードを作成する人が簡単に作業できるように、舞台裏で大量のデータを事前に取り込むことができます。重大度、優先度、デフォルトのイベント ID、カテゴリなどを設定できます。
  • アプリケーションの複雑さと成長の点で適切に拡張できます。小規模なアプリの場合は扱いが難しいように見えるかもしれませんが、時間の経過とともに成長し始めると、十分な余裕ができます.

これは、私が取り組んだプロジェクトの情報ログ クラスの例です。呼び出しが簡単な多数のパブリック メソッドと、フレームワークを呼び出す 1 つのプライベート メソッド (ConcreteLogInformation) があります。

public static void LogInformation(string title, string message)

public static void LogInformation(string title, Dictionary<string, object> extendedProperties)

public static void LogInformation(string title, int eventId, Dictionary<string, object> extendedProperties)

public static void LogInformation(string title, string message, Dictionary<string, object> extendedProperties)

public static void LogInformation(string title, string message, int eventId)

public static void LogInformation(string title, string message, int eventId, Dictionary<string, object> extendedProperties)

public static void LogInformation(string title, string message, int eventId, string category)

public static void LogInformation(string title, string message, int eventId, Dictionary<string, object> extendedProperties, string category)

private static void ConcreteLogInformation(string title, string message, int eventId, Dictionary<string, object> extendedProperties, string category)
于 2011-07-15T01:17:48.053 に答える
1

Ninject Contetual Binding ドキュメントの「ファクトリまたはファクトリ メソッドでリクエスト コンテキストを使用してコンテキスト バインディングを行う」セクションでは、(Ninjectese で) 次のようにして、コンテナを活用してクラスに適切なロガーを注入する例を示します。

Bind<ILog>().ToMethod( context => LogFactory.CreateLog( context.Request.Target.Type ) );

トレース タイプのものについては、Mark のインターセプトの記事で最良のアプローチが説明されています。

そして、@Mark Seemann の引用された記事をよく読んでから、賛成票を投じずに破棄するようお願いできますか。

于 2011-07-15T06:34:15.630 に答える