【Access VBA】クラスモジュールDebugLogOnAccdbでAccess VBAのデバッグログを取りデバッグを劇的に効率化しよう

【Access VBA】クラスモジュールDebugLogOnAccdbでAccess VBAのデバッグログを取りデバッグを劇的に効率化しよう

クラスモジュールDebugLogOnAccdbでAccess VBAのデバッグログを取りデバッグを劇的に効率化しよう

皆さんはAccess VBAコードのデバッグに苦労していませんか。

特にAccess内でフォーム、コントロールの動作を記述するイベントプロシージャではその生成時に同様のプロシージャ―名が多数生成されるため

いったい自分がどのイベントプロシージャのデバッグをしているのかがわからなくなったり、別フォームのイベントプロシージャを誤って修正してしまったりということはないでしょうか。

この記事では、このような悩みを解消するため、Accessのプロジェクト内にクラスモジュールDebugLogOnAccdbを定義し

イベントプロシージャ、あるいはそれ以外の一般的なプロシージャ、関数(Function)でこのDebugLogOnAccdb のメソッド .SaveFormLog.SaveLog を呼び出すことで、デバッグログを簡単に収集し、プロシージャ、イベントをトレースすることでデバッグを劇的に効率化する方法を紹介します。

具体的にはVBE内のメニューの

挿入(I) > クラスモジュール(C)

でクラスモジュール(C)内にDebugLogOnAccdbというクラスモジュールを登録し

【Access VBA】クラスモジュールDebugLogOnAccdbでAccess VBAのデバッグログを取りデバッグを劇的に効率化しよう
クラスモジュール挿入方法

 

【Access VBA】クラスモジュールDebugLogOnAccdbでAccess VBAのデバッグログを取りデバッグを劇的に効率化しよう
DebugLogOnAccdb クラスモジュール


標準モジュールの先頭でこのクラスモジュールを使ったパブリック型の DebugLog オブジェクトをインスタンス化し

Public DebugLog As New DebugLogOnAccdb


フォームモジュール内のイベントプロシージャ内で

DebugLog.SaveFormLog "Form_Open"
    :
DebugLog.SaveFormLog "Form_Open", Err.Description


と記述したり

標準モジュール、フォームモジュールに内の一般的なプロシージャや関数(Funcrion)内で

DebugLog.SaveLog "Procedure_Name"
    :
DebugLog.SaveLog "Procedure_Name", Err.Description


と記述したりすることで

以下のようなタイムスタンプ付きの実行ログを

  • イミディエットウインドウ内に表示
  • このAccessプロジェクト名に対し一意に決めれれたログファイル内に保存

することができます。

そしてこのログによりプログラムの実行状況が可視化されるため、デバッグを劇的に効率化することができるようになります。

2023/09/10 23:51:17 SampleDB.accdb : Sample : 起動されました。
2023/09/10 23:58:57 SampleDB.accdb : frm002 : Form_Open : Something good
2023/09/11 00:06:19 SampleDB.accdb : frm002 : Form_Open : 起動されました。
2023/09/11 00:06:19 SampleDB.accdb : frm002 : Form_Open : Something good
2023/09/11 00:06:22 SampleDB.accdb : frm001 : Form_Open : 起動されました。


この情報が読者の皆様のお役に立てることを願っています。

【Access VBA】クラスモジュールDebugLogOnAccdbでAccess VBAのデバッグログを取りデバッグを劇的に効率化しよう
しらかば堂

こんにちは。 しらかば堂です。
皆さんの VBA による Access フォームの開発はかどってますか?

解決できること

あなたの Access VBA プロジェクトにこの DebugLogOnAccdbクラスモジュールを定義し

このクラスモジュールを標準モジュール等でDebugLogオブジェクトとしてインスタンス化したのち

あなたが開発中の標準モジュールフォームモジュールプロシージャ関数(Funcrion)中に

  • DebugLog.SaveLogプロシージャ名“[,”追加情報”]
  • DebugLog.SaveFormLog, “プロシージャ名“[,”追加情報”]

といったメソッドを追記しておくと

デバッグ中あるいはデバッグ後にどのプロシージャ、関数(Function)オブジェクトが起動されたか、例外処理が走っていないか等をログから簡単に確認することが出来ます。

