Excel VBA 逆引き集 | ログ+例外テンプレ

Excel VBA
スポンサーリンク

ログ+例外テンプレ

つまずいた時に「何が起きたか」を残しつつ、止めずに安全に終わらせる。そのために、ログ出力と例外(エラー)処理をワンセットで使えるテンプレートをまとめました。初心者でもすぐ使える形で、例題付きで説明します。


基本の考え方と使い分け

  • 目的:
    • エラーが起きても止まらず「記録」「後始末」「通知」を行う。
  • 出力先の選択:
    • 開発中: Immediateウィンドウ(Debug.Print)。
    • 運用: ファイル出力 or シート出力(監査・追跡用)。
  • ログレベル(おすすめ):
    • INFO: 開始/終了/要点。
    • WARN: 想定外だが継続可能。
    • ERROR: 例外発生・中断・復旧内容。
    • DEBUG: 詳細トレース(開発時のみ)。

テンプレ1:最小構成(即使える)

' すぐ使える軽量ロガー(Immediate出力)
Sub Log(ByVal level As String, ByVal msg As String)
    Debug.Print Format(Now, "yyyy-mm-dd HH:NN:SS") & " [" & level & "] " & msg
End Sub

' 例外処理つきの基本形
Sub RunBasic()
    On Error GoTo ErrHandler
    Log "INFO", "処理開始"
    
    ' 本処理(例:レポート生成)
    Worksheets("Report").Range("A1").Value = "作成日: " & Date
    Log "DEBUG", "Report!A1 に日付を書き込み"

    ' 故意にエラー
    Worksheets("NoSheet").Activate
    
    Log "INFO", "処理正常終了"
    Exit Sub

ErrHandler:
    Log "ERROR", "Err " & Err.Number & " | " & Err.Description
    ' 必要なら後始末(ファイルクローズ、状態復元など)
End Sub
VB
  • ポイント:
    • 開始/終了を必ず記録。
    • 例外発生時に番号と説明を残す。
    • 後始末はエラー側でまとめると安全。

テンプレ2:共有ロガー(レベル+出力切替)

' 標準モジュール: Logger.bas
Public Enum LogLevel
    LOG_DEBUG = 1
    LOG_INFO = 2
    LOG_WARN = 3
    LOG_ERROR = 4
End Enum

Public CURRENT_LOG_LEVEL As LogLevel
Public OUTPUT_TO_FILE As Boolean
Public LOG_PATH As String

Public Sub LogInit(Optional lvl As LogLevel = LOG_INFO, _
                   Optional toFile As Boolean = False, _
                   Optional path As String = "C:\temp\vba.log")
    CURRENT_LOG_LEVEL = lvl
    OUTPUT_TO_FILE = toFile
    LOG_PATH = path
End Sub

Public Sub LogWrite(ByVal lvl As LogLevel, ByVal msg As String)
    If lvl < CURRENT_LOG_LEVEL Then Exit Sub
    
    Dim prefix As String
    Select Case lvl
        Case LOG_DEBUG: prefix = "DEBUG"
        Case LOG_INFO:  prefix = "INFO "
        Case LOG_WARN:  prefix = "WARN "
        Case LOG_ERROR: prefix = "ERROR"
    End Select
    
    Dim line As String
    line = Format(Now, "yyyy-mm-dd HH:NN:SS") & " [" & prefix & "] " & msg
    
    If OUTPUT_TO_FILE Then
        Dim fso As Object, ts As Object
        Set fso = CreateObject("Scripting.FileSystemObject")
        Set ts = fso.OpenTextFile(LOG_PATH, 8, True) ' 8=追記
        ts.WriteLine line
        ts.Close
    Else
        Debug.Print line
    End If
End Sub

Public Sub HandleError(ByVal procName As String)
    LogWrite LOG_ERROR, "Proc=" & procName & _
        " | Err " & Err.Number & " | " & Err.Description
    Err.Clear
