Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Bei wachsendendem Logfile auf bestimme Zeile reagieren (https://www.delphipraxis.net/171915-bei-wachsendendem-logfile-auf-bestimme-zeile-reagieren.html)

Ajintaro 1. Dez 2012 15:41

Delphi-Version: XE2

Bei wachsendendem Logfile auf bestimme Zeile reagieren
 
Hallo DP !

Ein Programm loggt Ereignisse mit und schreibt es in ein logfile.
Ich moechte nun dieses Logfile ueberwachen und bei einer bestimmte Zeile einen einfachen beep ausgeben.

Auszug aus dem Logfile:

1) Tomaten sind meistens rot
2) Telefonieren ist teuer
3) Tanken auch !
4) Delphi ist: [einfach toll]
5) Delphi ist: [total genial]
6) Wer mag Bananen?

Ich interessiere mich fuer folgende Zeilen: "Delphi ist: [Text]"
Ein Timer soll die Ueberwachung des Logfiles uebernehmen und einen beep ausgeben sobald die Zeile: "Delphi ist: [Text]" ins logfile geschrieben wird.

Delphi-Quellcode:
procedure TForm1.Timer1Timer(Sender: TObject);
var
   sl:TStringList;
   s :string;
begin
sl := TStringList.Create;
sl.LoadFromFile(e_logpath.Text);
//nach der Zeile suchen
//wenn gefunden: beep
sl.Free;
end;
Somit
Delphi-Quellcode:
sl.LoadFromFile(e_logpath.Text);
ist das ganze Logfile in der Stringlist. Ist aber nicht notwendig weil mich immer nur die neuen Zeilen interessieren, die nach dem aktivieren des Timers hinzukommen.

Mit
Delphi-Quellcode:
TStringList.IndexOf('Delphi ist: ');
kann ich das Vorkommen der Zeile sicherstellen.

Eigentlich hab ich fast alle Bausteine die notwendig sind, aber ich schaff es damit nicht mein Problem damit zu loesen.

Koennt ihr mir helfen?

Uwe Raabe 1. Dez 2012 15:56

AW: Bei wachsendendem Logfile auf bestimme Zeile reagieren
 
IndexOf vergleicht immer den gesamten String. Damit findest du mit
Delphi-Quellcode:
sl.IndexOf('Delphi ist: ');
die im Beispiel aufgeführten Zeilen nicht.

Ajintaro 1. Dez 2012 16:20

AW: Bei wachsendendem Logfile auf bestimme Zeile reagieren
 
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
const SearchString = 'Delphi ist: ';

var MyTextFileContent : TStringList;
    i : Integer;
    tempStr : String;
begin
  MyTextFileContent := TStringList.Create;
  try
    MyTextFileContent.LoadFromFile(e_logpath.Text);
  except
    Showmessage('Motz, kreisch');
    MyTextFileContent.Free;
    exit;
  end;
  for i := 0 to MyTextFileContent.Count -1 do
    if pos(SearchString,MyTextFileContent[i]) <> 0 then
    begin
      tempStr := MyTextFileContent[i];
      delete(tempStr,1,pos(SearchString,MyTextFileContent[i])+ length(SearchString)-1);
      showmessage('gefunden in Zeile ' + Inttostr(i +1));
      MyTextFileContent.Free;
      exit;
    end;
  MyTextFileContent.Free;
end;
Damit finde ich das 1. Vorkommen meines Suchstrings. Aber um das neuste Vorkommen des Suchstrings zur Laufzeit zu ermitteln ist fuer mich noch nicht loesbar.

Popov 1. Dez 2012 16:24

AW: Bei wachsendendem Logfile auf bestimme Zeile reagieren
 
Zweiteilen? Ein Logfile und ein Logfile Archiv? Logfile protokolliert letzte Aktionen, Archiv enthällt alles.

Ajintaro 1. Dez 2012 16:39

AW: Bei wachsendendem Logfile auf bestimme Zeile reagieren
 
Theoretisch muesste mein Programm beim Start direkt zum EOF des Logfiles springen und ab da mit der Ueberwachung anfangen. Aber wie stellt man sowas an ?

DeddyH 1. Dez 2012 17:21

AW: Bei wachsendendem Logfile auf bestimme Zeile reagieren
 
Wie wäre es mit Streams? Darin kann man doch prima navigieren.

Uwe Raabe 1. Dez 2012 22:42

AW: Bei wachsendendem Logfile auf bestimme Zeile reagieren
 
Zitat:

Zitat von Ajintaro (Beitrag 1193890)
Theoretisch muesste mein Programm beim Start direkt zum EOF des Logfiles springen und ab da mit der Ueberwachung anfangen. Aber wie stellt man sowas an ?

Wenn das Logfile immer nur größer wird, kannst du dir nicht die Anzahl Zeilen zwischen den Abfragen merken? Dann springst du beim nächsten Mal gleich an die letzte Zeile vom letzten Mal und liest von dort aus weiter.

