ExcelVBAでログ出力
ExcelVBAでアプリケーション開発時にエラーの内容を見たい
Excelで簡単なアプリケーションを作る中で、
処理のログを通常のアプリケーションログの様に出力したいなと思い、
試行錯誤試してみました。
作成したExcel VBAでエラーが起きた時にどのようなエラーがどこで起きたのか
把握するために作成してみました。
公開中:GitHub
求める機能
- 日時(フォーマット指定迄)
- ログレベル
- ログが出力されている関数名
- ログ内容(エラーメッセージ)
アプリケーションログと似た形にしていけば、エラーの特定が容易になる。
ログは、テキストファイルへの出力
ログが、Excel内のシートに出力されてしまっては
無駄なシートを作成する必要が出てきてしまう。
その為、指定のパスへテキストファイルとして出力を行いたい
パス指定も、簡単に変更できるようにしなければならない
これもまた、Excel内のセルにパスを入力するようにすると
設定シートなるものを作成したりしなければならないので、
configファイルを作成するようにしてみる
これなら、設定を勝手にいじったり消されたりすることはなくなる
(ファイルを消されたら元も子もないが・・・)
設定ファイルの作成
XML形式のファイルで設定を作成していく。
Microsoft XML, v6.0を使用してXMLの取込解析を行います
<?xml version="1.0" encoding="UTF-8" ?>
<config>
<logfile>C:\home\log\log.txt</logfile>
</config>
上記ファイルの設定を読み込む専用Classを作成
クラスモジュール
Option Explicit
Private xmlDoc As Object
Public Sub LoadConfig(ByVal configFilePath As String)
Set xmlDoc = CreateObject("MSXML2.DOMDocument.6.0")
xmlDoc.async = False
xmlDoc.Load configFilePath
If xmlDoc.parseError.ErrorCode <> 0 Then
Err.Raise xmlDoc.parseError.ErrorCode, , xmlDoc.parseError.reason
End If
End Sub
Public Function GetConfigValue(ByVal key As String) As String
On Error GoTo notvalue
GetConfigValue = xmlDoc.SelectSingleNode("/config/" & key).Text
Exit Function
notvalue:
'値がなかったら空白を返却
GetConfigValue = ""
End Function
上記でコンフィグの設定を取得することができる。
今回の場合は、
Private ConfigReader As ConfigReader
'コンフィグファイル取得
Set ConfigReader = New ConfigReader
'ログファイル出力 初期値:同じファイル階層
LogOutputPath = ConfigReader.GetConfigValue("logfile")
これで、ログ出力先のファイルパスを指定することができる。
ログをファイルに書き込む処理
ログをファイルに書き込む際、クラスでファイルを保持すると他の関数から呼び出しいたときに
書き込めない・何ならファイルを掴めずにエラーとなることがある。
というか、エラーになる。
そのため、ログ書き込み時にその都度ファイルを掴んで書き込みを行うようにする
Private Sub LogOutput(logLevelName As String, LogLevel As Integer, logMessage As String)
Call File_Open
Print #fileNo, Format(Now(), DateFormat) & " [" & logLevelName & "]" & Space(spaceCnt) & "[" & CallMethodName & "] " & logMessage
Call File_Close
End Sub
Private Sub File_Open()
fileNo = FreeFile
Open LogOutputPath For Append As #fileNo
End Sub
Private Sub File_Close()
Close #fileNo
End Sub
各ログ出力の関数(DEBUG/INFO/ALEART/ERROR)を呼び出すと
ファイルを開く・書き込む・閉じるという流れを踏むようにする。
静的クラスにすれば行けるのかもしれないが、Excelというファイルを使っている以上
複数の場所から同じ場所に書き込みが起きないとも限らないので、
今回は、書き込みのたびに開く・書き込む・閉じるという流れを採用した。
ログ出力
ログ出力する際に、
LogOutput("ログレベル","ログ内容",....
という関数にするかも迷ったが、ログレベルはすべて同じように出力するようにしたかったため、
それぞれのログレベルで関数を作成し呼び出すようにした
Public Sub DebugMsg(logMessage As String, methodName As String)
CallMethodName = methodName
'DEBUGログ出力
Call LogOutput("DEGUB", LOGLEVEL_DEBUG, logMessage)
End Sub
Public Sub InfoMsg(logMessage As String, methodName As String)
CallMethodName = methodName
'INFOログ出力
Call LogOutput("INFO", LOGLEVEL_INFO, logMessage)
End Sub
Public Sub AleartMsg(logMessage As String, methodName As String)
CallMethodName = methodName
'WARNINGログ出力
Call LogOutput("ALEART", LOGLEVEL_ALEART, logMessage)
End Sub
Public Sub ErrorMsg(logMessage As String, methodName As String)
CallMethodName = methodName
'ERRORログ出力
Call LogOutput("ERROR", LOGLEVEL_ERROR, logMessage)
End Sub
この方法をとることで、INFOがinfoになったり、Infoになったりとバラツキが出ないようにした。
同じになるというのはとても大事なことであると考えています。
必要に応じてログを出力するが、残念ながら行番号までは表示ができない…
VBA自体行番号を持っていないので、出力することすらできない…
VBAでまるで通常のアプリケーションのようなログ出力ができるようになった。
2024/06/18 11:30:00 [INFO] [メソッド名] ログメッセージ
使う機会は少ないかもしれないが、少し複雑なVBAを作成した時は何かしらバグが出ないとも限らない
その時に再度再現するための調査をするのは結構大変なのでログはとても重要な情報となる。
また気になる機能があったら都度追加したりしていきたいと思います。
公開中:GitHub