Probleme bestehendes Script: Debug, Exceptions, Logging

  • Hallo zusammen,
    ich habe ein Pythonscript, welches Serielle Schnittstellen einließt und GPIOs schaltet. Die Funktion des Scripts ist einwandfrei, allerdings geht der Langzeittest mächtig in die Hose. Mein Pi sitzt in einer Türsteuerung, welche fest im Haus eingebaut ist, deswegen muss das Script unbedingt stabil laufen.
    Ich habe versucht die Ausgabe des Scripts in eine Textdatei umzuleiten, die Textdatei blieb aber immer leer. (Ausgabe im Terminal funktioniert einwandfrei) Ich brauche irgend eine verlässliche Loggingmethode, die mir alle Fehler die auftreten mit Timestamp oder ähnlichem ausgibt, damit ich weiß warum das Script zu welchem Zeitpunkt abstürzt.
    Wenn ich den Pi starte, startet der Autostart das Script automatisch mit:


    Code
    1. python /home/pi/read.py /dev/USB1 /dev/USB2 /dev/USB3


    Dabei sind die /dev/USB1 etc. die Schnittstellen die ich dem Script übergebe. Das sind eingesteckte TTL->USB Wandler, an denen eine RFID Spule hängt. Somit lade ich die alle rein und bei Datenstrom wird das Script durchlaufen und wartet auf die nächsten Daten.
    Nach dem Start läuft das Script eine unbestimmte Zeit ohne Probleme, am kommenden Tag (über Nacht irgendwann), kommt allerdings keine Reaktion mehr. Eben auch nicht, dass der Chip irgendwie falsch gelesen wurde, also gehe ich davon aus, dass das Script komplett gecrasht ist. (Kann ich nicht feststellen ohne Fehlerlog etc. was da los ist..)


    Wunsch:
    - Ausgabe in eine Datei oder ähnliches, aufjedenfall so, dass ich die Fehler auch mitbekomme wenn das abstürzt.
    - Die Datei sollte im Fehlerfall gesichert sein, ansonsten beim Reboot überschrieben werden. (/tmp)
    - Exceptions abfangen. Wenn ein Fehler auftritt, soll der Process gekillt werden falls er noch läuft und automatisch neugestartet werden. Wenn es schwer ist den Prozess zu detektieren oder ähnliches, könnte bei einer Exception auch ein Reboot ausgeführt werden. Im dem Fall soll die Logdatei natürlich erstmal gesichert werden.


    Natürlich will ich vorrangig den Fehler finden, da der täglich / nach paar Stunden auftritt und beheben, dafür wie gesagt brauche ich einen Log. Da der Pi quasi 24/7 läuft wollte ich auch eine Sicherung + Reboot jeden Tag bzw. 1x die Woche ausführen. Ich denke je Woche sollte ausreichend sein, weil die Arbeit für den Pi ja sehr gering ist..


    So nun, wer kann sowas? Meine Pythonkenntnisse sind wirklich beschissen und nachdem meigrafd an dem Script rumgewerkelt hat (Danke nochmal!), ist es noch etwas undurchsichtiger für mich geworden. Möchte mir da jemand helfen (gerne auch im IRC oder sonstwo, damit man das zusammen machen kann, sonst einfach hier). Dann muss ich mit den Sachen an das Haus fahren und das vor Ort einbinden und hoffen den Fehler so zu bekommen...


    Script:


    Gruß
    JumpY

  • Hallo,


    also:


    * Für's Logging gibt es unter Python das logging-Modul
    * Wenn du es als systemd Service Unit startest, dann loggt systemd für dich zumindest , wenn das Skript gestartet wurde, wann es gecrasht ist etc.
    * Automatische Neustart geht auch über eine systemd Service Unit.
    * Nackte `except` im Code sind immer schlecht, weil du _alle_ Fehler abfängst und damit nicht bekommst, wann was schief geht. Grundsätzlich fängt man nur den Fehler ab, der jetzt gerade auftreten kann (z.B. ein ConnectionError, wenn was mit der DB-Verbindung ist).


    Den letzten Punkt solltest du als erstes angehen, damit du Fehler auch mitbekommst.


    Abgesehen davon ist das stilistisch sicherlich kein schönes Python - was aber das Helfen für externe extrem erschwert, weil beim Lesen des Quelltexts schwer ersichtlich ist, was hier eigentlich passieren soll. Besonders dieses Rumgefummel mit den Zeiten und die Datenbankzugriffe kann man mit Sicherheit eleganter lösen.


    Gruß, noisefloor

  • Hallo zusammen,
    danke ich werde mir das mal ansehen.


    Der Autostart ist hiermit gelöst: http://www.raspberrypi-spy.co.…pt-on-boot-using-systemd/
    Da sehe ich dann auch Fehler? Wenn ja müsste ich das ja wirklich mal suchen, habe bislang nix gefunden dazu..
    Automatischer Neustart geht auch darüber? Kannst du mir dazu näheres sagen?


    Was mache ich dann, wenn ich keine Exceptions oder sowas einbaue? Ich habe leider keine wirkliche Ahnung davon wie ich das am sinnigsten lösen soll..


    Ich kommentiere das Script mal ordentlich, dann wird das ersichtlicher. Leider ist mein Stil schlecht lesbar, aber ich kann es eben nicht besser aktuell. Bist du auch irgendwo anders unterwegs, als hier im Forum? (IRC,Skype, Whatever). Vielleicht findet man ja eine Zeit wo man mal eine Absprache halten kann.


    Gruß


    Hier das neue Script mit Kommentaren: http://pastebin.com/E11iGdcQ
    Die Zeit und Datumssteurung kann im Prinzip nicht beachtet werden, die Gültigkeit ist aktuell sowieso noch immer gegeben, kommt später zum Einsatz. Ist das jetzt so verständlich oder noch etwas unklar? Kurzer Ablauf in Worten:


    - Das Script öffnet 3 Serielle Schnittstellen die beim Aufruf übergeben werden
    - Diese werden immer geprüft ob Daten vorhanden sind
    - Die Daten werden ausgewertet, mit Startflag, Checksumme etc.
    - Die gefundene ID wird in Dezimal umgerechnet und mit der Datenbank verglichen
    - Wenn bekannt und gültig wird ein Relais und eine LED geschaltet und der Zutrittslog geschrieben
    - Ist die unbekannt, wird die in "Neue Tags" gespeichert und auch ein Access_log geschrieben. Zusätzlich blinkt die LED.


    Das soll in Dauerschleife laufen, damit halt jeder Lesevorgang immer erkannt wird.

  • Hallo,


    Zitat

    Automatischer Neustart geht auch darüber? Kannst du mir dazu näheres sagen?


    Du musst in der .service-Datei im Abschnitt `[service]` die Direktive `Restart=always` eintragen.


    Zitat

    Da sehe ich dann auch Fehler? Wenn ja müsste ich das ja wirklich mal suchen, habe bislang nix gefunden dazu..


    systemd legt standardmäßig eine Journal an, was die mit journalctl abfragen kannst. Allerdings bin ich mir nicht sicher, wie das genau bei Raspbian konfiguriert ist. Ggf. muss du das sonst noch aktivieren.


    Zitat

    Was mache ich dann, wenn ich keine Exceptions oder sowas einbaue?


    Du siehst halt die Fehler, weil die nicht von dem `except` abgefangen werden. Das sollte dir bei der Fehlersuche helfen.


    Gruß, noisefloor

  • Auszug aus dem journalctl:



    Wie man sieht, geht da mit der Datenbankverbindung etwas schief. Gut wäre es eigentlich, wenn die MySQL Sache "freiwillig" wäre, also die Abfrage versucht wird und bei einem Fehler quasi übersprungen. Das würde zumindest im Notfall den Absturz verhindern. Was da jetzt genau passiert ist, weiß ich nicht, da muss irgend ein dummer Fehler im Code sein. Die UID 00000000 darf eigentlich nie vorkommen. Vielleicht ist das ein Fehler vom Leser das er irgendwas sendet und das falsch erkannt wird oder einfach Datenmüll?
    Da wären die Pythonprofis gefragt =(


    BTW: Die Timestamps sind auch sehr verwirrend. Ist es so, dass das Journal die Meldungen erst beim Absturz bekommt? Dann wären das quasi alle Ausgaben aus dem Script die gemacht wurden auf einmal, deswegen der Timestamp? Dann sollte ich wohl einen Timestamp in jede Ausgabe einbauen, damit ich sehe wann das passiert ist..

  • Also der Fehler klingt eher danach, dass die MySQL komplett abraucht. Ist die denn noch da?

  • Jap, MySQL ist noch da.
    Ich habe in dem systemd Unit womit das Script im Autostart ist, einen automatischen Reboot vom Script eingestellt. Das Script startet nach dem Fehler direkt neu und läuft danach wieder, also kann auch wieder DB-Abfragen machen.
    Irgendwo muss da wohl ein Abfragefehler drin sein.. Kann man eine MySQL Abfrage denn nicht so machen, dass die Abfrage versucht wird, aber eben bei einem Fehler übersprungen und nicht abgebrochen wird?

  • kann man, aber in diesem doch sehr unübersichtlichen Skript ist das sehr anstrengend. Ich müsste das erstmal gründlich entrümpeln. Und es wäre auch nur Symptombekämpfung. Wenn du die Zutritte protokolliert haben möchtest, sollte das eher repariert werden. Wenn es wichtiger ist, das es überhaupt geht, dann schmeiss den MySQL -kram raus.

  • Das Ziel ist es natürlich, das Script in dem Umfang fehlerfrei zu gestalten, dass ist schon klar.
    Die Zutritte sollen aufjedenfall geloggt werden und da auch die Gültigkeit abgefragt wird, muss die Datenbank schon in dem Umfang eingebunden bleiben. Ich werde das ganze mal neu strukturieren müssen, hab auch keine Ahnung wo eine UID 0000000 herkommen soll, das sind irgendwelche falschen Daten die da erkannt werden.