Python Script beendet sich selbst - warum?

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.
Benutzeravatar
mode
User
Beiträge: 10
Registriert: Samstag 4. Oktober 2008, 17:14

Python Script beendet sich selbst - warum?

Beitragvon mode » Samstag 4. Oktober 2008, 17:25

Hallo,

ich habe unten stehenden Python Code auf einer SuSE 11 Maschine laufen, es wird zeilenweise von der Seriellen Schnittstelle ttyUSB0 gelesen (ist ein FTDI USB-> Seriell Wandler) und bei besimmten Zeichenketten etwas in die lokale DB geschrieben.
Dies funktioniert auch wunderbar jedoch beendet sich das Script nach einigen Stunden von alleine. Ich habe keine Ahnung warum. In den Systemlogs ist nichts zu finden.


Hier mal der Code:

Code: Alles auswählen

#!/usr/bin/python
import serial
import MySQLdb

conn = MySQLdb.connect (host = "localhost",
                           user = "XXX",
                           passwd = "XXX",
                           db = "TEST")
cursor = conn.cursor()

ser = serial.Serial('/dev/ttyUSB0', 38400, timeout=None)
while 1:
   line = ser.readline()   #read a '\n' terminated line
   if line[0:15] == "1234567890ABCDE":
      cursor.execute("INSERT INTO Main VALUES(NULL, '" + line[18] + "', '" + line[22] + "')")
      
   if line[3:24] == "FFFFFF AAAAA EEEEEEE!":
      cursor.execute("INSERT INTO Main VALUES(NULL, '0', NULL)")

   
cursor.close()
conn.close()
ser.close()


Jemand eine Idee??

Viele Grüße


Mode
Benutzeravatar
Hyperion
Moderator
Beiträge: 7471
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Beitragvon Hyperion » Samstag 4. Oktober 2008, 17:46

Zunächst einmal solltest Du deinen Query-String anders aufbauen!
[wiki]Parametrisierte SQL-Queries[/wiki]

Was steht denn in der Shell? Wirft das Script eine Exception? Speziell folgendes ist doch recht abenteuerlich:

Code: Alles auswählen

if line[0:15] == "1234567890ABCDE":

was passiert bei kürzeren Strings?

Du könntest auch im Script selber loggen und damit abgefangene Exceptions wegschreiben. So kannst Du auch Fehler finden, wenn das Programm als Backgroundprozess oder daemon ausgeführt word.

Als letztes fiele mir noch die Konfiguration der DB ein. Evtl gibt es eine maximale Dauer von Verbindungen? Wenn dem so ist, sollte das Script immer exakt nach derselben Zeit gestoppt werden. Evtl. solltest Du da mal recherchieren. Ich habe bei DBs meist nur im Zusammenhang mit Webapplikationen gearbeitet, da tritt so ein Problem natürlich nicht auf. Aber denkbar wäre es.
Benutzeravatar
mode
User
Beiträge: 10
Registriert: Samstag 4. Oktober 2008, 17:14

Beitragvon mode » Samstag 4. Oktober 2008, 18:05

Danke für die Tips, die SQL Querys werde ich anders aufbauen, und das mit dem Zugriff auf Line wenn ein kurzes Wort darin steht scheint in der Tat ein Problem zu sein. Wuerde dies eine Exception werfen die ich behandeln kann?

Ich habe nun erstmal

Code: Alles auswählen

import logging
LOG_FILENAME = '/tmp/py_logging.txt'
logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG,)

logging.debug('This message should go to the log file')

eingefügt um den Fehler einzugrenzen... Das Script laeuft in der tat als Daemon...

Melde mich dann mit den Ergebnissen


VG

Mode
Benutzeravatar
snafu
User
Beiträge: 5383
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Beitragvon snafu » Samstag 4. Oktober 2008, 18:52

mode hat geschrieben:das mit dem Zugriff auf Line wenn ein kurzes Wort darin steht scheint in der Tat ein Problem zu sein. Wuerde dies eine Exception werfen die ich behandeln kann?


Hast du schonmal irgendwo gesehen, dass ein if-Statement ne Exception wirft, wenn es nicht zutrifft? Das wäre wohl ein wenig sinnfrei, oder? ;)

EDIT: Achso, du meinst vermutlich ob ein IndexError auftreten würde... Nö, tut er nicht. Man kann aber natürlich prüfen ob der String eine bestimmte Mindestlänge besitzt.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7471
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Beitragvon Hyperion » Samstag 4. Oktober 2008, 19:13

Stimmt! Nen IndexError wird da nicht geworfen. Also ist das nicht die Fehlerquelle.
BlackJack

Beitragvon BlackJack » Samstag 4. Oktober 2008, 19:15

@mode: So etwas ist aber nun echt schneller ausprobiert, als in einem Forum gefragt:

Code: Alles auswählen

In [226]: line = 'hallo'

In [227]: line[0:100]
Out[227]: 'hallo'

In [228]: line[42]
---------------------------------------------------------------------------
<type 'exceptions.IndexError'>            Traceback (most recent call last)

/home/bj/<ipython console> in <module>()

<type 'exceptions.IndexError'>: string index out of range


Es wäre generell vielleicht eine gute Idee um das ganze Programm eine Ausnahmebehandlung zu machen, und auftretende Ausnahmen zu loggen.
Benutzeravatar
mode
User
Beiträge: 10
Registriert: Samstag 4. Oktober 2008, 17:14

Beitragvon mode » Sonntag 5. Oktober 2008, 17:06

Soo nun lief das Script fast einen Tag lang und ist dann wieder abgeschmiert. Leider wurde in die Log Datei keine Exception geschrieben. Was nun?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7471
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Beitragvon Hyperion » Sonntag 5. Oktober 2008, 17:11

Poste doch mal deinen kompletten Quellcode!

Beschreibe doch mal, wie das Script aufegrufen wird! (rc-script? in einer Shell? etc.)

Hast Du mal meine Theorie mit der Verbindung zur DB verfolgt?
Benutzeravatar
mode
User
Beiträge: 10
Registriert: Samstag 4. Oktober 2008, 17:14

Beitragvon mode » Sonntag 5. Oktober 2008, 20:44

Ok hier das Script:

Code: Alles auswählen

#!/usr/bin/python
import serial
import MySQLdb
import logging
LOG_FILENAME = '/tmp/py_logging.txt'
logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG,)

logging.debug('This message should go to the log file')



conn = MySQLdb.connect (host = "localhost",
                           user = "xx",
                           passwd = "xx",
                           db = "Test")

cursor = conn.cursor()

ser = serial.Serial('/dev/ttyUSB0', 38400, timeout=None)
while 1:
   line = ser.readline()   #read a '\n' terminated line
   if line[0:15] == "Finger erkannt!":
      user=line[18]
      finger=line[22]
      cursor.execute("INSERT INTO Main VALUES(NULL, %s, %s)",  (user,finger))
      
   if line[3:24] == "Finger nicht erkannt!":
      cursor.execute("INSERT INTO Main VALUES(NULL, '0', NULL)")
   
cursor.close()
conn.close()
ser.close()


So in der Log Datei erscheint immer nur die das was ich in Zeile 8 rein schreibe - keine Exception
Bei der Zuweisung von den Variablen User und Finger ist sichergestellt dass Line genug Elemente enthält.

Dass die Datenbank die Verbindung zuruecksetzt habe ich nicht beobachten koennen. Weder in den COnfig noch in den Logfiles des MySQLd konnte ich einen HInweis darauf finden.

Mein Python Script wird durch ein SuSE rc Script gestartet:

Code: Alles auswählen

DESCRIPTION="Test"
EXECUTABLE="/home/mode/fingerreader.py"

# Shell functions sourced from /etc/rc.status:
. /etc/rc.status

# First reset status of this service
rc_reset

case "$1" in
start)
        echo -n "Starting up" $DESCRIPTION
        startproc $EXECUTABLE
        rc_status -v
;;
...
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

Beitragvon Pekh » Sonntag 5. Oktober 2008, 21:37

Naja, so ganz von alleine werden die Exceptions nicht ins Log geschrieben. Hier mal ein vielleicht etwas umständliches Beispiel, wie ich das Logging normalerweise handhabe:

Code: Alles auswählen

import sys
import time
import logging
import traceback

def configure_logging():       
    logging.basicConfig(level=logging.DEBUG,
       format='%(levelname)-8s %(message)s',
       filename='kassenlog',
       filemode='a')
    logging.info("====== Programm gestartet am %s ======" %(time.ctime()))
    # Fehler sollen nicht nur im Log, sondern auch auf der Konsole landen:
    console = logging.StreamHandler()
    console.setLevel(logging.WARNING)
    formatter = logging.Formatter('%(message)s')
    console.setFormatter(formatter)
    logging.getLogger("").addHandler(console)

def hook(t,v,tb):
    l = traceback.format_exception(t,v,tb)
    s = ''.join(l)
    logging.exception(s)

if __name__ == "__main__":
    configure_logging()   
    sys.excepthook = hook


Statt des hooks kannst du auch ein try/except um deinen ganzen Code machen und dann im Except-Block logging.exception verwenden.
Benutzeravatar
mode
User
Beiträge: 10
Registriert: Samstag 4. Oktober 2008, 17:14

Beitragvon mode » Sonntag 5. Oktober 2008, 22:29

Ok das wusste ich nicht.
Also ein Try "Block" um das while 1 und darunter

Code: Alles auswählen

except:
    logging.exception


Lasse ich über Nacht mal laufen....
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

Beitragvon Pekh » Montag 6. Oktober 2008, 06:20

Jein. 'logging.exception()' ist eine Funktion, der du natürlich noch den zu loggenden Text übergeben mußt. Das kannst du mit eigenen Texten tun, dann mußt du aber eine ganze Reihe von denkbaren Exceptions abfangen und jeweils spezialisierte Fehlertexte schreiben lassen. Einfach nur zu schreiben: "Ein Fehler ist aufgetreten" dürfte dir nicht weiterhelfen.
Oder du nutzt wie ich in meinem Beispiel oben das Traceback-Modul.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7471
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Beitragvon Hyperion » Montag 6. Oktober 2008, 07:30

Vor allem solltest Du das Script einmal im Trockenlauf testen, d.h. mal per raise gezielt eine Exception in der Schleife auslösen. So brauchst Du nicht so lange zu warten, bis das Script mal wieder nach x Stunden abbricht ;-)

Außerdem würde ich ggf. mal die Queries loggen oder aber auch die Inputs der seriellen Schnittstelle. Vor allem siehst Du dann gut, ob es vor dem Crash Aktivitäten gegeben hat.
Benutzeravatar
Sr4l
User
Beiträge: 1091
Registriert: Donnerstag 28. Dezember 2006, 20:02
Wohnort: Kassel
Kontaktdaten:

Beitragvon Sr4l » Montag 6. Oktober 2008, 12:19

Wenn es immer genau 12Stunden sind liegt es am MySQL Connection Timeout. ;-)
MySQL Connections werden, auch wenn sie noch benutzt werden nach 12Std, bzw. das was die Config sagt getrennt.
Default sollte 12Std sein und man sollte das auch nicht hochsetzen, falls das überhaupt möglich ist?!?

Du beseitigst das Problem indem du ein `try` für `cursor.execute` machst wenn das fehlschlägt baust du die Verbindung neu auf und machst noch mal den `cursor.execute` in die DB.
Benutzeravatar
mode
User
Beiträge: 10
Registriert: Samstag 4. Oktober 2008, 17:14

Beitragvon mode » Montag 6. Oktober 2008, 15:20

Habe nun in meine except

Code: Alles auswählen

except:
    logging.exception (traceback.format_exc())


geschrieben - somit werde exceptions auch ins Log geschrieben.
Dein Code von Pekh habe ich nicht so ganz verstanden - daher habe mich fuer die minimalistische Version entschieden.

Des weiteren wird jetzt die DB Verbindung erst geoeffnet, wenn ein guelter String von der seriellen Schnittstelle gelesen wurde und danach direkt wieder geschlossen. Somit wird das Datenbanktimeoutproblem - wenn es das denn war umgangen.

Ich melde mich in einigen Tagen mit dem Resultat.


Viele Gruesse


Mode

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder