python

Python 104: cgitb (CGI Traceback)

⚠️ cgitb is deprecated since Python 3.11 and has been removed with Python 3.13!

Ich habe gerade mal wieder viel zu Lange über einen Python-Traceback gesessen, der mit einem annähernd nutzlosen TypeError: expected string or buffer endete. “Warum zum Henker gibt Python standarddmäßig nicht mehr Kontext aus?”

Bei meiner Recherche, wie mann z.B. für alle Stack-Frames eines Tracebacks zusätzliche die lokalen Variablen ausgiebt, bin ich dabei über das Standard-Python-Modul cgitb gestoßen, das genau das macht: Zusätzlich zum Traceback gibt es für jedes Frame die lokalen Variablen und sogar noch den umliegenden Code aus, wahlweise als HTML oder text/plain:

Python 2.7.9: /usr/bin/python
Wed Jun 6 22:37:55 2018

A problem occurred in a Python script. Here is the sequence of
function calls leading up to the error, in the order they occurred.

 /root/ in ()

: integer division or modulo by zero
 __class__ =
 __delattr__ =
 __dict__ = {}
 __doc__ = ‚Second argument to a division or modulo operation was zero.‘
 __format__ =
 __getattribute__ =
 __getitem__ =
 __getslice__ =
 __hash__ =
 __init__ =
 __new__ =
 __reduce__ =
 __reduce_ex__ =
 __repr__ =
 __setattr__ =
 __setstate__ =
 __sizeof__ =
 __str__ =
 __subclasshook__ =
 __unicode__ =
 args = (‚integer division or modulo by zero‘,)
 message = ‚integer division or modulo by zero‘

The above is a description of an error in a Python program. Here is
the original traceback:

Traceback (most recent call last):
 File „“, line 1, in
ZeroDivisionError: integer division or modulo by zero

/var/log/univention/tracebacks/tmpWrufjr.txt contains the description of this error.

Auf Wunsch schreibt es sogar diese Information in eine Datei und gibt statt dessen für den Benutzer eine lapidare Meldung folgender Art aus:

A problem occurred in a Python script.
/tmp/tmp7duTpd.txt contains the description of this error.

Das sollten wir IMHO standardmäßig in alle unsere Tools einbauen und sie nach /var/log/univention/tracebacks/ loggen lassen. Das kann dann ein CRON-Job regelmäßig abgrasen und uns zukommen lassen.

python -c '__import__("cgitb").enable(1,None,5,"text");1/0'
python -c '__import__("cgitb").enable(1,"/tmp/",5,"text");1/0'

Canonical mach übrigens in Ubuntu etwas ähnliches in /etc/python2.7/sitecustomize.py:

# install the apport exception handler if available
try:
 import apport_python_hook
except ImportError:
 pass
else:
 apport_python_hook.install()

Wer also standardmäßig den erweiterten Traceback haben will, kann z.B. folgendes machen:

install -m 1777 -d /var/log/univention/tracebacks
cat >/usr/local/lib/python2.7/dist-packages/apport_python_hook.py <<__PY__
#!/usr/bin/python
import cgitb
def install():
 cgitb.enable(1, "/var/log/univention/tracebacks", 5, "text")
__PY__
python -c '1 / 0'

Nur dummerweise führt /etc/univention/templates/files/etc/python2.7/sitecustomize.py.d/20utf8.py ein reload(sys) aus und macht es wieder Rückgänig. Der Trick ist also, die beiden UCR-Fragmente noch zu vertauschen.

Written on June 7, 2018