在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 相关文章推荐
python登录豆瓣并发帖的方法
Jul 08 Python
Python中使用bidict模块双向字典结构的奇技淫巧
Jul 12 Python
Python三种遍历文件目录的方法实例代码
Jan 19 Python
Python实现识别手写数字 Python图片读入与处理
Mar 23 Python
详解Python判定IP地址合法性的三种方法
Mar 06 Python
python smtplib模块自动收发邮件功能(二)
May 22 Python
python+selenium实现自动抢票功能实例代码
Nov 23 Python
不归路系列:Python入门之旅-一定要注意缩进!!!(推荐)
Apr 16 Python
关于Tensorflow分布式并行策略
Feb 03 Python
Python使用requests xpath 并开启多线程爬取西刺代理ip实例
Mar 06 Python
PyCharm 2020.2.2 x64 下载并安装的详细教程
Oct 15 Python
Python数据处理的三个实用技巧分享
Apr 01 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
phpMyAdmin下载、安装和使用入门教程
2007/05/31 PHP
PHP 采集程序 常用函数
2008/12/18 PHP
POSIX 风格和兼容 Perl 风格两种正则表达式主要函数的类比(preg_match, preg_replace, ereg, ereg_replace)
2010/10/12 PHP
PHP实现ASCII码与字符串相互转换的方法
2017/04/29 PHP
PHP使用Nginx实现反向代理
2017/09/20 PHP
给Flash加一个超链接(推荐使用透明层)兼容主流浏览器
2013/06/09 Javascript
jQuery实现磁力图片跟随效果完整示例
2016/09/16 Javascript
无阻塞加载js,防止因js加载不了影响页面显示的问题
2016/12/18 Javascript
JS封装通过className获取元素的函数示例
2016/12/20 Javascript
jQuery实现导航栏头部菜单项点击后变换颜色的方法
2017/07/19 jQuery
微信小程序之多文件下载的简单封装示例
2018/01/29 Javascript
vue-cli3搭建项目的详细步骤
2018/12/05 Javascript
前端深入理解Typescript泛型概念
2020/03/09 Javascript
JS实现多选框的操作
2020/06/24 Javascript
最全vue的vue-amap使用高德地图插件画多边形范围的示例代码
2020/07/17 Javascript
基于element-ui对话框el-dialog初始化的校验问题解决
2020/09/11 Javascript
vue 验证两次输入的密码是否一致的方法示例
2020/09/29 Javascript
Python 自动安装 Rising 杀毒软件
2009/04/24 Python
python 字符串split的用法分享
2013/03/23 Python
python利用urllib实现爬取京东网站商品图片的爬虫实例
2017/08/24 Python
Python3 处理JSON的实例详解
2017/10/29 Python
python将每个单词按空格分开并保存到文件中
2018/03/19 Python
Django中使用CORS实现跨域请求过程解析
2019/08/05 Python
使用批处理脚本自动生成并上传NuGet包(操作方法)
2019/11/19 Python
Spring实战之使用util:命名空间简化配置操作示例
2019/12/09 Python
numpy库ndarray多维数组的维度变换方法(reshape、resize、swapaxes、flatten)
2020/04/28 Python
django 获取字段最大值,最新的记录操作
2020/08/09 Python
美国时装品牌:Nautica(诺帝卡)
2016/08/28 全球购物
宝拉珍选官方旗舰店:2%水杨酸精华液,收缩毛孔粗大和祛痘
2018/07/01 全球购物
网站美工岗位职责
2014/04/02 职场文书
责任心演讲稿
2014/05/14 职场文书
2014财务人员自我评价范文
2014/09/21 职场文书
2014年督导工作总结
2014/11/19 职场文书
小学班主任工作总结2015
2015/04/07 职场文书
观看禁毒宣传片后的感想
2015/08/11 职场文书
心得体会该怎么写呢?
2019/06/27 职场文书