ローテーション可能なIsolatedStorageTargetを書く

やることはこのFileTargetクラスからログのアーカイブとローテーションの機能を抜き出してIsolatedStorageTargetクラスにポートすることである。

ということで早速やってみた。ただし、FileTargetのアーカイブ/ローテーション機能をIsolatedStorageTargetに移す中で元々のFileTargetに実装されている以下の機能は不要又は不可能ということで移植の対象外とする。

  • キャッシュ機能
  • アペンダ機能

これを前提にして、まずは以下のプロパティをFileTargetから持ってくる。

IsolatedStorageTarget.cs (プロパティ定義部)
    [RequiredParameter]
    public Layout FileName { get; set; }
    public Encoding Encoding { get; set; }
    public long ArchiveAboveSize { get; set; }
    public FileArchivePeriod ArchiveEvery { get; set; }
    public ArchiveNumberingMode ArchiveNumbering { get; set; }
    [DefaultValue(9)]
    public int MaxArchiveFiles { get; set; }
    public Layout ArchiveFileName { get; set; }

それぞれの意味は以下の通り。

    • FileName パターンを含むファイル名
    • Encoding ログファイルの文字エンコーディング
    • ArchiveAboveSize ログファイルをアーカイブする閾値
    • FileArchivePeriod ファイルをアーカイブする期間(毎回、年、月、日、時、分)
    • ArchiveNumberingMode アーカイブファイルに付ける番号のモード(シーケンス|ローリング)
    • MaxArchiveFiles アーカイブするファイル数の上限
    • ArchiveFileName パターンを含むアーカイブファイル名

[RequiredParameter]、[DefaultValue(9)]はNLog自身で用意されているプロパティに作用する属性。それぞれ、値が設定されていることをバリデーションする属性、既定値をセットする属性。前者の必須属性は制約を満たさないと初期化時にNLogConfigurationExceptionがスローされる。あまりよく判っていないので、これはFileTargetで記述されたままにする。

あとはロジックを移しつつ、通常のファイルシステムへの操作をIsolatedStorageFileに置換えて行けばよい。例えばログイベントをファイルに書き出すWriteメソッドは以下のようになる。

IsolatedStorageTarget.cs (Writeメソッド)
    protected override void Write(LogEventInfo logEvent)
    {
        if (!System.ComponentModel.DesignerProperties.IsInDesignTool)
        {
            string fileName = this.FileName.Render(logEvent);
            byte[] bytes = this.GetBytesToWrite(logEvent);

            if (this.ShouldAutoArchive(fileName, logEvent, bytes.Length))
            {
                //this.InvalidateCacheItem(fileName);
                this.DoAutoArchive(fileName, logEvent);
            }

            using (IsolatedStorageFile store =
                    IsolatedStorageFile.GetUserStoreForApplication())
            {
                using (Stream stream =
                    new IsolatedStorageFileStream(fileName
                        , FileMode.Append, FileAccess.Write, store))
                {
                    var writer = new BinaryWriter(stream);
                    writer.Write(bytes);
                    writer.Close();
                }
            }
        }
    }

Fileオブジェクトを作る代わりにIsolatedStorageFileオブジェクトを、FileStreamオブジェクトを作る代わりにIsolatedStorageFileStreamを作ることでログイベントをレンダリングしている。他のファイルIO部分も同様に修正するだけで良い。

なお、既に書いたがキャッシュ機構は付けないのでメソッド自体省略している。

IsolatedStorageFileの完全なソースコードは近いうちに公開する予定。