はじめに
前回、VBScriptをお手軽にデバッグして開発する方法 にて、VBScriptの開発方法を書いてみましたので、開発の例としてログ監視ツールを作ってみようと思いました。
仕様
- 特定のテキストの中身を監視する
- テキスト中に、特定の文字列が新規で検知したらアラートを上げる。
- 検知アラートはメッセージボックスを使用する。任意の設定で音が鳴るようにする。
- 検知アラートのメッセージボックスのOKボタンを押すと、そこから監視を継続する。
- ファイル中の文字数が前と比べて少なくなっていたら、ファイルの最初から確認する(ログローテーション対応)
- インターフェースを作成し監視終了をできるようにする
- 検知アラートの時間をログに出力するようにする
- 想定外のエラーが発生したらメッセージボックスを上げる
中身の解説
コードの全文は後ろの方にありますので、説明抜きで理解出来る方はこの辺りは飛ばしてどうぞ。
設定箇所
ユーザーが設定する必要が箇所は冒頭で設定可能なようにします。
Const MONITORED_FILE_PATH = "D:\test.log" ' 監視ファイルの設定
Const MONITORING_STRING = "ErrorString" ' 監視する文字列の設定
Const ALERT_SOUND_FILE = "Alert.wav" ' 検知時に鳴らすサウンド設定.
Const ERROR_SOUND_FILE = "Error.wav" ' スクリプトのエラー発生時に鳴らすサウンド設定.
' サウンドファイルは同一フォルダにある必要があります)
' 鳴らさない場合は、空白指定。例: ALERT_SOUND_FILE = ""
' 使用するプレイヤーは拡張子に紐づけられているプレイヤー
Const logFileName = "監視ログ.txt" ' 監視ログのファイル名
設定確認箇所
設定した内容は起動時に確認できるようにします。キャンセルボタンで終了するようにします。
' 監視開始メッセージを出力する
temp = "監視をスタートします。" & vbCrLf & vbCrLf _
& "監視ファイル:" & MONITORED_FILE_PATH & vbCrLf _
& "監視文字:" & MONITORING_STRING & vbCrLf & vbCrLf _
& "終了する際は「監視終了」ボタンを押してください。"
If MsgBox(temp, vbInformation + vbOKCancel, "スタート") = vbCancel Then
WScript.Quit
End If
監視ファイルの確認箇所
監視対象ファイルが存在しなければエラーを出して終了します。
存在したなら中身を全部読み取り、現時点の文字数を記録しておきます。この文字数がどこまで監視したかを示す値となります。ファイルの中身が空っぽならばカウントはゼロです。
' ファイルの存在確認
If fso.FileExists(MONITORED_FILE_PATH) = False Then
temp = "対象ファイル『" & MONITORED_FILE_PATH & "』が存在しません。" & vbCrLf _
& "設定を確認してください。" & vbCrLf & "終了します。"
MsgBox temp, vbCritical, "エラー"
WScript.Quit
End If
' 初回のファイル中身の取得
Set objFile = fso.OpenTextFile(MONITORED_FILE_PATH, 1)
If objFile.AtEndOfStream = False Then
fileText = objFile.ReadAll ' ファイル内容をすべて読み込み
objFile.Close ' ファイルをクローズ
monitoredLength = Len(fileText)
Else
monitoredLength = 0
End If
監視開始時のファイルの更新日時の取得箇所
更新日時を確認し、開始時の更新日時を覚えておきます。
' 監視前のファイルの更新日時の取得
preFileUpdateTime = ""
If fso.FileExists(MONITORED_FILE_PATH) Then
preFileUpdateTime = fso.GetFile(MONITORED_FILE_PATH).DateLastModified
End If
インターフェースを作成
インターフェースとしてIEオブジェクトを使用します。長いので関数化してあります。
' インターフェース用にIEのオブジェクト作成します。
Set ie = CreateInterfaceIE()
' インターフェース用のIEを作成する
Function CreateInterfaceIE()
' IEのオブジェクトを作り、画面の設定をして表示
Dim ie
Set ie = CreateObject("InternetExplorer.Application")
ie.Width = 300
ie.Height = 170
ie.Toolbar = False
ie.StatusBar = False
ie.Resizable = False
ie.Visible = True
ie.Navigate "about:blank"
Do While ie.Busy
WScript.Sleep (100)
Loop
Dim HTML
HTML = "" _
+ "<form>" _
+ " <input type=""hidden"" name=""CLICKED"" value=""false""/>" _
+ " 監視対象ファイル: " & MONITORED_FILE_PATH & "<br/>" _
+ " 監視対象文字列: " & MONITORING_STRING & "<br/>" _
+ " <input type=""button"" " _
+ " onClick = ""getElementsByName('CLICKED')(0).value = 'true';""" _
+ " value=""監視終了"" />" _
+ "</form>"
ie.Document.Body.InnerHtml = HTML
ie.Document.Title = "監視中."
Set CreateInterfaceIE = ie
End Function
監視のためのループ部分
監視内容はループ文で実装します。
ループを抜ける条件は、インターフェースの「監視終了」ボタンが押された時と、エラーが発生した時です。
' エラーが起こっても無視して進む
On Error Resume Next
' 監視実行(無限ループ)
Do While ie.Busy Or Not is_clicked(ie)
If Err.Number <> 0 Then ' エラーが発生したら終了
PlaySound(ERROR_SOUND_FILE) ' 音を鳴らす
MsgBox "エラーが発生しました。監視を停止します。", vbCritical, "エラー"
Exit Do
End If
WScript.Sleep (1000) ' 1秒待機
''' (中略)
Loop
監視内容の部分
ファイルの更新日時が変化していたら(新しくなっていたらでは無い)、ファイルの中身を確認しに行きます。
既に監視済みの文字数と、現在のファイルの文字数から、まだ監視していない文字数を確定します。マイナス(ログローテーションなどの理由で文字が削除された)ならば全ての文字が監視対象とします。
監視テキストを確定し、その中に特定のキーワードが存在したら、アラートを発生させます。
' 現在の監視ファイルの更新日時の取得
curFileUpdateTime = ""
If fso.FileExists(MONITORED_FILE_PATH) Then
curFileUpdateTime = fso.GetFile(MONITORED_FILE_PATH).DateLastModified
End If
' 変更前後のファイル更新日時を比較
If preFileUpdateTime <> curFileUpdateTime Then
'変更日時が変わっているならば中身を取得
Set objFile = fso.OpenTextFile(MONITORED_FILE_PATH, 1)
fileText = objFile.ReadAll ' ファイルを読み込む
objFile.Close ' ファイルを閉じる
num = Len(fileText) - monitoredLength ' まだ監視していない文字数を取得する
If num <= 0 Then ' もし文字数がマイナスになったならば(ログローテーションなどでファイルの文字が削除された場合)
num = Len(fileText) ' 監視対象文字数は全てとする
End If
monitoredText = Right(fileText, num) ' 監視対象テキストを確定させる
If InStr(monitoredText, MONITORING_STRING) > 0 Then
' 監視文字が存在している場合は
WriteLog ' ログに残す
PlaySound(ALERT_SOUND_FILE) ' 音を鳴らす
' アラートを出す
MsgBox "発見:" & MONITORING_STRING, vbExclamation, "注意:"
End If
monitoredLength = Len(fileText) ' 監視済み文字数をセット
End If
preFileUpdateTime = curFileUpdateTime ' 変更後日時を変更前日時として設定
監視ツールのスクリプト全文
スクリプトの全文を記載します。
不明点や不備な点がありましたら本ページのコメントに書いていただけますと出来る限り対応しますのでお気軽にどうぞ。
Option Explicit
MonitoringFile 'VBSの場合
''***************************************************************************
''監視ツール.vbs : 指定ファイルを監視するスクリプト
''************************************************************************
Const MONITORED_FILE_PATH = "D:\test.log" ' 監視ファイルの設定
Const MONITORING_STRING = "ErrorString" ' 監視する文字列の設定
Const ALERT_SOUND_FILE = "Alert.wav" ' 検知時に鳴らすサウンド設定.
Const ERROR_SOUND_FILE = "Error.wav" ' スクリプトのエラー発生時に鳴らすサウンド設定.
' サウンドファイルは同一フォルダにある必要があります)
' 鳴らさない場合は、空白指定。例: ALERT_SOUND_FILE = ""
' 使用するプレイヤーは拡張子に紐づけられているプレイヤー
Const logFileName = "監視ログ.txt" ' 監視ログのファイル名
Dim thisScriptPath ' 現Scriptのパス
' 監視を実行
Public Sub MonitoringFile()
Dim fso ' ファイル入出力オブジェクト
Dim objFile ' ファイルオブジェクト
Dim fileText ' ファイルの中身
Dim monitoredLength ' 監視済みの文字数
Dim curFileUpdateTime ' 現在のファイルの更新日時
Dim preFileUpdateTime ' 一つの前のファイルの更新日時
Dim monitoredText ' 監視対象テキスト
Dim num ' 数値の一時的変数
Dim temp ' 一時的変数
Dim ie ' IEオブジェクト(インターフェース用)
' ファイルパスを記録する
thisScriptPath = Replace(WScript.ScriptFullName, WScript.ScriptName, "")
' 監視開始メッセージを出力する
temp = "監視をスタートします。" & vbCrLf & vbCrLf _
& "監視ファイル:" & MONITORED_FILE_PATH & vbCrLf _
& "監視文字:" & MONITORING_STRING & vbCrLf & vbCrLf _
& "終了する際は「監視終了」ボタンを押してください。"
If MsgBox(temp, vbInformation + vbOKCancel, "スタート") = vbCancel Then
WScript.Quit
End If
' ファイルシステムオブジェクトセット
Set fso = CreateObject("Scripting.FileSystemObject")
' ファイルの存在確認
If fso.FileExists(MONITORED_FILE_PATH) = False Then
temp = "対象ファイル『" & MONITORED_FILE_PATH & "』が存在しません。" & vbCrLf & "設定を確認してください。" & vbCrLf & "終了します。"
MsgBox temp, vbCritical, "エラー"
WScript.Quit
End If
' 初回のファイル中身の取得
Set objFile = fso.OpenTextFile(MONITORED_FILE_PATH, 1)
If objFile.AtEndOfStream = False Then
fileText = objFile.ReadAll ' ファイル内容をすべて読み込み
objFile.Close ' ファイルをクローズ
monitoredLength = Len(fileText)
Else
monitoredLength = 0
End If
' 監視前のファイルの更新日時の取得
preFileUpdateTime = ""
If fso.FileExists(MONITORED_FILE_PATH) Then
preFileUpdateTime = fso.GetFile(MONITORED_FILE_PATH).DateLastModified
End If
' インターフェース用にIEのオブジェクト作成する
Set ie = CreateInterfaceIE()
' エラーが起こっても無視して進む
On Error Resume Next
' 監視実行(無限ループ)
Do While ie.Busy Or Not is_clicked(ie)
If Err.Number <> 0 Then ' エラーが発生したら終了
PlaySound(ERROR_SOUND_FILE) ' 音を鳴らす
MsgBox "エラーが発生しました。監視を停止します。", vbCritical, "エラー"
Exit Do
End If
WScript.Sleep (1000) ' 1秒待機
' 現在の監視ファイルの更新日時の取得
curFileUpdateTime = ""
If fso.FileExists(MONITORED_FILE_PATH) Then
curFileUpdateTime = fso.GetFile(MONITORED_FILE_PATH).DateLastModified
End If
' 変更前後のファイル更新日時を比較
If preFileUpdateTime <> curFileUpdateTime Then
'変更日時が変わっているならば中身を取得
Set objFile = fso.OpenTextFile(MONITORED_FILE_PATH, 1)
fileText = objFile.ReadAll ' ファイルを読み込む
objFile.Close ' ファイルを閉じる
num = Len(fileText) - monitoredLength ' まだ監視していない文字数を取得する
If num <= 0 Then ' もし文字数がマイナスになったならば(ログローテーションなどでファイルの文字が削除された場合)
num = Len(fileText) ' 監視対象文字数は全てとする
End If
monitoredText = Right(fileText, num) ' 監視対象テキストを確定させる
If InStr(monitoredText, MONITORING_STRING) > 0 Then
' 監視文字が存在している場合は
WriteLog ' ログに残す
PlaySound(ALERT_SOUND_FILE) ' 音を鳴らす
' アラートを出す
MsgBox "発見:" & MONITORING_STRING, vbExclamation, "注意:"
End If
monitoredLength = Len(fileText) ' 監視済み文字数をセット
End If
preFileUpdateTime = curFileUpdateTime ' 変更後日時を変更前日時として設定
Loop
ie.Quit
Set fso = Nothing
End Sub
' ログを残す
Sub WriteLog()
Dim fso ' ファイル入出力オブジェクト
Dim objFile ' ファイルオブジェクト
Set fso = CreateObject("Scripting.FileSystemObject")
' ログに残す
' ファイルを追記モードで開く(ファイルが無ければ作成)
Set objFile = fso.OpenTextFile(thisScriptPath & "\" & logFileName, 8, True)
objFile.WriteLine Now & "," & MONITORING_STRING & "," & MONITORED_FILE_PATH ' ログを書き込む
objFile.Close ' ファイルをクローズ
' 使用したオブジェクトをクリア
Set objFile = Nothing
Set fso = Nothing
End Sub
' 音を鳴らす
Sub PlaySound(soundFile)
Dim ws ' Wscript shellのオブジェクト
If soundFile<> "" Then
'音源が設定されていた場合は鳴らす
Set ws = CreateObject("Wscript.Shell")
ws.Run thisScriptPath & "\" & soundFile, 1, False
End If
End Sub
' インターフェース用のIEを作成する
Function CreateInterfaceIE()
' IEのオブジェクトを作り、画面の設定をして表示
Dim ie
Set ie = CreateObject("InternetExplorer.Application")
ie.Width = 300
ie.Height = 170
ie.Toolbar = False
ie.StatusBar = False
ie.Resizable = False
ie.Visible = True
ie.Navigate "about:blank"
Do While ie.Busy
WScript.Sleep (100)
Loop
Dim HTML
HTML = "" _
+ "<form>" _
+ " <input type=""hidden"" name=""CLICKED"" value=""false""/>" _
+ " 監視対象ファイル: " & MONITORED_FILE_PATH & "<br/>" _
+ " 監視対象文字列: " & MONITORING_STRING & "<br/>" _
+ " <input type=""button"" " _
+ " onClick = ""getElementsByName('CLICKED')(0).value = 'true';""" _
+ " value=""監視終了"" />" _
+ "</form>"
ie.Document.Body.InnerHtml = HTML
ie.Document.Title = "監視中."
Set CreateInterfaceIE = ie
End Function
' クリックされたかの判定を行う
Function is_clicked(ie)
is_clicked = ie.Document.GetElementsByName("CLICKED")(0).Value <> "false"
End Function