แสดงการติดตามสแต็กจากแอ็พพลิเคชัน Python ที่กำลังรัน


340

ฉันมีแอพพลิเคชั่น Python ตัวนี้ติดอยู่เป็นครั้งคราวและหาที่ไหนไม่เจอ

มีวิธีใดที่จะส่งสัญญาณให้ล่าม Python เพื่อแสดงรหัสที่แน่นอนที่ใช้งานอยู่

stacktrace แบบ on-the-fly บางอย่าง?

คำถามที่เกี่ยวข้อง:


เกี่ยวข้อง: stackoverflow.com/q/4163964/1449460
Nikana Reklawyks

คำตอบ:


315

ฉันมีโมดูลที่ฉันใช้สำหรับสถานการณ์เช่นนี้ - ที่กระบวนการจะทำงานเป็นเวลานาน แต่บางครั้งก็ติดขัดด้วยเหตุผลที่ไม่รู้จักและไม่สามารถแก้ไขได้ มันค่อนข้างแฮ็คและใช้ได้กับยูนิกซ์เท่านั้น (ต้องใช้สัญญาณ):

import code, traceback, signal

def debug(sig, frame):
    """Interrupt running process, and provide a python prompt for
    interactive debugging."""
    d={'_frame':frame}         # Allow access to frame object.
    d.update(frame.f_globals)  # Unless shadowed by global
    d.update(frame.f_locals)

    i = code.InteractiveConsole(d)
    message  = "Signal received : entering python shell.\nTraceback:\n"
    message += ''.join(traceback.format_stack(frame))
    i.interact(message)

def listen():
    signal.signal(signal.SIGUSR1, debug)  # Register handler

หากต้องการใช้เพียงแค่เรียกใช้ฟัง () ฟังก์ชั่นในบางช่วงเวลาที่โปรแกรมของคุณเริ่มทำงาน (คุณสามารถติดไว้ใน site.py เพื่อให้โปรแกรมไพ ธ อนทั้งหมดใช้งานได้) และปล่อยให้มันทำงาน ส่งสัญญาณ SIGUSR1 ไปยังจุดใดก็ได้โดยใช้ kill หรือ python:

    os.kill(pid, signal.SIGUSR1)

