Elemente aus einem Logfile zur Suche in einem anderen verwenden

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
fredvonfat
User
Beiträge: 51
Registriert: Mittwoch 12. September 2018, 10:00
Wohnort: Berlin

Hallo zusammen,

ich bin Python Neuling und zwar aus der Not heraus geboren. Ich betreue ein System, welches mir zwei relevante Logfiles liefert.
Das erste ist eine Kurzfassung um ein Überblick zu erhalten und das zweite ist das, in dem jede Kleinigkeit mitgeschrieben wird.
Es geht bei dem System um Kommunikation DTMF-Ton basierter Geräte. im Zuge der Umstellung der Telefonnetze auf Voip, kommt es zu Fehlkommunikation zwischen den Gräten. Ziel meines Projektes ist, die Kommunikation zweier Geräte aus dem Logfile zu separieren und über einen gewissen Zeitraum zu dokumentieren / auszuwerten.

Bislang habe ich dazu ein Debian 9 System aufgesetzt, das sich täglich die Logfiles kopiert. Anhand von Shell-Skripten habe ich schon ein paar Erfahrungen mit den Eigenarten der beiden Logfiles sammeln können, allerdings bin ich dort an Grenzen gestoßen, die ich hoffe mit Python überwinden zu können.

Logfile 1 (log_file) wird immer am Ende einer gelungenen bzw. misslungenen Kommunikation geschrieben.

Es sollen, die Zeilen mit "ISDN Fehlanruf" extrahiert werden, diese sehen, wie folgt aus:

1620 31/08/18 00:09:36 ISDN Fehlanruf C:00 xxxx xxxxxxxxxxx Diag:DEKODIERUNGSFEHLER ,
^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^ ^^^^ ^^^^^^^^^^^^^^
Lfd. Zeitstempel Beschreibung Duwa Rufnummer

und daraus folgende Angaben zur Weiterverarbeitung entnommen werden:
1. Datum im Format Jahr-Monat-Tag plus entsprechendem Zeitstempel,
2. Die Durchwahlnummer (Duwa),
3. Die Rufnummer (11 stellig, manchmal auch 10stellig)

Diese Angaben sollen im weiteren Verlauf, dazu Verwendet werden, die entsprechende Kommunikation aus dem zweiten Logfile zu isolieren.

Bislang habe ich ein Skript geschrieben, welches mit der Angabe des Datums aufgerufen wird und mir die gewünschten Parameter aus dem Logfile in die Standardausgabe schreibt.

Wie kann der von mir konstruierte Ausgabe String evtl. vereinfacht werden?
Die "print" Anweisung funktioniert, die "write" Anweisung leider nicht mit der gleichen Syntax. Worin muss sich die Syntax zwischen print und write unterscheiden, so dass mein konstruierter String in der write Anweisung funktioniert?
Wie kann ich folgendes Skript eleganter gestalten?

#!/usr/bin/python
#
#
import sys

Datum = sys.argv[1]

err = "ISDN Fehlanruf"
log_path = "/var/log/ESI/ESI2/"
log_file = "F1log_"
write_path = "/home/marc/python/"
write_file = "PY_Auswertung.txt"

fobj_in = open(log_path + log_file + Datum + ".txt")
fobj_out = open(write_path + write_file ,"w")

for line in fobj_in:
if err in line:
print ("20" + line[11:13] + "-" + line[8:10] + "-" + line[5:7] + " " + line[14:22] + " " + line[43:59])

