【入門編】【実務中級者向け】FSOログ解析による特定アラート(FATAL/WARN)出現回数カウントと閾値超過メッセージ生成 – VBScript (Visual Basic Scripting Edition)解析バイブル

スポンサーリンク
スポンサーリンク

ログ監視の自動化へ:FSOを極めて「システムを監視する力」を手に入れる

こんにちは。現場の設計と実装を渡り歩いてきた、あなたのエンジニアライフを支えるチーフアーキテクトです。

「マクロの記録」から一歩踏み出し、「自分でスクリプトを書いて、業務を自動化したい」――そう思ったあなたは、すでにエンジニアとしての正しい階段を登り始めています。素晴らしい一歩です。

しかし、単に「ファイルをコピーする」「フォルダを作る」といった操作だけでは、プロの現場で戦う武器としては少し足りません。真に価値のある自動化とは、「データを読み解き、状況を判断し、異常があれば報告する」という、いわば「思考」を伴うプロセスです。

今日は、VBScriptの心臓部とも言える`FileSystemObject` (FSO) を使い、膨大なログファイルの中から「致命的なエラー」を見つけ出し、閾値(しきい値)を超えたときだけアラートを出す、実戦的なログ解析スクリプトを一緒に構築していきましょう。

これをマスターすれば、あなたは「作業を自動化する人」から、「システムを監視する仕組みを作る人」へと進化できるはずです。

1. 設計図:ログ解析のメカニズム

いきなりコードを書き始めるのは、設計図なしにビルを建てるようなものです。まずは、私たちが作ろうとしているプログラムの「動き」を整理しましょう。

graph TD
    A[開始] --> B[指定フォルダ内のログファイルを走査]
    B --> C{ファイルはあるか?}
    C -- Yes --> D[ファイルを1行ずつ読み込む]
    D --> E{FATAL/WARNが含まれるか?}
    E -- Yes --> F[カウントをインクリメント]
    E -- No --> D
    F --> D
    C -- No --> G[終了]
    D -- ファイル末尾に到達 --> H{カウント > 閾値?}
    H -- Yes --> I[アラート用サマリーを出力]
    H -- No --> G
    I --> G

ここがエンジニアの視点

この設計の肝は、「ファイルを丸ごとメモリに読み込まない」ことです。
数GBもあるような巨大なログファイルを `ReadAll` メソッドで一気に読み込もうとすると、メモリを食いつぶしてスクリプトがクラッシュします。私たちは、`ReadLine` を使って「一行ずつ、慎重に」処理を進める、プロの作法を身につけます。

2. 実装:ログ解析エンジンの構築

それでは、魂を込めたコードを見ていきましょう。このスクリプトは、そのままコピーして、パスを書き換えるだけで動作するように設計しています。

' ==============================================================================
' Script Name: LogAnalyzerPro.vbs
' Description: ログファイルを走査し、FATAL/WARNの発生回数をカウント。
'              閾値を超えた場合にサマリーレポートを生成する。
' Author:      Chief Architect
' ==============================================================================

Option Explicit ' 変数の強制宣言(これを行うだけでバグの8割は防げます)

' --- 設定エリア ---
Const TARGET_FOLDER   = "C:\Logs\AppLogs\"      ' 調査対象のフォルダ
Const REPORT_FILE     = "C:\Logs\AlertReport.txt" ' 警告レポートの出力先
Const THRESHOLD_FATAL = 3                       ' FATALの許容回数
Const THRESHOLD_WARN  = 10                      ' WARNの許容回数

' --- 変数宣言 ---
Dim fso, folder, file, ts
Dim fatalCount, warnCount
Dim lineContent, reportText
Dim isAlertTriggered

' オブジェクトの初期化
Set fso = CreateObject("Scripting.FileSystemObject")

' 1. フォルダの存在確認(ここを怠るとエラーで即死します)
If Not fso.FolderExists(TARGET_FOLDER) Then
    MsgBox "エラー: 指定されたフォルダが存在しません: " & TARGET_FOLDER, vbCritical
    WScript.Quit
End If

' カウンターの初期化
fatalCount = 0
warnCount = 0
isAlertTriggered = False

' 2. フォルダ内のファイル走査開始
Set folder = fso.GetFolder(TARGET_FOLDER)

For Each file In folder.Files
    ' 拡張子が .log のファイルのみを対象とする
    If LCase(fso.GetExtensionName(file.Name)) = "log" Then
        
        ' ファイルを読み込みモードで開く
        ' 3 = ForReading (読み取り専用)
        Set ts = file.OpenTextFile(1, 1) 
        
        ' 3. ファイルを一行ずつ走査(メモリ節約の極意)
        Do Until ts.AtEndOfStream
            lineContent = ts.ReadLine
            
            ' キーワード判定 (InStr は大文字小文字を区別しない設定で使うのが定石)
            If InStr(1, lineContent, "FATAL", vbTextCompare) > 0 Then
                fatalCount = fatalCount + 1
            ElseIf InStr(1, lineContent, "WARN", vbTextCompare) > 0 Then
                warnCount = warnCount + 1
            End If
        Loop
        
        ts.Close ' 開いたファイルは必ず閉じる(リソース解放の鉄則)
        Set ts = Nothing
    End If
Next

' 4. 閾値判定とレポート生成
If fatalCount >= THRESHOLD_FATAL Or warnCount >= THRESHOLD_WARN Then
    isAlertTriggered = True
    
    ' レポート内容の組み立て
    reportText = "【重要】ログ監視アラート" & vbCrLf & _
                 "発生日時: " & Now & vbCrLf & _
                 "------------------------------------" & vbCrLf & _
                 "FATAL検知数: " & fatalCount & " (閾値: " & THRESHOLD_FATAL & ")" & vbCrLf & _
                 "WARN  検知数: " & warnCount & " (閾値: " & THRESHOLD_WARN & ")" & vbCrLf & _
                 "------------------------------------" & vbCrLf & _
                 "至急、システム状況を確認してください。"

    ' レポートファイル書き出し (2 = ForWriting, True = 上書き作成)
    Set ts = fso.CreateTextFile(REPORT_FILE, True)
    ts.WriteLine(reportText)
    ts.Close
    
    MsgBox "警告! 閾値を超えました。レポートを確認してください。" & vbCrLf & REPORT_FILE, vbExclamation
Else
    ' 正常な場合は何もせず終了(あるいはログに記録)
    ' MsgBox "チェック完了: 異常なし", vbInformation
End If

' 5. 後片付け(オブジェクトのライフサイクル管理)
Set folder = Nothing
Set fso = Nothing

WScript.Echo "ログ解析プロセスが正常に完了しました。"

3. アーキテクトの解説:ここが「プロ」の分かれ道

コードをただ眺めるだけでは不十分です。なぜこのように書いたのか、その「意図」を理解してください。

① `Option Explicit` の威力

冒頭に書いたこの一行。これがないと、タイポ(打ち間違い)をして変数名が違っていても、VBScriptは「新しい変数だ」と勝手に解釈して実行を続けてしまいます。これが原因で、カウントが合わないといった「原因不明のバグ」が多発します。「変数は必ず宣言する」。これは鉄則です。

② `InStr` 関数による柔軟な検索

`If lineContent = “FATAL” Then` と書いてしまうと、行の中に「[ERROR] FATAL: System down」のように他の文字が含まれていた場合に検知できません。`InStr` を使うことで、文字列の「どこかに含まれているか」を判定できます。`vbTextCompare` を指定することで、大文字・小文字の揺れ(fatal / FATAL)も吸収できる、非常に堅牢な書き方です。

③ リソースのライフサイクル(重要!)

`ts.Close` を忘れていませんか? ファイルを開いたままにすると、そのファイルは「使用中」となり、他のプログラムや、次回のスクリプト実行がファイルを操作できなくなります。「開けたら閉じる」。これはOSとの約束事です。

④ エラーハンドリングの思想

今回のコードでは、最初に `fso.FolderExists` でフォルダの存在を確認しています。プロのスクリプトは、「想定外の事態」が起きたときに、エラーで止まるのではなく、「何が原因で止まったのか」をユーザーに優しく(かつ正確に)伝えるように設計します。

4. 陥りやすい罠(トラブルシューティング)

実務で運用する際、以下の2点には特に注意してください。

1. ファイルのロック問題
ログを出力しているアプリケーションがファイルを「排他的にロック」している場合、`OpenTextFile` でエラーが発生することがあります。その場合は、エラーハンドリング(`On Error Resume Next` を適切に使い、エラー時にリトライするかスキップするか決める)が必要になります。
2. 文字コードの壁
VBScriptのFSOは、標準では ANSI (Shift-JIS) を想定しています。もしログファイルが UTF-8 で保存されている場合、日本語が文字化けしたり、正しく判定できなかったりします。その場合は、`ADODB.Stream` オブジェクトという、さらに高度な道具を使う必要が出てきます。

最後に

お疲れ様でした。あなたは今、単なる「コードの書き手」ではなく、「システムの健全性を守るロジックの設計者」としての第一歩を踏み出しました。

このスクリプトは、あくまで基本形です。ここから「特定の時間帯だけ解析する」「メールで通知を送る」「解析結果をデータベースに書き込む」といった拡張が無限に可能です。

「なぜこう動くのか?」という問いを常に持ち続けてください。その積み重ねが、あなたを伝説的なエンジニアへと押し上げるのです。

また次の現場でお会いしましょう。応援していますよ!

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