在Linux下调试Python代码的各种方法


Posted in Python onApril 17, 2015

 这是一个我用于调试或分析工具概述,不一定是完整全面,如果你知道更好的工具,请在评论处标记。

日志

是的,的确,不得不强调足够的日志记录对应用程序是多么的重要。您应该记录重要的东西,如果你的记录足够好的话,你可以从日志中找出问题从而节省大量的时间。

如果你曾经用print语句来调试代码现在停下吧,用logging.debug替代,开始可以慢慢来,以后完全禁用它...

追踪
有时看到程序如何被执行会很有帮助。你可以使用IDE的调试共轭ngn一步一步的运行程序,但你需要知道你要找的是什么,否则这将会是一个漫长的过程。
标准库中有一个 trace模块,可以打印所有执行过程中的内容(像制作 覆盖率报告)。
 

python -mtrace --trace script.py

这将产生大量输出(每个行会被打印输出,所以你最好通过管道,用grep只看自己感兴趣的部分),例如:
 

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

如果你喜欢新特性,那么你可以尝试 smiley - 它可以显示变量内容变化,还可以用它来远程追踪程序。

PDB
 

import pdb
pdb.set_trace() # opens up pdb prompt

或者:
 

try:
  code
  that
  fails
except:
  import pdb
  pdb.pm() # or pdb.post_mortem()

或(按键盘C键启动脚本):
 

python -mpdb script.py

像在REPL中那样:

  •     c or continue
  •     q or quit
  •     l or list, 在当前界面显示源码
  •     w or where, 显示回溯
  •     d or down, 显示回溯的下一界面
  •     u or up, 显示回溯的上一界面
  •     <enter>, 重复最后一个命令
  •     其他任何东西,在当前界面评估源码 (t还有其他的一些命令)
  • corcontinue
  • qorquit
  • lorlist,显示在当前帧的源
  • worwhere,显示回溯
  • dordown,下山1帧回溯
  • uorup,上升1帧回溯
  • 回车,重复最后一个命令

几乎任何东西,评估当前帧的Python代码(还有其他几个命令)

可以替代pdb的:

  •     ipdb (easy_install ipdb) - 像 ipython (自动补齐, 颜色等)
  •     pudb (easy_install pudb) - 基于curses (类gui), 浏览源码有很好的表现。

远程 PDB
 

sudo apt-get install winpdb

替代 pdb.set_trace():
 

import rpdb2
rpdb2.start_embedded_debugger("secretpassword")

现在运行Winpdb , 输入密码 到 File > Attach。
不喜欢 Winpdb ? 只要通过 TCP运行 PDB

使用下面代码:
 

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()

想要 REPL ? IPython 怎么样?

如果你不需要一个整体的调试器,只要启动IPython用下面的代码:
 

import IPython
IPython.embed()

标准Linux工具

他们未被充分利用很令我惊讶。通过这些工具集你能弄清楚诸如这些的很多问题:从性能问题(太多的系统调用,内存分配等)到死锁,网络,磁盘等问题。
 

sudo apt-get install htop
sudo htop

最有用的是降权运行strace,只需运行速冻 strace -P 12345 或strace-f 命令参数(-f表示strace分支进程)。 通常有很多的输出,你最好将输出重定向输出到一个文件(命令后添加 &> 文件名)来进行更深入的分析。

然后就是ltrace,它和strace相似不过是通过库调用的,参数基本相同。
lsof可以提供 你看过ltrace/ strace的处理号,这样使用:lsof -P 12345

让跟踪更深点

它很容易使用以及可以做很多事,前提是大家都已经安装了htop!

现在,找你所想的进程,仅仅需要按:

  •     s  显示系统调用跟踪(strace)
  •     L  显示库调用跟踪(ltrace)
  •     l   显示lsof

监视

没有更好的替代品了,服务器持续监视,你曾经是否发现自己使用奇奇怪怪的跟踪方法去找出为什么哪里慢了以及资源怎么被消耗了,那么不要再被iotop, iftop, htop, iostat, vmstat等等烦扰了,赶快使用dstat吧,它可以做大多数上述的提到的工具能做的,而且可以做得更好!

它会以紧凑,时尚的代码着色(亲,不像iostat, vmstat哟)持续显示你的数据,而且你可以一直看到以往的数据(与iftop, iotop, htop不同哟)。

仅仅运行这个:
 

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

还有一点就是这里还有更简单的方式来写哟,如shell历史记录(shell history)或则重命名命令(aliases)

GDB

这是一个相当复杂和强大的工具,但我仅仅涉及到基础的东西(设置和基本命令)。
 

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

现在请使用:

    bt- 堆栈轨迹(C 级)
    pystack- python 堆栈轨迹,前提是你需要拥有~/.gdbinit 并使用python-dbg
    c(继续)

有出现 segfaults 么 ?用 faulthandler !

除了Python 3.3其他的都会出现这个可怕的错误, 回到Python 2.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

你会得到一个像 这样的图表(警告:这个图表非常大)。你也会得到 dot输出。
 
内存利用

有时你想使用更少的内存。少分配内存通常会使程序运行的更快更好,用户们都喜欢精益求精:)