p80286 1. Dez 2012 23:52

AW: Bei wachsendendem Logfile auf bestimme Zeile reagieren
 
Zitat:

Zitat von Ajintaro (Beitrag 1193890)
Theoretisch muesste mein Programm beim Start direkt zum EOF des Logfiles springen und ab da mit der Ueberwachung anfangen. Aber wie stellt man sowas an ?

Delphi-Quellcode:
lf:=tfiestream.create(mylogfile,...);
lf.seek(lf.size,sofrombeginning);
...
lf.write(....);
so z.B. oder mit verschiedenen Kombinationen der notwendigen Streams.

nicht empfehlenswert ist die Verwendung von Textfile und Append.

Gruß
K-H

Bjoerk 2. Dez 2012 12:02

AW: Bei wachsendendem Logfile auf bestimme Zeile reagieren
 
Zitat:

Zitat von Ajintaro (Beitrag 1193886)
Damit finde ich das 1. Vorkommen meines Suchstrings. Aber um das neuste Vorkommen des Suchstrings zur Laufzeit zu ermitteln ist fuer mich noch nicht loesbar.

Delphi-Quellcode:
  for i := MyTextFileContent.Count - 1 downto 0

Jood 2. Dez 2012 13:41

AW: Bei wachsendendem Logfile auf bestimme Zeile reagieren
 
Schau dir doch mal Cromis.DirectoryWatch an, damit läßt sich sowas ohne Probleme lösen.
Du bekommst bei jeder Dateiänderung im vorgegebenen Pfad ein Event.

[Delphi]
procedure TMF.OnNotify(const Sender: TObject; const Action: TWatchAction; const FileName: string);
....
If (FileName = 'LogFile.txt') and (Action = waModified) then
Begin
NewFileSize := getFileSize(CombatLog);
If NewFileSize <> OldFileSize then
Begin
...
[/Delphi}

Furtbichler 2. Dez 2012 15:24

AW: Bei wachsendendem Logfile auf bestimme Zeile reagieren
 
Merk Dir die Größe der Datei seit dem letzten Prüfvorgang (=StartPos).
Zum periodischen Prüfen:

1. Gehe in der Datei an Die Stelle 'StartPos+1'
2. Suche ab da bis zum Ende der Datei.
3. Anschließend setzt Du StartPos auf <Größe der Datei>

StartPos ist am Anfang 0.

Bummi 2. Dez 2012 16:28

AW: Bei wachsendendem Logfile auf bestimme Zeile reagieren
 
@Furtbichler > #7

Popov 2. Dez 2012 16:49

AW: Bei wachsendendem Logfile auf bestimme Zeile reagieren
 
Wobei man gelegentlich das Archivieren von Logfiles nicht vergessen sollte. Eine zeitlang klappt das Anhängen. Ich hab mal eine Log von knapp 2 GB gesehen. Kunde meinte, dass das Programm früher etwas schneller war. Also ab und zu vorne etwas abschneiden, archivieren und alles anpassen.

Furtbichler 2. Dez 2012 19:20

AW: Bei wachsendendem Logfile auf bestimme Zeile reagieren
 
Zitat:

Zitat von Bummi (Beitrag 1194007)
@Furtbichler > #7

Das ist nicht das Gleiche, denn er spricht in seinem Ansatz von 'Zeilen' und mir ist nicht bekannt, das ich in die X.te Zeile per Filestream springen kann.

Na ja, eigentlich ist es doch das Gleiche aber eben nicht ganz.:roll:

Ajintaro 3. Dez 2012 14:56

AW: Bei wachsendendem Logfile auf bestimme Zeile reagieren
 
Ich habe mir erstmal folgende Loesung gebastelt:

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  Inhalt: string;
  p:integer;
begin
  Assignfile(Src,'C:\Users\tomatenmann\Documents\logoutput\Log.txt');
  Reset(Src);
  memo1.Clear;
    while not EOF(Src) do
    begin
      ReadLn(Src, Inhalt);
      p := Pos('Suchtext', Inhalt);
      if p > 0 then
      begin
       //Reaktion auf gefundenen Suchstring
       memo1.Lines.Add(Inhalt);
      end;
    end;
    CloseFile(Src);
end;
Mit diesem Code werden beim Programmstart nur die Zeilen in das Memo uebertragen, welche dem Suchstring entsprechen.
Jeder weitere Eintrag in das Memo loest die gewuenschte Reaktion aus.

Funktioniert.

Das dumme ist:
Wenn das Logfile mehrere Dutzend Megabytes gross wird kann es auf Dauer etwas unperformant werden, da ich bei jeder pruefung das gesamte logile zeilenweise neu einlese.
Bloed ist auch dass mein Programm das File fuer andere Anwendungen "blockiert", deshalb muss ich bei jedem Vorgang das file wieder "closen"

Bummi 3. Dez 2012 15:44

AW: Bei wachsendendem Logfile auf bestimme Zeile reagieren
 
Der bereits mehrfach erwähnte FileStream ([fmopenRead,fmShareDenyNone]), lesen ab letztem bekannten Ende, sollte diese Probleme lösen.

p80286 3. Dez 2012 16:48

AW: Bei wachsendendem Logfile auf bestimme Zeile reagieren
 
Fassen wir doch mal zusammen,
Du hast eine Program (prg1) das in eine Datei schreibt (lg1).
in dieser Datei werden verschiedene vordefinierte strings geschrieben,
es wird kein Datum und keine Uhrzeit geschrieben.

Zu einem beliebigen Zeitpunkt wird ein weiteres Program (prg2) gestartet, das alle Einträge, die nach prg2.Start in das lg1 gemacht werden, auf bestimmte Inhalte überprüft und ggf. eine optische und/oder akustische Meldung absetzt.

ist das soweit richtig?

Gruß
K-H

Ajintaro 3. Dez 2012 17:22

AW: Bei wachsendendem Logfile auf bestimme Zeile reagieren
 
Zitat:

Zitat von p80286 (Beitrag 1194128)
Fassen wir doch mal zusammen,
Du hast eine Program (prg1) das in eine Datei schreibt (lg1).
in dieser Datei werden verschiedene vordefinierte strings geschrieben,
es wird kein Datum und keine Uhrzeit geschrieben.

Zu einem beliebigen Zeitpunkt wird ein weiteres Program (prg2) gestartet, das alle Einträge, die nach prg2.Start in das lg1 gemacht werden, auf bestimmte Inhalte überprüft und ggf. eine optische und/oder akustische Meldung absetzt.

ist das soweit richtig?

Gruß
K-H

zu 100% korrekt.

Bjoerk 3. Dez 2012 20:32

AW: Bei wachsendendem Logfile auf bestimme Zeile reagieren
 
Ich würd' mir was von TStringList ableiten:

Delphi-Quellcode:
  TLogFile = class(TStringList)
  private
    FLoadCount: integer;
    FFileName: string;
  public
    procedure UpDate;
    procedure Refresh;
    function IndexOfSubString(const SubStr: string; var Index: integer): integer;
    function DeleteSubString(const SubStr: string): boolean;
    property LoadCount: integer read FLoadCount;
    property FileName: string read FFileName;
    constructor Create(const AFileName: string);
  end;
Delphi-Quellcode:
constructor TLogFile.Create(const AFileName: string);
begin
  inherited Create;
  FFileName:= AFileName;
  FLoadCount:= 0;
  Refresh;
end;

procedure TLogFile.Refresh;
begin
  if FileExists(FFileName) then
  begin
    LoadFromFile(FFileName);
    FLoadCount := Count;
  end;
end;

procedure TLogFile.Update;
begin
  if FileExists(FFileName) then
    LoadFromFile(FFileName);
end;

function TLogFile.IndexOfSubString(const SubStr: string; var Index: integer): integer;
var
  I: integer;
begin
  UpDate;
  Result := -1;
  Index := 0;
  for I:= FLoadCount to Count -1 do
  begin
    Index:= Pos(SubStr, Strings[I]);
    if Index > 0 then
    begin
      Result := I;
      Break;
    end;
  end;
end;

function TLogFile.DeleteSubString(const SubStr: string): boolean;
var
  I, J: integer;
  S: string;
begin
  Result:= false;
  I:= IndexOfSubString(SubStr, J);
  if I > -1 then
  begin
    Result:= true;
    S:= Strings[I];
    System.Delete(S, J, Length(SubStr)); // ???
    Strings[I]:= S;
  end;
end;

DeddyH 3. Dez 2012 20:37

AW: Bei wachsendendem Logfile auf bestimme Zeile reagieren
 
Hat eigentlich jemand #10 bemerkt? Wozu sollte man die komplette Datei in den Speicher laden, wenn man nur einen Bruchteil davon braucht? Wenn man sich die Dateigröße beim Programmstart merkt, muss man doch nur ab dort untersuchen, wenn man über eine Änderung informiert wird.

Bjoerk 3. Dez 2012 21:47

AW: Bei wachsendendem Logfile auf bestimme Zeile reagieren
 
Ist die Datei so groß? Falls ja, dann ist das hier an mir vorbeigegangen. Sorry. Meine Easylösung würde ich nur für Dateien so bis 1 MB empfehlen, sonst ist das viel zu langsam. :oops:

implementation 3. Dez 2012 21:48

AW: Bei wachsendendem Logfile auf bestimme Zeile reagieren
 
Wenn es nicht unbedingt per Delphi geloest werden muss, sondern bloss irgendwie, dann wuerde ich mal was mit sed probieren.
Sowas in die Richtung:
Code:
sed -rne 's/^.*fu.*$/'$(echo -e "\007")'/gp' test.log


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:55 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 by Thomas Breitkreuz