2015-05-14 7 views
18

Wie kann meine Delphi-App problemlos in das Windows-Ereignisprotokoll schreiben?Mit Delphi in das Windows-Ereignisprotokoll schreiben

Was ist der Unterschied zwischen TEventLogger und ReportEvent? Wie verwende ich die ReportEvent-Funktion?

+2

Suche Stack Overflow für diese scheinbar einfache Frage gibt Antworten zwischen vielen Fragen verteilt. Ich habe eine neue einfache Frage erstellt und Zeit investiert, um die Antworten zu kombinieren und zusätzliche Informationen hinzuzufügen, die in den anderen Antworten nicht enthalten waren. Ich habe das getan, weil ich nicht zum ersten Mal nach dieser Antwort suchte und dachte, die detaillierte Antwort und das Beispielprojekt könnten auch anderen Menschen helfen. –

+2

Sie hätten das bei der anderen Frage tun können. Es ist auch hier in Ordnung. Die Fragen sind jetzt verknüpft. Es ist alles gut. http://blog.stackoverflow.com/2010/11/dr-strangedupe-or-how-i-learned-to-stop-beorrying-and-love-duplication/ –

+0

Ah ok, danke David, ich verstehe jetzt besser wie Es klappt. –

Antwort

25

Wenn Sie einen Windows-Dienst schreiben und müssen dem lokalen Computer des Windows-Ereignisprotokoll schreiben, dann können Sie TService.LogMessage wie erwähnt here nennen.

//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; 

Für jede andere Art von Anwendungen, die Sie die SvcMgr verwenden können. TEventLoggerundocumented Hilfsklasse für TService zum Schreiben des Windows-Ereignisprotokolls des lokalen Rechners wie erwähnt here, here und 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; 

Sie können auch die Windows-API-ReportEvent Funktion als here und here erwähnt.

Ich habe eine einfache Klasse erstellt, um es einfacher zu machen, es ist 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 unterstützt auf einem lokalen oder Remote-Rechner Ereignisprotokoll einen Protokolleintrag zu schreiben. Für ein Remote-Beispiel siehe John Kaster's EDN article.


Beachten Sie, dass Sie auch an create a message file und register your event source sonst alle Ihre Log-Meldungen wie diese werden beginnend mit etwas hätte:

Die Beschreibung für Ereignis-ID xxx von der Quelle xxxx nicht sein kann gefunden. Entweder ist die Komponente, die dieses Ereignis auslöst, nicht auf Ihrem lokalen Computer installiert oder die Installation ist beschädigt. Sie können installieren oder die Komponente auf dem lokalen Computer reparieren. Wenn das Ereignis von einem anderen Computer stammt, müssen die Anzeigeinformationen mit dem Ereignis gespeichert werden.

Die folgenden Informationen wurden mit dem Ereignis enthalten:

1, Für weitere Informationen darüber, wie eine Nachrichtendatei Finn Tolderlund's tutorial oder Michael Hex's article sehen erstellen oder Sie können eine vorhandene MC und RES file included in the GitHub project verwenden.

2, Betten Sie die RES-Datei in Ihre Anwendung ein, indem Sie MessageFile.res in Ihre DPR-Datei einfügen. Alternativ können Sie eine DLL für die Nachrichten erstellen.

program MyTestApp; 

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

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

begin 
    Application.Initialize; 

3, Die einmalige Registrierung erfordert Admin-Rechte für die Registrierung zu schreiben, so dass es uns in der Regel als Teil Ihrer Anwendung Installationsprozess durchgeführt.

//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; 

Wenn Sie Windows-Ereignisprotokollierung benötigen und andere Protokollierung Anforderungen Sie auch Logging Frameworks wie log4d und TraceTool


Siehe here verwenden können, wenn Sie in das Ereignisprotokoll schreiben wollen Fenster in der Delphi-IDE.

+4

Gut gemacht! Nur zu deinem Logbuch. Ich würde bevorzugen, dass ihre Methoden die Instanzmethoden und nicht die Klassenmethoden sind, um die sich wiederholende Ereignisquelle für das Registrieren und das Aufheben der Registrierung zu vermeiden. Ich würde die Ereignisquelle registrieren, wenn die Instanz der Klasse erstellt wird, und die Registrierung bei der Zerstörung aufheben. Oder machen Sie eine globale Threadvariable und initialisieren Sie sie einmal. – TLama

+0

Wenn Sie die Registrierung bei der Vernichtung der Instanz aufheben, führt dies nicht dazu, dass vorhandene Ereignisprotokolleinträge nicht mehr gelesen werden können? Mit anderen Worten, die Instanz musste aktiv sein, damit der Operator alte Ereignisprotokolleinträge anzeigen konnte. Ich denke eher, dass die Registrierung der Ereignisquelle Teil der Installation und Aufhebung der Registrierung für die Deinstallation der ausführbaren Datei sein sollte. –

+0

Hallo Tondrey, ich vermute, TLama meinte den "RegisterEventSource" API Aufruf, nicht "Registrieren Sie die Ereignisquelle, indem Sie sie der Registry hinzufügen" :-) –

Verwandte Themen