fobj_out.write("20" + line[11:13] + "-" + line[8:10] + "-" + line[5:7] + " " + line[14:22] + " " + line[43:59] n')

fobj_in.close()
fobj_out.close()
fredvonfat
User
Beiträge: 51
Registriert: Mittwoch 12. September 2018, 10:00
Wohnort: Berlin

Inzwischen sieht mein Script wie folgt aus:

#!/usr/bin/python
#
# Pythonscript
#
# ESI Logfile Auswertung
#
#
#
#
import sys
import string


Datum = sys.argv[1]
#did = sys.argv[2]
err = "ISDN Fehlanruf"
log_path = "/var/log/ESI/ESI2/"
log_file = "F1log_"
log_file2 = "F1spy_"
write_path = "/home/marc/python/"
write_file = "PY_Auswertung.txt"
fobj_in = open(log_path + log_file + Datum + ".txt")
fobj_out = open(write_path + write_file ,"w")
fobj_in2 = open(log_path + log_file2 + Datum + ".txt")

for line in fobj_in:
if err in line:
day = ("20" +line[11:13] + "-" + line[8:10] + "-" + line[5:7])
time = (line[14:22])
time_stamp = (day + " " + time)
duwa = (line[43:47])
numa = (line[48:59])
items = (time_stamp + " " + duwa + " " + numa)
fobj_out.write(items + "\n")


fobj_in.close()
fobj_out.close()
fobj_in2.close()


...und die write Anweisung funktioniert.
jetzt habe ich innerhalb von "for" eine Reihe Variablen definiert, mit denen ich nun das zweite Logfile zeilenweise durchsuchen und bei match die entsprechende Zeile ausgeben möchte.

Wenn ich jetzt eine weitere "for" Anweisung starte, scheint die aber die Variablen nicht mehr zu kennen.

Ich könnte nun die Daten erneut aus dem "write_file" lesen, nur erscheint mir das nicht sehr elegant.
Gibt es eine andere Methode?
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@fredvonfat: Was heisst wenn Du eine weitere ``for``-Anweisung startest? Die Namen werden in der vorhandenen Schleife in jedem Schleifendurchlauf an den jeweils aktuellen Wert gebunden. Und das ändert sich auch nicht dadurch das man in der ``for``-Schleife eine weitere, verschachtelte Schleife schreibt.

Selbst wenn man *nach* der ersten ``for``-Schleife noch eine weitere schreibt, sind diese Namen an den Wert vom letzten Schleifendurchlauf der ersten Schleife gebunden. Man kann dann natürlich nur mit den letzten Werten etwas machen. Nur wenn die erste ``for``-Schleife keine Fehlerzeile gefunden hat, sind die Namen undefiniert.

Anmerkungen zum Quelltext: `string` wird importiert, aber nirgends verwendet.

Namen werden klein_mit_unterstrichen geschrieben. Ausnahmen: Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase).

Eine Zeichenkette `log_file` zu nennen ist verwirrend. Das ist keine Datei, sondern ein Datei*name*. Wenn man etwas an einen Namen mit `*_file` bindet, dann erwartet der Leser das es sich auch tatsächlich um ein Dateiobjekt handelt. Das was Du kryptisch `fobj_in` nennst, wäre das `log_file`.

Pfadteile setzt man mit `os.path.join()` zusammen. Und auch sonst wird zuviel ``+`` für Zeichenketten verwendet, was man mit Zeichenkettenformatierung mit der `format()`-Methode besser lösen kann.

Dateien sollte man zusammen mit der ``with``-Anweisung öffnen, damit sie auch sicher wieder geschlossen werden.

Bei den Variablenzuweisungen in der Schleife sind unnötige Klammern um die Ausdrücke.

Kryptische Abkürzungen sollte man vermeiden. Bei `err`, `duwa`, und `numa`, muss man raten was das bedeuten mag. Wobei `err` noch am deutlichsten ist, aber meistens für Ausnahmen verwendet wird.

Zwischenstand wäre dann (ungetestet):

Code: Alles auswählen

#!/usr/bin/python
#
# ESI Logfile Auswertung.
#
import os
import sys

ERROR_TEXT = 'ISDN Fehlanruf'
LOG_PATH = '/var/log/ESI/ESI2'
LOG_FILENAME_TEMPLATE = 'F1log_{}.txt'
SPY_FILENAME_TEMPLATE = 'F1spy_{}.txt'
WRITE_PATH = '/home/marc/python'
RESULT_FILENAME = 'PY_Auswertung.txt'


def main():
    datum = sys.argv[1]
    
    log_filename = os.path.join(LOG_PATH, LOG_FILENAME_TEMPLATE.format(datum))
    result_filename = os.path.join(WRITE_PATH, RESULT_FILENAME)
    with open(log_filename) as log_file, open(result_filename, 'w') as out_file:
        for line in log_file:
            if ERROR_TEXT in line:
                day = '20{}-{}-{}'.format(line[11:13], line[8:10], line[5:7])
                time = line[14:22]
                time_stamp = '{} {}'.format(day, time)
                durchwahl = line[43:47]
                number = line[48:59]
                out_file.write(
                    '{} {} {}\n'.format(time_stamp, durchwahl, number)
                )


if __name__ == '__main__':
    main()
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
fredvonfat
User
Beiträge: 51
Registriert: Mittwoch 12. September 2018, 10:00
Wohnort: Berlin

Hallo blackjack,

vielen Dank für Deine Korrekturen, da habe ich erst mal ne ganze Reihe an Hausaufgaben zu lösen, um den code im Detail zu verstehen. ;-)
Auf jeden Fall funktioniert er so wie er ist.

Das bisher geschriebene dient zunächst, um Parameter aus einem Logfile zu extrahieren, um dann mit diesen, in einem zweiten Logfile die eigentlichen Informationen zu finden.

Nach dem derzeitigen stand würde ich nun RESULT_FILENAME öffnen und dann die entsprechenden Parameter erneut auslesen.
Macht man das auch so unter Python oder gibt es dafür elegantere Wege?
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@fredvonfat: Man könnte sich die Informationen aus der ersten Schleife merken, statt sie neu einzulesen.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
fredvonfat
User
Beiträge: 51
Registriert: Mittwoch 12. September 2018, 10:00
Wohnort: Berlin

__blackjack__ hat geschrieben: Donnerstag 13. September 2018, 09:41 @fredvonfat: Man könnte sich die Informationen aus der ersten Schleife merken, statt sie neu einzulesen.
...und das mache ich mit einer Liste, Matrix, Funktion oder einer Kombi aus denen?
Bin schon fleißig am googeln, finde allerdings noch keine ähnlichen Ansätze. Die in den Tutorials dargestellten Beispiele sind für mich zwar einleuchtent, allerdings fehlt mir noch die Fähigkeit sie auf meinen Fall zu transferieren.

Wenn hier jemand weiterführende Links kennt und sie preisgeben würde, würde mir das sehr helfen.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@fredvonfat: Nicht nach ähnlichen Lösungen googlen, sondern einfach mal das Tutorial in der Python-Dokumentation durcharbeiten bis einschliesslich der Grunddatentypen, also bis einschliesslich Kapitel 5 „Data Structures“. Mit denen muss man umgehen können. Ohne Listen, Tupel, Mengen, und Wörterbücher kommt man nicht aus. Auch wenn man in einem Programm nicht alle verwendet, muss man die trotzdem kennen, um entscheiden zu können welche man verwendet.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
fredvonfat
User
Beiträge: 51
Registriert: Mittwoch 12. September 2018, 10:00
Wohnort: Berlin

Danke für die Anregungen.

Also nach meinen neusten gewonnenen Erkenntnissen, würde ich nun eine liste erzeugen, diese in eine Menge umwandeln (damit die Einträge vereinzelt werden) und dann wieder in eine Liste schreiben.

num_list.append(number)
menge_num_list = set(num_list)
uniq_num_list = list(menge_num_list)

Als nächstes möchte ich jeden Eintrag aus "uniq_num_list" in "spy_file" suchen und alle entsprechenden Zeilen zunächst erstmal ausgeben.

with open(spy_filename) as spy_file, open(result_filename, 'w') as out_file2:
for line in spy_file:
if uniq_num_list in line:
print num

Mein Problem ist nun, "if" erwartet einen String, wie erkläre ich "if" jetzt, dass er die Einträge aus der Liste nacheinander als String verwenden soll?
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@fredvonfat: Die Frage ist, ob Du die ganzen Umwandlungen am Anfang tatsächlich brauchst. Die erste auf jeden *nicht* wenn Du gleich mit einem `set()` anfängst und da schon beim Einlesen die Einträge drin speicherst. Und bisher sehe ich noch nicht warum das `set()` danach in eine Liste umgewandelt werden müsste, denn auch bei einem `set()` kann man über die Elemente iterieren.

``if`` erwartet keine Zeichenkette sondern der ``in``-Operator. ``if erwartet einen Wert der als Wahrheitswert verwendet wird.

Wenn man nacheinander etwas für jedes Element aus einer Liste, oder einem anderen iterierbaren Objekt, machen will, braucht man eine Schleife die das gewünschte für jedes Element durchführt. In diesem Fall kann man die dann mit ``break`` abbrechen wenn man einen Treffer gefunden und verarbeitet hat.

Mit der `any()`-Funktion und einem Generatorausdruck bekäme man das auch mit einem Ausdruck nach dem ``if`` hin.

Die Namen sind übrigens wieder nicht so gut gewählt. Grunddatentypen sollten da gar nicht drin vorkommen, denn den konkreten Datentyp ändert man doch ab und zu mal, hier zum Beispiel von `liste` in `set`, und dann müsste man überall die Namen anpassen. Ich würde das einfach `numbers` nennen.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
fredvonfat
User
Beiträge: 51
Registriert: Mittwoch 12. September 2018, 10:00
Wohnort: Berlin

Oha.
Ja, mit ner while Schleife und der Indizierung der liste experimentiere ich gerade rum, aber "any" Funktion hört sich erst mal spannender an.

Danke dafür.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@fredvonfat: Warum ``while`` und warum Indexzugriffe? Man kann da wie schon gesagt mit einer ``for``-Schleife drüber iterieren, ohne den Umweg über einen Index.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
fredvonfat
User
Beiträge: 51
Registriert: Mittwoch 12. September 2018, 10:00
Wohnort: Berlin

Ok, also

numbers = set()
numbers.add(number)is soweit klar.

Allerdings kann ich mir die Syntax für any() mit "for" noch nicht so ganz vorstellen.

Wie schreibt man in Python den Satz; " Für jeden Eintrag, aus der Menge, "numbers", der in der Datei, "spy_file" vorkommt, drucke mir die ganze Zeile aus."?
Im zweiten Step möchte ich ein bestimmtes Muster aus den Zeilen extrahieren, um dann alle Zeilen, die dieses Muster besitzen in ein neues file zu schreiben.
Der Hintergrund ist der, ich möchte die komplette Kommunikation zweier Geräte in einem File isolieren, über die Telefonnummer komme ich an die Leitungsbezeichnung ran, über die Leitungsbezeichnung komme ich dann an die komplette Kommunikation ran.

Im letzten Step muss noch ein Zeitfilter eingebaut werden, da die Leitungsbezeichnung mehrfach am Tag vorkommen kann und dann die Kommunikation anderer Geräte in dem file auftauchen würden.
fredvonfat
User
Beiträge: 51
Registriert: Mittwoch 12. September 2018, 10:00
Wohnort: Berlin

So, ich bin ein Schritt weiter.
container = set()
with open(spy_filename) as spy_file, open(temp2_filename, 'w') as temp_file:
for line in spy_file:
if any(x in line for x in numbers):
container.add(line)
temp_file.write(line)
fredvonfat
User
Beiträge: 51
Registriert: Mittwoch 12. September 2018, 10:00
Wohnort: Berlin

Jetzt auch mit Tags ;-)

Code: Alles auswählen

    container = set()
    with open(spy_filename) as spy_file, open(temp2_filename, 'w') as temp_file:
        for line in spy_file:
            if any(x in line for x in numbers):
                container.add(line)
                temp_file.write(line)
                
fredvonfat
User
Beiträge: 51
Registriert: Mittwoch 12. September 2018, 10:00
Wohnort: Berlin

So, bis auf den Zeitfilter macht der code erst einmal was er soll, vielleicht hat noch jemand eine Idee, wie man ganze noch etwas zusammenfassen, komprimieren, o.ä. kann.

Code: Alles auswählen

#!/usr/bin/python
#
import os
import sys
import re

ERROR_TEXT = 'ISDN Fehlanruf'
LOG_PATH = '/var/log/ESI/ESI2'
LOG_FILENAME_TEMPLATE = 'F1log_{}.txt'
SPY_FILENAME_TEMPLATE = 'F1spy_{}.txt'
WRITE_PATH = '/home/marc/python'
RESULT_FILENAME = 'PY_Auswertung.txt'
TEMP_FILENAME = 'tempfile.txt'
TEMP2_FILENAME = 'tempfile2.txt'
COM_ID = r".{2},.{4},[0-9]{9,10}"

def main():
    datum = sys.argv[1]
    log_filename = os.path.join(LOG_PATH, LOG_FILENAME_TEMPLATE.format(datum))
    result_filename = os.path.join(WRITE_PATH, RESULT_FILENAME)
    temp_filename = os.path.join(WRITE_PATH, TEMP_FILENAME)
    temp2_filename = os.path.join(WRITE_PATH, TEMP2_FILENAME)
    spy_filename = os.path.join(LOG_PATH, SPY_FILENAME_TEMPLATE.format(datum))
    numbers = set()
    with open(log_filename) as log_file, open(temp_filename, 'w') as out_file:
        for line in log_file:
            if ERROR_TEXT in line:
                day = '20{}-{}-{}'.format(line[11:13], line[8:10], line[5:7])
                time = line[14:22]
                time_stamp = '{} {}'.format(day, time)
                durchwahl = line[43:47]
                number = line[48:59]
                numbers.add(number)
                out_file.write(
                    '{} {} {}\n'.format(time_stamp, durchwahl, number)
                )
    
    container = set()
    container2 = set()
    with open(spy_filename) as spy_file:
        for line in spy_file:
            if any(x in line for x in numbers):
                container.add(line)
        for line in container:
            if re.search(COM_ID,line):
                com_id = line[56:64]
                container2.add(com_id)
    with open(spy_filename) as spy_file, open(result_filename, 'w') as result_file:
        for line in spy_file:
            if any(x in line for x in container2):
                print line
                result_file.write(line)

if __name__ == '__main__':
    main()
[\code]
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Ich würde das ganze os.path.join()-Zeug rausnehmen und den Pfad direkt ins Template schreiben. Die Funktion ist eher dafür gedacht, unbekannte Pfade zusammen zu setzen. Aber hier weiß man ja schon alles vor Programmstart aufgrund der Konstanten. Insofern finde ich das an der Stelle unnötig kompliziert.

Ansonsten hätte ich den Ablauf zwecks Übersicht in mehrere Funktionen aufgeteilt. Was du oben ausliest und wieder neu zusammensetzt, könnte auch als Tupel zurückgeliefert werden. Eine weitere Funktion übernähme das Filtern der relevanten Zeilen. (Hier übrigens: container und container2 sind wirklich keine schönen Namen. Besser wäre etwas wie matching_lines und matching_ids.) Und eine dritte Funktion würde die Zeilen dannn wieder schreiben. Das alles hätte ich dann in main() kombiniert. Aber so hat jeder seinen eigenen Stil. Vielleicht kommt es dir dann auch unnötig aufgebläht vor. Musst du wissen...

Achja, und zum sauberen Lesen und Schreiben von Datumsangaben gibt es das datetime-Modul aus der Standardbibliothek mit seinen Funktionen strptime() bzw strftime(). Da kannst du mittels Templates festlegen, wie das Format aussehen soll. Im Übrigen besteht ein Tag nicht aus Monats- und Jahresangaben. ;-)
fredvonfat
User
Beiträge: 51
Registriert: Mittwoch 12. September 2018, 10:00
Wohnort: Berlin

Hallo Snafu,

vielen Dank für dein Feedback.
Ja, das "os.path.join()-Zeug" wird wahrscheinlich, selbst wenn ich mal das Betriebssystem wechseln sollte, nie wirklich notwendig werden. Da das allerdings noch meine ersten Gehversuche in Python sind, finde ich das noch ziemlich cool. ;-)

Die Sache mit den Funktionen ist mir noch nicht so ganz klar, was ich bislang in Erfahrung bringen konnte, es kann falsch sein, ist,
- Die Verwendung der Funktion "main()" dient der Übersichtlichkeit und der vereinfachten Fehleranalyse bei längerem Code,
- Man kann mit selbst definierten Funktionen auf Code mit einfachen Anweisungen komfortabler zurückgreifen.

Ich habe die Funktionen also nicht bewußt rausgelassen, sondern eher, weil ich noch zu "Bash-lastig" denke und mich damit noch nicht so intensiv beschäftigt habe.
Was du oben ausliest und wieder neu zusammensetzt, könnte auch als Tupel zurückgeliefert werden.
Welchen Vorteil habe ich davon ? Ich hatte die Menge gewählt, damit die extrahierten Nummern vereinzelt werden, falls Du das meinst.
container und container2 sind wirklich keine schönen Namen
Ja, ich bin da noch nicht sehr kreativ, was die Namensfindung angeht, deshalb nehme ich deinen Vorschlag dankend an.
Und eine dritte Funktion würde die Zeilen dannn wieder schreiben.
Ja, am Anfang habe ich ein paar Dinge herausgearbeitet, die im weiteren Verlauf gar keine Berücksichtigung mehr finden. Noch nicht.
Da möchte ich aber später drauf zugreifen, also werde ich mich mal intensiver mit den Funktionen beschäftigen.
Achja, und zum sauberen Lesen und Schreiben von Datumsangaben gibt es das datetime-Modul aus der Standardbibliothek mit seinen Funktionen strptime() bzw strftime(). Da kannst du mittels Templates festlegen, wie das Format aussehen soll.
Danke, top Tip, ich schau es mir an.
Im Übrigen besteht ein Tag nicht aus Monats- und Jahresangaben.
Hmmm, hier könnten wir philosophisch werden. :-)
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Zur Verwendung von Funktionen bitte mal hier einlesen:
https://py-tutorial-de.readthedocs.io/d ... definieren
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Das mit den os.path.join ist schon so in Ordnung, weil es ja einen Basispfad gibt (WRITE_PATH) in dem dann wieder verschiedene Dateien liegen; dort, wo es sich aber um Konstanten handelt, kann man sie auch als Konstanten am Anfang definieren.

Dass alles in Funktionen ist auch ok, nur `main` ist inzwischen etwas lang, so dass man es besser in mehreren Funktionen aufteilt. Dann fällt auch auf, dass manche Funktionalität doppelt im Code steht.

Code: Alles auswählen

#!/usr/bin/python
import os
import sys
import re

ERROR_TEXT = 'ISDN Fehlanruf'
LOG_PATH = '/var/log/ESI/ESI2'
LOG_FILENAME_TEMPLATE = os.path.join(LOG_PATH, 'F1log_{}.txt')
SPY_FILENAME_TEMPLATE = os.path.join(LOG_PATH, 'F1spy_{}.txt')
WRITE_PATH = '/home/marc/python'
RESULT_FILENAME = os.path.join(WRITE_PATH, 'PY_Auswertung.txt')
TEMP_FILENAME = os.path.join(WRITE_PATH, 'tempfile.txt')
TEMP2_FILENAME = os.path.join(WRITE_PATH, 'tempfile2.txt')
COM_ID = r".{2},.{4},[0-9]{9,10}"

def read_logfile(log_filename):
    with open(log_filename) as log_file:
        for line in log_file:
            if ERROR_TEXT in line:
                time_stamp = '20{y}-{m}-{d} {time}'.format(y=line[11:13], m=line[8:10], d=line[5:7], time=line[14:22])
                durchwahl = line[43:47]
                number = line[48:59]
                yield time_stamp, durchwahl, number
    
def filter_numbers(spy_filename, numbers):
    with open(spy_filename) as spy_file:
        for line in spy_file:
            if any(x in line for x in numbers):
                yield line

def main():
    datum = sys.argv[1]
    log_filename = LOG_FILENAME_TEMPLATE.format(datum)
    spy_filename = SPY_FILENAME_TEMPLATE.format(datum)
    numbers = set()
    with open(TEMP_FILENAME, 'w') as out_file:
        for time_stamp, durchwahl, number in read_logfile(log_filename):
            numbers.add(number)
            out_file.write(
                '{} {} {}\n'.format(time_stamp, durchwahl, number)
            )

    com_ids = set()
    for line in filter_numbers(spy_filename, numbers):
        if re.search(COM_ID, line):
            com_id = line[56:64]
            com_ids.add(com_id)
    with open(RESULT_FILENAME, 'w') as result_file:
        for line in filter_numbers(spy_filename, com_ids):
            print line
            result_file.write(line)

if __name__ == '__main__':
    main()
Statt magischer Indexwerte zu verwenden, solltest Du die Zeilen der Dateien wirklich parsen, und nur die Teile vergleichen, die auch eine Nummer enthalten, sonst kann es vorkommen, dass die Zahlenfolge an einer anderen Stelle der Zeile auftaucht und als False-Positive im Ergebnis landet.
fredvonfat
User
Beiträge: 51
Registriert: Mittwoch 12. September 2018, 10:00
Wohnort: Berlin

Hallo Sirius3,

vielen Dank für Deine Anregungen, so langsam fange ich an zu begreifen, wie deine "Code-Umstellung" funktioniert.

Nur leider kann ich
Statt magischer Indexwerte zu verwenden, solltest Du die Zeilen der Dateien wirklich parsen, und nur die Teile vergleichen, die auch eine Nummer enthalten, sonst kann es vorkommen, dass die Zahlenfolge an einer anderen Stelle der Zeile auftaucht und als False-Positive im Ergebnis landet.
noch nicht so ganz greifen. Das mit den Indexen war nen kurzes experiment, als ich noch nichts von "any()" wußte oder welchen Code-Schnipsel meinst Du mit "Indexwerte verwenden"?

Im Grunde hast Du Recht, wenn Du meinst, dass es nur Sinn macht nach Zeilen zu suchen, die die Form "..,....,number" haben.
Weil ich es nicht besser wusste habe ich also alle zeilen mit "number" extrahiert und im nächsten schritt nach "..,....," gefiltert, vereinzelt um dann erneut nach Zeilen mit identischen "..,....,ohne number" zu suchen.

Es erscheint sicherlich etwas umständlich, nur bekomme ich lediglich über die "number", die Call-id heraus und nur über die kann ich den Call separieren.

Das Ergebnis sieht dann so aus:
2018-08-31 21:45:26.681 - TRACE RNIS reçu sur c:0 : X C,16,0032,durchwahl,number,T
2018-08-31 21:45:26.682 - GRNIS[00,16,0032,] : New communication ->
2018-08-31 21:45:26.682 - GRNIS[00,16,0032,] : map nb de comm=1 :
2018-08-31 21:45:26.683 - GRNIS[00,16,0032,] : IdentifierProtocoleSDA, affectation du Protocole et du Transfert ->
2018-08-31 21:45:26.683 - GRNIS[00,16,0032,] : map nb de comm=1 :
2018-08-31 21:45:26.709 - TRACE RNIS emis sur c:0 : F G,16,0032,B,080
2018-08-31 21:45:26.735 - TRACE RNIS emis sur c:0 : F C,16,0032,DTMF,010,010
2018-08-31 21:45:26.741 - TRACE RNIS reçu sur c:0 : X g,16,0032,0
2018-08-31 21:45:26.767 - TRACE RNIS emis sur c:0 : F L,16,0032,1,D
2018-08-31 21:45:32.031 - TRACE RNIS emis sur c:0 : F L,16,0032,1,D
2018-08-31 21:45:32.284 - TRACE RNIS reçu sur c:0 : X A,16,0032,5
2018-08-31 21:45:33.096 - TRACE RNIS reçu sur c:0 : X A,16,0032,3
2018-08-31 21:45:33.302 - TRACE RNIS reçu sur c:0 : X A,16,0032,8
2018-08-31 21:45:33.506 - TRACE RNIS reçu sur c:0 : X A,16,0032,3
2018-08-31 21:45:33.692 - TRACE RNIS reçu sur c:0 : X A,16,0032,3
2018-08-31 21:45:33.902 - TRACE RNIS reçu sur c:0 : X A,16,0032,3
2018-08-31 21:45:34.107 - TRACE RNIS reçu sur c:0 : X A,16,0032,0
2018-08-31 21:45:34.294 - TRACE RNIS reçu sur c:0 : X A,16,0032,3
2018-08-31 21:45:34.504 - TRACE RNIS reçu sur c:0 : X A,16,0032,5
2018-08-31 21:45:34.702 - TRACE RNIS reçu sur c:0 : X A,16,0032,7
2018-08-31 21:45:34.894 - TRACE RNIS reçu sur c:0 : X A,16,0032,8
2018-08-31 21:45:35.104 - TRACE RNIS reçu sur c:0 : X A,16,0032,2
2018-08-31 21:45:35.305 - TRACE RNIS reçu sur c:0 : X A,16,0032,B
2018-08-31 21:45:35.305 - GRNIS[00,16,0032,] : P100 check -> .58333035782B.
2018-08-31 21:45:35.305 - GRNIS[00,16,0032,] : P100 recu:43, calcule:45.
2018-08-31 21:45:35.331 - TRACE RNIS emis sur c:0 : F L,16,0032,1,D
2018-08-31 21:45:36.899 - TRACE RNIS reçu sur c:0 : X r,16,0032,number
2018-08-31 21:45:36.907 - GRNIS[00,16,0032,] : Suppression d'une communication ->
2018-08-31 21:45:36.907 - GRNIS[00,16,0032,] : map nb de comm=0 :
2018-08-31 21:46:05.973 - TRACE RNIS reçu sur c:0 : X C,19,0014,Durchwahl,number,T
2018-08-31 21:46:05.974 - GRNIS[00,19,0014,] : New communication ->
2018-08-31 21:46:05.974 - GRNIS[00,19,0014,] : map nb de comm=1 :
2018-08-31 21:46:05.974 - GRNIS[00,19,0014,] : IdentifierProtocoleSDA, affectation du Protocole et du Transfert ->
2018-08-31 21:46:05.975 - GRNIS[00,19,0014,] : map nb de comm=1 :
2018-08-31 21:46:06.001 - TRACE RNIS emis sur c:0 : F G,19,0014,B,080
2018-08-31 21:46:06.027 - TRACE RNIS emis sur c:0 : F C,19,0014,DTMF,010,010
2018-08-31 21:46:06.033 - TRACE RNIS reçu sur c:0 : X g,19,0014,0
2018-08-31 21:46:06.059 - TRACE RNIS emis sur c:0 : F L,19,0014,1,D
2018-08-31 21:46:12.029 - TRACE RNIS emis sur c:0 : F L,19,0014,1,D
2018-08-31 21:46:13.155 - TRACE RNIS reçu sur c:0 : X A,19,0014,3
2018-08-31 21:46:13.365 - TRACE RNIS reçu sur c:0 : X A,19,0014,8
2018-08-31 21:46:13.557 - TRACE RNIS reçu sur c:0 : X A,19,0014,3
2018-08-31 21:46:13.755 - TRACE RNIS reçu sur c:0 : X A,19,0014,3
2018-08-31 21:46:13.965 - TRACE RNIS reçu sur c:0 : X A,19,0014,3
2018-08-31 21:46:14.155 - TRACE RNIS reçu sur c:0 : X A,19,0014,0
2018-08-31 21:46:14.353 - TRACE RNIS reçu sur c:0 : X A,19,0014,3
2018-08-31 21:46:14.563 - TRACE RNIS reçu sur c:0 : X A,19,0014,5
2018-08-31 21:46:14.755 - TRACE RNIS reçu sur c:0 : X A,19,0014,7
2018-08-31 21:46:14.965 - TRACE RNIS reçu sur c:0 : X A,19,0014,8
2018-08-31 21:46:15.163 - TRACE RNIS reçu sur c:0 : X A,19,0014,2
2018-08-31 21:46:15.356 - TRACE RNIS reçu sur c:0 : X A,19,0014,B
2018-08-31 21:46:15.356 - GRNIS[00,19,0014,] : P100 check -> .38333035782B.
2018-08-31 21:46:15.356 - GRNIS[00,19,0014,] : P100 recu:43, calcule:43.
2018-08-31 21:46:15.356 - GRNIS[00,19,0014,] : Recherche de l'IDCOMM (A.S.)
2018-08-31 21:46:15.386 - TRACE RNIS emis sur c:0 : F L,19,0014,1,A
2018-08-31 21:46:15.702 - TRACE RNIS reçu sur c:0 : X r,19,0014,number
2018-08-31 21:46:15.702 - GRNIS[00,19,0014,] : Suppression d'une communication ->
2018-08-31 21:46:15.702 - GRNIS[00,19,0014,] : map nb de comm=0 :
"..,....," entspricht dem ISDN-Kanal und einer "Call-ID".
Antworten