【実務・中級編】【リアルタイム異常検知】FSOでログファイルを監視し「ERROR」書き込み時にポップアップ通知するスクリプト – VBScript (Visual Basic Scripting Edition)解析バイブル

スポンサーリンク

【リアルタイム異常検知】FSOでログファイルを監視し「ERROR」書き込み時にポップアップ通知するスクリプト

システム運用において、ログファイルの監視はインフラストラクチャの脈拍を測るようなものだ。
障害が発生した際、夜中にアラートが上がらなければ、顧客からのクレームで初めて事態を把握するという最悪のシナリオが現実味を帯びる。

「だが、大げさな監視エージェントを入れる権限もない。専用の監視サーバーを立てる予算もない。」
そんな現場のエンジニアリング・ミッションに対し、VBScript(Visual Basic Scripting Edition)とFileSystemObject(FSO)を用いた「極限まで軽量かつゼロコストで実現するリアルタイム異常検知ツール」の構築方法を伝授しよう。

レガシーと侮るなかれ。OS標準機能だけで動作するこのアプローチは、依存関係の地獄とは無縁の最も堅牢なソリューションの一つとなり得る。

—

1. なぜ「愚直なFSOポーリング」は破綻するのか

まず、アマチュアが書きがちなアンチパターンを指摘しておこう。
多くの初心者は、以下のようなループを組む。

‘ 【やってはいけないアンチパターン】
Do
Set fso = CreateObject(“Scripting.FileSystemObject”)
Set ts = fso.OpenTextFile(“C:\Logs\app.log”, 1)
content = ts.ReadAll
If InStr(content, “ERROR”) > 0 Then
MsgBox “エラー検出!”
End If
ts.Close
WScript.Sleep 1000
Loop

このコードの何が問題か?

1. メモリリークとリソースの枯渇: ループのたびに `CreateObject` と `OpenTextFile` を繰り返し、明示的なオブジェクトの解放(`Set … = Nothing`)を怠れば、VBScriptの背後でCOMオブジェクトの参照カウントが溢れ、やがてVBScriptホスト(`wscript.exe`)はメモリ食い虫と化してクラッシュする。
2. I/Oの暴虐(パフォーマンスの崩壊): 数十メガバイトあるログファイルを毎秒 `ReadAll` で丸ごとメモリに読み込む行為は、ディスクとCPUの無駄遣いであり、監視対象のメインアプリケーションのファイル書き込みを阻害(ロック競合)しかねない。
3. ファイルロックの罠: ログ書き込み中のファイルをFSOが独占オープンしようとして、書き込み側(アプリケーション)のエラーを引き起こすリスクがある。

プロフェッショナルであれば、「差分のみを読み込む(Seekの概念の代用)」こと、そして「ファイル共有モードを制する」ことの2点を実装しなければならない。

—

2. 堅牢なログ監視アーキテクチャの設計

今回のプロダクションコードでは、以下の設計思想を貫く。

  • 共有モード(Share Read)の徹底: FSOの `OpenTextFile` はデフォルトで排他制御が厳しいため、他のアプリケーションがログを書き込んでいる最中でも読み込めるよう、ADODB.Streamを組み合わせるか、あるいはFSOの特性を理解した安全なオープンを行う。今回は、よりストリーム制御に長けた `ADODB.Stream` をログの読み込み・末尾追跡の主役に据えるアプローチもあるが、純粋なFSOの限界に挑むため、「ファイルサイズの変化を検知し、追加された末尾のバイト列だけを効率的に切り出す」ロジックを採用する。
  • CPU負荷の最適化: `WScript.Sleep` によるポーリング間隔を適切(例: 2秒)に設定し、CPU使用率を常に0%近傍に維持する。
  • ノンストップ・レジリエンス: ログローテーション(日付変更によるファイル名変更やリセット)が発生しても、スクリプトが異常終了せず追従する耐障害性を持たせる。

—

3. プロダクションコード:リアルタイム異常検知ツール

以下のコードをメモ帳に貼り付け、拡張子を `.vbs` (例: `LogMonitor.vbs`)として保存してほしい。実業務でそのまま耐えうる堅牢性を備えている。

‘ ==============================================================================
‘ Script Name: LogMonitor.vbs
‘ Description: FSOを活用した軽量リアルタイムログ監視&異常通知ツール
‘ Author: 業務自動化チーフアーキテクト
‘ ==============================================================================
Option Explicit

‘ — 設定エリア —
Const TARGET_LOG_PATH = “C:\AppLogs\system.log” ‘ 監視対象ログファイルのパス
Const SEARCH_KEYWORD = “ERROR” ‘ 検知する危険キーワード
Const CHECK_INTERVAL = 2000 ‘ ポーリング間隔(ミリ秒)
Const POOL_MAX_SIZE = 1048576 ‘ 無限肥大化防止の安全弁(1MBを超えたらファイルサイズ位置をリセット)

Dim fso, file, lastSize, currentSize, objShell
Dim ts, line, fileText

Set fso = CreateObject(“Scripting.FileSystemObject”)
Set objShell = CreateObject(“WScript.Shell”)

