ich benötige etwas Hilfe mit einer neuen Funktion, die ich einbauen will.
Aufgabenstellung:
------------------------
Ich will Zeilen in Logfiles nach dem Auftreten bestimmter Strings durchsuchen und dann alle Zeilen mit dem Suchbegriff zusammenstellen ( die Textzeilen, nicht die Zeilennummern).
Exakt das, was grep auf einem Linux System macht.
Also z.B.:
grep "error" mylog.log
Gleiches geht aber z.B. auch mit Notepad++ ( "Find all in current document")
In meiner Applikation ist das Logfile bereits in ein EditorGadget eingelesen, wenn der Grep-Filter auf den darin befindlichen Text angewendet werden soll.Das Resultat der Grep-Funktion wird
dann wieder in das EditorGadget kopiert.
Zeilennummern der Übereinstimmungen wären ein netter Nebeneffekt, interessieren mich aber im Moment eher weniger.
Ich habe erstmal klassisch angefangen, mit Findstring und ohne Tricks:
Code: Alles auswählen
Procedure.s GrepText(text.s, greptext.s)
GrepStartTime = ElapsedMilliseconds()
searchstart = 1
While FindString(text.s, greptext.s, searchstart) ; search the grep string
StartPos = FindString(text.s,greptext.s, searchstart)
EndPos = FindString( text.s, #CRLF$, Startpos)
For pos = StartPos To 1 Step -1
startofline = FindString(text.s, #CRLF$, pos)
If startofline >0 And startofline < EndPos
startofline+2
Length = Endpos - startofline
grepline.s = grepline.s + Mid(text.s, startofline, Length) + #CRLF$
searchstart = EndPos+1
Break
EndIf
Next pos
Wend
ElapsedTime.d = ElapsedMilliseconds()-GrepStartTime
ElapsedTime.d = ElapsedTime.d/1000
Debug "Grep process took "+ElapsedTime.d+" seconds to find "+match+" Matches in "+ListSize(LogList())+" Lines"
ProcedureReturn grepline.s
EndProcedure
Also ich suche den Suchstring, dann das darauf folgende CRLF, um das Zeilenende zu bekommen.Dann such ich mit einer Schleife rückwärts nach dem
vorherigen CRLF, um den Zeilenanfang zu bekommen.
Dass funktioniert, ist aber für meine Anwendung ( Logfiles mit mehreren MBytes, in extremen Fällen auch mal 100Mbyte, mehrere tausend Zeilen) viiiiieeeeel zu langsam.
Für ein gegebenes Logfile mit + 4.5 Mbyte und 50241 Zeilen benötigt diese Routine 245 Sekunden, um 2700 Matches zu finden und in einen String zusammenzustellen.
Also habe ich mal einen anderen Ansatz probiert:
Code: Alles auswählen
Global NewList LogList.s()
Procedure.s FastGrepText(LogFileName.s, greptext.s)
FastGrepStartTime = ElapsedMilliseconds() ; ermittelt die aktuelle Zeit
FileHandle_log = ReadFile(#PB_Any, LogFileName.s)
If FileHandle_log
While Not Eof(FileHandle_log)
AddElement(LogList()) : LogList() = ReadString(FileHandle_log)
Wend
CloseFile(FileHandle_log)
EndIf
If ListSize(LogList())
ForEach LogList()
If FindString(LogList(), greptext.s)
match+1
greppedText.s +LogList()+#CRLF$
EndIf
Next
EndIf
ElapsedTime.d = ElapsedMilliseconds()-FastGrepStartTime
ElapsedTime.d = ElapsedTime.d/1000
Debug "FastGrep process took "+ElapsedTime.d+" seconds to find "+match+" Matches in "+ListSize(LogList())+" Lines"
ClearList(LogList())
ProcedureReturn greppedText.s
EndProcedure
Die gleiche Suche dauert damit nur 0.85 Sekunden, was schon sehr viel schneller ist.Allerdings ist so, dass ich das Logfile eigentlich bereits vorher schon eingelesen habe
und der komplette Inhalt in einem EditorGadget existiert, wenn die Grep-Routine aufgerufen wird.Daher war der natürliche Ansatz, den Text des EditorGadgets zu nehmen und zu
durchsuchen, was aber eben um Größenordnungen zu langsam ist.
Das erneute Einlesen des Logfiles wäre akzeptabel für mich, da es verglichen mit der Suche wenig Zeit kostet, ist aber suboptimal, da die Zeit mit Größe des Files auch skaliert..Außerdem ist selbst die Routine mit der List immer noch zu langsam.Bei gleichem Logfile wie oben dauert das finden von 28.774 Matches dann bereits 71 Sekunden.
Bei Notepad++ ist das schweineschnell, da dauert die Suche mit den 28.000 Matches keine Sekunde.
Meine App dreht sich um das Anschauen von Logfiles und ich habe vieles auf Geschwindigkeit optimiert ( innerhalb meiner Möglichkeiten ) , ich finde warten auf eine Software
nervig, wie die meisten von uns.
ich habe natürlich erstmal ein paar Tage das Forum durchforstet, interessante Dinge gefunden, aber nichts, was auf meine Aufgabenstellung genau paßt.
Hat jemand eine Idee, wie man es schneller machen kann ?