Abfangen ALLER Fehler

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
wonk
User
Beiträge: 25
Registriert: Mittwoch 15. November 2023, 21:29

Hallo!
Sorry, Python Dummy!
Gibt es irgendeine Möglichkeit beim ALLEN möglichen Absturzursachen eines Python-Progs mir eine Fehlermail senden zu lassen?
Wie das mit der Fehlermail durch Aufruf einer entsprechenden Routine im gleichen Pythonprog geht, weiß ich, aber ich müßte dazu try..except an vielen Stellen einbauen. Oder kann / sollte ich dazu bei Absturz ein ANDERES Prog aufrufen?
Gruß, wonk
Gruss, wonk
Benutzeravatar
sparrow
User
Beiträge: 4623
Registriert: Freitag 17. April 2009, 10:28

Warum müsstest du das an vielen Stellen einbauen und nicht als Wrapeer für die main Funktion?
Benutzeravatar
__blackjack__
User
Beiträge: 14268
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@wonk: Innerhalb des Programms selbst ist das nicht möglich. Da kann man nur am Einstiegspunkt einen ``try``/``except``-Block setzen, der alle Ausnahmen behandelt die bis dort hin durchkommen. Aber man kann keine echten Abstürze in einem Programm behandeln, das ja gerade abgestürzt ist. Das ist als wenn Du jemandem sagst, sag bitte Bescheid wenn Du gestorben bist. ;-)

Aus dem gleichen Grund kannst Du bei Absturz kein anderes Programm aufrufen. Was man machen kann ist das Programm von Anfang an von einem anderen Programm aus aufzurufen und dort darauf reagieren wie Programm endet. Das ist plattformabhängig ob und wie genau man welche Ursachen ermitteln kann.
“Programming is partially an artform and, like artists, programmers will do it even if they don't get money.” — Linus Torvalds
Benutzeravatar
DeaD_EyE
User
Beiträge: 1309
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Exceptions haben die Eigenschaft, dass die nach oben poppen, wenn sie nicht abgefangen werden. Ausnahme sind Threads.

Code: Alles auswählen

def func1():
    1 / 0

def func2():
    func1()


def main():
    func2()

In main() kannst die Exception von func1() abfangen.
In der REPL sieht das dann so aus:

Code: Alles auswählen

Python 3.14.2 (tags/v3.14.2:df79316, Dec  5 2025, 17:18:21) [MSC v.1944 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
... def func1():
...     1 / 0
...
... def func2():
...     func1()
...
...
... def main():
...     func2()
...
>>> main()
Traceback (most recent call last):
  File "<python-input-1>", line 1, in <module>
    main()
    ~~~~^^
  File "<python-input-0>", line 10, in main
    func2()
    ~~~~~^^
  File "<python-input-0>", line 6, in func2
    func1()
    ~~~~~^^
  File "<python-input-0>", line 3, in func1
    1 / 0
    ~~^~~
ZeroDivisionError: division by zero
>>> try:
...     main()
... except ZeroDivisionError:
...     print("Division durch 0")
...
Division durch 0
>>>
Man sollte aber nicht den Fehler machen und Exceptions abfangen und nichts ausgeben. Dann braucht man für die Fehlersuche länger, da dann die ursprünglichen Probleme nicht angezeigt werden, das aber zu Folgeproblemen führt.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
wonk
User
Beiträge: 25
Registriert: Mittwoch 15. November 2023, 21:29

Hallo,
Danke! Damit verstehe ich jetzinzelnet, was in Beitrag #2 gemeint ist. Ich versuche es mal. Kann ich spezielle einzelne Fehler zusätzlich in main mit zugehörigen try..except abfangen?
Gruß, wonk
Gruss, wonk
Benutzeravatar
noisefloor
User
Beiträge: 4276
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

in welchem Kontext brauchst du das denn? Eine alternative zum selber implementieren ist, sowas wie Sentry zu benutzen, dass genau da drauf spezialisiert ist. Gibt es auch in einer kostenfreien Variante, habe ich selber allerdings auch noch nicht aktiv genutzt.

Gruß, noisefloor
wonk
User
Beiträge: 25
Registriert: Mittwoch 15. November 2023, 21:29

Hallo,
es ist eine Heizungssteuerung, die rund um die Uhr läuft.
Der wesenliche Teil ist eine Schleife, in der Temperatursensoren abgefragt werden, Werte in eine Datenbank geschrieben und gelesen werden, und ein Ausgang des Raspi gesetzt wird.
Bei einem Absturz wird es bei mir kalt, ich merke das oft erst Stunden später und brauche dann lange zum Wiederaufheizen.
Gruß, wonk
Gruss, wonk
Sirius3
User
Beiträge: 18347
Registriert: Sonntag 21. Oktober 2012, 17:20

Dafür benutzt man systemd, dass der abgestürzte Service automatisch neu gestartet wird.
Benutzeravatar
Dennis89
User
Beiträge: 1664
Registriert: Freitag 11. Dezember 2020, 15:13

Wenn das öfters vor kommt, dann würde ich mich erst mal um ein sauberes logging kümmern und wenn es dann immer die gleiche Ursache ist, die den Service zum abstürzen bringt, dann genau diese eine Ursache beheben.
Im Vorfeld alles auf Verdacht mit `try`/`except` zu versehen, sieht für mich nicht nach einem robusten Programm aus.

Gerne kannst du hier den Code auch zeigen, dann wirst du bestimmt ein paar Ratschläge bekommen.

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
wonk
User
Beiträge: 25
Registriert: Mittwoch 15. November 2023, 21:29

Sirius3 hat geschrieben: Samstag 17. Januar 2026, 11:30 Dafür benutzt man systemd, dass der abgestürzte Service automatisch neu gestartet wird. eintragen
Nur in die *.service
Restart= always
RestartSec=10s eintragen?
Kann ich den Service dann noch mit systemctl stoppen?

Das Prog stüzt nicht häufig ab, aber der Absturz ist sehr unschön. Ich habe ein Log und kann die Fehlermeldung nachher sehen und den Fehler beheben. Das Listing ist länglich.
Gruß, wonk
Gruss, wonk
Sirius3
User
Beiträge: 18347
Registriert: Sonntag 21. Oktober 2012, 17:20

Der Sevice startet ja nur neu, wenn er abstürzt. Wenn Du ihn stoppst, ist er gestoppt.
wonk
User
Beiträge: 25
Registriert: Mittwoch 15. November 2023, 21:29

Hallo,
Danke, der Restart ist erst mal die einfachste Lösung. Eine Fehlermail an mich muss ich dann noch durch weitere try..except implementieren.
Gruß, wonk
Gruss, wonk
Benutzeravatar
noisefloor
User
Beiträge: 4276
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

nee, musst du nicht. Das geht auch mit systemd. system kennt für den `Unit` Abschnitt die Direktive OnFailure, mit der du eine andere Unit ausführen kannst - wie eine Mail schicken. Alternative kannst du in der Service Unit im Abschnitt `Service` die Direktive `ExecStartPost` nutzen, mit der du z.B. eine Mail verschicken kannst, wenn die Unit erfolgreich gestartet wurde. Dann kriegst du halt eine Mail, wenn die Unit regulär startet, z.B. bei einem geplanten Neustart des Systems - aber halt auch bei jedem anderen (Neu-) Start der Unit.

Wenn du Fehler mit `try... except` abfängst / wegbügelst, landen die halt auch _nicht_ im systemd Log und die findest sie nicht. Von daher sollte man beim robuster machen des Skripts eher wenig Fehler abfangen, um an den Kern der Fehlerursache zu kommen.

Gruß, noisefloor
wonk
User
Beiträge: 25
Registriert: Mittwoch 15. November 2023, 21:29

Hallo!
Das geht auch mit systemd. system kennt für den `Unit` Abschnitt die Direktive OnFailure, mit der du eine andere Unit ausführen kannst - wie eine Mail schicken.
Das wäre natürlich Klasse. Aber was heißt hier "eine andere unit ausführen"? Kann ich damit ein gesondertes Python-Prog aufrufen, das die Fehlermail sendet?
Das muss ich mal alles mit provozierten Abstürzen testen.
Gruß, wonk
Gruss, wonk
Benutzeravatar
noisefloor
User
Beiträge: 4276
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Aber was heißt hier "eine andere unit ausführen"? Kann ich damit ein gesondertes Python-Prog aufrufen, das die Fehlermail sendet?
Genau. Eine andere (Service) Unit ausführen heißt genau das: eine anderes Skript / Python Program etc. aufrufen, nur halt über eine Service Unit. Unit deshalb, weil man dann z.B. auch Abhängigkeiten definieren kann. Wenn du z.B. eine Mail versenden willst, sollte das `network-online.target` erreicht sein (was es bei laufendem System i.d.R. ist).

Gruß, noisefloor
wonk
User
Beiträge: 25
Registriert: Mittwoch 15. November 2023, 21:29

Hallo,
ich habe es jetzt mal getestet, klappt leider nicht.
Ich habe eine "fritz.service" mit folgendem Inhalt:

Code: Alles auswählen

[Unit]
Description=fritz.py
After=syslog.target network.target ntp.service rc-local.service
OnFailure=/home/pi/fehlermail.py
#OnFailure='/home/pi/python3 fehlermail.py'        alternativ

[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi/
ExecStart=/home/pi/fritz.py
StandardOutput=file:/home/pi/zaehler.log
#StandardOutput=null

[Install]
WantedBy=multi-user.target
In fritz.py tritt etwa 3s nach dem Start ein Divison/ 0 Fehler auf, sie stüzt ab, entsprechende Ausgaben sehe ich im Log.
fehlermail.py versendet eine mail, wenn ich sie einzeln starte. Sie wird aber nicht aus der *.service gestartet. Besitzer der Dateien ist pi, der *.service root, es gibt jeweils alle Rechte.
Woran kann das liegen?
Gruss, wonk
Gruss, wonk
Benutzeravatar
noisefloor
User
Beiträge: 4276
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

`OnFailure` startet eine andere Unit, _kein_ Skript. Das kann so also auf keinen Fall funktionieren. Du musst hat das Python-Skript zum Mailen in eine Unit packen, die dann 1x gestartet wird und so konfiguriert ist, dass sie beendet ist, wenn das darin gestartete Skript durch ist.

Gruß, noisefloor
Antworten