![]() |
Log-Datei realisieren
Hallo allerseits,
ich möchte gerne eine Log-Datei realisieren, in die mehrere Programme (bzw. mehrere Instanzen desselben Programms) ihre Einträge machen. Wie realisiere ich so etwas am besten, ohne dass die Programme sich beim Hineinschreiben in die Datei in die Quere kommen? Bisher hatte ich folgende Routine vorgesehen für das Anhängen von Log-Einträgen:
Delphi-Quellcode:
Hier kann es aber theoretisch passieren, dass zwei Programme gleichzeitig die Datei öffnen wollen und dann kracht es bei dem Programm, das einen Tick später drangekommen ist.
AssignFile(f, 'C:\Test.log');
try Append(f); Writeln(f, 'Ein Log-Eintrag'); finally CloseFile(f); end; |
Re: Log-Datei realisieren
Da gibt es viele Möglichkeiten. Eine einfache wäre zum Beispiel, dass mit CreateMutex ein benannter Mutex erzeugt wird. Mit WaitForSingleObject wartet dann ein Programm darauf, dass es Zugriff auf den Mutex kriegt. Dann schreibt es in die Datei (wie du vorgeschlagen hast), und ermöglicht mit ReleaseMutex dem nächsten Programm den Zugriff.
Zum Mitschreiben:
Delphi-Quellcode:
//Irgendwo bei Programmstart
MutexHandle:=CreateMutex(nil, false, 'MeinEindeutigerName'); //Zum loggen: WaitForSingleObject(MutexHandle, INFINITE); //warten, bis kein Programm mehr schreibt try AssignFile(f, 'C:\Test.log'); try Append(f); Writeln(f, 'Ein Log-Eintrag'); finally CloseFile(f); end; finally ReleaseMutex(MutexHandle); //jetzt dürfen wieder andere end; //am Ende CloseHandle(MutexHandle); |
Re: Log-Datei realisieren
Mit Mutexen hab ich bisher noch keinerlei Erfahrungen gemacht (wird daher höchste Zeit!), aber hört sich auf jeden Fall gut an! Vielen Dank schonmal.
Was hat denn der Parameter "MeinEindeutigerName" genau für eine Bewandnis? EDIT: Achja: was ich vergaß zu erwähnen, die mehreren Instanzen einer Anwendung laufen in meinem Fall leider auf verschiedenen Rechnern über Netzlaufwerk und sollen auf diesem Wege auch auf die Log-Datei zugreifen. In dem Fall bringt einen ein Mutex ja nicht weiter, oder? Das würde ja nur für ein und derselben Maschine gelten. |
Re: Log-Datei realisieren
Nun, alle Programme brauchen ja ein Handle zum gleichen Mutex, denn sonst funktioniert die Synchronisation nur mit mehreren Threads im gleichen Prozess. Und Windows bietet eben die Möglichkeit, dass ein Programm den Mutex eines anderen Programms öffnet, sofern der Mutex einen Namen hat.
Wenn es andererseit ein anderes Programm gibt, dass unbeabsichtigt den gleichen Namen verwendet, führt das zu Problemen. |
Re: Log-Datei realisieren
Wie in meinen oberen Post hineineditiert, lässt sich mein Problem wohl eher doch nicht über ein Mutex lösen, oder?
|
Re: Log-Datei realisieren
Kannst du nicht ins Eventlog von Windows deine Logs eintragen?
|
Re: Log-Datei realisieren
Also im Netzwerk scheiden Mutexe schonmal aus. Das einzige, was mir noch einfällt, wäre ein Log-Server, mit dem über Named Pipes kommuniziert wird - die funktionieren nämlich im Netzwerk. Aber ein Server für Logs ist unelegant und unpraktisch.
|
Re: Log-Datei realisieren
Zitat:
|
Re: Log-Datei realisieren
Am Einfachsten und Sichersten ist, wenn die Datei selbst das Mutex ist.
Wenn Process A die Datei exklusiv offen hat, müssen alle anderen Prozesse warten, bis die Resource (die Datei) wieder verfügbar wird. Sobald A die Datei wieder schliest, gewinnt der schnellste Prozess, u.s.w. Dazu gibt es in der Code-Library schon eine fertige Klasse: ![]() Das funktioniert übrigens auch im Netzwerk. |
Re: Log-Datei realisieren
@ shmia,
mich hat deine Klasse sehr interssiert und ich habe es mir angeschaut. Erst einmal mein Respekt für deine Arbeit hierzu und das zur Verfügung stellen des Sources. :thumb: Leider bekomme ich das Testprojekt nicht kompiliert. In dem Source-Abschnitt wo du das GetTickCount-Problem (wegen dem "neureseten") umgehst, erscheint bei mir eine Fehlermeldung: [DCC Fehler] FileStreamUtils.pas(281): E2003 Undefinierter Bezeichner: 'SFOpenError'
Delphi-Quellcode:
Ich verwende D2007 Prof unter Vista 32 Bit.
error := GetLastError;
curtime := GetTickCount; if ((curtime - starttime) >= timeout) or ((error<>ERROR_SHARING_VIOLATION) and (error<>ERROR_LOCK_VIOLATION)) then raise EFOpenError.CreateFmt(SFOpenError+#13#10+ //<-- Fehlermeldung SysErrorMessage(error), [FileName]); Ich kann die Fehlermeldung nun leider nicht auflösen... Weißt du vllt. was hier schief läuft? Evtl. mit etwas Erläuterung zu genau dieser Zeile 281 (raise...)? Denn genau diese Stelle kapier ich eben nicht... (vermutlich kennt Vista das nicht mehr) Danke! //Edit: Habe die Lösung selbst gefunden. :-D Liegt an der Delphiversion (vor Delphi 6) Ab den Delphi 6-Versionen wurden einige Konstanten von Borland in die RtlConsts Unit "verschoben". Man muss also unter der Uses-Klausel noch die "RtlConsts" mit aufnehmen. @ shmia, evtl. den Hinweis mit in deinen Code aufnehmen? |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:59 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz