Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Log-Datei realisieren (https://www.delphipraxis.net/103023-log-datei-realisieren.html)

MatthiasR 8. Nov 2007 15:03


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:
AssignFile(f, 'C:\Test.log');
try
  Append(f);
  Writeln(f, 'Ein Log-Eintrag');
finally
  CloseFile(f);
end;
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.

Apollonius 8. Nov 2007 15:10

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

MatthiasR 8. Nov 2007 15:36

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.

Apollonius 8. Nov 2007 15:40

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.

MatthiasR 8. Nov 2007 15:44

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?

Jelly 8. Nov 2007 15:47

Re: Log-Datei realisieren
 
Kannst du nicht ins Eventlog von Windows deine Logs eintragen?

Apollonius 8. Nov 2007 15:51

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.

MatthiasR 8. Nov 2007 15:54

Re: Log-Datei realisieren
 
Zitat:

Zitat von Jelly
Kannst du nicht ins Eventlog von Windows deine Logs eintragen?

Wie geht das und was ist das Windows-Eventlog? Wobei ich nicht glaube, dass mir das etwas bringt, da man die Log-Datei später auch auf einfachem Wege wegkopieren/per Mail verschicken/maschinell auswerten können soll.

shmia 8. Nov 2007 15:55

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:
http://www.delphipraxis.net/internal...ct.php?t=62072
Das funktioniert übrigens auch im Netzwerk.

juergen 8. Nov 2007 20:13

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:
      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 verwende D2007 Prof unter Vista 32 Bit.

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?

Reinhard Kern 9. Nov 2007 00:41

Re: Log-Datei realisieren
 
Zitat:

Zitat von Infect
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:
AssignFile(f, 'C:\Test.log');
try
  Append(f);
  Writeln(f, 'Ein Log-Eintrag');
finally
  CloseFile(f);
end;
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.

Hallo,

warum versuchst du nicht das Eingachste: die Logdatei exklusiv zu öffen. Das kann immer nur ein Programm, ein anderes muss es später nochmal versuchen.

Gruss Reinhard

himitsu 9. Nov 2007 01:36

Re: Log-Datei realisieren
 
ohne Stream gehts genauso ... einfach versuchen die Datei exklusiv zu öffnen
Delphi-Quellcode:
AssignFile(F, LogFile);
FileMode := fmOpenReadWrite or fmShareExclusive;
{$I-}
Append(F);
WriteLn(F, S);
If IOResult <> 0 Then <<ging nich>>;
CloseFile(F);
{$I+}
tja und wenn's nich geht, dann halt 'ne Weile versuchen
Delphi-Quellcode:
AssignFile(F, LogFile);
FileMode := fmOpenReadWrite or fmShareExclusive;
Try
  Repeat
    {$I-} Append(F); {$I+}
    Sleep(10);
  Until IOResult = 0;
  WriteLn(F, S);
Finally
  CloseFile(F);
End;
soooo, und jetzt noch 'ne Zeitbegrenzung und so'n Zeugs rein ... fertsch (denk'sch ma)
Delphi-Quellcode:
Function AddLog(Const LogFile, S: String; TimeOut{ms}: LongWord = 3000): Boolean;
  Var F: TextFile;
    C: LongWord;
    M: Byte;

  Begin
    Result  := False;
    M       := FileMode;
    FileMode := fmOpenReadWrite or fmShareExclusive;
    AssignFile(F, LogFile);
    Try
      C := GetTickCount;
      While True do Begin
        {$I-} Append(F); {$I+}
        If IOResult = 0 Then Break;
        If GetTickCount - C > TimeOut Then Exit;
        //Application.ProcessMessages;
        Sleep(10);
      End;
      WriteLn(F, S);
      Result := True;
    Finally
      CloseFile(F);
      FileMode := M;
    End;
  End;

If not AddLog('a.log', 'irgendwas muß rein') Then Error...
OK, als WinAPI sieht's och nett aus ^^
Delphi-Quellcode:
Function AddLog(LogFile, S: String; TimeOut{ms}: LongWord = 3000): Boolean;
  Var H: THandle;
    C: LongWord;

  Begin
    Result := False;
    S     := S + #13#10;
    C     := GetTickCount;
    Repeat
      H := CreateFile(PChar(LogFile), GENERIC_WRITE, 0, nil, OPEN_ALWAYS, 0, 0);
      If H <> INVALID_HANDLE_VALUE Then Begin
        SetFilePointer(H, 0, nil, FILE_END);
        WriteFile(H, S[1], Length(S), C, nil);
        CloseHandle(H);
        Result := True;
        Exit;
      End;
      //Application.ProcessMessages;
      Sleep(10);
    Until GetTickCount - C > TimeOut;
  End;
[add]
ich sollt vielleicht ma weniger nebenbai chatten ... da is doch plötlich 'nen neuer Beitrag drin und sogar mit RedBox ^^

[edit]
immer diese Rechtschreibfehler :wall:

Andreas H. 9. Nov 2007 05:29

Re: Log-Datei realisieren
 
Hallo,

nur so aus der Hüfte geschossen...

wenn das exklusive Öffnen nix is, dann vielleicht nen kleinen Server aufsetzen, in dem per POST oder so die Logmeldungen gesendet werden. Ist natürlich aufwendiger, als "nur" ne Prozedur zu schreiben. Dann wäre auch das Dateiformat und der Speicherort gekapselt.

Vielleicht läuft ja schon ein Apache oÄ. And ein paar Zeilen PHP...

Aber wenn denn schon von verschiedenen Programmen auf verschiedenen Rechnern Logmeldungen zentral gesichert werden sollen...

Gruß Andreas

peschai 9. Nov 2007 05:40

Re: Log-Datei realisieren
 
Hallo
ich hätte auch noch eine grundsätzliche idee:
Parallele schreibzugriffe schreiben in temporäre weitere neue log's, welche beim nächsten schreibzugang wieder zusammengeführt werden. Die weiteren templogs', welche es nur gab, weil das Hauptlog gesperrt war, leben nur so lange, wie der nächste schreibzugriff erfolgt. Wer also das Hauptlog exclusiv öffnen kann, muss zuerst die anderen templogs auslesen und reinschreiben, dann diese templogs löschen und dann erst seine eigenen Sachen eintragen ...

was meint ihr ?

peschai 9. Nov 2007 05:44

Re: Log-Datei realisieren
 
Noch etwas zum EventLog des Betriebssystem. Das ist eigentlich fürs betriebssystem nahe Applikationen. Wenn da jeder seinen Müll reinwirft, dann hat es ein Admi wirklich schwer...
Tip das Eventlog für eigene Programme NICHT verwenden! Besser eine Logdatei abgelegt unter "Einstellungen und Dokumente" ...
:???:

mkinzler 9. Nov 2007 06:38

Re: Log-Datei realisieren
 
Der trend geht aber zum Eventlog, welcher i9n Vista deshalb stark erweitert wurde.

marabu 9. Nov 2007 06:58

Re: Log-Datei realisieren
 
Hallo Leute,

ein logfile soll ja für einen bestimmten Zeitraum ein lückenloses Protokoll der Aktionen oder Ereignisse im Leben eines Programms liefern. Wenn das Protokoll wichtig ist, dann muss es lokal geschrieben werden, da bei einer instabilen Netzwerkverbindung ein Entscheidungsproblem entsteht: Muss der Client jetzt seine Arbeit einstellen. In einem Client-Server-Scenario lässt man den Server protokollieren. Schreiben die Clients eigene lokale Protokolle, dann ist eine übergreifende Auswertung durch Zusammenführen der logfiles möglich, auch wenn ich mir die Notwendigkeit gerade nicht vorstellen kann.

Grüße vom marabu

MatthiasR 9. Nov 2007 10:28

Re: Log-Datei realisieren
 
Erstmal Danke für die vielen Vorschläge! Ich habe mir nun anhand von himitsus Beispielen noch etwas selbst zusammengebaut. Bitte schaut euch das mal an, was es daran auszusetzen gibt. Zuvor aber noch ein paar für mich offene Fragen:
  • Was bewirkt die Compiler-Direktive {$I}? Ist die nur dazu da, dass bei Append keine Exception ausgelöst wird, wenn die Datei schon offen ist? Könnte man die Direktive also auch weglassen und stattdessen mit Exceptions arbeiten (wie ich in meinem Beispiel)?
  • Was bewirkt die Zeile "FileMode := fmOpenReadWrite or fmShareExclusive;" genau? Ich habe mir dazu mal bissle die Hilfe durchgelesen, aber so richtig schlau wurde ich nicht daraus.
  • Müsste das finale "CloseFile" nicht auch wieder mit der Direktive {$I} geklammert werden, zumindest bei mir kommt ein "E/A-Fehler 103", wenn ich "CloseFile" aufrufe und die Datei war zuvor nicht mit "Append" geöffnet worden. Oder man führt einfach ein weiteres Flag ein, wie in meiner Lösung, ob das Öffnen zuvor geklappt hat.

Hier mein Entwurf:
Delphi-Quellcode:
procedure TForm1.btnWriteLnClick(Sender: TObject);
var
  s: String;
  FFile: TextFile;
  bSuccess: Boolean;
  iBeginTime: Integer;
  iWaitTime: Integer;
begin
  bSuccess := False;
  iBeginTime := GetTickCount;
  iWaitTime := 0;
  AssignFile(FFile, 'C:\Test.log');
  try
    while (iWaitTime < 10000) do
    begin
      try
        Append(FFile);
        if (ParamCount > 0) then
          s := 'Programm ' + ParamStr(1)
        else
          s := 'Programm 1';
        WriteLn(FFile, s);
        bSuccess := True;
        Break;
      except
        Sleep(10);
        iWaitTime := getTickCount - iBeginTime;
      end;
    end;

    if (not bSuccess) then
      ShowMessage('Schreiben fehlgeschlagen.')
    else
      ShowMessage('Schreiben erfolgreich.')
  finally
    if bSuccess then
      CloseFile(FFile);
  end;
end;

shmia 9. Nov 2007 13:59

Re: Log-Datei realisieren
 
Zitat:

Zitat von Infect
Ich habe mir nun anhand von himitsus Beispielen noch etwas selbst zusammengebaut.

Ich verstehe nicht, weshalb du eine Bastel-Lösung gegenüber einer Profilösung bevorzugst ? :?
Delphi-Quellcode:
var
  logstream: TExclusiveFileStream;
  s : string;
begin
  logstream := TExclusiveFileStream.Create('C:\Test.log', 10000);
  try
    logstream.SeektoEnd; // Ans Dateiende, wir wollen anhängen
    if (ParamCount > 0) then
      s := 'Programm ' + ParamStr(1)
    else
      s := 'Programm 1';    
    s := s + #13#10; // Zeilenvorschub
    logstream.WriteBuffer(s[1], length(s)); // Daten schreiben
  finally
    logstream.Free;
  end;
end;

Reinhard Kern 9. Nov 2007 14:11

Re: Log-Datei realisieren
 
Zitat:

Zitat von Infect
Erstmal Danke für die vielen Vorschläge! Ich habe mir nun anhand von himitsus Beispielen noch etwas selbst zusammengebaut. Bitte schaut euch das mal an, was es daran auszusetzen gibt. Zuvor aber noch ein paar für mich offene Fragen:
  • Was bewirkt die Zeile "FileMode := fmOpenReadWrite or fmShareExclusive;" genau? Ich habe mir dazu mal bissle die Hilfe durchgelesen, aber so richtig schlau wurde ich nicht daraus.

Hallo,

dadurch, dass du das einfach weglässt, ist dein Entwurf reiner Unsinn. Du hast weder meinen noch den Beitrag himitsus auch nur annähernd verstanden. Vielleicht solltest du mal ganz einfach anfangen "watt is eine Datei"...

Gruss Reinhard

Reinhard Kern 9. Nov 2007 14:22

Re: Log-Datei realisieren
 
Zitat:

Zitat von marabu
Hallo Leute,

ein logfile soll ja für einen bestimmten Zeitraum ein lückenloses Protokoll der Aktionen oder Ereignisse im Leben eines Programms liefern. Wenn das Protokoll wichtig ist, dann muss es lokal geschrieben werden, da bei einer instabilen Netzwerkverbindung ein Entscheidungsproblem entsteht: Muss der Client jetzt seine Arbeit einstellen. In einem Client-Server-Scenario lässt man den Server protokollieren. Schreiben die Clients eigene lokale Protokolle, dann ist eine übergreifende Auswertung durch Zusammenführen der logfiles möglich, auch wenn ich mir die Notwendigkeit gerade nicht vorstellen kann.

Grüße vom marabu

Hallo marabu,

der Einwand ist durchaus berechtigt. Ich würde das Logfile sowohl lokal als auch auf dem Server schreiben (zumindest dort natürlich ergänzt um die Client Identifikation), weil das immer noch die einfachste Variante ist. Findet man im Serverlog keine Einträge mehr, kann man im Clientlog nachschauen.

Für die aktuelle Diskussion ist das ziemlich irrelevant, solang noch nicht einmal das Schreiben überhaupt funktioniert.

Gruss Reinhard

MatthiasR 9. Nov 2007 14:42

Re: Log-Datei realisieren
 
Zitat:

Zitat von shmia
Zitat:

Zitat von Infect
Ich habe mir nun anhand von himitsus Beispielen noch etwas selbst zusammengebaut.

Ich verstehe nicht, weshalb du eine Bastel-Lösung gegenüber einer Profilösung bevorzugst ? :?

Weil ich diese Profilösung, bevor ich sie in eine Anwendung einbaue, gerne vorher verstehen würde. Und das tue ich bei deiner Profilösung leider nicht, weil ich wahrscheinlich, wie Herr Kern es vermutet, schlichtweg zu blöd zum Programmieren bin.
Zitat:

Zitat von Herr Kern
Hallo,

dadurch, dass du das einfach weglässt, ist dein Entwurf reiner Unsinn. Du hast weder meinen noch den Beitrag himitsus auch nur annähernd verstanden. Vielleicht solltest du mal ganz einfach anfangen "watt is eine Datei"...

Gruss Reinhard

Wenn Sie die Güte hätten, mich an Ihrem Wissen teilhaben zu lassen, und mir mitteilen könnten, warum mein Entwurf reiner Unsinn ist, dann könnte ich vielleicht etwas weniger blöd sterben und es (vielleicht, aber nur vielleicht) in 2 bis 65 Jahren zu einem halbwegs fähigen Software-Entwickler schaffen.

EDIT: Um wieder bisschen runterzukommen: watt is eine Datei???

Reinhard Kern 10. Nov 2007 01:25

Re: Log-Datei realisieren
 
Zitat:

Zitat von Infect
...
Wenn Sie die Güte hätten, mich an Ihrem Wissen teilhaben zu lassen, und mir mitteilen könnten, warum mein Entwurf reiner Unsinn ist, dann könnte ich vielleicht etwas weniger blöd sterben und es (vielleicht, aber nur vielleicht) in 2 bis 65 Jahren zu einem halbwegs fähigen Software-Entwickler schaffen.

EDIT: Um wieder bisschen runterzukommen: watt is eine Datei???

EXCLUSIVE ist das entscheidende: ich habe es vorgeschlagen, hamamitsu hat damit eine ganze Beispielprozedur geschrieben und shmia hat eine Alternative mit TExclusiveFileStream vorgeschlagen, die intern das gleiche tut. Vielleicht sind wir ja blöd, aber immerhin sind wir schon zu dritt.

Da du nix verstanden hast, lässt du das entscheidende Statement mit fmShareExclusive einfach weg. So was nenne ich beratungsresistent.

Wenn du dich mal mit Dateien beschäftigen würdest, dann würdest du auch auf den Begriff "exklusiver Zugriff" stossen. Meine Meinung zum Thema: solange du diesen Punkt nicht verstanden hast, kannst du dein Problem nicht lösen - stattdessen auf Mutexe u.a. auszuweichen, ist Blödsinn, weil das das Problem nur anders einkleidet und dazu noch komplizierter ist als Datei-Zugriffe.

Natürlich hast du als Jungprogrammierer das Recht, alles anders zu sehen und alle Erkenntnisse der IT mit Verachtung zu strafen. Schon ein Konkurrent weniger.

Gruss Reinhard

Hansa 10. Nov 2007 02:41

Re: Log-Datei realisieren
 
Ooohh, wie ist das schöön. :lol: Meine 10 ct zum Thema : externes Logfile z.B. Windows ist Käse. Ich würds zumindest nicht damit machen. Eigenes Logfile ist besser. Dazu würde ich aber keine Datei verwenden, sondern Datenbank. Ob die auf einem Server liegt oder lokal, das ist wohl nicht so wichtig. Notfalls muss sie eben regelmäßig lokal gesichert werden. Das gilt natürlich auch für die Daten an sich. Die sind schließlich wichtiger, als ein gesichertes Logfile ohne Daten. :mrgreen: Man könnte die zu protokollierenden Sachen auch in die vorhandene Datenbank schreiben und basta. Aber je nachdem, was da wie reingeschrieben wird kann es durchaus sein, dass das Logfile bzw. die Tabelle (viel) größer wird, als die vorhandenen Daten. In einem Programm protokolliere ich z.B. jede gedruckte Zeile. Das aber immer mitzusichern wäre völlig überdimensioniert. Für den Fall der Fälle sollte man das zwar schon mal sichern, aber doch nicht dauernd. Obwohl, ich schreibe hier über Datensicherung etc. und das ist wohl sowieso eher von untergeordneter Bedeutung. :P

himitsu 10. Nov 2007 02:47

Re: Log-Datei realisieren
 
das mit fmShareExclusive wurde ja schon angesprochen,
aber gern nochmals - dieses sorgt dafür daß NUR Einer zur selben Zeit die Datei öffnen kann und nicht Mehrere.


ups, ja stimmt ... ohne TimeOut wird die Schleife ja nicht verlassen, bevor die Datei nicht geöffnet wurde, also kein Problem,
aber mit TimeOut sollte man die mögliche Exception bei CloseFile natürlich auch abfangen,
also {$I-} CloseFile(F); {$I+}.

Und was das Arbeiten mit Exceptionen angeht, klar ist es möglich, aber hier gab's schonmal ein Streitgespräch darüber, ob man überhaupt absichtlich Exceptionen auslösen soll, um den Programmablauf zu steuern und da meinten die Meisten berechtigt nein.



Zitat:

Zitat von peschai
Wer also das Hauptlog exclusiv öffnen kann, muss zuerst die anderen templogs auslesen und reinschreiben, dann diese templogs löschen und dann erst seine eigenen Sachen eintragen ...

was meint ihr ?

ja und dann muß man wieder die TempLogs gegen gleichzeitigen Zugriff absichern,
denn wenn ein anderer Prozess grad noch in ein TempLog reinschreibt, dann gibt es bestimmt Probleme wenn plötzlich gleichzeitig jemand anderes versucht diesen auszulesen (um ihn in den HauptLog einzutragen).

im Prinzip eine nette Lösung, aber da es sich hier nur um kurzzeitige Sperrungen des HauptLogs handelt (eie Zeile einzufügen dauert ja nicht lange), wäre der Aufwand wohl eher zu groß.
Sowas würde sich mehr für Dinge lohnen wo die Sperrung viel zu lange zum Warten dauert.

Alternativ könnte man auch im Programm sowas wie eine Warteliste anlegen, wo man die Logeinträge einfügt und welche dann bei nächster Gelegenheit in die Logdatei eingetragen werden.

Hansa 10. Nov 2007 03:19

Re: Log-Datei realisieren
 
Ne, himitsu. Immer noch zu kurz gesprungen. Wer so was narrensicher und komfortabel machen will, der kommt um DB nicht rum. Es geht schließlich auch um die Nachbearbeitung. Angenommen am 5.6.2006 ist irgendwas passiert und man will wissen, was jetzt genau war. Gut, dann wird eben so lange gescrollt, bis man bei dem Tag ist. Viel Vergnügen bei 100 Einträgen pro Tag. :P Da entwerfe ich mir lieber sinnvoll eine DB-Tabelle und schreibe die Zeile SELECT * FROM LOGTABLE WHERE DATUM='05.06.2006'. Es wurde auch noch nicht angesprochen, dass der Rechner / Task eindeutig gekennzeichnet werden müsste ! Wird das Programm mehrfach gestartet, dann wäre es wohl schon sinnvoll das festzuhalten. Sollte man schon auslesen. Bei mir wird das allerdings gar nicht erst zugelassen. Beim Programmstart wird eine Semaphore gesetzt.

mkinzler 10. Nov 2007 10:01

Re: Log-Datei realisieren
 
Ich frage mich dann, warum Datenbanken so gut wie nie für Logfiles verwendet werden? BTW. Per WMI kann man auch Abfragen aif Eventlogs absetzen.

himitsu 10. Nov 2007 10:15

Re: Log-Datei realisieren
 
weil es vermutlich einacher ist 'ne "billige" Textdatei anzulegen, statt erst 'ne Datenbank zu implementieren.
und ich glaub kaum, daß viele sich auch nur einen einzigen Gedenkan über gleichzitigen Zugriff gemacht haben ...

diese "Billig"Variante ist bestimmt seht weit verbreitet :stupid:
Delphi-Quellcode:
AssignFile(F, 'my.log');
Append(F);
WriteLn(F, S);
CloseFile(F);
PS: und wie soll man "keine verbindung zur Datenbank" in dieser loggen? :roll:


z.B. in PHP mit defekter oder nicht vorhandener DB-Anbindung,
da macht sich 'ne Textdatei doch sehr gut?
(auf besondere Features wie z.B. automatische Größenanpassung muß auch keiner verzichten)
ja und für den exklusiven Zugriff ist hier mal flock verantwortlich.
Code:
$Logdatei = array('Name' => 'index.log.php', 'Max' => 1048576, 'Min' => 786432,
               'Zeile 1' => '<?PHP exit; /* Zeit "Benutzername" "Meldung" '
                          . 'Provider/IP:Port Methode:Link Postdaten Browser */ ?>');


function AddLog($S) {
  global $Meldungen, $BenutzernameAnzeige, $Logdatei;
  $H = gethostbyaddr($_SERVER['REMOTE_ADDR']);
  $S = date('d.m.Y H:i:s', time()) . "\t\"" . addslashes($BenutzernameAnzeige) . "\"\t\"" . addslashes($S) . "\"\t"
    . (($_SERVER['REMOTE_ADDR'] != $H) ? $H : 'unbekannt') . '/' . $_SERVER['REMOTE_ADDR'] . ':' . $_SERVER['REMOTE_PORT'] . "\t"
    . $_SERVER['REQUEST_METHOD'] . ':' . $_SERVER['VHOST'] . $_SERVER['REQUEST_URI'] . "\t"
    . serialize($_POST) . "\t"
    . "\"" . addslashes($_SERVER['HTTP_USER_AGENT']) . "\"\r\n";

  @touch('./' . $Logdatei['Name']);
  @chmod('./' . $Logdatei['Name'], 0660);
  $Datei = @fopen('./' . $Logdatei['Name'], 'r+');
  if ($Datei) {
    @flock($Datei, LOCK_EX);
    @fseek($Datei, 0, SEEK_END);
    $i = @ftell($Datei);
    if (($i == 0) || ($i > $Logdatei['Max'] - strlen($S))) {
      $i -= $Logdatei['Min'] - strlen($Logdatei['Zeile 1'] . "\r\n") - strlen($S);
      @fseek($Datei, 0);
      while (($i - @ftell($Datei) > $Logdatei['Min']) && (@fgets($Datei) !== false)) ;
      $i = @ftell($Datei);

      @fseek($Datei, 0);
      @fputs($Datei, $Logdatei['Zeile 1'] . "\r\n");
      $k = @ftell($Datei);

      while (($t = @fgets($Datei)) !== false) {
        $i = @ftell($Datei);

        @fseek($Datei, $k);
        @fputs($Datei, $t);
        $k = @ftell($Datei);

        @fseek($Datei, $i);
      }
      @ftruncate($Datei, $k);
      @fseek($Datei, $k);
    }
    @fputs($Datei, $S);
    @flock($Datei, LOCK_UN);
    @fclose($Datei);
  } else $Meldungen[] = '*Logdatei konnte nicht geöffnet werden.';
}

Hansa 10. Nov 2007 10:19

Re: Log-Datei realisieren
 
Zitat:

Zitat von mkinzler
Ich frage mich dann, warum Datenbanken so gut wie nie für Logfiles verwendet werden? BTW. Per WMI kann man auch Abfragen aif Eventlogs absetzen.

Und ich frage mich, warum solche Log-Mechanismen dann z.B. in IBExpert zur Verfügung stehen. Tools -> Log Manager. Inserts, Updates, Delete kann man da mit geringem Aufwand protokollieren. Es werden Log-Tables angelegt und verwaltet (per Trigger). Diesen Code kann man sich im eigenen Programm locker sparen und konkurrierende Zugriffe können in keinem Fall Schaden anrichten.

P.S.: kann sein, dass das angesprochene nur in der Vollversion geht und deshalb nicht so bekannt ist.

Faxman 10. Nov 2007 10:24

Re: Log-Datei realisieren
 
senfe auch noch einen dazu und gebe hansa absolut recht.
10 -> n user in einem programm mit 2000 transaktions etc. am tag, wie soll man das noch sinnvoll ohne db überwachen, kontrollieren, sichern und auswerten.
der aufwand ist realtiv gering auch wenn's nur ein einzelner user werden soll.
lokale files, na ja, es soll ja auch noch lokale .ini's geben :wink:

juergen 10. Nov 2007 13:26

Re: Log-Datei realisieren
 
Hallo zusammen,
(ich hoffe, dass meine nachfolgende Frage zu diesem Thread paßt und kein neuer Thread dafür erstellt werden braucht)

Wenn man nun die Größe der Protokolldatei festlegen will/muss, wie sollte man da am besten vorgehen?
Die Protokolldatei jedes mal in z.B. eine TStringList laden und wenn eine vorgegebene Größe erreicht ist, dann einfach einen festen "Block" (z.B. die ersten 20000 Zeilen) löschen?
Dann hätte man immer noch eine gewisse Historie.
(das wäre dann quasi eine selbst reorganisierende Datei)

Eine andere Möglichlkeit wäre noch, wenn die Protokolldatei die vorgegebene Größe erreicht hat, dann diese Datei einfach umzubenennen und die Protokollierung in eine neue und damit "leere" Protokolldatei fortzusetzen.

marabu 10. Nov 2007 13:36

Re: Log-Datei realisieren
 
Hallo Jürgen,

ich würde an Hand von Erfahrungswerten ein Zeitintervall bestimmen, nach dessen Ablauf automatisch auf eine neue Protokolldatei umgestellt wird.

Grüße vom marabu

juergen 10. Nov 2007 14:11

Re: Log-Datei realisieren
 
Hallo marabu,
so einfach?! :-D :wall:
Ehrlich gesagt, an diese Variante hatte ich noch gar nicht gedacht.
Ich werde das bei mir jetzt auch genauso ändern, dass ein eigenen Ordner (Protokollierung) innerhalb der Anwendung angelegt wird.
Dann wird für jeden Monat eine Protokolldatei geschrieben.
Und dann noch einen "Protokoll-Viewer" basteln. Fertig ist's.

Danke und ein schönes Wochenende!

himitsu 10. Nov 2007 14:23

Re: Log-Datei realisieren
 
also in meiner PHP-Version ist es so gelöst, das bei Erreichen einer maximalen Dateigröße die Datei bis zum Minimum(Dateigröße) alte Einträge entfernt werden.
(hab mir das so einfallen lassen, da in dem Projekt seltener Einträge vorgenommen werden und eh nur die Einträge der näheren Vergangenheit interesant sind)

und jedesmal die Datei komplett einzulesen wäre auch nicht grad optimal.
(verbraucht nur unnötig Resourcen und Zeit)

Hansa 10. Nov 2007 18:19

Re: Log-Datei realisieren
 
Trotz der Einwände bleibe ich hier bei der Ausgangsfrage :

Zitat:

Zitat von Infect
..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?

Die Gefahr besteht bei Textdateien immer, dass in eine zum Lesen geöffnete Datei versucht wird, was reinzuschreiben. Kann bei DB kaum passieren, sofern die entsprechende Tabelle zumindest einen eindeutigen Primärschlüssel besitzt. Oder soll unnötig rumgeeiert werden ? :shock: Faxman hat die Problematik erkannt, sonst keiner.

MatthiasR 12. Nov 2007 08:14

Re: Log-Datei realisieren
 
Zitat:

Zitat von Reinhard Kern
EXCLUSIVE ist das entscheidende: ich habe es vorgeschlagen, hamamitsu hat damit eine ganze Beispielprozedur geschrieben und shmia hat eine Alternative mit TExclusiveFileStream vorgeschlagen, die intern das gleiche tut. Vielleicht sind wir ja blöd, aber immerhin sind wir schon zu dritt.

Da du nix verstanden hast, lässt du das entscheidende Statement mit fmShareExclusive einfach weg. So was nenne ich beratungsresistent.

Wenn du dich mal mit Dateien beschäftigen würdest, dann würdest du auch auf den Begriff "exklusiver Zugriff" stossen. Meine Meinung zum Thema: solange du diesen Punkt nicht verstanden hast, kannst du dein Problem nicht lösen - stattdessen auf Mutexe u.a. auszuweichen, ist Blödsinn, weil das das Problem nur anders einkleidet und dazu noch komplizierter ist als Datei-Zugriffe.

Natürlich hast du als Jungprogrammierer das Recht, alles anders zu sehen und alle Erkenntnisse der IT mit Verachtung zu strafen. Schon ein Konkurrent weniger.

Gruss Reinhard

Das mit dem exclusiven Öffnen der Log-Datei habe ich schon verstanden, jedoch bin ich davon ausgegangen, dass das bei Windows bei schreibenden Zugriffen automatisch so gesteuert wird. Und Append ist für meine Begriffe ja ein schreibender Zugriff. Diese Annahme wurde für mich dadurch bekräftigt, dass ein schreibendes Öffnen ein und derselben Datei mittels Append eben NICHT durch mehrere Programme gleichzeitig möglich ist, sondern in einer Exception endet. Auch ohne diese besagte Zeile!!! Das einzige, was ich daher von euch wissen wollte, ist, was das vorige setzten des FileMode genau bewirkt. Für mich ergeben sich zumindest bei mir KEINE sichtbaren Änderungen, wenn ich diese Zeile einfüge!!! Mein Programm verhält sich kein Stück anders, als wenn ich die Zeile weglasse. Deswegen wollte ich es genau wissen, was intern abgeht, bevor ich diese Zeile blindlings übernehme. Ich hoffe, du siehst es mir nach, dass ich Dinge lieber erstmal hinterfrage. Genauso bei shmias Klasse. Wenn ich selbst eine Lösung gefunden habe, die zwar womöglich nicht ganz so komfortabel ist, jedoch ihren Dienst verrichtet, auf meinem eigenen Mist gewachsen ist und ich daher auch 100%ig durchsteige, was da intern eigentlich abläuft, dann ziehe ich diese Lösung vor.

Also frage ich nochmal: was bewirkt die Zeile
Delphi-Quellcode:
FileMode := fmOpenReadWrite or fmShareExclusive;
genau? Was ist anders, wenn ich die Zeile einfach weglasse? Mein Programm verhält sich wie gesagt genauso...

Hansa 12. Nov 2007 08:49

Re: Log-Datei realisieren
 
Zitat:

Zitat von Infect
..dass ein schreibendes Öffnen ein und derselben Datei mittels Append eben NICHT durch mehrere Programme gleichzeitig möglich ist...

So ist es. Es geht um eine einzelne Datei. Noch nie in Word die Meldung gesehen : "Dokument von anderem Benutzer im Zugriff ! Schreibgeschützt öffnen ?" oder so ähnlich ? Genau das ist der Punkt. Natürlich kann ich das umgehen, indem ich das eine Word-Dokument verlasse (oder die Log-Datei schließe) und dann den vorher geänderten und abgespeicherten Text neu öffne und dann eben nicht schreibgeschützt. Der ganze Firlefanz entfällt bei Einsatz einer Datenbank. Wenn einige auch Logdatei mit Textdatei gleichsetzen, es geht damit nur so : Öffnen (Append), schreiben, schließen. Im Zeitraum zwischen öffnen und schließen kann KEIN anderer Benutzer etwas schreiben !!

himitsu 12. Nov 2007 08:53

Re: Log-Datei realisieren
 
per Default ist MileMode nur auf fmOpenReadWrite gesetzt (in der Unit System)

also werden Dateien damit nicht exlusiv geöffnet.



Zitat:

Zitat von Infect
jedoch bin ich davon ausgegangen, dass das bei Windows bei schreibenden Zugriffen automatisch so gesteuert wird.

indows macht nichts automaisch (wär ja auch noch schöner, weil sonst wüßte man ja nicht was windows wann machen würde), das muß man schon selber angeben.

Zitat:

Zitat von Infect
Und Append ist für meine Begriffe ja ein schreibender Zugriff.

jupp, isser


Zitat:

Zitat von Infect
Diese Annahme wurde für mich dadurch bekräftigt, dass ein schreibendes Öffnen ein und derselben Datei mittels Append eben NICHT durch mehrere Programme gleichzeitig möglich ist, sondern in einer Exception endet. Auch ohne diese besagte Zeile!!!

mein Tipp, wenn du uns nicht glaubst:
versuch doch einfach mal eine Datei mehrmals zu öffnen.

Zitat:

Zitat von Infect
Das einzige, was ich daher von euch wissen wollte, ist, was das vorige setzten des FileMode genau bewirkt.

das wurde doch schon mehrmals gesagt.

Zitat:

Zitat von Infect
Für mich ergeben sich zumindest bei mir KEINE sichtbaren Änderungen, wenn ich diese Zeile einfüge!!!

nicht?

Zitat:

Zitat von Infect
Also frage ich nochmal: was bewirkt die Zeile
Delphi-Quellcode:
FileMode := fmOpenReadWrite or fmShareExclusive;
genau? Was ist anders, wenn ich die Zeile einfach weglasse? Mein Programm verhält sich wie gesagt genauso...

siehe oben (da per Default nicht gesetzt)


aber de Witz Dabei, ich hab es eben selbst mal ausprobiert und war "geschockt"
im Delphi 7 hier wird die Datei bei Schreibzugriff (Rewrite oder Append) immer im exklusiven Modus geöffnet, selbst wenn der nicht angegeben ist.

Und besonsters geschockt war ich, als ich selber angegeben hab, daß mit Sharing-Rechten (nicht Exklusiv) geöffnet werden sollte :shock:

Ich würde das jetzt mal ganz einfach als Delphifehler auslegen
und dazu raten dieses lieber nicht auszunutzen/vorauszusetzten (wer weiß ob/wann das mal repariert wird/wurde)


eigentlich müßte das Erste ohne Exception durchlaufen und das Zweite wie gewollt bei Append(F2); eine Exception auslösen.
Delphi-Quellcode:
Var F, F2: TextFile;

Begin
  // testdatei erstellen
  AssignFile(F, 'test.txt');
  Rewrite(F);
  CloseFile(F);

  //FileMode := fmOpenReadWrite or fmShareDenyNone;

  // mit sharing-rechten
  AssignFile(F, 'test.txt');
  Append(F);

  AssignFile(F2, 'test.txt');
  Append(F2);
  CloseFile(F2);

  CloseFile(F);



  FileMode := fmOpenReadWrite or fmShareExclusive;

  // exklusiv
  AssignFile(F, 'test.txt');
  Append(F);

  AssignFile(F2, 'test.txt');
  Append(F2);
  CloseFile(F2);

  CloseFile(F);
End;

MatthiasR 12. Nov 2007 09:52

Re: Log-Datei realisieren
 
Zitat:

Zitat von himitsu
...aber de Witz Dabei, ich hab es eben selbst mal ausprobiert und war "geschockt"
im Delphi 7 hier wird die Datei bei Schreibzugriff (Rewrite oder Append) immer im exklusiven Modus geöffnet, selbst wenn der nicht angegeben ist.

Und besonsters geschockt war ich, als ich selber angegeben hab, daß mit Sharing-Rechten (nicht Exklusiv) geöffnet werden sollte :shock:

Ich würde das jetzt mal ganz einfach als Delphifehler auslegen
und dazu raten dieses lieber nicht auszunutzen/vorauszusetzten (wer weiß ob/wann das mal repariert wird/wurde)...

AHA, da liegt also der Hund begraben! Ich hoffe jetzt versteht jeder von euch (v.a. du Reinhard!!!) warum mir nicht einleuchten wollte, warum ich unbedingt den FileMode umstellen muss, wenn es ohne genauso funktioniert (weil der FileMode wie ihr seht scheinbar standardmäßig auf Exclusive umgestellt wird). Da wurde mein Programm wohl etwas vorschnell als "reiner Unsinn" abgestempelt, wenn man es wie mir scheint zuvor nicht einmal selbst ausprobiert hat! Eigentlich wäre da ne Entschuldigung fällig...

Wie dem auch sei: danke himitsu, dass du der Sache auch mal auf den grund gegangen bist! So stellt sich das alles für mich in einem ganz neuen Licht dar! Wenn man wirklich davon ausgeht, dass es sich bei diesem Verhalten um einen Delphi-Fehler handelt, dann ergibt das explizite Umstellen (und Rückstellen!!!) des FileMode durchaus einen Sinn, das sehe ich absolut genau so! Seht ihr, man kann mich durchaus überzeugen (so viel zum Thema "Jungprogrammierer" und "Erkenntnisse der IT"...).

himitsu 12. Nov 2007 10:04

Re: Log-Datei realisieren
 
Zitat:

Zitat von Infect
dann ergibt das explizite Umstellen (und Rückstellen!!!) des FileMode durchaus einen Sinn

also das vorherige Speichern und nachfolgende Zückstellen MUß nicht unbedingt gemacht werden
FileMode ist leider eine Progamminterne Variable und wird in allen nachfolgenden Reset/Rewrite/Append-Aufrufen werwendet.
Wenn also irgendwo anders im Programm wieder eine Datei geöffnet wird, dann wäre es besser wenn man da den alten Wert wiederherstellt, da es da sonst zu problemen kömmen kann (wenn dort ein anderer oder der Standardwert benötigt wird)

nja, das Schlimme daran ist eigentlich daß man aufgrund dieses Fehlers keine Dateien mehrfach öffnen kann, selbst wenn man wöllte :wall:
(na ja, zum Glück hab ich mich da komplett auf die WinAPI umgestellt und dort läuft alles wie gewünscht ^^)


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:05 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz