Yoshi's Software Factory

開発資料

以下は開発中の備忘録(メモ)を兼ねた,作業記録メモです。 興味を持って頂けるようでしたら,お読み下さい。

この資料は作成中です。今後も少しずつ追記します。

ファイル更新の検出

最初に検討したのは,ログファイルの更新を検出するための機構です。 この目的に使えそうな機能として,.Net/CLRではFileSystemWatcher クラスがありますので,実装ではこれを使用することにします。

FileSystemWatcherの詳細については,MSDN等の資料を参照して 下さい。このクラスでファイル更新を監視する方法は複数ありますが,今回の実装 では次のような手順を採用しました。

  1. 監視するディレクトリと対象ファイル名(パターン)を指定して, FileSystemWatcherインスタンスを生成する。
  2. ファイル更新時にコールされるDelegateを設定する。
  3. ファイル書き込みを通知対象とするように,監視する変更(NotifyFilter)を指定する。

コードは以下のようになります。

    FileSystemWatcher fsWatcher_ = new FileSystemWatcher(directoryPath, filePattern);
    fsWatcher_.Changed += new FileSystemEventHandler(onFileChange);
    fsWatcher_.NotifyFilter = NotifyFilters.LastWrite;

ファイル監視の開始・終了は,FileSystemWatcherインスタンスの プロパティEnableRaisingEventsの値を変更することで操作できます。

以上の処理を実装して,ファイル検出を行うクラスを作成しました。

    class FileChecker : IDisposable {

        private FileSystemWatcher fsWatcher_;

        internal FileCheckerImpl(string directoryPath, string filePattern) {
            this.fsWatcher_ = new FileSystemWatcher(directoryPath, filePattern);
            this.fsWatcher_.Changed += new FileSystemEventHandler(onFileChange);
            this.fsWatcher_.NotifyFilter = NotifyFilters.LastWrite;
        }

        public override void Dispose() {
            this.fsWatcher_.EnableRaisingEvents = false;
            this.fsWatcher_.Dispose();
            this.fsWatcher_ = null;
        }

        public override bool Monitor {
            get { return  this.fsWatcher_.EnableRaisingEvents; }
            set { this.fsWatcher_.EnableRaisingEvents = value; }
        }
    }

ファイル読み込み

更新を検出したファイルの情報(ファイルパス名と読み込みオフセット値)を引数として, ログファイルの読み込みを行います。この処理を実行するクラスLogFileReaderを 作成しました。

LogFileReaderインスタンスには,前記のファイル情報に加えて,イベントログ 出力行を選択するクラスLogDataFilterのリストを保持します。ファイルから順次読み 込まれた内容はこのフィルタに渡され,イベントログ書き込み対象であるかを判定(フィルタ)さ れた後に,所定のイベントログエントリに記入されます。

LogDataFilterの実態は,以下のような簡単なメソッドを定義したインターフェース です。

    /// <summary>
    /// イベントハンドラ管理を実装した抽象クラス
    /// </summary>

    public abstract class AbstractLogDataFilter : LogDataFilter {
        protected FilterHandler filterHandler_;
        public AbstractLogDataFilter(FilterHandler handler) {
            this.filterHandler_ = handler;
        }
        public abstract bool DoFilter(string filename, string lineData);
    }

このインターフェースを実装するクラスとして,以下の3つを実装しました。

AbstractLogDataFilter
イベントハンドラ管理を実装した抽象クラス
RegExLogDataFilter
正規表現による行選択を実装したフィルタクラス
FixStrLogDataFilter
固定文字列によるパターンマッチ処理を実装したフィルタクラス

各クラスの実装コードをリストに示します。

    /// <summary>
    /// イベントハンドラ管理を実装した抽象クラス
    /// </summary>

    public abstract class AbstractLogDataFilter : LogDataFilter {
        protected FilterHandler filterHandler_;
        public AbstractLogDataFilter(FilterHandler handler) {
            this.filterHandler_ = handler;
        }
        public abstract bool DoFilter(string filename, string lineData);
    }

    /// <summary>
    /// 正規表現による行選択を実装したフィルタクラス
    /// </summary>
    
    public class RegExLogDataFilter : AbstractLogDataFilter {
        private Regex dataRegEx_;
        public RegExLogDataFilter(string pattern, FilterHandler handler) : base(handler) {
            this.dataRegEx_ = new Regex(pattern);
        }
        public override bool DoFilter(string fileName, string lineData) {
            Match m = this.dataRegEx_.Match(lineData);
            if(m != null && m.Success) {
                this.filterHandler_(fileName, lineData);
                return true;
            } else {
                return false;
            }
        }
    }

    /// <summary>
    /// 固定文字列によるパターンマッチ処理を実装したフィルタクラス
    /// </summary>

    public class FixStrLogDataFilter : AbstractLogDataFilter {
        private string pattern_;
        public FixStrLogDataFilter(string pattern, FilterHandler handler) : base(handler) {
            this.pattern_ = pattern;
        }
        public override bool DoFilter(string fileName, string lineData) {
            if(lineData != null && lineData.Contains(this.pattern_)) {
                this.filterHandler_(fileName, lineData);
                return true;
            } else {
                return false;
            }
        }
    }