Speicherüberlauf verhindern

Heute ist Stammtischzeit:
Jeden Donnerstag 20:30 Uhr hier im Chat.
Wer Lust hat, kann sich gerne beteiligen. ;)
  • Hallo,

    ich habe folgende Zeile um eine komplette Textdatei in eine Liste einzulesen.

    line_list = f.read().splitlines()

    Wie kann ich nun verhindern das ich eine 1 GB Datei so einzulesen versuche bzw. was würde dann pasieren?

    Momentan ist es zwar nur der apache access log, aber man weiss ja nie:-)

    VM

  • Hallo,

    Zitat

    Wie kann ich nun verhindern das ich eine 1 GB Datei so einzulesen


    In dem du den Befehl nicht ausführst :D

    Oder, sinnvoller, vorher die Dateigröße checken, wie dunklesToast schon gezeigt hast.

    Zitat

    bzw. was würde dann pasieren?


    IMHO bekommst du eine OutOfMemory Exception oder der Linux-Kernel schießt den Prozess irgendwann ab (hatte selber noch nie so eine große Datei).

    Frage: _Musst_ du die Daten komplett im Speicher haben? Wenn ja, warum? Ansonsten kannst du ja auch zeilenweise für die Datei iterieren.

    Gruß, noisefloor

  • Hallo, Danke zunächst.

    natürlich kann ich die Größe abfragen, ab wann soll ich denn dann abbrechen?

    Ich weiß, die ganze Diskussion ist eher sehr theoretisch, aber ich habe nun mal gelernt jeden noch so unmöglichen Fall anzunehmen. Und warum sollen wir nicht auch mal darüber sprechen.

    Warum alles einlesen? Ich weiss es nicht besser.

    Ich prüfe Apache access log und merke mir wieviel Einträge da sind,
    anzahl = len(f.readlines())

    Dann lese ich in einer Endloschleife den Log jede x Minute wieder ein, sind neue Einträge dazu gekommen werden mir die via telegram geschickt.

    Ich brauche also immer nur die letzten x Einträge bezogen auf Anzahl.

    Klappt ja auch im Übrigen prima:-)

    Bin schon bei 788!

    Und ich denke auch 100.000 Logeinträge sprengen nicht den Speicher:-)

    Und ja, ich habe mit MS-DOS angefangen mit max. 640 kB Hauptspeicher:-)
    So war das in der guten alten Zeit. Da hiess das noch IBM-DOS. Da war 64kB das höchste was man dem Speicher so zumuten konnte.

    In diesem Sinne

    Danke

    VM

  • Hallo Villamarinella,

    um die letzten Zeilen einer Datei einzulesen, nutze ich eine Pipe, die auf dem Linux-Kommando

    Code
    tail


    aufbaut.

    Hier brauchst Du nur einzulesen, bis eine eingelesene Zeile den gleichen Datumszeitstempel wie die erste Zeile (= letzte Zeile in der Datei) beim letzten Einlesen aufweist.

    Und da dürften übersvchaubar wenige Zeile dazu gekommen sein.

    Beste Grüße

    Andreas

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

    Einmal editiert, zuletzt von Andreas (2. Juni 2016 um 19:27)

  • Wenn Du schauen willst, ob Zeilen dazugekommen sind, würde ich tatsächlich die Größe abfragen und überprüfen, ob die sich verändert hat. Falls ja, per seek(0,<alte Größe>) ans ehemalige Ende der Datei und dann ab da einlesen.

  • Hallo,

    villamarinella: dein Ansatz hat IMHO mehrere Fehler.

    1. willst du das Skript eigentlich gar nicht in einer Endlosschleife laufen lassen - dann ist es nämlich 99,9% der Zeit mit nichts tun beschäftigt. Wenn du es periodisch brauchst, dann rufe es periodisch auf, z.B. über eine systemd Timer Unit.
    2. besteht für die absolut keine Notwendigkeit, den gesamten Inhalt der Datei im Speicher zu halten - weil dich ja nur eine (kleiner) Teil der Daten interessiert.

    Hier mal ein schnell zusammengehaktes Python 3 Skript (läuft unter Python 3.4), was eine Datei liest und sich die letzte Zeilenanzahl merkt. Wird es nochmal aufgerufen, werden nur Zeilen ausgegeben, die dazu gekommen sind:

    [code=php]import dbm
    from itertools import islice
    from sys import maxsize

    with dbm.open('linecount.dbm', 'c') as db:
    try:
    linecount = int(db['linecount'])
    except KeyError:
    linecount = 0
    db['linecount'] = str(linecount)
    with open('dokument.txt', 'r') as f:
    counter = ''
    for counter, line in enumerate(islice(f, linecount, maxsize, 1)):
    print(line)
    if counter != '':
    linecount = linecount+counter+1
    db['linecount'] = str(linecount)[/php]

    Im Prinzip selbsterklärend - spätestens dann, wenn man die Doku zu dbm und islice gelesen hat.

    3. wird auch dieses Skript irgendwann versagen, weil die Apache Logdateien dem logrotate unterliegen, d.h. irgendwann wird die aktuelle Logdatei archiviert und eine neue angelegt. Dann funktioniert die Zeilenzählung nicht mehr.

    Gruß, noisefloor

  • @noiseflloor

    Vielen Dank für Deinen ausführlichen Hinweis.

    Bevor ich das ausprobiere, JA, Du hast so Recht, an dieses "Schliessen" und archivieren des Logs habe ich ja auch schon gedacht, habs halt nuir verdrängt:-)
    Ich wollte das mit einer Abfrage lösen wenn plötzlich kleiner starte alles neu.

    Für mich reicht die alte Lösung völlig aus, wenn ich 100 Zugriffe im Monat habe bin ich glücklich:-)

    Nichtsdestotrotz sollte man es sauber programmieren, insofern stimme ich allen bisher zu!

    Und werde mir alles genau ansehen und ausprobieren.

    Es ist halt so, ich habe mich nun ganz gut mit Python arrangiert und insofern programmiere ich alles Mögliche um zu üben und um nicht in das berühmte Rentnerloch zu fallen. Und JA, es hilft mir sehr! Und IHR auch!

    VM

  • Tach ...


    ... Dann lese ich in einer Endloschleife den Log jede x Minute wieder ein, sind neue Einträge dazu gekommen werden mir die via telegram geschickt.
    ...


    dann köntest Du auch einfach einen tail -f auf die Logdatei machen (das gibt die laufend dazukommenden Zeilen aus) und das Ergebnis mit einer pipe z.B. nach sendmail umleiten ...

    cu,
    -ds-

  • @ dreamshader

    Ja, alles ist bei EUCH immer einfach.
    Ich habe da immer meine Probleme.

    was ist hier falsch?kl@kld:~/play$ tail -f /var/log/apache2/access.log > aaa.txt
    tail: /var/log/apache2/access.log: Datei abgeschnitten

    Die Datei ist voll mit Einträgen, ich ändere was, verstehe aber das Ergebnis nicht.
    OK, das > ist wohl keine Pipe:-)
    Das ist MEIN simpler Code den ich geschrieben habe. basierend wie immer auf Google copy und paste für zwei Zeilen, den Rest habe ich alleine hinbekommen.

    Wie bekomme ich hier eine Pipe hin??????????????ß

    @ noisefloor

    Habe Deinen Code zwar ans laufen bekommen, habe aber NICHTS verstanden.
    Der Code ist mir unverständlich, sorry, soweit bin ich noch lange nicht. siehe oben meinen Kindercode.
    Offensichtlich speicherst Du die Anzahl der Datensätze, kommt was dazu wird es nach erneutem Aufruf angezeigt.
    Nur wie fängst Du den Wechsel auf wenn log neu erstellt wird?
    Und wie könnte ich es nützen?
    Egal, DANKE.

    Externer Inhalt www.youtube.com
    Inhalte von externen Seiten werden ohne deine Zustimmung nicht automatisch geladen und angezeigt.
    Durch die Aktivierung der externen Inhalte erklärst du dich damit einverstanden, dass personenbezogene Daten an Drittplattformen übermittelt werden. Mehr Informationen dazu haben wir in unserer Datenschutzerklärung zur Verfügung gestellt.

  • Hallo,

    das "Problem" mit dem logrotate sollte sich vielleicht so umgehen lassen, dass man die ersten X Zeichen der zuletzt eingelesenen Zeile speichert und mit `dropwhile` aus den itertools und der passenden Bedingung sich nur die neuen Zeilen ausgeben lässt. Dann ist man unabhängig von Zeilenzählerei.

    dreamshader schrieb:

    Zitat

    dann köntest Du auch einfach einen tail -f auf die Logdatei machen (das gibt die laufend dazukommenden Zeilen aus) und das Ergebnis mit einer pipe z.B. nach sendmail umleiten ...


    Wobei man dann aber für _jede_ neue Zeile in der Datei eine Nachricht bekommt - auf Dauer vielleicht ein wenig nervig ;)

    Gruß, noisefloor

  • N'Abend noisefloor,


    ... für _jede_ neue Zeile in der Datei eine Nachricht bekommt - auf Dauer vielleicht ein wenig nervig ;)
    Gruß, noisefloor


    das ist schon richtig, lässt sich aber einfach umgehen.
    Kommt halt drauf an wieviel Aufwand unser TO da reinstecken würde.

    greetz,
    -ds-

  • Und JA, JA, JA

    ich will jeden Zugriff "SOFORT" wissen, sonst hätte ich das Ding ja nicht geschrieben!

    Sieh hier:

    Externer Inhalt www.youtube.com
    Inhalte von externen Seiten werden ohne deine Zustimmung nicht automatisch geladen und angezeigt.
    Durch die Aktivierung der externen Inhalte erklärst du dich damit einverstanden, dass personenbezogene Daten an Drittplattformen übermittelt werden. Mehr Informationen dazu haben wir in unserer Datenschutzerklärung zur Verfügung gestellt.

    OK, LAN blende ich aus und HACKER BLENDE ICH AUS, interessant wie viele und woher die sind.

    In dem shell script wird u. a. ein GEOIP aufgerufen und die Zugriffe werden in separaten Dateien gespeichert.

    So sehe ich unmittelbar woher man meine Livecam aufruft.

    Um das noch einmal zu erklären, ich feile alles was ich mache bis zum letztmöglichen aus.
    Und das alles ist u. a. Teil von:

    http://www.kwss.ddns.net
    or
    http://www.kwss.4irc.com/
    Username: forum
    Passwort: raspberry

    Neben dem Post hier laufen da noch weitere weil ich Probleme habe um ein Video mit Ton und Text zu versehen.
    Auch gibt es noch Probleme mit telegram.
    Das nur dazu.
    Also, probiert meine Livecam aus und ich finde Euch dann in meinem Log:-)

    Danke für Euer geballtes Wissen...........

    VM

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!