VBScriptを支配せよ:ログ肥大化を封じる「世代管理」ロギングモジュールの極意
レガシーシステムの墓場と揶揄されることもあるVBScriptだが、その真価は「OSに深く根を下ろした軽量な自動化」にある。しかし、多くのエンジニアが犯す最大の過ちは、ログ出力を単なる`Scripting.FileSystemObject`(以下FSO)への追記処理と甘く見ていることだ。
数ヶ月で数GBに膨れ上がったログファイルがI/Oボトルネックを引き起こし、システムをダウンさせる。そんな初歩的な障害を「仕方ない」で済ませるのか? 本稿では、メモリの断片化を回避し、堅牢な世代管理を実現する「VBScriptロギングクラス」の設計思想を説く。
—
1. なぜ「素の書き込み」ではダメなのか
VBScriptの実行環境(WSH)は、ガベージコレクションが極めて脆弱だ。`Set obj = Nothing`を怠ればメモリリークは必至であり、特にログ出力のような「高頻度で呼ばれる処理」において、不適切なオブジェクト生成は致命的となる。
我々が目指すべきは、「I/Oを最小化し、メモリを汚さない」設計だ。
2. ログローテーション・アーキテクチャの要点
ログのローテーションには二つのトリガーが存在する。
1. サイズ制限: 指定容量を超過した場合(例: 5MB)。
2. 日付更新: 日付が変更された場合(例: 日次切り替え)。
これを実装する際、`GetFile`によるメタデータ取得を毎回行うのは非効率だ。クラス内部で状態を保持し、I/Oコストを最小化する戦略を取る。
3. 実装:堅牢なLoggerクラス
以下は、実戦投入を想定した「世代管理機能付きロガー」の原型である。
‘ Logger Class: メモリ効率を重視した最小構成のロギングモジュール
Class Logger
Private fso, ts, logPath, maxBytes
Private Sub Class_Initialize()
Set fso = CreateObject(“Scripting.FileSystemObject”)
maxBytes = 5 1024 1024 ‘ 5MB制限
End Sub
‘ ログ書き込み処理
Public Sub WriteLog(message)
Dim currentPath, logFile
currentPath = “app_” & Replace(Date, “/”, “”) & “.log”
‘ ログローテーション判定
If fso.FileExists(currentPath) Then
Set logFile = fso.GetFile(currentPath)
If logFile.Size > maxBytes Then
‘ リネームによる退避(即時処理)
fso.MoveFile currentPath, “app_” & Replace(Date, “/”, “”) & “_” & Timer & “.log”
End If
Set logFile = Nothing
End If
‘ ファイル追記モードでオープン(8 = ForAppending)
Set ts = fso.OpenTextFile(currentPath, 8, True)
ts.WriteLine Now & ” | ” & message
ts.Close
Set ts = Nothing
End Sub
Private Sub Class_Terminate()
‘ オブジェクトの明示的解放(メモリ管理の鉄則)
Set fso = Nothing
End Sub
End Class
‘ — 利用例 —
Dim logger: Set logger = New Logger
logger.WriteLog “システム初期化完了”
Set logger = Nothing
—
4. シニアエンジニアが押さえるべき「極限の知見」
A. I/O競合を回避する排他制御
VBScript単体では完全な排他制御(Mutex)は難しい。もし複数プロセスから同時書き込みが発生する場合、`fso.OpenTextFile`の第4引数(Tristate)だけでなく、エラーハンドリングを駆使して「リトライ機構」を設けるべきだ。「ファイルが使用中です」というエラーで落ちるツールは、プロの現場では許されない。
B. 世代管理の自動クリーンアップ
上記コードはファイルを退避させるだけだが、実運用では「退避したファイルを何日保持するか」のポリシーが必要だ。`fso.GetFolder(“.”).Files` をループし、作成日時を判定して `DeleteFile` するメソッドをクラスに追加せよ。ただし、全ファイルを走査するのは巨大ディレクトリ環境では遅延の原因となるため、特定のバックアップフォルダへ移動させる構成を推奨する。
C. パフォーマンスのためのバッファ戦略
高頻度ログが発生するバッチ処理の場合、毎回の `OpenTextFile` はディスクヘッドを酷使する。クラスの寿命をプロセスの寿命と一致させ、`ts` をメンバ変数として保持したまま、明示的な `Flush`(VBScript標準では非対応だが、APIで対応可能)や、`Close`のタイミングを工夫することで、パフォーマンスを劇的に改善できる。
—
最後に:レガシーを「負債」にするか「武器」にするか
VBScriptで書かれたシステムは、適切に設計されていれば、数十年単位で稼働し続ける堅牢な武器になる。ログローテーション一つとっても、単なる文字列出力と捉えるか、プロセスライフサイクルの一環として捉えるかで、システムの寿命は決定的に変わる。
君たちが記述するコードが、5年後の担当者に「このコードは誰が書いたんだ? 完璧だ」と言わしめるものであることを期待する。自動化エンジニアの腕の見せ所は、こうした地味な細部にこそ宿るのだから。
