монитор ошибок должна работать как
Искусство управления ошибками. |
Раздел Подземелье Магов Часть I : |
Автор: Даутов Ильдар, дата публикации 05 января 2000 |
Продолжая тему "Управление ошибками в Delphi", поставим следующие задачи :
- программа- монитор ошибок должна работать как системный сервис Windows NT
- журнал ошибок должен сохраняться на диске и постоянно пополняться
- список текущих ошибок и полный журнал ошибок должны быть доступны для просмотра на любом компьютере локальной сети предприятия
- ошибка, возникшая в клиентской программе, передается по сети монитору-сервису Windows NT. Для передачи используем механизм каналов Mailslot
- монитор сохраняет текст ошибки на диске. Для хранения используем текстовый файл
- монитор пересылает по сети текст ошибки программе просмотра ошибок. Для передачи используем механизм каналов Mailslot
- программа просмотра принимает текст ошибки и отображает его на экране
- программа просмотра может запросить полный журнал ошибок. Для получения полного журнала используем механизм разделяемых сетевых файловых ресурсов
Монитор ошибок
Оформить программу как сервис Windows NT (Win32 service) не составляет большого труда :
- создаем новое приложение File | New... | New | Service Application. Создается приложение с глобальной переменной Application типа TServiceApplication и объектом типа TService, который и реализует всю функциональность сервиса
- устанавливаем требуемые свойства объекта TService
- имя сервиса
- параметры запуска сервиса
- имя и пароль пользователя, от имени которого стартует сервис
ErrorMonitorService.exe /install
Удаление сервиса :
ErrorMonitorService.exe /uninstall
Запуск сервиса выполняется из командной строки следующим образом :
net start ErrorMonitor
Останов сервиса :
net stop ErrorMonitor
Оформив эту последовательность команд как BAT-файл, можно значительно облегчить себе жизнь при отладке сервиса.
Достаточно подробную информацию о сервисах Windows NT можно найти в книге : А.В.Фролов, Г.В.Фролов 'Программирование для Windows NT (часть вторая)', Москва, ДИАЛОГ-МИФИ, 1997
Для сохранения протокола (журнала) пользовательских ошибок используем следующую схему :
- журнал ведется в текстовом файле в определенном каталоге Windows NT
- журнал имеет имя yyyy-mm-dd.log, соответствующее календарной дате запуска сервера
- при каждом запуске монитор проверяет наличие файла, имя которого соответствует текущей дате. При отсутствии - файл создается, иначе происходит дозапись в конец файла
- сохраняются только последние 7 файлов журнала
Окно просмотра ошибок
Текст программы окна просмотра ошибок приведен ниже : unit fErrorMonitorMessage; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, ScktComp; type TfmErrorMonitorMessage = class(TForm) // протокол текущих ошибок meErrorTextNow: TMemo; meJournals: TMemo; // таймер для опроса канала Timer: TTimer; paJournals: TPanel; buJournals: TButton; lbJournals: TListBox; laJournals: TLabel; procedure FormCreate(Sender: TObject); procedure TimerTimer(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure buJournalsClick(Sender: TObject); private public end; // сетевой разделяемый ресурс, где сохраняются журналы // (укажите здесь имя своего ресурса и обеспечьте права для доступа) const LogDir='\\MyServer\C$\Log\'; var fmErrorMonitorMessage: TfmErrorMonitorMessage; h : THandle; // handle Mailslot-канала str : string[250]; // буфер обмена MsgNumber,MsgNext,Read : DWORD; implementation {$R *.DFM} procedure TfmErrorMonitorMessage.FormCreate(Sender: TObject); var sr : TSearchRec; i : integer; begin // создание Mailslot-канала с именем EMonMess // по этому каналу будем получать сообщения об ошибках от сервиса NT h:=CreateMailSlot('\\.\mailslot\EMonMess',0,MAILSLOT_WAIT_FOREVER,nil); if h=INVALID_HANDLE_VALUE then begin ShowMessage('Ошибка создания канала !'); Halt; end; // интервал опроса канала Mailslot - 3 секунды Timer.Interval:=3000; // таймер первоначально был выключен Timer.Enabled:=True; // заполнение списка доступных журналов i:=FindFirst(LogDir+'*.log',faAnyFile,sr); while i = 0 do begin lbJournals.Items.Add(sr.Name); i:=FindNext(sr); end; lbJournals.ItemIndex:=lbJournals.Items.Count-1; FindClose(sr); end; procedure TfmErrorMonitorMessage.TimerTimer(Sender: TObject); var str : string[250]; begin Timer.Enabled:=False; // определение наличия сообщения в канале if not GetMailSlotInfo(h,nil,DWORD(MsgNext),@MsgNumber,nil) then begin ShowMessage('Ошибка сбора информации !'); Close; end; if MsgNext <> MAILSLOT_NO_MESSAGE then begin beep; // чтение сообщения из канала и добавление в текст протокола if ReadFile(h,str,200,DWORD(Read),nil) then meErrorTextNow.Lines.Add(str) else ShowMessage('Ошибка чтения сообщения !'); end; Timer.Enabled:=True; end; procedure TfmErrorMonitorMessage.FormClose(Sender: TObject; var Action: TCloseAction); begin CloseHandle(h); end; procedure TfmErrorMonitorMessage.buJournalsClick(Sender: TObject); var Journal : TFileStream; s : string; begin // получение журнала ошибок за дату meJournals.Lines.Clear; meJournals.Lines.Add('Файл журнала '+lbJournals.Items[lbJournals.ItemIndex]); Journal:=TFileStream.Create(LogDir+lbJournals.Items[lbJournals.ItemIndex], fmOpenRead or fmShareDenyNone); SetLength(s,Journal.Size); Journal.Read(PChar(s)^,Journal.Size); meJournals.Lines.Add(s); Journal.Free; end; end.
Ильдар Даутов
|