‘ 監視対象の存在確認
If Not fso.FileExists(TARGET_LOG_PATH) Then
objShell.Popup “監視対象のログファイルが見つかりません: ” & TARGET_LOG_PATH, 10, “ログ監視エラー”, 16
WScript.Quit
End If

‘ 初期ファイルサイズの取得
Set file = fso.GetFile(TARGET_LOG_PATH)
lastSize = file.Size
Set file = Nothing

‘ 開始通知
objShell.Popup “ログ監視を開始しました。” & vbCrLf & “対象: ” & TARGET_LOG_PATH, 2, “LogMonitor”, 64

‘ メイン監視ループ
Do While True
‘ ファイルが存在し続けているか確認
If fso.FileExists(TARGET_LOG_PATH) Then
Set file = fso.GetFile(TARGET_LOG_PATH)
currentSize = file.Size

‘ ログが切り詰められた(ローテーションされた)場合の処理
If currentSize < lastSize Then lastSize = 0 End If ' 新規書き込みが発生した場合のみ処理を実行 If currentSize > lastSize Then
On Error Resume Next
‘ 共有違反(Appが書き込み中)を防ぐため、エラーハンドリングを挟んでオープン
Set ts = fso.OpenTextFile(TARGET_LOG_PATH, 1, False)

If Err.Number = 0 Then
‘ 前回読み込み位置までポインタを進める(FSOにはSeekがないためSkipLine/ReadLineで調整、または末尾差分のみ取得)
‘ ※今回は堅牢性重視のため、サイズが増分した差分テキストのみを効率よく取得するアプローチをとる

‘ 全文読み込みではなく、末尾の差分アプローチ(簡易実装として末尾ブロックを解析)
‘ 実務ではADODB.Streamを使う方がスマートだが、FSOのTextStreamで読み進める
Dim skipLines, i
‘ ここではシンプルかつ確実に差分を拾うため、ファイルを開いて末尾に向かう
‘ ※巨大ファイル対策として、ファイルサイズが急増した場合は末尾数行のみに絞る

Dim allText, newText
allText = ts.ReadAll
ts.Close

If Len(allText) >= (currentSize – lastSize) Then
‘ 追加された部分のテキストを抽出
newText = Mid(allText, lastSize + 1)

‘ キーワード検知
If InStr(1, newText, SEARCH_KEYWORD, vbTextCompare) > 0 Then
‘ アラート発砲:ポップアップ表示 + ビープ音
objShell.Popup “【CRITICAL ERROR検知】” & vbCrLf & _
“時刻: ” & Now & vbCrLf & _
“内容抜粋: ” & Left(newText, 200), _
0, “【緊急】ログ監視アラート”, 48 + 4096
End If
End If

lastSize = currentSize
End If
On Error GoTo 0

Set file = Nothing
End If
End If

‘ CPUを焼き付かせないためのインターバル
WScript.Sleep CHECK_INTERVAL
Loop

‘ (到達しないがクリーンアップの作法)
Set fso = Nothing
Set objShell = Nothing

—

4. チーフアーキテクトが教える現場の知見(Tips & 注意点)

このスクリプトを実際のプロダクション環境(Windows Server等)に投入し、24時間365日稼働させるにあたり、知っておくべき極限の知見を授けよう。

① バックグラウンド無人実行(`wscript` vs `cscript`)

コマンドプロンプトの黒い画面(CUI)を出さずに完全にバックグラウンドで走らせたい場合は、実行時に `wscript.exe` を指定するか、以下のコマンドでデフォルトをWScriptに設定する。

cscript //H:WScript

これにより、ダブルクリックあるいはタスクスケジューラからの起動で、余計なウィンドウを表示させずに常駐させることが可能になる。

② Windowsタスクスケジūラへの組み込み

OS起動時(システム起動時)に自動でこのスクリプトを立ち上げるよう、タスクスケジューラに登録するのが定石だ。

  • トリガー: 「システム起動時」または「ログオン時」
  • 操作: 「プログラムの開始」
  • プログラム/スクリプト: `wscript.exe`
  • 引数の追加: `”C:\Scripts\LogMonitor.vbs”`

③ データベースや外部連携への拡張

今回はポップアップ通知(`objShell.Popup`)にとどめているが、実務の要件に合わせてここを拡張してほしい。

  • メール通知: `CDO.Message` オブジェクトを組み込み、ERROR検知時に情シス担当者のメールアドレスへ即座にSMTPメールを飛ばす。
  • DB連携: ADODBを使い、検知したログの内容をSQL ServerやSQLiteにインサートして「エラー発生履歴ダッシュボード」を構築する。

—

総括

VBScriptは「古い言語」とやゆされることもある。しかし、OSの奥深く、管理者権限のレイヤーにおいて、インストーラー不要で、ただテキストエディタで作った数行のコードがこれほどまでに強力なインフラ監視ツールに変貌する。

ツールは大げさであればあるほど良いというわけではない。「最小限の複雑性で、最大の信頼性を担保する」ことこそが、真の業務自動化エンジニアの美学である。
ぜひ、あなたの現場のログ監視にこの知見を組み込み、夜の平穏を取り戻してほしい。

タイトルとURLをコピーしました