4

コードの任意の部分から呼び出すことができる標準インターフェイスを実装する独自の Logging クラスを (C# で) 作成したいと考えています。

私の考えは、複数の Log クラスに Logger インターフェースを実装させ、それぞれが特定のログの宛先に対応するようにすることです。データベーステーブルなどへのロギングを実装します。

さらに、各ロガー クラスは、ネストされたロガー クラスまたはチェーンされたロガー クラスを持つことができるため、アプリケーション コードから Log() メソッドを 1 回呼び出すだけで、メッセージを複数の宛先に記録できます。1 回の呼び出しでフォームのファイルとテキスト ボックスにログを記録します。

私が直面している困難はこれです:

通常、実行中のログ ファイル (デバッグに必要なすべてのログ メッセージが含まれます)、レビュー ログ ファイル (ユーザーが確認するログ メッセージ、またはユーザーの操作が必要なログ メッセージのみが含まれます)、複数行のテキスト ボックスにログを記録します。画面 (すべてのログ メッセージを複製してユーザーに進行状況を示す) と、別の複数行テキスト ボックス (ユーザーが確認する必要があるメッセージのみをログに記録する) です。

logger.Log(message) を呼び出すと、一部のメッセージが特定のログの宛先に適用されない場合があります。たとえば、一部のメッセージは、実行中のログ ファイルまたは進行状況のテキスト ボックスにのみ記録され、ユーザー レビューのテキスト ボックスには記録されないことがあります。その逆も同様です。

1 つの関数呼び出しで必要なすべての宛先にログインできるようにロガーが連鎖されるため、特定のロガーは、ログ メッセージが自分宛てのものではないことをどのように識別し、ログ メッセージを無視できるでしょうか?

サンプル ログ インターフェイスは次のとおりです。

public interface Logger
{
    public void Log(string msg);
    public void Log(string msgType, string msg);
    public void InitLogSession();
    public void EndLogSession();
    public void AddLogger(Logger chainedLogger);
    public void RemoveLogger(Logger chainedLogger);
}

public class FileLogger : Logger
{
      //implement methods
}

public class TextBoxLogger : Logger
{
      //implement methods
}

public class DBLogger : Logger
{
      //implement methods
}

編集1:

より正確には、2 つのファイル ロガーと 2 つのテキストボックス ロガーの 4 つのロガーが存在する可能性があります。特定のメッセージは、1 つのテキストボックス ロガーと 1 つのファイル ロガーを対象としていると想定されます。私のデザインはこれをどのように処理する必要がありますか?

編集 2: 既存のロギング フレームワークを提案しないでください。自分で書きたい!

編集3:わかりました。私はデザインを持っています。フィードバックをお寄せください。おそらくギャップを埋めてください。

改訂されたインターフェース:

public interface Logger
{
    public void Log(string msg);
    public void Log(string msgType, string msg);
    public void Log(int loggerIds, string msg);
    public void Log(int loggerIds, string msgType, string msg);
    public void InitLogSession();
    public void EndLogSession();
    public int getLoggerId();
}

public enum LoggerType
{
    File,
    TextBox
};

public class LoggerFactory
{
    public Logger getLogger(LoggerType loggerType)
    {

    }
}

LoggerFactory クラスは、ロガーをインスタンス化する唯一の方法です。このクラスは、ロガーの各インスタンスに一意の ID を割り当てます。この一意の ID は 2 の累乗になります。たとえば、1 番目のロガーは ID 1 を取得し、2 番目は ID 2 を取得し、3 番目は 4 を取得し、4 番目は 8 を取得します。

返されたロガー オブジェクトを特定のクラスに型キャストすることができ、さらに filePath や textbox などの値を呼び出し元が設定することもできます。または、LoggerFactory に複数のメソッドを設定することもできます。特定のパラメーターを受け入れるロガーの型ごとに 1 つです。 .

したがって、ID が 1、2、4、8 の 4 つのロガーがあるとします。1 番目と 3 番目のロガー (つまり、ロガー ID 1 と 4) で処理する必要がある特定のメッセージは、次の関数を使用してログに記録する必要があります。

    public void Log(int loggerIds, string msg);

loggerIds に渡す値は「0101」にする必要があります。各ロガーは、ロガー ID ビットがオンであるかどうかをチェックします。はいの場合のみ、メッセージがログに記録されます。

関数シグネチャで int 型について言及しましたが、ビット操作と比較を実行するために最適化された特定の型はどれですか?

このアプローチでは、おそらく最大数に制限がある可能性があります。ロガーの、しかしそれは私には問題ありません。フィードバックをお寄せください。

注: 現在、私はまだ .NET 2.0 を使用しています。可能であれば、.NET 2.0 内での解決策を提案してください。それ以外の場合は、より高いバージョンに移行できます。

この設計の短所: ログを記録する必要がある各クラスは、アプリケーションによってインスタンス化された使用可能なすべてのロガーを認識し、それに応じてビット パターンを設定する必要があります。疎結合設計のアイデアはありますか?

4

6 に答える 6

8

log4netNLogなどの既存のロギングフレームワークを見てみませんか(または実際に使用してみませんか)。

これらには、ログレベル(トレース、情報、エラーなど)の概念があり、ログの名前(通常はログ呼び出しを呼び出した完全修飾型名)でフィルタリングできます。次に、これらを1つ以上の「ターゲット」にマップできます。

于 2012-12-28T09:35:58.850 に答える
2

「既存のロギング フレームワークを提案しないでください。自分で書きたいだけです。」

受け入れられた答え: 車輪を再発明しないでください! この既存のロギング フレームワークを使用してください。

顔やし

私の答えである最良の答えは、次のようになります。プラグ アンド プレイ機能が必要な場合は、インターフェイスを使用します。簡単に構成可能にすることができます。これがハイレベルのランダウンです。

  1. 構成ファイルを使用して、ログ インターフェイスを実装するロガーのタイプを示します。

  2. リフレクションを使用して、実行時に構成ファイルから取得した型をインスタンス化します。

  3. クラス内のコンストラクター注入を介して、作成したばかりのロガー インターフェイスを渡します。

インターフェースで設計することによって車輪を再発明しているわけではありません。インターフェースを十分に一般化すると、実装は非固有になります (理想的には)。これは、 log4netが駄目になったり、サポートされなくなったりした場合に、すべての呼び出しコードを削除して変更する必要がないことを意味します。これは、ランプを家に直接配線して点灯させるようなものです。神の愛のために、そうしないでください。インターフェイスは、実装ではなく、コンポーネントが相互作用する契約を定義します。

私が考えられる唯一のことは、既存のロギング フレームワークを見て、共通の要素を見つけ、共通の機能の交差点としてインターフェイスを作成することです。明らかに、あなたが見逃している機能があるでしょう。どの程度の柔軟性が必要かによって異なります。Log4net、Microsoft Event Viewer ロガー、またはその両方を使用できます。実装の詳細は再実装されません。また、コード内のすべてを 1 つのテクノロジ/フレームワークに結び付けるよりも、結合がはるかに少ないシステムです。

于 2016-02-08T16:09:14.580 に答える
1

少し前に自分のロガーを書きました。正直なところ、無料で入手できるものほど良くはなく、すでに丸い車輪を再発明しようとしていることに気付きました!

独自のコードを書きたいと考えているようですが、それでもオープン ソース ソリューションを調べて、それらを使用したり、独自のニーズに合わせて変更したりすることをお勧めします。

私は現在 TracerX を使用しています: http://www.codeproject.com/Articles/23424/TracerX-Logger-and-Viewer-for-NET これはオープン ソース プロジェクトなので、必要なソース コードを簡単に変更できます。もちろん、言及されている他のロガーも優れています。

編集

これは、ここでの私の質問に対する受け入れられた回答に基づいています:疎結合アプリケーションでステータス情報を GUI に渡す方法したがって、 私はこれに独創性を主張しません。あなたのログメッセージは現時点では単純だと思います

私の提案する答えは、実行時に渡されるロジックに基づいて、またはファクトリを使用して、実行時の条件に応じてさまざまなメッセージ タイプを作成することによって、処理できる (たとえば) さまざまなロガーに自分自身を送信できるメッセージ タイプを使用することです。

そう

  1. プロセス メソッドを持つ抽象メッセージ クラスまたはインターフェイスを作成します。
  2. 実行したいさまざまなタイプのロギングを表す抽象クラスまたはインターフェースから継承するいくつかのメッセージ タイプを作成します。process メソッドは、それらの送信先を決定できます。
  3. ファクトリを使用して実行時に必要なメッセージ タイプを作成することを検討してください。必要なタイプを事前に決定する必要はありません。
  4. ログ メッセージを生成するときは、プロセス メッセージを使用して、メッセージを送信先のロガーにルーティングします。
于 2012-12-28T10:36:27.657 に答える
1

devdigital が書いたように、これらのフレームワークは通常、次のようなロギング用の指定されたメソッドを提供することでこれを行います: Warn("..."), Fail("...")...

城プロジェクトの伐採施設ILoggerのインターフェースを探すこともできます。(ILogger.cs ソースコードをググってみてください)

共通のインターフェースを持つ連鎖ロガーのアプローチ (連鎖メカニズムも実装する必要があります) を引き続き使用する場合は、Log() メソッドに一種のログ レベルを提供する必要があります。これは単なる整数または列挙型の場合もあります。

このような:

    public interface Logger
    {
        public void Log(LogLevel level, string msg);
        public void Log(LogLevel level, string msgType, string msg);
        public void InitLogSession();
        public void EndLogSession();
        public void AddLogger(Logger chainedLogger);
        public void RemoveLogger(Logger chainedLogger);
    }

次のようなログ レベルの列挙を使用します。

public enum LogLevel
{
    Info,
    Warn,
    Debug,
    Error,
    Fail
}

使用するロガーは、一連の責任の範囲内で選択されます。

于 2012-12-28T09:51:50.230 に答える
0

これは、拡張メソッドを使用するのに適した場所のようです。

基本クラスを作成し、その拡張メソッドを作成します。

BaseLogger(LogMessage).toTextBoxLog().toFileLog().toDatabaseLog().

このように、常に を呼び出してから、必要に応じて拡張メソッドBaseLoggerのみを呼び出します。

于 2013-07-30T20:29:06.417 に答える