2015-05-14 8 views
18

Как мое приложение Delphi может легко записывать в журнал событий Windows?Запись в журнал событий Windows с помощью Delphi

В чем разница между TEventLogger и ReportEvent? Как использовать функцию ReportEvent?

+2

Поиск переполнения стека для этого, казалось бы, простого вопроса возвращает ответы, распределенные между многими вопросами. Я создал новый простой вопрос и потратил время, чтобы объединить ответы и добавить дополнительную информацию, которой не было в других ответах. Я сделал это, потому что не первый раз, когда я пришел сюда, ища этот ответ, и подумал, что подробный ответ и образец проекта могут помочь другим людям. –

+2

Вы могли бы сделать это по другому вопросу. Здесь тоже хорошо. Вопросы сейчас связаны. Все хорошо. http://blog.stackoverflow.com/2010/11/dr-strangedupe-or-how-i-learned-to-stop-worrying-and-love-duplication/ –

+0

О, спасибо, Дэвид, теперь я лучше понимаю, как оно работает. –

ответ

25

Если вы пишете службу Windows и нужно писать в журнал событий Windows на локальном компьютере, то вы можете позвонить TService.LogMessage, как указано here.

//TMyTestService = class(TService) 

procedure TMyTestService.ServiceStart(Sender: TService; var Started: Boolean); 
begin 
    LogMessage('This is an error.'); 
    LogMessage('This is another error.', EVENTLOG_ERROR_TYPE); 
    LogMessage('This is information.', EVENTLOG_INFORMATION_TYPE); 
    LogMessage('This is a warning.', EVENTLOG_WARNING_TYPE); 
end; 

Для любого другого типа приложений, которые вы можете использовать в SvcMgr. TEventLoggerundocumented Вспомогательный класс для TService для записи журнала событий Windows на локальном компьютере, как указано here, here и here.

uses 
    SvcMgr; 

procedure TForm1.EventLoggerExampleButtonClick(Sender: TObject); 
begin 
    with TEventLogger.Create('My Test App Name') do 
    begin 
    try 
     LogMessage('This is an error.'); 
     LogMessage('This is another error.', EVENTLOG_ERROR_TYPE); 
     LogMessage('This is information.', EVENTLOG_INFORMATION_TYPE); 
     LogMessage('This is a warning.', EVENTLOG_WARNING_TYPE); 
    finally 
     Free; 
    end; 
    end; 
end; 

Вы также можете использовать API ReportEvent функции Windows, как уже упоминалось here и here.

Я создал простой класс, чтобы сделать его проще, это available on GitHub.

//----------------- EXAMPLE USAGE: --------------------------------- 

uses 
    EventLog; 

procedure TForm1.EventLogExampleButtonClick(Sender: TObject); 
begin 
    TEventLog.Source := 'My Test App Name'; 

    TEventLog.WriteError('This is an error.'); 
    TEventLog.WriteInfo('This is information.'); 
    TEventLog.WriteWarning('This is a warning.'); 
end; 

//------------------------------------------------------------------ 

unit EventLog; 

interface 

type 
    TEventLog = class 
    private 
    class procedure CheckEventLogHandle; 
    class procedure Write(AEntryType: Word; AEventId: Cardinal; AMessage: string); static; 
    public 
    class var Source: string; 
    class destructor Destroy; 

    class procedure WriteInfo(AMessage: string); static; 
    class procedure WriteWarning(AMessage: string); static; 
    class procedure WriteError(AMessage: string); static; 

    class procedure AddEventSourceToRegistry; static; 
    end; 

threadvar EventLogHandle: THandle; 

implementation 

uses Windows, Registry, SysUtils; 

class destructor TEventLog.Destroy; 
begin 
    if EventLogHandle > 0 then 
    begin 
    DeregisterEventSource(EventLogHandle); 
    end; 
end; 

class procedure TEventLog.WriteInfo(AMessage: string); 
begin 
    Write(EVENTLOG_INFORMATION_TYPE, 2, AMessage); 
end; 

class procedure TEventLog.WriteWarning(AMessage: string); 
begin 
    Write(EVENTLOG_WARNING_TYPE, 3, AMessage); 
end; 

class procedure TEventLog.WriteError(AMessage: string); 
begin 
    Write(EVENTLOG_ERROR_TYPE, 4, AMessage); 
end; 

class procedure TEventLog.CheckEventLogHandle; 
begin 
    if EventLogHandle = 0 then 
    begin 
    EventLogHandle := RegisterEventSource(nil, PChar(Source)); 
    end; 
    if EventLogHandle <= 0 then 
    begin 
    raise Exception.Create('Could not obtain Event Log handle.'); 
    end; 