またプロシージャ内へのVBAコーディングの際にはインテリセンス機能により、このオブジェクトで利用可能なプロパティ名、メソッド名を表示できます。

【Access VBA】クラスモジュールDebugLogOnAccdbでAccess VBAのデバッグログを取りデバッグを劇的に効率化しよう
利用可能なプロパティ名、メソッド名の表示
【Access VBA】クラスモジュールDebugLogOnAccdbでAccess VBAのデバッグログを取りデバッグを劇的に効率化しよう
しらかば堂

このログの出力有無は クラスモジュール DebugLogOnAccdb中に定義されたDEBUG_MODE というBoolean型の定数の設定値により制御します。

また、このログを最大何行まで保存可能とするかをMAX_LOG_LINESというInteger型の定数の設定値により指定します。

この保存行の上限設定はこのプロジェクトのデバッグ終了後に
DEBUG_MODE =False
への設定をし忘れたようなケースで、ログ容量増大によりシステム破壊等が起きないようにするためのものです。

定数名 設定値 意味
DEBUG_MODE プロジェクトの実行モード、ログの出力有無を決めるオブジェクトクラス内定数。
True デバッグ中モードでログ出力あり
False 通常運用中モードでログ出力無し
MAX_LOG_LINES

ログの最大保存数。

デバッグモードで、無用なログ増大によるシステム障害等を回避するため

直近から最大MAX_LOG_LINESで定義された行数になるまで保存されます。また過去のMAX_LOG_LINESを超える過去部分は自動的に削除します。

読んでほしい方

フォームを含む Access VBAのデバッグに苦労されている方、

イベントプロシージャ、通常プロシージャにまたがったタイムスタンプ付きログ収集の仕組みを検討されている方、

には必見の内容です。

クラスモジュールについて

クラスモジュールはVBAでオブジェクト志向型プログラムを行うため
クラス(オブジェクトの設計図)実装を行うためのモジュールで

VBE内のメニューの

挿入(I) > クラスモジュール(C)

でクラスモジュール(C)内にクラス名をつけたモジュールを登録することで定義します。

【Access VBA】クラスモジュールDebugLogOnAccdbでAccess VBAのデバッグログを取りデバッグを劇的に効率化しよう
クラスモジュール挿入方法

 

【Access VBA】クラスモジュールDebugLogOnAccdbでAccess VBAのデバッグログを取りデバッグを劇的に効率化しよう
DebugLogOnAccdb クラスモジュール

VBAのクラス実装では一般にこのモジュール中に次のような記述を行います。

種類 説明
プロパティ  

クラス内に保有するデータのこと。

クラスの設計者はこのクラス内で使用するデータを自由に定義します。

一般にクラス内に定義されたデータは外部からは参照しませんが Property ステートメントを使った

  • Getterプロパティ
  • Setterプロパティ

という仕組みを利用し、外部から参照したり、値を変更したりすることを許すこともできます。

Getterプロパティ

外部から参照可能なデータのプロパティです。

Setterプロパティ

外部から設定可能なデータのプロパティです。

メソッド  

ユーザーに対してこのクラスが提供する機能をプロシージャ、Funcrion(関数)の形で定義します。

またこのプロシージャの中には

  • クラスの初期化を行うClass_Initialize
  • クラスの終了処理を行うClass_Terminate

という予約定義された特別なプロシージャも定義出来ます。

Class_Initialize() クラスの初期化を行うプロシージャです。
このメソッドは以下のようにこのクラスを使ったオブジェクトがインスタンス化されたとき起動されます。

Public DebugLog As New DebugLog

Class_Terminate() クラスの終了処理を行うプロシージャです。
このメソッドは以下のようにインスタンス化されたオブジェクトが廃棄されたとき起動されます。

Set DebugLog = Nothing

DebugLogOnAccdbクラスモジュール の概要

プロパティ

このDebugLogOnAccdbクラスモジュールは、Accessのフォーム配下のイベントプロシージャやその他の通常プロシージャで、タイムスタンプ付のログを保存するための仕組みを提供するためのもので

以下のようなプロパティメソッドを定義しています。

プロパティ名 意味
FilePath String

ログの格納されるファイルの絶対パスを格納しています。
参照のみが可能で、設定はできません。

この絶対パスはイミディエットウインドウ中で
? DebugLog.FilePath
を実行すると確認できます。

IsDebugMode


Boolean

このDebugLogクラスモジュールの実行モードを格納しています。
参照のみ可能で、設定はできません。

この値の変更はデバッグ、あるいは運用開始時にこのクラスモジュールの先頭にあるDEBUG_MODE 定数を修正することで行います。

この数はイミディエットウインドウ中で
? DebugLog.IsDebgMode
を実行すると確認できます。

Yes

デバッグモード中です。

MAX_LOG_LINES で指定された最大行数まで直近のログの保存を行い、最大行を超える過去ログは古いものから順に削除されます。

No

デバッグモード中ではありません(=通常運用モードです)。

通常運用モードとしてログの保存は行いません。

メソッド

メソッド名 パラメータ名 省略可否 意味
SaveFormLog フォーム内のイベントプロシージャ内で
タイムスタンプ付きのログを保存するメソッドです。

ログ中あるいはイミディエットウインドウ内に自動的にフォーム名が挿入されます。

proc_name String 不可 ログに記録したいプロシージャ名を指定します。
error_message String ログ中に追記したいErr.Description等の文字列を指定します。

この指定が省略された場合には「起動されました。」という文字列が自動挿入されます。

これはイベントプロシージャの先頭でそのプロシージャが起動されたことを記録する場合に使用します。

SaveLog フォーム内以外の一般プロシージャ、関数の内でタイムスタンプ付きのログを保存するメソッドです。

ログ中あるいはイミディエットウインドウ内にフォーム名は挿入されません

proc_name String 不可 ログに記録したいプロシージャ名、関数名を指定します。
error_message String

ログ中に追記したいErr.Description等の文字列を指定します。

この指定が省略された場合には「起動されました。」という文字列が自動挿入されます。

これはプロシージャや関数の先頭でそのプロシージャ、関数が起動されたことを記録する場合に使用します。

ShowLog なし

デバッグモードのとき

直近で記録されたログMAX_LOG_LINES行をイミディエットウインドウ内に表示します。

DebugLogOnAccdbクラスモジュール の使い方

標準モジュール内でのオブジェクトのインスタンス化

VBAコードの標準モジュールの先頭で以下のように Public な DebugLog オブジェクトをインスタンス化します。

クラスはこのようにインスタンス化(実体化)して初めてオブジェクトとして利用可能になります。

Public DebugLog As New DebugLogOnAccdb

フォームのイベントプロシージャ内での使用例

ログを記録したいプロシージャの中で以下のようなログ保存のメソッド
DebugLog.SaveFormLog
を プロシージャ名を表す文字列、そして必要に応じた追加情報の文字列をパラメータとして呼び出します。

Private Sub Form_Open(Cancel As Integer)
    DebugLog.SaveFormLog "Form_Open"
    Call StandardizeTextboxes(Me)
    On Error GoTo Err_Form_Open
' ここに個別処理を記述
Exit_Form_Open:
    Exit Sub
Err_Form_Open:
    DebugLog.SaveFormLog "Form_Open", Err.Description
    Resume Exit_Form_Open
    
End Sub
【Access VBA】クラスモジュールDebugLogOnAccdbでAccess VBAのデバッグログを取りデバッグを劇的に効率化しよう
しらかば堂

2行目の
Call StandardizeTextboxes(Me)
は以下の参照記事でご紹介しているプロシージャで
フォーム内のテキスト、ラベル等の書式をあわせるプロシージャです。

【特集】AccessフォームのコントロールプロパティをVBAで一括設定して見ばえを統一しよう

 

コラム:プロシージャの起動記録、例外処理について

イベントプロシージャ内に限らず
プロシージャを実装する際には、その起動時間の記録、例外発生原因の記録を含めた以下のような標準的なテンプレートを利用すると

プロシージャの実行ログ、例外処理が発生した場合の原因確認が簡単にできるので、おすすめです。

Private Sub Form_Open(Cancel As Integer)
    DebugLog.SaveFormLog "Form_Open"
    On Error GoTo Err_Form_Open
    ' ここに個別処理を記述
Exit_Form_Open:
    Exit Sub
Err_Form_Open:
    DebugLog.SaveFormLog "Form_Open", Err.Description
    Resume Exit_Form_Open
End Sub

 

VBAコード 説明
1 Private Sub Form_Open
 (Cancel As Integer)
プロシージャ名 “Form_Open” の開始
2 DebugLog.SaveFormLog
“Form_Open”
でこのプロシージャが開始したことをタイムスタンプ付きでログに取ります。
3 On Error GoTo Err_Form_Open 例外発生時のジャンプ先を Err_プロシージャ名 という形で定義します。
5-6 Exit_Form_Open:
Exit Sub
このプロシージャの出口となるジャンプ先を Exit_プロシージャ名 という形で定義します。
7-9 Err_Form_Open:
DebugLog.SaveFormLog
“Form_Open”, Err.Description

Resume Exit_Form_Open
例外処理の開始アドレスを
Err_プロシージャ名:
という形で定義します。
そしてその原因記述Err.Description
を含めた例外発生原因をタイムスタンプ付きでログに取り
Exit_Form_Open
へ戻ります。
10 End Sub プロシージャ名 “Form_Open” の終了

フォーム以外の一般的なプロシージャ、関数内での使用例

ログを記録したい一般的なプロシージャ、関数内で以下のようなログ保存のメソッド
DebugLog.SaveLog
を プロシージャ名を表す文字列、そして必要に応じた追加情報の文字列をパラメータとして呼び出します。

Sub Sample()
    DebugLog.SaveLog "Sample"    
    On Error GoTo Err_Sample
    ' ここに個別処理を記述
Exit_Sample:
    Exit Sub
Err_Sample:
    DebugLog.SaveLog "Sample", Err.Description
    Resume Exit_Sample
End Sub


これはフォーム名が表示されないだけで、その他については 先ほどの
DebugLog.SaveFormLog
とほぼ同様です。

【Access VBA】クラスモジュールDebugLogOnAccdbでAccess VBAのデバッグログを取りデバッグを劇的に効率化しよう
しらかば堂

何故フォームプロシージャとそれ以外の一般プロシージャで同じ機能を持ったメソッドがわかれているかというと

  • 一般プロシージャにはフォームプロシージャが備えているCodeContextObject.Name というプロパティが存在しない
  • VBA自身に現在実行中のモジュール名を知る手段が提供されていない

ためです。

ログデータの表示方法

このVBAコードを含むツール(例えばSampleDB.accdb)中のVBEイミディエットウインドウ内で DebugLog.Show メソッドを実行すると

DebugLog.Show
2023/09/10 23:51:17 SampleDB.accdb : Sample : 起動されました。
2023/09/10 23:58:57 SampleDB.accdb : frm002 : Form_Open : Something good
2023/09/11 00:06:19 SampleDB.accdb : frm002 : Form_Open : 起動されました。
2023/09/11 00:06:19 SampleDB.accdb : frm002 : Form_Open : Something good
2023/09/11 00:06:22 SampleDB.accdb : frm001 : Form_Open : 起動されました。


というように保存されたログファイルを簡単に参照できます。

【Access VBA】クラスモジュールDebugLogOnAccdbでAccess VBAのデバッグログを取りデバッグを劇的に効率化しよう
しらかば堂

このログは分離用の “:” を除くと以下のようになっています。

  • 起動された日付
  • 起動された時間
  • プロジェクト名(つまりAccessのファイル名)
  • フォーム名(フォームから起動された場合のみ)
  • プロセス名
  • 備考情報(起動、Error.Description等、コード中で設定した文字列)

ログファイルの絶対パス、デバッグモードの表示方法

必要に応じてこのVBAコードを含むツール(例えばSampleDB.accdb)中のVBEイミディエットウインドウ内で 以下のコマンドを実行すると

? DebugLog.FilePath
C:\Users\devel\Tools_Data_Logs\accdb\Sampledb.log

? DebugLog.IsDebugMode
True


というように簡単にログファイルの絶対パス、デバッグモードの表示ができます。

【Windows業務効率化】バッチファイルでツールのフォルダ環境を自動生成しよう

VBAコード

DebugLogOnAccdbクラスモジュール

