- 「エラーが発生しているけど、処理のどこで発生しているかわからない……」
- 「運用端末でエラーが発生するけど、開発端末では問題ないからデバッグができない……」
といったケースのお問い合わせを、弊社テクニカルサポートでも時々頂戴します。
そんな時にログをテキストに逐次出力することで、
処理がどこまで成功していて、どこでエラーになったのか追跡することが容易になります。
そんなテキストログの出力手順をご紹介します。
【手順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)に到達することなくエラーになったということが読み取れます。
そこから、ロジックのどの部分でエラーが発生したかが特定しやすくなります。