Filtern von Protokollen mit Regex in Java

8

Die Beschreibung ist ziemlich lang, also bitte ertragen Sie mit mir:
Ich habe Protokolldateien von 300 MB bis 1,5 GB Größe, die mit einem Suchschlüssel gefiltert werden müssen.

Das Format der Protokolle ist ungefähr so:

%Vor%

Mit dem Suchschlüssel 123456 muss ich folgendes holen:

%Vor%

Das folgende awk-Skript erledigt meine Arbeit (sehr langsam):

%Vor%

Es dauert ungefähr 8 Minuten, um eine Protokolldatei mit einer Größe von 1 GB zu durchsuchen. Und ich muss das für viele solche Dateien tun. Um das Ganze abzurunden, habe ich mehrere solcher Suchschlüssel, was die ganze Aufgabe unmöglich macht.

Meine erste Lösung ist Multithreading. Ich habe einen FixedThreadPoolExecutor verwendet, eine Aufgabe für jede Datei eingereicht, die gefiltert werden muss. In der Aufgabenbeschreibung habe ich einen neuen Prozess mit javas Runtime () erzeugt, der das gawk-Skript mit bash ausführen und die Ausgabe in eine Datei schreiben und dann alle Dateien zusammenführen würde.

Obwohl dies vielleicht ein schlechter Weg zu sein scheint, da die Filterung E / A-abhängig und nicht CPU ist, gab es eine Beschleunigung gegenüber dem sequentiellen Ausführen des Skripts für jede Datei.

Aber es ist immer noch nicht ausreichend, da die ganze Sache 2 Stunden dauert, für einen einzigen Suchschlüssel, mit 27 GB Log-Dateien. Im Durchschnitt habe ich 4 solche Suchschlüssel und muss alle ihre Ergebnisse holen und zusammensetzen.

Meine Methode ist nicht effizient, weil:

A) Es greift mehrfach auf jede Protokolldatei zu, wenn mehrere Suchschlüssel angegeben werden, und verursacht noch mehr E / A-Overhead.
B) Es entsteht der Aufwand, einen Prozess innerhalb jedes Threads zu erstellen.

Eine einfache Lösung für all das ist, sich von awk zu entfernen und das Ganze in Java zu tun, indem man eine Regex-Bibliothek benutzt. Die Frage ist, was ist diese Regex-Bibliothek, die mir die gewünschte Ausgabe liefern könnte? Mit awk habe ich die /filter/{action} -Eigenschaft, mit der ich einen Bereich von mehreren Zeilen festlegen kann, die erfasst werden sollen (wie oben zu sehen). Wie kann ich das gleiche in Java machen?

Ich bin offen für alle Arten von Vorschlägen. Eine extreme Option wäre beispielsweise, die Protokolldateien in einem gemeinsamen Dateisystem wie S3 zu speichern und die Ausgabe mit mehreren Computern zu verarbeiten.

Ich bin neu bei Stackoverflow und ich weiß nicht einmal, ob ich das hier posten kann. Aber ich arbeite seit einer Woche daran und ich brauche jemanden mit Erfahrung, der mich dabei unterstützt. Vielen Dank im Voraus.

    
gitmorty 21.06.2017, 08:52
quelle

2 Antworten

1

Sie haben ein paar Optionen.

Am besten wäre es, ein inverses Wörterbuch zu verwenden. Das bedeutet, dass Sie für jedes in mindestens einem der Protokolle enthaltene Schlüsselwort x einen Verweis auf alle Protokolle, die es enthalten, speichern. Aber da Sie bereits eine Woche mit dieser Aufgabe beschäftigt waren, würde ich Ihnen raten, etwas zu verwenden, das bereits da ist und genau das tut: . Sie können den gesamten ELK-Stack (elasticsearch, logstash, kibana - hauptsächlich für Logs) verwenden, um die Logs sogar zu parsen, da Sie einfach einen Regex-Ausdruck in die Konfigurationsdatei einfügen können. Sie müssen die Dateien nur einmal indizieren und erhalten Suchvorgänge in wenigen Millisekunden.

Wenn Sie wirklich Energie verschwenden möchten und nicht die beste Lösung suchen, können Sie map-reduce auf hadoop verwenden, um das Protokoll zu filtern. Aber das ist keine Aufgabe, bei der map-reduce optimal ist und eher wie ein Hack aussehen würde.

    
Dinu Sorin 21.06.2017 15:28
quelle
0

Die Umstellung auf Java ist möglicherweise nicht die beste Option, wenn Sie Ihre Ausführungszeit beschleunigen möchten, aber wenn Sie darüber nachdenken, habe ich eine Java-Klasse geschrieben, die Ihnen helfen könnte.

Sie können damit einen oder mehrere Schlüssel in einer Datei gleichzeitig suchen. Da Sie eine Protokolldatei lesen, kann davon ausgegangen werden, dass alle Zeilen dem korrekten Format ohne Fehler folgen. Anstatt also die gesamte Zeile im Regex-Format zu überprüfen, springt sie einfach dorthin, wo der Schlüssel sein sollte (die Ziffern nach dem ersten ] ) und vergleicht sie mit dem erforderlichen Wert (vorausgesetzt, es handelt sich immer um eine Zahl).

Benutze es so:

%Vor%

Das dritte Argument ist eine benutzerdefinierte Schnittstelle KeySearch.Callback , die Zeilen empfängt, sobald sie gefunden werden. Ich verwende eine Methodenreferenz als Beispiel, aber es kann alles sein, was Sie wollen. Hier ist die Klasse (benötigt mindestens Java 8).

%Vor%     
Leo Aso 22.06.2017 15:15
quelle

Tags und Links