Запись в Log-файл
Запись отладочной информации в файл протокола (Log-файл) существенно отличается от предыдущих приемов записи, так как это уже нельзя назвать "быстро и грязно". Это отличная технология, которую можно использовать в любом приложении.
Запись в файл протокола выполняется так же, как и вывод на консоль, но вместо WriteLn (. . . ) используется WriteLn (LogFile, . . . ), где LogFile — имя файловой переменной типа TextFile. Надо также не забывать открывать этот файл в начале работы приложения и закрывать — в конце. Проще всего этого добиться, поместив соответствующий код в свой модуль, который благодаря возможности условной компиляции подключается только в отладочной версии вашей программы.
Листинг 2.1. Модуль протоколирования отладочной информации.
unit uLoq;
interface
procedure Log(S: Strings-implementation uses
Windows, SysUtils;
var
LogFile: TextFile;
LogCriticalSection: TRtlCriticalSection;
procedure Log(S: String);
var
SystemTime: TSystemTime;
FileTime: TFileTime;
begin
GetSystemTime (SystemTime) ;
SystemTimeToFileTime(SystemTime, FileTime) ;
EnterCriticalSection(LogCriticalSection);
WriteLn(LogFile, Format('%s %.8x%.8x %5',
[FormatDateTime('yy.mm.dd hh.inm.ss'. Now),
FileTime.dwHighDateTime, FileTime.dwLowDateTime, S])) ;
LeaveCriticalSection(LogCriticalSection) ;
end;
procedure Startup;
var
FileName: String;
begin
InitializeCriticalSection(LogCriticalSection);
FileName := Format("Log file for %s at %s.txf,
[ParamStr(O), DateTimeToStr(Now)]) ;
while Pos(':', FileName) 0 do
FileName[Pos(':', FileName)] := '.';
while Pos('/', FileName) 0 do
FileName[Pos('/', FileName)] := '-';
while Pos('\', FileName) 0 do
FileName[Pos('\', FileName)] := '.';
AssignFile(LogFile, FileName);
Rewrite(LogFile) ;
end;
procedure Shutdown;
begin
CloseFile(LogFile) ;
DeleteCriticalSection(LogCriticalSection) ;
end;
initialization Startup;
finalization Shutdown;
end.
Этот модуль сам создает, открывает и закрывает файл протокола. Имя файла создается с учетом имени приложения и текущих даты и времени, что исключает возможность записи информации поверх существующего файла. Для использования модуля условно включите его, как показано ниже.
unit MyUnit;
interface
uses
($ifdef Debug} uLog, {$endif)
Windows, Messages, SysUtils, Classes,
. . .
Затем используйте его приблизительно так.
{$ifdef Debug)
Log(Format(' Entering the Foo procedure; Bar = %d',[Bar]));
{$endif}
He забывайте размещать вызов между директивами условной компиляции, иначе при компиляции коммерческой версии возникнет ошибка.
Модуль uLog обладает двумя интересными и полезными свойствами. Во-первых, каждая запись в файл предваряется информацией о дате, времени и шестнадцатеричным числом, соответствующим системному времени в миллисекундах. Эта информация может быть весьма полезной, особенно когда вы хотите отследить последовательность событий в приложении. Во-вторых, модуль использует критические разделы (critical section), что обеспечивает доступ к файлу только одной подзадачи в один момент времени.
На рис. 2.25 показан типичный файл протокола в программе Notepad.
Рис. 2.25. Пример отладочного файла протокола
Как правильно использовать файл протокола? Какую информацию в него записывать? Сколько программистов, столько и ответов на эти вопросы. Лично я предпочитаю придерживаться золотой середины между "записывай все" и "записывай только то, что отлаживаешь".