この DebugLogOnAccdbクラスは、Access VBAを用いたフォームの開発等に応じてその実行ログ、エラーログを簡単にトレース可能とするためのクラスで

VBAのクラスモジュール(C)に DebugLogOnAccdbという名前のクラスモジュールを定義し、標準モジュール内でこれをオブジェクトとしてインスタンス化することで、他の標準モジュール、フォームモジュールからの参照が可能となります。

【Access VBA】クラスモジュールDebugLogOnAccdbでAccess VBAのデバッグログを取りデバッグを劇的に効率化しよう
【Access VBA】クラスモジュールDebugLogOnAccdbでAccess VBAのデバッグログを取りデバッグを劇的に効率化しよう

以下このDebugLogOnAccdbクラスオブジェクトについて簡単にご紹介します。

プロパティ定義

まず、クラスモジュールの先頭に、このクラス内で利用するPrivate変数、Private定数を定義しています。

Option Compare Database

' ログファイルのパスを格納する変数
Private logFilePath As String

' ログファイルの最大行数
Private Const MAX_LOG_LINES As Integer = 50

' デバッグモードの有効/無効を切り替えるフラグ
Private Const DEBUG_MODE As Boolean = True

' ログのファイルパスのGetterプロパティ
Property Get FilePath() As String
    FilePath = logFilePath
End Property

' デバッグモードのGetterプロパティ
Property Get IsDebugMode() As Boolean
    IsDebugMode = DEBUG_MODE
End Property


そして外部への参照を可能とするFilePathIsDebugMode Propertyステートメントを使ってプロパティとして公開設定しています。

コラム: Property ステートメント

Property ステートメントはクラスモジュールにカスタム プロパティを作成するステートメントで、クラスモジュール内に定義したローカル変数を外部から参照したり、値を設定したいときに使用します。

記述例 説明
Property Get FilePath() As String
FilePath = logFilePath
End Property
プロパティ FilePathに読み取り可能なパーミッションを設定します。

イミディエットウインドウ中で
? DebugLog.FilePath
を実行すると現在のログの絶対パスが確認可能です。

Property Let FilePath(ByVal file_path As String)
logFilePath = file_path
End Property
プロパティ FilePathに書きこみ可能なパーミッションを設定します。

運用上の不要なので本記事では使用していませんが、イミディエットウインドウ中で
DebugLog.FilePath= “filePathOfLogfile”
を実行すると、デバッグログの絶対パスを変更することができます。

この Property ステートメントには他にオブジェクトに対しての値設定を行う
Property Set というステートメントもありますが、これらを含む詳細な情報に関しては Excelの神髄 (@yamaoka_ss)さんのサイト
第140回.Property {Get|Let|Set} ステートメント
に良質な情報が掲載されていますので、必要に応じてそちらもご確認ください。

Class_Initialize

Class_Initialize というVBAで予約されたプロシージャ名は、インスタンス化されたオブジェクトの初期設定処理を行います。

' クラスの初期化
Private Sub Class_Initialize()
    
    ' ファイルシステムオブジェクトの生成
    Dim fsObject As Object
    Set fsObject = CreateObject("Scripting.FileSystemObject")
    
    ' ユーザーのプロファイルディレクトリにログディレクトリを作成
    logFilePath = Environ("UserProfile") & "\Tools_Data_Logs"
    If Not fsObject.FolderExists(logFilePath) Then
        MkDir (logFilePath)
    End If
    
    ' ログディレクトリ内に.accdbディレクトリを作成
    logFilePath = logFilePath & "\accdb"
    If Not fsObject.FolderExists(logFilePath) Then
        MkDir (logFilePath)
    End If
    
    Set fsObject = Nothing
    
    ' ログファイルのパスを設定
    logFilePath = Environ("UserProfile") & "\Tools_Data_Logs\accdb\" & Replace(CurrentProject.Name, ".accdb", ".log")
    
End Sub



ここではインスタンス化されたオブジェクト内に定義された

logFilePath

という内部変数に、環境変数 %USERPROFILE% を起点としたこのAccessプロジェクトのログ保存フォルダの絶対パス

%USERPROFILE%\Tools_Data_Logs\accdb\実行中のプロジェクト名.log

を設定しています。

こうしたツールのフォルダ環境については必要に応じて以下の記事も参照ください。

【Windows業務効率化】バッチファイルでツールのフォルダ環境を自動生成しよう



Class_Terminate

Class_TerminateというVBAで予約されたプロシージャ名は、インスタンス化されたオブジェクトの終了処理を行います。

' クラスの終了処理
Private Sub Class_Terminate()
    
    ' ファイルシステムオブジェクトの生成
    Dim fsObject As Object
    Set fsObject = CreateObject("Scripting.FileSystemObject")
    
    ' ログファイルが存在する場合、削除
    If fsObject.FileExists(logFilePath) = True Then
        fsObject.DeleteFile filespec:=logFilePath, force:=True
        Debug.Print logFilePath & " が削除されました。"
    End If
    
End Sub


ログというファイルの性質から、運用時にこのメソッドを使用する局面はないと思われますが、もし収集されたログを全て削除したい場合はVBEのイミディエットウインドウ内で以下のコマンドを入力すると、このプロジェクトファイルのログが削除されます。

Set DebugLog = Nothing
C:\Users\devel\Tools_Data_Logs\accdb\Access開発_実践ノウハウ.log が削除されました。



TruncateLog

次の SaveFormLogSaveLog から呼び出されるプロシージャで ログファイルの保存行数が MAX_LOG_LINES を超えているとき、古いものから順に削除するプロシージャです。

' ログファイルの行数を制限するサブルーチン
Private Sub TruncateLog()
    
    ' ログファイルの内容を一時的に保持する配列
    Dim logBuffer() As String
    Dim logLineCounter As Integer
    Dim line As String
    
    ' ファイルシステムオブジェクトの生成
    Dim fsObject As Object
    Set fsObject = CreateObject("Scripting.FileSystemObject")
    
    ' ログファイルが存在する場合
    If fsObject.FileExists(logFilePath) = True Then
        
        Dim fileNo As Integer
        fileNo = FreeFile
    
        ' ログファイルを読み込み、行数を数える
        Open logFilePath For Input As #fileNo
        
        logLineCounter = 0
        Do Until EOF(1)
            Line Input #fileNo, line
            If (Len(line) <> 0) Then
                logLineCounter = logLineCounter + 1
            End If
        Loop
        Close #fileNo
        
        ' ログバッファの初期化
        ReDim logBuffer(logLineCounter)
        
        ' ログファイルを再度読み込み、ログバッファに格納
        Open logFilePath For Input As #fileNo
        
        logLineCounter = 0
        Do Until EOF(1)
            Line Input #fileNo, line
            If Len(line) <> 0 Then
                logBuffer(logLineCounter) = line
                logLineCounter = logLineCounter + 1
            End If
        Loop
        Close #fileNo
                
        ' ログファイルが最大行数を超える場合、古いログを削除して新しいログを保存
        If logLineCounter > MAX_LOG_LINES Then
            fsObject.DeleteFile filespec:=logFilePath, force:=True
            fileNo = FreeFile
            
            ' ログファイルを追記モードで開き、最新のログだけを保存
            Open logFilePath For Append As #fileNo
            
            Dim index As Integer
            For index = logLineCounter - MAX_LOG_LINES To logLineCounter
                Print #fileNo, logBuffer(index)
            Next index
            
            Close #fileNo
            
        End If
        
    End If
    
End Sub

SaveFormLog

フォーム内のイベントプロシージャから呼ばれることを前提としたメソッドの実装プロシージャで、第二パラメータerror_message が省略された場合には
error_message = “起動されました。”
を補完した上で

整形されたタイムスタンプ、CurrentProject.Name から得られるウロジェクト名、CodeContextObject.Nameから得られるフォーム名、proc_nameで指定されたプロシージャ名、error_messageで指定されたメッセージを

イミディエットウインドウに表示し

ログファイルに保存し

そしてログの行数を制限します。

' フォームのログを保存するサブルーチン
Sub SaveFormLog(proc_name As String, Optional error_message As String)
    
    ' エラーメッセージが指定されていない場合、"起動されました。"を使用
    If error_message = "" Then
        error_message = "起動されました。"
    End If
        
    ' デバッグモードが有効な場合のみログを出力
    If debug_mode = True Then
        
        ' デバッグウィンドウにログを出力
        Debug.Print Format(Now(), "yyyy/mm/dd hh:nn:ss") & " " & CurrentProject.Name & " : " & CodeContextObject.Name & " : " & proc_name & " : " & error_message
        
        Dim fileNo As Integer   ' ファイル番号
        fileNo = FreeFile
        
        ' ログファイルを追記モードで開き、ログを保存
        Open logFilePath For Append As #fileNo
        Print #fileNo, Format(Now(), "yyyy/mm/dd hh:nn:ss") & " " & CurrentProject.Name & " : " & CodeContextObject.Name & " : " & proc_name & " : " & error_message
        Close #fileNo
        
        ' ログの行数を制限
        Call TruncateLog
        
    End If
    
End Sub

SaveLog

フォーム内以外の一般的なイベントプロシージャ、関数から呼ばれることを前提としたメソッドの実装プロシージャで、第二パラメータerror_message が省略された場合には
error_message = “起動されました。”
を補完した上で

整形されたタイムスタンプ、CurrentProject.Name から得られるプロジェクト名、proc_nameで指定されたプロシージャ名、error_messageで指定されたメッセージを

イミディエットウインドウに表示し

ログファイルに保存し

そしてログの行数を制限します。

' プロシージャ・関数のログを保存するサブルーチン
Sub SaveLog(proc_name As String, Optional error_message As String)
    
    ' エラーメッセージが指定されていない場合、"起動されました。"を使用
    If error_message = "" Then
        error_message = "起動されました。"
    End If
        
    ' デバッグモードが有効な場合のみログを出力
    If debug_mode = True Then
        
        ' デバッグウィンドウにログを出力
        Debug.Print Format(Now(), "yyyy/mm/dd hh:nn:ss") & " " & CurrentProject.Name & " : " & proc_name & " : " & error_message
        
        Dim fileNo As Integer   ' ファイル番号
        fileNo = FreeFile
        
        ' ログファイルを追記モードで開き、ログを保存
        Open logFilePath For Append As #fileNo
        Print #fileNo, Format(Now(), "yyyy/mm/dd hh:nn:ss") & " " & CurrentProject.Name & " : " & proc_name & " : " & error_message
        Close #fileNo
        
        ' ログの行数を制限
        Call TruncateLog
        
    End If
    
End Sub



ShowLog

ログ表示を行うメソッドの実装プロシージャで、logFilePath に設定されているログファイルの絶対パスをもとにログファイルの内容をイミディエットウインドウに出力します。

' ログを表示するサブルーチン
Sub ShowLog()
    
    ' ファイルシステムオブジェクトの生成
    Dim fsObject As Object
    Set fsObject = CreateObject("Scripting.FileSystemObject")
    
    Dim logLine As String
    
    ' デバッグモードが有効な場合のみログを表示
    If DEBUG_MODE = True Then
        
        ' ログファイルが存在する場合
        If fsObject.FileExists(logFilePath) = True Then
            
            Dim fileNo As Integer
            fileNo = FreeFile
            
            ' ログファイルを読み込み、内容をデバッグウィンドウに表示
            Open logFilePath For Input As #fileNo
            
            Do Until EOF(1)
                Line Input #fileNo, logLine
                Debug.Print logLine
            Loop
            Close #fileNo
            
        End If
        
    End If
    
End Sub

まとめ

この記事では、Access内でフォーム、コントロールの動作を記述する多数のイベントプロシージャに対するデバッグを行う中で

  • いったい自分がどのイベントプロシージャのデバッグをしているのかがわからなくなった経験がある
  • 別フォームのイベントプロシージャを誤って修正してしまったことがある

といった悩みを解消するため

Accessのプロジェクト内にクラスモジュールDebugLogOnAccdbを定義し、標準モジュール内でこれを DebugLog というオブジェクトとしてインスタンス化したあと

イベントプロシージャ、あるいはそれ以外の一般的なプロシージャ、関数(Function)でこのDebugLog のメソッド DebugLog.SaveFormLogDebugLog.SaveLog を呼び出すことで

デバッグログを簡単に収集し、プロシージャ、イベントをトレースすることで、デバッグを劇的に効率化する方法を紹介しました。

この情報が読者の皆様のお役に立てることを願っています。

ライブラリ一覧