有许多工具可以拿来使用 [1] ,但在我看来最好的是pytracemalloc - 与其他工具相比较,它的开销很小(不需要依赖于削弱速度的 sys.settrace)并且它的输出非常详尽。令人头疼的是它的配置,因为需要你重编译python,但是spt使其很容易做到。

只要运行以下命令,然后你就可以去买午餐或者做其他事了:
 

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(请注意:如果你是在虚拟环境中做的这些操作,那么在python重新安装后,你需要重建它-仅运行virtualenv myenv即可):
 

pip install pytracemalloc
 

现在,你就可以通过以下代码来封装你的应用程序:
 

import tracemalloc, time
tracemalloc.enable()
top = tracemalloc.DisplayTop(
  5000, # log the top 5000 locations
  file=open('/tmp/memory-profile-%s' % 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
 
...
Python 相关文章推荐
使用Python3中的gettext模块翻译Python源码以支持多语言
Mar 31 Python
Python实现的多线程http压力测试代码
Feb 08 Python
浅谈Tensorflow模型的保存与恢复加载
Apr 26 Python
Python常见MongoDB数据库操作实例总结
Jul 24 Python
python 处理数字,把大于上限的数字置零实现方法
Jan 28 Python
pybind11和numpy进行交互的方法
Jul 04 Python
解决Python中回文数和质数的问题
Nov 24 Python
Python字典生成式、集合生成式、生成器用法实例分析
Jan 07 Python
python 截取XML中bndbox的坐标中的图像,另存为jpg的实例
Mar 10 Python
浅谈Python3多线程之间的执行顺序问题
May 02 Python
浅析python 动态库m.so.1.0错误问题
May 09 Python
Python threading模块condition原理及运行流程详解
Oct 05 Python
Python脚本在Appium库上对移动应用实现自动化测试
Apr 17 #Python
Python中生成器和yield语句的用法详解
Apr 17 #Python
使用Python脚本在Linux下实现部分Bash Shell的教程
Apr 17 #Python
使用Python的Scrapy框架编写web爬虫的简单示例
Apr 17 #Python
用Python的Django框架编写从Google Adsense中获得报表的应用
Apr 17 #Python
在Docker上开始部署Python应用的教程
Apr 17 #Python
使用Python装饰器在Django框架下去除冗余代码的教程
Apr 16 #Python
You might like
第五节 克隆 [5]
2006/10/09 PHP
ThinkPHP3.1基础知识快速入门
2014/06/19 PHP
自定义min版smarty模板引擎MinSmarty.class.php文件及用法
2016/05/20 PHP
PHP实现微信小程序人脸识别刷脸登录功能
2018/05/24 PHP
JQuery 获得绝对,相对位置的坐标方法
2010/02/09 Javascript
jquery实现图片左右间隔滚动特效(可自动播放)
2013/05/08 Javascript
JavaScript实现的圆形浮动标签云效果实例
2015/08/06 Javascript
jQuery仿360导航页图标拖动排序效果代码分享
2015/08/24 Javascript
NodeJS的Promise的用法解析
2016/05/05 NodeJs
微信小程序-滚动消息通知的实例代码
2017/08/03 Javascript
vue-cli项目中怎么使用mock数据
2017/09/27 Javascript
Vue实现搜索结果高亮显示关键字
2019/05/28 Javascript
用Vue.js在浏览器中实现裁剪图像功能
2019/06/18 Javascript
浅谈微信小程序列表埋点曝光指南
2019/10/15 Javascript
VSCode写vue项目一键生成.vue模版,修改定义其他模板的方法
2020/04/17 Javascript
JS call()及apply()方法使用实例汇总
2020/07/11 Javascript
three.js着色器材质的内置变量示例详解
2020/08/16 Javascript
Python编程入门之Hello World的三种实现方式
2015/11/13 Python
Python导入模块时遇到的错误分析
2017/08/30 Python
十分钟利用Python制作属于你自己的个性logo
2018/05/07 Python
python实现贪吃蛇游戏
2020/03/21 Python
python selenium爬取斗鱼所有直播房间信息过程详解
2019/08/09 Python
Python中join()函数多种操作代码实例
2020/01/13 Python
python数据抓取3种方法总结
2021/02/07 Python
HTML5 canvas画矩形时出现边框样式不一致的解决方法
2013/10/14 HTML / CSS
英国领先的奢侈品零售商之一:CRUISE
2016/12/02 全球购物
Max&Co官网:意大利年轻女性时尚品牌
2017/05/16 全球购物
怎样让char类型的东西转换成int类型
2013/12/09 面试题
大唐面试试题(CPU,UNIX等等)
2012/01/11 面试题
酒店出纳岗位职责
2013/12/29 职场文书
2014年商场超市庆元旦活动方案
2014/02/14 职场文书
师德师风整改措施
2014/10/24 职场文书
中职班主任培训心得体会
2016/01/07 职场文书
爱国之歌(8首)
2019/09/29 职场文书
golang 如何用反射reflect操作结构体
2021/04/28 Golang
Python中time标准库的使用教程
2022/04/13 Python