- 「エラーが発生しているけど、処理のどこで発生しているかわからない……」
- 「運用端末でエラーが発生するけど、開発端末では問題ないからデバッグができない……」
といったケースのお問い合わせを、弊社テクニカルサポートでも時々頂戴します。
そんな時にログをテキストに逐次出力することで、
処理がどこまで成功していて、どこでエラーになったのか追跡することが容易になります。
そんなテキストログの出力手順をご紹介します。
【手順1:ログ書き出し処理の作成】
共通処理として以下のような手続き(procedure)を作成しておきます。
データモジュールやdprファイルのようなどこからでも呼び出せるユニット内に
記述しておくと、各ユニットに個別に記述する必要がないため便利です。
{******************************************************************************* 目的: ログ書き出し処理(簡易版) 引数: AMsg - 出力するメッセージ内容 戻値: *******************************************************************************} procedure WriteLog(AMsg: String); var FLog: TextFile; // テキストファイル制御変数 SLog: string; // 出力文字列(AMsgに情報追加し、実際に出力する文字列) sLogFileName: String; // 出力するログファイルのフルパス begin // ログファイル名の取得 ※1 sLogFileName := ChangeFileExt(Application.ExeName, '.log'); // ログ書き出し処理 try // ファイル変数の関連付け AssignFile(FLog, sLogFileName); try if FileExists(sLogFileName) then Append(FLog) // ファイルの末尾に追加 else Rewrite(FLog); // 新しいファイルを作成し開く // 出力メッセージ文字列を作成 ※2 SLog := FormatDateTime('YYYY/MM/DD HH:NN:SS', Now) + ' … ' + AMsg; // ファイルへ書き出し Writeln(FLog, SLog); finally // ファイル関連付け終了 CloseFile(FLog); end; except // ログ書き出しに失敗した場合、0.5秒待機して再処理 // (※ログファイルが掴まれていた場合は書き出しに失敗します) Sleep(500); WriteLog(AMsg); // 同じ引数でもう一度呼び出す // このまま抜ければエラーは画面に表示されない end; end;
※1:この例では、EXEと同階層にEXEと同名のログファイルが作成されます。
実際のコーディング時は任意のパスを(フルパスで)指定して下さい。
※2:この例では、タイムスタンプと引数のメッセージが以下のように出力されます。
2021/06/14 12:02:05 … (1)データセットを閉じました
【手順2:ログ書き出し処理の呼び出し】
実際の処理中では、以下の例のように記述することで、
手順1で作成した「WriteLog」を通るたびにテキスト出力処理が行われます。
(※コンパイルエラーになった場合は、uses節に「System」を追加)
procedure TForm1.Button2Click(Sender: TObject); begin FDQuery1.Close; WriteLog('(1)データセットを閉じました'); // ★★テキストログ出力 FDQuery1.SQL.Text := '~~~'; FDQuery1.ParamByName(~~~).AsString := '~~~'; WriteLog('(2)SQLとパラメータをセットしました'); // ★★テキストログ出力 Call4001.Execute; WriteLog('(3)事前に呼んでおくCLを呼出完了しました'); // ★★テキストログ出力 try FDQuery1.Open; WriteLog('(4)FDQuery1のオープンが完了しました'); // ★★テキストログ出力 except on e: Exception do begin // エラー発生時にも活用できる WriteLog('エラー発生! エラークラス名=' + e.ClassName + ' ' + 'エラーメッセージ=' + e.Message); // ★★テキストログ出力 // 本来出るはずだったエラーを画面に再表示する //(raiseしていないと、エラーを画面に出さずに抜けられる) raise; end; end; end;
<出力されるテキストのイメージ>
この例では、例えばエラー発生時に(1)(2)(3)までのログのみ残っていて
次の行が「エラー発生!」のログになっていた場合、
(4)に到達することなくエラーになったということが読み取れます。
そこから、ロジックのどの部分でエラーが発生したかが特定しやすくなります。