สิ่งนี้จะทำให้โปรแกรมแตกไปยังคอนโซล python ณ จุดที่มันอยู่ในปัจจุบันแสดงการติดตามสแต็กและให้คุณจัดการตัวแปร ใช้ control-d (EOF) เพื่อทำงานต่อไป (แม้ว่าโปรดทราบว่าคุณอาจขัดจังหวะ I / O ฯลฯ ณ จุดที่คุณส่งสัญญาณดังนั้นมันจึงไม่รบกวนอย่างสมบูรณ์

ฉันมีสคริปต์อื่นที่ทำสิ่งเดียวกันยกเว้นมันจะสื่อสารกับกระบวนการทำงานผ่านไพพ์ (เพื่ออนุญาตให้ทำการดีบักกระบวนการที่อยู่เบื้องหลังเป็นต้น) ของมันกัดขนาดใหญ่ไปยังโพสต์ที่นี่ แต่ฉันได้เพิ่มเป็นสูตรหลามตำรา


1
ขอบคุณ! นี่คือสิ่งที่ฉันกำลังมองหา บางทีคุณอาจโพสต์สคริปต์นั้นด้วยไพพ์ไพพ์ในบางเว็บไซต์ของ Python
Seb

2
ตอนนี้ฉันโพสต์ไว้ที่เว็บไซต์หนังสือทำหลาม - เพิ่มลิงค์แล้ว
Brian

1
ฉันต้องการเพิ่ม "นำเข้า readline" เพื่อเปิดใช้งานคุณสมบัติประวัติ
miracle2k

2
สุดยอดเคล็ดลับ! นอกจากนี้ยังใช้เพื่อส่งสัญญาณไปยังกระบวนการทั้งหมดที่มีคำว่า "mypythonapp": pkill -SIGUSR1 -f mypythonapp
Alexander

10
หากแอปพลิเคชั่นติดอยู่ Python interpreter loop อาจไม่สามารถประมวลผลสัญญาณได้ ใช้faulthandlerโมดูล (และ backport ที่พบใน PyPI) สำหรับตัวจัดการสัญญาณระดับ C ที่จะพิมพ์ Python stack โดยไม่ต้องใช้ห่วง interpreter เพื่อตอบสนอง
gps

146

คำแนะนำในการติดตั้งตัวจัดการสัญญาณเป็นสิ่งที่ดีและฉันใช้มันมาก ตัวอย่างเช่นbzrโดยค่าเริ่มต้นจะติดตั้งตัวจัดการ SIGQUIT ที่จะเรียกใช้pdb.set_trace()เพื่อปล่อยคุณลงในพร้อมท์pdbทันที (ดูแหล่งที่มาของโมดูลbzrlib.breakinสำหรับรายละเอียดที่แน่นอน) ด้วย pdb คุณไม่เพียง แต่จะได้รับการติดตามสแต็กปัจจุบัน แต่ยังตรวจสอบตัวแปร ฯลฯ

อย่างไรก็ตามบางครั้งฉันต้องแก้จุดบกพร่องกระบวนการที่ฉันไม่ได้มีความสุขุมในการติดตั้งตัวจัดการสัญญาณใน linux คุณสามารถแนบ gdb กับกระบวนการและรับ python stack trace กับ gdb macros บางตัว ใส่http://svn.python.org/projects/python/trunk/Misc/gdbinitใน~/.gdbinitแล้ว:

  • แนบ gdb: gdb -p PID
  • รับการติดตามสแตกหลาม: pystack

มันไม่น่าเชื่อถืออย่างสิ้นเชิงโชคไม่ดี แต่มันใช้งานได้เกือบตลอดเวลา

ท้ายที่สุดการแนบstraceอาจทำให้คุณมีความคิดที่ดีว่ากระบวนการกำลังทำอะไรอยู่


2
ยอดเยี่ยม! บางครั้งคำสั่ง pystack ล็อค แต่ก่อนที่มันจะทำให้ฉันติดตามกองสมบูรณ์ของกระบวนการในบรรทัดรหัสหลามโดยไม่จำเป็นต้องเตรียมการใด ๆ
muudscope

26
การอัปเดตย่อย: เทคนิค gdb นี้ (และรหัสที่อัปเดต) มีการบันทึกไว้ที่wiki.python.org/moin/DebuggingWithGdbมีการพัฒนาอยู่ด้านหน้านี้บันทึกไว้ที่ URL นั้นและเห็นได้ชัดว่า gdb 7 มีการสนับสนุน Python บางอย่าง
เนลสัน

7
เท่าที่ฉันสามารถบอกได้มันใช้งานได้จริงถ้าคุณมีสัญลักษณ์การดีบักที่รวบรวมไว้ในไพ ธ อนของคุณเช่นคุณรันโปรแกรมด้วย python2-dbg (บน Ubuntu นี่เป็นแพ็กเกจแยกต่างหากpython-dbg) หากไม่มีสัญลักษณ์เหล่านี้คุณจะไม่ได้รับข้อมูลที่เป็นประโยชน์มากนัก
drevicko

1
ในกรณีของฉันกลับUnable to locate python frameไปที่แต่ละคำสั่งนี้
seriyPS

6
gdb 7+ - รองรับด้วย python ให้บริการโดย python-gdb.py รายละเอียดเพิ่มเติมได้ที่นี่: chezsoi.org/lucas/blog/2014/11/07/en-gdb-python-macros
Lucas Cimon

71

ฉันมักจะจัดการกับหลายหัวข้อและหัวข้อหลักโดยทั่วไปไม่ได้ทำอะไรมากดังนั้นสิ่งที่น่าสนใจที่สุดคือการถ่ายโอนกองทั้งหมด (ซึ่งเป็นเหมือนการถ่ายโอนข้อมูลของ Java) นี่คือการดำเนินการตามบล็อกนี้ :

import threading, sys, traceback

def dumpstacks(signal, frame):
    id2name = dict([(th.ident, th.name) for th in threading.enumerate()])
    code = []
    for threadId, stack in sys._current_frames().items():
        code.append("\n# Thread: %s(%d)" % (id2name.get(threadId,""), threadId))
        for filename, lineno, name, line in traceback.extract_stack(stack):
            code.append('File: "%s", line %d, in %s' % (filename, lineno, name))
            if line:
                code.append("  %s" % (line.strip()))
    print "\n".join(code)

import signal
signal.signal(signal.SIGQUIT, dumpstacks)

53

การเดินทางกองติดตามของไม่ได้เตรียมตัวไว้โปรแกรมหลามทำงานในหลามหุ้นโดยไม่ต้องแก้จุดบกพร่องสัญลักษณ์ที่สามารถทำได้ด้วยpyrasite ทำงานเหมือนมีเสน่ห์สำหรับฉันใน Ubuntu Trusty:

$ sudo pip install pyrasite
$ echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
$ sudo pyrasite 16262 dump_stacks.py # dumps stacks to stdout/stderr of the python program

(Hat tip ถึง @Albert ซึ่งคำตอบมีตัวชี้ถึงสิ่งนี้รวมถึงเครื่องมืออื่น ๆ )


5
สิ่งนี้ใช้ได้ผลดีสำหรับฉันอยู่ที่ไหนdump_stacks.pyง่าย ๆimport traceback; traceback.print_stack()
John Lehmann

2
traceback -lให้รายการของสคริปต์ python ที่กำหนดไว้ล่วงหน้าที่คุณสามารถใช้ได้และdump_stacks.pyเป็นหนึ่งในสคริปต์เหล่านั้น หากคุณกำลังใช้งานของคุณเอง (ตัวอย่างเช่นการเขียนการติดตามสแต็กไปยังไฟล์) คุณควรใช้ชื่ออื่น
johndodo

12
เคล็ดลับสำคัญ: เรียกใช้apt-get install gdb python-dbg(หรือเทียบเท่า) ก่อนที่จะเรียกใช้ pyrasite มิฉะนั้นจะล้มเหลวอย่างเงียบ ๆ ทำงานเหมือนมีเสน่ห์เป็นอย่างอื่น!
johndodo

การแพร่กระจายของ pyrasite ครั้งสุดท้ายในปี 2555
Boris

35
>>> import traceback
>>> def x():
>>>    print traceback.extract_stack()

>>> x()
[('<stdin>', 1, '<module>', None), ('<stdin>', 2, 'x', None)]

นอกจากนี้คุณยังสามารถจัดรูปแบบเป็นอย่างดีกองติดตามดูที่เอกสาร

แก้ไข : หากต้องการจำลองพฤติกรรมของ Java ตามที่ @Douglas Leeder แนะนำให้เพิ่ม:

import signal
import traceback

signal.signal(signal.SIGUSR1, lambda sig, stack: traceback.print_stack(stack))

ไปที่รหัสเริ่มต้นในแอปพลิเคชันของคุณ จากนั้นคุณสามารถพิมพ์สแต็กโดยส่งSIGUSR1ไปยังกระบวนการ Python ที่ทำงานอยู่


2
สิ่งนี้จะพิมพ์ backtrace ของเธรดหลักเท่านั้น ฉันยังหาวิธีแก้ปัญหาสำหรับการดูการติดตามสำหรับเธรดทั้งหมด ในความเป็นจริงหลามดูเหมือนว่าจะไม่มี API ในการเรียกคืนสแต็กจากเธรดวัตถุแม้ว่า threading.enumerate () จะให้การเข้าถึงวัตถุเธรดทั้งหมด
haridsv

วิธีนี้ใช้งานได้ดีบน cygwin มันพิมพ์เพียงสามบรรทัดของการติดตามสแต็ก แต่ก็พอที่จะได้รับเบาะแส
slashdottir

28

tracebackโมดูลมีฟังก์ชั่นที่ดีบางอย่างในหมู่พวกเขา: print_stack:

import traceback

traceback.print_stack()

1
หากต้องการเขียนการติดตามสแต็กลงในไฟล์ให้ใช้: import traceback; f = open('/tmp/stack-trace.log', 'w') traceback.print_stack(file=f) f.close()
GuruM

1
+1 ถึง @gulgi สำหรับคำตอบที่ใช้งานง่ายของเขา คำตอบอื่น ๆ ดูซับซ้อนมากสำหรับงานง่าย ๆ ของฉันในการรับการติดตามสแต็กการโทรจากฟังก์ชันของสคริปต์
GuruM

24

คุณสามารถลองโมดูล faulthandler ติดตั้งโดยใช้pip install faulthandlerและเพิ่ม:

import faulthandler, signal
faulthandler.register(signal.SIGUSR1)

ที่จุดเริ่มต้นของโปรแกรมของคุณ จากนั้นส่ง SIGUSR1 ไปยังกระบวนการของคุณ (เช่น:) เพื่อkill -USR1 42แสดงการติดตาม Python ของเธรดทั้งหมดไปยังเอาต์พุตมาตรฐาน อ่านเอกสารประกอบเพื่อดูตัวเลือกเพิ่มเติม (เช่นเข้าสู่ไฟล์) และวิธีอื่น ๆ ในการแสดงการย้อนกลับ

โมดูลนี้เป็นส่วนหนึ่งของ Python 3.3 สำหรับ Python 2 โปรดดูที่http://faulthandler.readthedocs.org/


20

สิ่งที่ช่วยฉันได้ที่นี่คือเคล็ดลับของเข็ม (ซึ่งฉันจะลงคะแนนและแสดงความคิดเห็นหากฉันมีคะแนนชื่อเสียง) สำหรับการติดตามสแต็คจากกระบวนการ Python ที่ไม่ได้เตรียมตัวไว้ ยกเว้นมันไม่ได้ทำงานจนกว่าฉันจะปรับเปลี่ยนสคริปต์ gdbinit ดังนั้น:

  • ดาวน์โหลดhttp://svn.python.org/projects/python/trunk/Misc/gdbinitและวางไว้ใน~/.gdbinit

  • แก้ไขโดยเปลี่ยนPyEval_EvalFrameเป็นPyEval_EvalFrameEx[แก้ไข: ไม่ต้องการอีกต่อไป; ไฟล์ที่เชื่อมโยงมีการเปลี่ยนแปลงนี้ตั้งแต่วันที่ 2010-01-14]

  • แนบ gdb: gdb -p PID

  • รับการติดตามสแตกหลาม: pystack


gdbinit ที่ URL ที่กล่าวถึงดูเหมือนจะมีโปรแกรมแก้ไขที่คุณแนะนำ ในกรณีของฉันเมื่อฉันพิมพ์ pystack CPU ของฉันเพิ่งจะแขวน ไม่แน่ใจว่าทำไม
Jesse Glick

2
ไม่ไม่ - ฉันไม่ชัดเจนขอโทษเพราะเส้นนั้นปรากฏในสามแห่ง แพทช์ที่ฉันเชื่อมโยงกับรายการที่ฉันเปลี่ยนไปเมื่อฉันเห็นงานนี้
Gunnlaugur Briem

2
เช่นเดียวกับคำตอบของ @ spiv สิ่งนี้ต้องการให้โปรแกรมทำงานภายใต้ python ที่คอมไพล์ด้วยสัญลักษณ์การดีบัก มิฉะนั้นคุณจะได้รับNo symbol "co" in current context.
โคล

12

ฉันจะเพิ่มนี่เป็นความคิดเห็นเพื่อตอบสนองของ haridsvแต่ฉันขาดชื่อเสียงที่จะทำเช่นนั้น:

พวกเราบางคนยังคงติดอยู่กับ Python เวอร์ชันที่เก่ากว่า 2.6 (จำเป็นสำหรับ Thread.ident) ดังนั้นฉันจึงได้รหัสที่ทำงานใน Python 2.5 (แต่ไม่มีชื่อเธรดที่แสดง) ดังนี้:

import traceback
import sys
def dumpstacks(signal, frame):
    code = []
    for threadId, stack in sys._current_frames().items():
            code.append("\n# Thread: %d" % (threadId))
        for filename, lineno, name, line in traceback.extract_stack(stack):
            code.append('File: "%s", line %d, in %s' % (filename, lineno, name))
            if line:
                code.append("  %s" % (line.strip()))
    print "\n".join(code)

import signal
signal.signal(signal.SIGQUIT, dumpstacks)

11

python -dv yourscript.py

สิ่งนี้จะทำให้ล่ามทำงานในโหมดดีบั๊กและให้ร่องรอยของสิ่งที่ล่ามกำลังทำอยู่

หากคุณต้องการดีบักโค้ดแบบโต้ตอบคุณควรเรียกใช้ดังนี้:

python -m pdb yourscript.py

นั่นเป็นการบอกให้ล่ามไพ ธ อนรันสคริปต์ของคุณด้วยโมดูล "pdb" ซึ่งเป็นดีบักเกอร์ไพ ธ อนถ้าคุณเรียกใช้เช่นนั้นล่ามจะถูกดำเนินการในโหมดโต้ตอบเหมือนกับ GDB


นี่ไม่ได้ตอบคำถาม คำถามเกี่ยวกับกระบวนการที่กำลังดำเนินอยู่
dbn

11

ดูfaulthandlerโมดูลใหม่ใน Python 3.3 faulthandlerย้ายกลับสำหรับการใช้งานในหลาม 2 มีอยู่ใน PyPI


2
คำตอบล่าสุดโดย @haypo ครอบคลุมรายละเอียดนี้มากขึ้น ฉันไม่แน่ใจว่าวิธีนี้มักจะจัดการใน SO แต่รู้สึกผิดที่จะมีสองคำตอบหลักที่ซ้ำกัน ...
Nickolay

7

บน Solaris คุณสามารถใช้ pstack (1) ไม่จำเป็นต้องเปลี่ยนรหัส python เช่น.

# pstack 16000 | grep : | head
16000: /usr/bin/python2.6 /usr/lib/pkg.depotd --cfg svc:/application/pkg/serv
[ /usr/lib/python2.6/vendor-packages/cherrypy/process/wspbus.py:282 (_wait) ]
[ /usr/lib/python2.6/vendor-packages/cherrypy/process/wspbus.py:295 (wait) ]
[ /usr/lib/python2.6/vendor-packages/cherrypy/process/wspbus.py:242 (block) ]
[ /usr/lib/python2.6/vendor-packages/cherrypy/_init_.py:249 (quickstart) ]
[ /usr/lib/pkg.depotd:890 (<module>) ]
[ /usr/lib/python2.6/threading.py:256 (wait) ]
[ /usr/lib/python2.6/Queue.py:177 (get) ]
[ /usr/lib/python2.6/vendor-packages/pkg/server/depot.py:2142 (run) ]
[ /usr/lib/python2.6/threading.py:477 (run)
etc.

2
ดูเหมือนว่าจะมีโปรแกรม Debian / Ubuntu pstackที่ทำสิ่งเดียวกัน
Rory

1
ดูเหมือนว่าจะให้ backtrace ภายใต้ linux เท่านั้นไม่ใช่ Python traceback พร้อมชื่อไฟล์และหมายเลขบรรทัด
ogrisel

6

หากคุณใช้ระบบ Linux ใช้สุดยอดของgdbกับ Python debug Extensions (สามารถอยู่ในpython-dbgหรือpython-debuginfoแพ็คเกจ) นอกจากนี้ยังช่วยในแอพพลิเคชั่นแบบมัลติเธรดแอพพลิเคชั่น GUI และโมดูล C

เรียกใช้โปรแกรมของคุณด้วย:

$ gdb -ex r --args python <programname>.py [arguments]

สิ่งนี้แนะนำgdbให้เตรียมpython <programname>.py <arguments>และrถอดออก

ตอนนี้เมื่อคุณโปรแกรมแฮงค์ให้เปลี่ยนเป็นgdbคอนโซลกดCtr+Cแล้วดำเนินการ

(gdb) thread apply all py-list

ดูเซสชั่นตัวอย่างและข้อมูลเพิ่มเติมที่นี่และที่นี่


6

ฉันกำลังมองหาวิธีการแก้ปัญหาในการแก้ปัญหาหัวข้อของฉันและฉันพบมันที่นี่ขอบคุณ haridsv ฉันใช้เวอร์ชันที่เรียบง่ายเล็กน้อยซึ่งใช้ traceback.print_stack ():

import sys, traceback, signal
import threading
import os

def dumpstacks(signal, frame):
  id2name = dict((th.ident, th.name) for th in threading.enumerate())
  for threadId, stack in sys._current_frames().items():
    print(id2name[threadId])
    traceback.print_stack(f=stack)

signal.signal(signal.SIGQUIT, dumpstacks)

os.killpg(os.getpgid(0), signal.SIGQUIT)

สำหรับความต้องการของฉันฉันยังกรองหัวข้อตามชื่อ


3

มันควรค่าแก่การดูที่Pydb "ตัวขยายดีบัก Python เวอร์ชันที่ขยายขึ้นโดยยึดตามชุดคำสั่ง gdb" มีตัวจัดการสัญญาณซึ่งสามารถดูแลการเริ่มต้นดีบักเกอร์เมื่อส่งสัญญาณที่ระบุ

2006 Summer of Code โครงการมองไปที่การเพิ่มคุณสมบัติระยะไกลดีบัก pydb ในโมดูลที่เรียกว่าmpdb


ดูเหมือนว่าจะผ่านสอง ( 1 ) เขียนใหม่ ( 2 ) โดยไม่ต้องเพิ่มคุณสมบัติ Attach-by-PIDฉันกำลังมองหา ...
Nickolay

3

ฉันแฮ็คเครื่องมือร่วมกันซึ่งเชื่อมโยงกับกระบวนการ Python ที่ทำงานอยู่และฉีดโค้ดบางอย่างเพื่อรับ Python shell

ดูที่นี่: https://github.com/albertz/pydbattach


1
หมายเหตุ: ไม่ชัดเจนว่าจะสร้างสิ่งนี้อย่างไร ขอบคุณสำหรับลิงค์ที่คุณใส่ไว้ใน README แม้ว่าpyrasiteทำงานได้อย่างสมบูรณ์แบบ!
Nickolay

3

ก็สามารถทำได้ด้วยดีเยี่ยมPY สายลับ มันเป็นโปรแกรมสร้างตัวอย่างสำหรับโปรแกรม Pythonดังนั้นหน้าที่ของมันคือแนบไปกับกระบวนการของ Python และสุ่มตัวอย่าง call stack ของมัน ดังนั้นpy-spy dump --pid $SOME_PIDเป็นสิ่งที่คุณต้องทำเพื่อถ่ายโอนการเรียกสแต็คของเธรดทั้งหมดใน$SOME_PIDกระบวนการ โดยทั่วไปจะต้องมีสิทธิ์เพิ่ม (เพื่ออ่านหน่วยความจำกระบวนการเป้าหมาย)

นี่คือตัวอย่างลักษณะของแอปพลิเคชัน Python แบบเธรด

$ sudo py-spy dump --pid 31080
Process 31080: python3.7 -m chronologer -e production serve -u www-data -m
Python v3.7.1 (/usr/local/bin/python3.7)

Thread 0x7FEF5E410400 (active): "MainThread"
    _wait (cherrypy/process/wspbus.py:370)
    wait (cherrypy/process/wspbus.py:384)
    block (cherrypy/process/wspbus.py:321)
    start (cherrypy/daemon.py:72)
    serve (chronologer/cli.py:27)
    main (chronologer/cli.py:84)
    <module> (chronologer/__main__.py:5)
    _run_code (runpy.py:85)
    _run_module_as_main (runpy.py:193)
Thread 0x7FEF55636700 (active): "_TimeoutMonitor"
    run (cherrypy/process/plugins.py:518)
    _bootstrap_inner (threading.py:917)
    _bootstrap (threading.py:885)
Thread 0x7FEF54B35700 (active): "HTTPServer Thread-2"
    accept (socket.py:212)
    tick (cherrypy/wsgiserver/__init__.py:2075)
    start (cherrypy/wsgiserver/__init__.py:2021)
    _start_http_thread (cherrypy/process/servers.py:217)
    run (threading.py:865)
    _bootstrap_inner (threading.py:917)
    _bootstrap (threading.py:885)
...
Thread 0x7FEF2BFFF700 (idle): "CP Server Thread-10"
    wait (threading.py:296)
    get (queue.py:170)
    run (cherrypy/wsgiserver/__init__.py:1586)
    _bootstrap_inner (threading.py:917)
    _bootstrap (threading.py:885)  

2

pyringeเป็นดีบักเกอร์ที่สามารถโต้ตอบกับการทำงานของกระบวนการ python, พิมพ์ร่องรอยสแต็ค, ตัวแปร, ฯลฯ โดยไม่มีการตั้งค่าเบื้องต้นใด ๆ

แม้ว่าฉันเคยใช้ตัวจัดการสัญญาณในอดีตบ่อยครั้งมันก็ยังคงเป็นเรื่องยากที่จะทำให้เกิดปัญหาซ้ำในบางสภาพแวดล้อม


3
เห็นได้ชัดว่ามันเข้ากันไม่ได้กับบาง gdb builds (เช่นที่ฉันติดตั้งบน Ubuntu): github.com/google/pyringe/issues/16ต้องสร้างใหม่ด้วยตนเอง ผู้ดีบักอีกpyrasiteคนทำงานเหมือนเสน่ห์สำหรับฉัน
Nickolay

1

ไม่มีวิธีที่จะขอเข้าสู่กระบวนการ python ที่ทำงานอยู่และรับผลลัพธ์ที่สมเหตุสมผล ฉันจะทำอย่างไรถ้ากระบวนการล็อกอัพกำลังเชื่อมต่อกับ strace และพยายามคิดว่าเกิดอะไรขึ้น

โชคไม่ดีที่ผู้คนมักสังเกตเห็นว่า "แก้ไข" สภาพการแข่งขันเพื่อให้ผลลัพธ์ที่ออกมานั้นไร้ประโยชน์เช่นกัน


1
ใช่นี่เป็นเรื่องจริง มันเป็นความอัปยศแม้ว่า PDB พระธาตุไม่สนับสนุนแนบกับกระบวนการทำงาน ...
Bartosz Radaczyński

นี่ไม่เป็นความจริง. ดูคำตอบโดย "spiv" ด้านบนซึ่งแสดงวิธีการเชื่อมต่อ gdb และรับ Python stack trace
andrew cooke

มันไม่เหมือนกัน - มาโคร gdb เหล่านั้นไม่น่าเชื่อถือและไม่ได้ให้อินเทอร์เฟซแบบเต็มกำลัง / อินเตอร์เฟสที่คุ้นเคยของ pdb ฉันมักจะต้องการใครสักคนเขียนแอปขนาดเล็กที่จะใช้ ptrace เพื่อฉีด Python bytecode ลงในกระบวนการ Python ที่กำลังรันอยู่และให้มันรัน 'import pdb'; pdb.set_trace () 'อาจจะหลังจากเปลี่ยนเส้นทาง sys.stdin / stdout ชั่วคราว
Marius Gedminas

สิ่งนี้ไม่เป็นความจริงอีกต่อไปดูคำตอบอื่น ๆ ที่ชี้ไปยัง pyringe / pyrasite
Nickolay

1

คุณสามารถใช้PuDBตัวดีบัก Python พร้อมกับ curses interface เพื่อทำสิ่งนี้ เพียงเพิ่ม

from pudb import set_interrupt_handler; set_interrupt_handler()

รหัสของคุณและใช้ Ctrl-C เมื่อคุณต้องการที่จะทำลาย คุณสามารถทำต่อไปcและทำลายได้อีกหลายครั้งหากคุณพลาดและต้องการลองใหม่อีกครั้ง


เมื่อคุณใช้คำสั่งข้างต้นใน django อย่าลืมเรียกใช้เซิร์ฟเวอร์อย่างถูกต้องเพื่อป้องกันความผิดพลาด: "Manage.py runserver --noreload --nothreading"
potar

1

ฉันอยู่ในค่าย GDB ด้วยส่วนขยายหลาม ติดตามhttps://wiki.python.org/moin/DebuggingWithGdbซึ่งหมายถึง

  1. dnf install gdb python-debuginfo หรือ sudo apt-get install gdb python2.7-dbg
  2. gdb python <pid of running process>
  3. py-bt

ยังพิจารณาและinfo threadsthread apply all py-bt


มันเป็นเรื่องปกติที่จะได้รับการตอบสนองเช่นTraceback (most recent call first): Python Exception <class 'gdb.error'> No frame is currently selected.: Error occurred in Python command: No frame is currently selected.เมื่อทำงานpy-btในgdb?
crookedleaf

1
ไม่เป็นไร. มันเป็นเพราะ app sudoของฉันถูกเรียกว่าเป็น ฉันต้องทำงานgdb pyton <pid>เป็น sudo ด้วย
crookedleaf

1

วิธีดีบักฟังก์ชันใด ๆในคอนโซล :

สร้างฟังก์ชั่นที่คุณใช้ pdb.set_trace ()จากนั้นฟังก์ชั่นที่คุณต้องการแก้ปัญหา

>>> import pdb
>>> import my_function

>>> def f():
...     pdb.set_trace()
...     my_function()
... 

จากนั้นเรียกใช้ฟังก์ชันที่สร้างขึ้น:

>>> f()
> <stdin>(3)f()
(Pdb) s
--Call--
> <stdin>(1)my_function()
(Pdb) 

การแก้ไขข้อบกพร่องที่มีความสุข :)


0

ฉันไม่รู้ว่าอะไรคล้ายกับการตอบสนองของจาวากับ SIGQUITดังนั้นคุณอาจต้องสร้างมันขึ้นมาในแอปพลิเคชันของคุณ บางทีคุณอาจสร้างเซิร์ฟเวอร์ในเธรดอื่นที่สามารถรับ stacktrace จากการตอบกลับข้อความบางชนิดได้?


0

ใช้โมดูลตรวจสอบ

นำเข้าตรวจสอบความช่วยเหลือ (ตรวจสอบสแต็ค) ช่วยในฟังก์ชั่นสแต็คในโมดูลตรวจสอบ:

stack (context = 1) ส่งคืนรายการเร็กคอร์ดสำหรับสแต็กเหนือเฟรมของผู้โทร

ฉันคิดว่ามันมีประโยชน์มากจริงๆ


0

ใน Python 3 pdb จะติดตั้งตัวจัดการสัญญาณโดยอัตโนมัติในครั้งแรกที่คุณใช้ c (ont (inue)) ในตัวดีบั๊ก การกด Control-C หลังจากนั้นจะทำให้คุณกลับมาที่นั่นอีกครั้ง ใน Python 2 ต่อไปนี้เป็นหนึ่งในสายการบินที่ควรใช้งานได้แม้ในเวอร์ชั่นที่ค่อนข้างเก่า (ทดสอบใน 2.7 แต่ฉันตรวจสอบแหล่ง Python กลับไปที่ 2.4 และดูโอเค):

import pdb, signal
signal.signal(signal.SIGINT, lambda sig, frame: pdb.Pdb().set_trace(frame))

pdb คุ้มค่าที่จะเรียนรู้ถ้าคุณใช้เวลาในการดีบัก Python อินเทอร์เฟซนั้นค่อนข้างป้าน แต่ควรคุ้นเคยกับทุกคนที่ใช้เครื่องมือที่คล้ายกันเช่น gdb


0

ในกรณีที่คุณต้องทำสิ่งนี้กับ uWSGI มันมีPython Tracebackerในตัวและเป็นเรื่องของการเปิดใช้งานในการกำหนดค่า (หมายเลขที่แนบมากับชื่อสำหรับผู้ปฏิบัติงานแต่ละคน):

py-tracebacker=/var/run/uwsgi/pytrace

เมื่อคุณทำสิ่งนี้แล้วคุณสามารถพิมพ์ backtrace เพียงแค่เชื่อมต่อกับซ็อกเก็ต:

uwsgi --connect-and-read /var/run/uwsgi/pytrace1

0

ในจุดที่มีการเรียกใช้รหัสคุณสามารถแทรกข้อมูลโค้ดขนาดเล็กนี้เพื่อดูการติดตามสแต็กที่จัดรูปแบบได้อย่างดี ถือว่าคุณมีโฟลเดอร์ที่เรียกว่าlogsที่ไดเรกทอรีรากของโครงการ

# DEBUG: START DEBUG -->
import traceback

with open('logs/stack-trace.log', 'w') as file:
    traceback.print_stack(file=file)
# DEBUG: END DEBUG --!
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.