Heim >Backend-Entwicklung >Python-Tutorial >Häufig verwendete Python-Debugging-Tools

Häufig verwendete Python-Debugging-Tools

巴扎黑
巴扎黑Original
2017-04-30 15:52:281860Durchsuche

Im Folgenden finden Sie eine Übersicht über die Tools, die ich beim Debuggen oder Analysieren verwende. Wenn Sie ein besseres Tool kennen, hinterlassen Sie es bitte in den Kommentaren, ohne eine vollständige Einführung zu geben.

Protokoll

Das ist richtig, es ist ein Protokoll. Es kann nicht genug betont werden, wie wichtig es ist, in Ihrer Anwendung angemessene Protokolle zu führen. Sie sollten die wichtigen Dinge protokollieren. Wenn Ihre Protokolle gut genug sind, können Sie das Problem einfach durch einen Blick auf die Protokolle finden. Das spart Ihnen viel Zeit.

Wenn Sie print-Anweisungen in Ihrem Code zufällig verwendet haben, hören Sie jetzt damit auf. Verwenden Sie stattdessen logging.debug. Sie können sie in Zukunft weiterhin wiederverwenden oder alle deaktivieren usw.

Tracking

Manchmal ist es besser, sich anzusehen, welche Anweisungen ausgeführt wurden. Sie können zum schrittweisen Durchlaufen den Debugger einiger IDEs verwenden, Sie müssen jedoch genau wissen, nach welchen Anweisungen Sie suchen, da der gesamte Prozess sonst sehr langsam abläuft.
Das Trace-Modul in der Standardbibliothek kann zur Laufzeit alle ausgeführten Anweisungen der darin enthaltenen Module ausdrucken. (Wie das Erstellen eines Projektberichts)

python -mtrace –trace script.py

Dies führt zu einer großen Ausgabe (jede ausgeführte Zeile wird gedruckt. Möglicherweise möchten Sie grep verwenden, um die Module zu filtern, die Sie interessieren
). Zum Beispiel:

python -mtrace –trace script.py | egrep '^(mod1.py|mod2.py)'

Debugger

Das Folgende ist eine grundlegende Einführung, die mittlerweile jeder kennen sollte:

import pdb
pdb.set_trace() # 开启pdb提示

Oder

try:
(一段抛出异常的代码)
except:
    import pdb
    pdb.pm() # 或者 pdb.post_mortem()

Oder (geben Sie c ein, um mit der Ausführung des Skripts zu beginnen)

python -mpdb script.py

In der Umgebung der Eingabe-Berechnung-Ausgabe-Schleife (Hinweis: REPL, Abkürzung für READ-EVAL-PRINT-LOOP) können die folgenden Operationen ausgeführt werden:

  • c oder weiter


  • q oder aufhören


  • l oder Liste, zeigt den Quellcode des aktuellen Schrittrahmens an


  • wo oder wo, den Aufrufvorgang zurückverfolgen


  • d oder nach unten, gehen Sie einen Frame zurück (Hinweis: entspricht einem Rollback)


  • u oder nach oben, einen Frame vorwärts bewegen


  • (Enter), wiederholen Sie den vorherigen Befehl

Fast alle verbleibenden Anweisungen (mit Ausnahme einiger anderer Befehle) werden als Python-Code im aktuellen Schrittrahmen analysiert.

Wenn Ihnen das nicht anspruchsvoll genug ist, versuchen Sie es mit Smiley – es zeigt Ihnen die Variablen und Sie können es verwenden, um das Programm aus der Ferne zu verfolgen.

Ein besserer Debugger

Drop-in-Ersatz für PDB:
ipdb (easy_install ipdb) – ähnlich wie ipython (mit automatischer Vervollständigung, Anzeigefarben usw.)
pudb (easy_install pudb) – basierend auf Curses (ähnlich der grafischen Benutzeroberfläche), besonders geeignet zum Durchsuchen von Quellcode

​Remote-Debugger

Installationsmethode:

sudo apt-get install winpdb

Ersetzen Sie die vorherige pdb.set_trace() durch die folgende Methode:

import rpdb2
rpdb2.start_embedded_debugger("secretpassword")

Führen Sie nun winpdb, Dateizuordnung

aus Gefällt Ihnen Winpdb nicht? Sie können PDB auch direkt umschließen, um es auf TCP auszuführen!

Tun Sie dies:

import loggging

class Rdb(pdb.Pdb):
    """
    This will run pdb as a ephemeral telnet service. Once you connect no one
    else can connect. On construction this object will block execution till a
    client has connected.

    Based on https://github.com/tamentis/rpdb I think ...

    To use this::

        Rdb(4444).set_trace()

    Then run: telnet 127.0.0.1 4444
    """
    def __init__(self, port=0):
        self.old_stdout = sys.stdout
        self.old_stdin = sys.stdin
        self.listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.listen_socket.bind(('0.0.0.0', port))
        if not port:
            logging.critical("PDB remote session open on: %s", self.listen_socket.getsockname())
            print >> sys.__stderr__, "PDB remote session open on:", self.listen_socket.getsockname()
            sys.stderr.flush()
        self.listen_socket.listen(1)
        self.connected_socket, address = self.listen_socket.accept()
        self.handle = self.connected_socket.makefile('rw')
        pdb.Pdb.__init__(self, completekey='tab', stdin=self.handle, stdout=self.handle)
        sys.stdout = sys.stdin = self.handle

    def do_continue(self, arg):
        sys.stdout = self.old_stdout
        sys.stdin = self.old_stdin
        self.handle.close()
        self.connected_socket.close()
        self.listen_socket.close()
        self.set_continue()
        return 1

    do_c = do_cont = do_continue

def set_trace():
    """
    Opens a remote PDB on first available port.
    """
    rdb = Rdb()
    rdb.set_trace()

Sie möchten einfach nur eine REPL-Umgebung? Wie wäre es, wenn Sie IPython ausprobieren würden?

Wenn Sie keinen vollständigen Debugger benötigen, müssen Sie ein IPython nur auf folgende Weise starten:

import IPython
IPython.embed()

Standard-Linux-Tools

Ich bin oft überrascht, wie wenig sie genutzt werden. Mit diesen Tools können Sie eine Vielzahl von Problemen lösen: von Leistungsproblemen (zu viele Systemaufrufe, Speicherzuweisungen usw.) bis hin zu Deadlocks, Netzwerkproblemen, Festplattenproblemen und mehr.
Am nützlichsten ist strace, das am direktesten ist. Sie müssen nur den Befehl sudo strace -p 12345 oder strace -f ausführen (-f bedeutet, dass gleichzeitig der aus der Verzweigung kommende untergeordnete Prozess verfolgt wird), und das war's . Die Ausgabe wird in der Regel ziemlich groß sein, sodass Sie sie zur weiteren Analyse möglicherweise in eine Datei umleiten möchten (fügen Sie einfach &> zum Dateinamen hinzu).

Dann gibt es ltrace, das strace etwas ähnelt. Der Unterschied besteht darin, dass es Bibliotheksfunktionsaufrufe ausgibt. Die Parameter sind ungefähr gleich.

Außerdem wird lsof verwendet, um auf die Bedeutung der Handle-Werte hinzuweisen, die Sie in ltrace/strace sehen. Zum Beispiel:

lsof -p 12345

Bessere Verfolgung

Es ist einfach zu bedienen und kann viel – jeder sollte htop installieren!

sudo apt-get install htop
sudo htop

Suchen Sie nun die gewünschten Prozesse und geben Sie ein:

s - 代表系统调用过程(类似strace)
L - 代表库调用过程(类似ltrace)
l - 代表lsof

Überwachung

Es gibt keine gute kontinuierliche Serverüberwachung, aber wenn Sie jemals auf etwas Seltsames stoßen, z. B. warum alles so langsam läuft, was machen all diese Systemressourcen? . . Wenn Sie diese Probleme verstehen möchten, aber keinen Anfang haben, müssen Sie keine Tools wie iotop, iftop, htop, iostat und vmstat verwenden, sondern einfach dstat verwenden! Es kann die meisten der zuvor erwähnten Dinge tun, und vielleicht sogar noch besser!
Es zeigt Ihnen kontinuierlich Daten auf kompakte, durch Code hervorgehobene Weise an (anders als iostat, vmstat), und Sie können oft frühere Daten sehen (im Gegensatz zu iftop, iostop, htop).

Führen Sie einfach aus:

dstat --cpu --io --mem --net --load --fs --vm --disk-util --disk-tps --freespace --swap --top-io --top-bio-adv

  很可能有一种更简短的方式来写上面这条命令,

  这是一个相当复杂而又强大的工具,但是这里我只提到了一些基本的内容(安装以及基础的命令)