end; 

class procedure TEventLog.Write(AEntryType: Word; AEventId: Cardinal; AMessage: string); 
begin 
    CheckEventLogHandle; 
    ReportEvent(EventLogHandle, AEntryType, 0, AEventId, nil, 1, 0, @AMessage, nil); 
end; 

// This requires admin rights. Typically called once-off during the application's installation 
class procedure TEventLog.AddEventSourceToRegistry; 
var 
    reg: TRegistry; 
begin 
    reg := TRegistry.Create; 
    try 
    reg.RootKey := HKEY_LOCAL_MACHINE; 
    if reg.OpenKey('\SYSTEM\CurrentControlSet\Services\Eventlog\Application\' + Source, True) then 
    begin 
     reg.WriteString('EventMessageFile', ParamStr(0)); // The application exe's path 
     reg.WriteInteger('TypesSupported', 7); 
     reg.CloseKey; 
    end 
    else 
    begin 
     raise Exception.Create('Error updating the registry. This action requires administrative rights.'); 
    end; 
    finally 
    reg.Free; 
    end; 
end; 

initialization 

TEventLog.Source := 'My Application Name'; 

end. 

ReportEvent поддерживает журнальную запись в журнале событий локального или удаленного компьютера. Для удаленного примера см. John Kaster's EDN article.


Обратите внимание, что вы также должны create a message file и register your event source в противном случае все ваши сообщения журнала будут начинать что-то вроде этого:

описание для события ххх от источника хххх не может быть найденный. Либо компонент, который повышает это событие, не установлен на на вашем локальном компьютере, или установка повреждена. Вы можете установить или восстановить компонент на локальном компьютере.

Если событие возникло на другом компьютере, информация о событии должна была быть сохранена вместе с событием.

Следующая информация была включена с событием:

1, Для получения дополнительной информации о том, как создать файл сообщений см Finn Tolderlund's tutorial или Michael Hex's article или вы можете использовать существующий MC и RES file included in the GitHub project.

2, Вставьте файл RES в свое приложение, включив MessageFile.res в свой файл DPR. В качестве альтернативы вы можете создать DLL для сообщений.

program MyTestApp; 

uses 
    Forms, 
    FormMain in 'FormMain.pas' {MainForm}, 
    EventLog in 'EventLog.pas'; 

{$R *.res} 
{$R MessageFile\MessageFile.res} 

begin 
    Application.Initialize; 

3, The одноразовой регистрация требует прав администратора при записи в реестр, так это нас обычно делаются как часть процесса установки приложения.

//For example 
AddEventSourceToRegistry('My Application Name', ParamStr(0)); 
//or 
AddEventSourceToRegistry('My Application Name', 'C:\Program Files\MyApp\Messages.dll'); 

//-------------------------------------------------- 

procedure AddEventSourceToRegistry(ASource, AFilename: string); 
var 
    reg: TRegistry; 
begin 
    reg := TRegistry.Create; 
    try 
    reg.RootKey := HKEY_LOCAL_MACHINE; 
    if reg.OpenKey('\SYSTEM\CurrentControlSet\Services\Eventlog\Application\' + ASource, True) then 
    begin 
     reg.WriteString('EventMessageFile', AFilename); 
     reg.WriteInteger('TypesSupported', 7); 
     reg.CloseKey; 
    end 
    else 
    begin 
     raise Exception.Create('Error updating the registry. This action requires administrative rights.'); 
    end; 
    finally 
    reg.Free; 
    end; 
end; 

Если необходимо ведение журнала событий Windows и другие требования ведения журнала можно также использовать рамки протоколирования, такие как log4d и TraceTool


См here, если вы хотите написать в журнал событий окна в среде Delphi.

+4

Молодцы! Просто к вашему классу журнала. Я бы предпочел, чтобы их методы были методами экземпляра, а не методами класса, чтобы избежать повторного регистрации и удаления регистрационного события. Я бы зарегистрировал источник события, когда экземпляр класса создан и отменяется регистрацию при уничтожении. Или сделайте глобальный threadvar и инициализируйте его один раз. – TLama

+0

Если вы отмените регистрацию при уничтожении экземпляра, не приведет ли это к тому, что существующие записи журнала событий больше не могут быть прочитаны? Другими словами, экземпляр должен был быть жив, чтобы оператор мог просматривать старые записи журнала событий? Я скорее считаю, что регистрация источника событий должна быть частью установки и отмены регистрации для удаления исполняемого файла. –

+0

Привет, Энн, я подозреваю, что TLama означал вызов API «RegisterEventSource», а не «Зарегистрировать источник события, добавив его в реестр» :-) –

Смежные вопросы