misc.log

日常茶飯事とお仕事と

ログ出力に汎用性を持たせる

先日書いた「自メソッドを呼んだメソッドを知る(http://www.backyrd.net/entry/20131112/1384184120)」で、コンソール出力にログを出していたモノをちょいと改良。ログ出力処理ロジック自体を好きに差し替えられるようにしてみます。

方針は

  • 具体的なログ出力処理はDelegate(デリゲート)を用いて外部から指定できるようにする。
  • Delegateは.NET標準の「Action」タイプを用いる(楽なので)。

というわけで時間が無いので書いたものを掲載します。

class Logger
{
    /// <summary>
    /// コンストラクタ。
    /// </summary>
    /// <param name="writerMethod">ログ書き出しに用いるメソッドを指定する。</param>
    public Logger(Action<string> writerMethod)
    {
        this.WriteProcess = writerMethod;
    }

    /// <summary>
    /// ログ出力の実処理を行うデリゲートプロパティ。
    /// </summary>
    public Action<String> WriteProcess { get; set; }


    public void WriteLog(string message)
    {
        WriteProcess(message);
    }

    public void WriteLog(string message, Exception ex)
    {
        WriteProcess(message);
        string errorMessage;
        errorMessage = ex.Message + Environment.NewLine;
        errorMessage += ex.StackTrace;
        WriteProcess(errorMessage);
    }

    public void WriteLog2(string message)
    {
        // 1つ前のスタックフレームを指定して、メソッド名を取り出す
        System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace();
        System.Diagnostics.StackFrame caller = new System.Diagnostics.StackFrame(0);
        string methodName = caller.GetMethod().Name;
        string className = caller.GetMethod().ReflectedType.FullName;

        string logMessage = string.Format("[{0}.{1}] {2}", className, methodName, message);
        WriteProcess(logMessage);
    }
}

ログ出力を行う「メソッド(関数)へのポインタ」を渡すプロパティとして「WriteProcess」というものを「Action」型で指定。プロパティやコンストラクタで「どういうメソッド(実処理)をログ出力で用いるか」を指定できるようにします。

これで、

  • コンソール出力に出す
  • メッセージボックスで出す
  • テキストファイルで出す
  • DBに出す

など、出し方は使い手が選べるようになります。

実際、呼び側の処理はこんな感じです。

static Logger logWriter=new Logger(Program.Writer);

static void Main(string[] args)
{
    MainProcess("はじまります。");
}

public static void Writer(string message)
{
    //Console.WriteLine(message);
    System.Windows.Forms.MessageBox.Show(message);
}

private static void MainProcess(string message)
{
    try
    {
        logWriter.WriteLog(message);
        MainProcess2(message);
    }
    catch (Exception ex)
    {
        logWriter.WriteLog("エラーが起きたようです。", ex);
    }
}

上記はコンソールアプリのメイン処理中身です。初期処理で「はじまります」という文字列を渡されたMainProcessは、いきなり渡された文字列をログ出力。この前に、logWriterには、自クラス内にStaticで用意した「Writer」メソッドを指定して初期化。

ログの出力はWriterメソッドに書いた方式で実行されます。この例では処理自体を自分の中に定義したメソッドにしましたが、実際にはこれを処理だだけを記述したクラスのメソッドという形で実装すれば、そのクラスさえ差し替えれば処理が変わる、といった利用が可能になります。

というわけで、ちょっと.NETらしいことをやってみたり。

プログラミングC# 第6版

プログラミングC# 第6版