Вывод на консоль
Еще один способ вывода отладочной информации- вывод на консоль с использованием процедур Write и WriteLn. Вы можете конвертировать проект в консольное приложение, например, выбрав соответствующую опцию (команду Project/Options, вкладку Linker и опцию Generate Console Application) или поместив директиву $APPTYPE CONSOLE в главный DPR-файл. Учитывая, что ваше приложение- не консольное, воспользуйтесь возможностями условной компиляции и используйте директиву $APPTYPE как показано ниже:
{$ifdef Debug} {$APPTYPE CONSOLE} {$endif}
Теперь вывод на консоль будет осуществляться только в отладочной версии вашего приложения.
Если вы попытались использовать функцию Write или WriteLn и получили сообщение об ошибке I/O Еггог, значит, вы забыли сделать проект консольным приложением.
Обратите внимание, что здесь применяется тот же код, что и раньше, но теперь мы используем вывод на консоль вместо ShowMessage. Убедитесь, что вы создаете консольное приложение, и измените обработчик так, как показано ниже.
procedure TFormI.ButtonlClick(Sender: T0bject); var MemStat: TMemoryStatus; begin MemStat.dwLength:= SizeOf(TMemoryStatus); GlobalMemoryStatus(MemStat); with MemStat do begin WriteLn(Format('Memory load: %d%%',[dwMemoryLoad])); WriteLn(Format('Total physical: %d',[dwTotalPhys])); WriteLn(Format('Available physical: %d',[dwAvailPhys])); WriteLn(Format('Total page file: %d',[dwTotalPageFile])); WriteLn(Format('Available page file: %d',[dwAvailPageFile])); WriteLn(Format('Total virtual: %d',[dwTotalVirtual])); WriteLn(Format('Available virtual: %d',[dwAvailVirtual])); end; end;
Опытные пользователи Pascal заметят, что функция Format использовалась там, где это не было необходимо (WriteLn имеет свои возможности форматирования). Однако я везде использую Format как мощный инструмент; кроме того, используя везде одну лишь функцию Format, я избавляюсь от необходимости помнить два набора правил форматирования.
Запись в 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), что обеспечивает доступ к файлу только одной подзадачи в один момент времени.
Как правильно использовать файл протокола? Какую информацию в него записывать? Сколько программистов, столько и ответов на эти вопросы. Лично я предпочитаю придерживаться золотой середины между "записывай все" и "записывай только то, что отлаживаешь".
1 2
8 8 8
| |