End Sub
VB
' 使い方例
Sub RunWithSharedLogger()
    On Error GoTo ErrHandler
    LogInit LOG_DEBUG, True, "C:\temp\run.log" ' レベル=DEBUG, 出力=ファイル
    
    LogWrite LOG_INFO, "日次処理開始"
    ' …処理…
    LogWrite LOG_DEBUG, "入力件数=123"
    ' 故意にエラー
    Worksheets("NoSheet").Activate
    
    LogWrite LOG_INFO, "日次処理正常終了"
    Exit Sub
ErrHandler:
    HandleError "RunWithSharedLogger"
End Sub
VB
  • ポイント:
    • レベルで絞り込み(運用はINFO以上、開発はDEBUG)。
    • 出力先切替(Immediate/ファイル)で使い回し。
    • 共通エラーハンドラに処理名を渡して特定しやすくする。

テンプレ3:例外境界(Try風)と後始末(Finally風)

' Try-Finally風のパターン(VBAにはFinallyがないため、手動で後始末を保証)
Sub TryFinallyExample()
    Dim fso As Object, ts As Object, ok As Boolean
    On Error GoTo ErrHandler
    
    Log "INFO", "ファイル書き込み開始"
    Set fso = CreateObject("Scripting.FileSystemObject")
    Set ts = fso.OpenTextFile("C:\temp\out.txt", 2, True) ' 2=書き込み
    ts.WriteLine "処理開始: " & Now
    
    ' 本処理…
    ts.WriteLine "データ: 123"
    ok = True
    
CleanUp:
    ' 後始末(必ず通る)
    On Error Resume Next
    If Not ts Is Nothing Then ts.Close
    Set ts = Nothing: Set fso = Nothing
    On Error GoTo 0
    
    If ok Then
        Log "INFO", "ファイル書き込み正常終了"
    Else
        Log "WARN", "ファイル書き込みは後始末済み(エラーあり)"
    End If
    Exit Sub

ErrHandler:
    Log "ERROR", "Err " & Err.Number & " | " & Err.Description
    ok = False
    GoTo CleanUp
End Sub
VB
  • ポイント:
    • CleanUpラベルで「Finally風」の後始末を保証。
    • 成否フラグを使って終了ログのレベルを切り替える。

テンプレ4:1件ずつの堅牢処理(Resume Next+集計)

Sub RobustPerItem()
    Dim ws As Worksheet: Set ws = Worksheets("Input")
    Dim cell As Range
    Dim okCount As Long, ngCount As Long
    
    Log "INFO", "行単位処理開始"
    
    For Each cell In ws.Range("A1:A20")
        On Error Resume Next
        ' 各行の小さな失敗はスキップして集計
        cell.Offset(0, 1).Value = CLng(cell.Value) ' ここで失敗する可能性
        If Err.Number <> 0 Then
            Log "WARN", "変換失敗 at " & cell.Address & " | " & Err.Description
            Err.Clear
            ngCount = ngCount + 1
        Else
            okCount = okCount + 1
        End If
        On Error GoTo 0
    Next
    
    Log "INFO", "行単位処理終了 OK=" & okCount & " NG=" & ngCount
End Sub
VB
  • ポイント:
    • Resume Nextは「1件失敗でも全体継続」したい時に有効。
    • 必ずErr判定+Err.Clearで後続への影響を断つ。
    • 最後に件数集計をログ出力。

例題で練習(すぐ試せる)

  • 例1: テンプレ1を使って、存在しないシート参照エラーを記録しつつ終了ログを出す。
  • 例2: テンプレ2の共有ロガーでレベルをINFOにして、実運用向けファイルログを作る。
  • 例3: テンプレ3のCleanUpを使って、ファイル出力やADO接続を安全に後始末する。
  • 例4: テンプレ4でA1:A20を整数変換し、失敗件数をWARNログに残す。

初心者向けポイント(実務で効くコツ)

  • 開始・終了ログは必須: 走ったかどうか、どこで終わったかが分かる。
  • 例外情報は3点セット: 番号、説明、処理名(関数名)。
  • Resume Nextは限定使用: ループ内など「継続が重要」な場面に絞る。
  • 後始末は必ず共通化: ファイル/接続/画面状態はCleanUpで確実に戻す。
  • 運用時はINFO/WARN/ERRORだけ: DEBUGは開発時のみで十分。
タイトルとURLをコピーしました