sudo apt-get install gdb python-dbg
zcat /usr/share/doc/python2.7/gdbinit.gz > ~/.gdbinit

  用python2.7-dbg 运行程序:

sudo gdb -p 12345

  现在使用:

bt - 堆栈跟踪(C 级别)
pystack - python 堆栈跟踪,不幸的是你需要有~/.gdbinit 并且使用python-dbg
c - 继续

  发生段错误?用faulthandler !

  python 3.3版本以后新增的一个很棒的功能,可以向后移植到python2.x版本。只需要运行下面的语句,你就可以大抵知道什么原因引起来段错误。

import faulthandler
faulthandler.enable()

  内存泄露

  嗯,这种情况下有很多的工具可以使用,其中有一些专门针对WSGI的程序比如Dozer,但是我最喜欢的当然是objgraph。使用简单方便,让人惊讶!

  它没有集成WSGI或者其他,所以你需要自己去发现运行代码的方法,像下面这样:

import objgraph
objs = objgraph.by_type("Request")[:15]
objgraph.show_backrefs(objs, max_depth=20, highlight=lambda v: v in objs,
filename="/tmp/graph.png")
Graph written to /tmp/objgraph-zbdM4z.dot (107 nodes)
Image generated as /tmp/graph.png

  你会得到像这样一张图(注意:它非常大)。你也可以得到一张点输出。

  内存使用

  有时你想少用些内存。更少的内存分配常常可以使程序执行的更快,更好,用户希望内存合适好用)
有许多可用的工具,但在我看来最好用的是pytracemalloc。与其他工具相比,它开销非常小(不需要依赖于严重影响速度的sys.settrace)而且输出非常详尽。但安装起来比较痛苦,你需要重新编译python,但有了apt,做起来也非常容易。

  只需要运行这些命令然后去吃顿午餐或者干点别的:

apt-get source python2.7
cd python2.7-*
wget? https://github.com/wyplay/pytracemalloc/raw/master/python2.7_track_free_list.patch
patch -p1 < python2.7_track_free_list.patch
debuild -us -uc
cd ..
sudo dpkg -i python2.7-minimal_2.7*.deb python2.7-dev_*.deb

  接着安装pytracemalloc (注意如果你在一个virtualenv虚拟环境下操作,你需要在重新安装python后再次重建 – 只需要运行 virtualenv myenv)

pip install pytracemalloc

  现在像下面这样在代码里包装你的应用程序

import tracemalloc, time
tracemalloc.enable()
top = tracemalloc.DisplayTop(
    5000, # log the top 5000 locations
    file=open(&#39;/tmp/memory-profile-%s&#39; % time.time(), "w")
)
top.show_lineno = True
try:
    # code that needs to be traced
finally:
    top.display()

  输出会像这样:

2013-05-31 18:05:07: Top 5000 allocations per file and line
 #1: .../site-packages/billiard/_connection.py:198: size=1288 KiB, count=70 (+0),
average=18 KiB
 #2: .../site-packages/billiard/_connection.py:199: size=1288 KiB, count=70 (+0),
average=18 KiB
 #3: .../python2.7/importlib/__init__.py:37: size=459 KiB, count=5958 (+0),
average=78 B
 #4: .../site-packages/amqp/transport.py:232: size=217 KiB, count=6960 (+0),
average=32 B
 #5: .../site-packages/amqp/transport.py:231: size=206 KiB, count=8798 (+0),
average=24 B
 #6: .../site-packages/amqp/serialization.py:210: size=199 KiB, count=822 (+0),
average=248 B
 #7: .../lib/python2.7/socket.py:224: size=179 KiB, count=5947 (+0), average=30
B
 #8: .../celery/utils/term.py:89: size=172 KiB, count=1953 (+0), average=90 B
 #9: .../site-packages/kombu/connection.py:281: size=153 KiB, count=2400 (+0),
average=65 B
 #10: .../site-packages/amqp/serialization.py:462: size=147 KiB, count=4704
(+0), average=32 B

  …

  很美,不是吗?

  补充:更多有关调试的内容见这里。

  原文链接: Ionel Cristian Mărieș   翻译: 伯乐在线 - 高磊

Das obige ist der detaillierte Inhalt vonHäufig verwendete Python-Debugging-Tools. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn