欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  后端开发

打印日志 (log) 是比单步跟踪 (debugger) 更好的 Python 排错手段吗?

程序员文章站 2022-05-14 10:17:00
...
首页 - Woodpecker Wiki for CPUG

以动手实践为荣 , 以只看不练为耻;
以打印日志为荣 , 以单步跟踪为耻;
以空格缩进为荣 , 以制表缩进为耻;
以单元测试为荣 , 以人工测试为耻;

以模块复用为荣 , 以复制粘贴为耻;
以多态应用为荣 , 以分支判断为耻;
以Pythonic为荣 , 以冗余拖沓为耻;
以总结分享为荣 , 以跪求其解为耻;

相关问题:

为什么打印(跟踪)日志的调试效力远高于普通的 Debugger 排错方式? - 编程

回复内容:

日志和 debugger 都是有其优缺点和最佳应用的场景的。合格的程序员应该分清楚自己面对的问题所处的场景,根据日志、debugger 各自的优缺点选择最合适的工具来处理问题。

使用日志来进行调试,在日志输出科学,并且程序员本人对系统熟悉的前提下,找出错误所在的时效性是很高的——很多简单的错误都可以通过日志“秒杀”之,就不用麻烦开动“大杀器” debugger 来重现场景了。现实生产环境下,有一些 bug 是在极端的场景下出现的,自己手动重现的可能性几乎是 0,所以使用调试器去查错也是几乎不可能的。在这个时候,我们可以通过在可疑代码段挂上日志输出的代码,将代码上下文以及环境信息打到日志*后续分析。日志能够做到很多 debugger 做不到的东西。

使用 debugger 来进行调试,可以获得几乎最为详细的代码运行时的上下文、环境信息,而且你能够控制程序的逻辑,能够更快地验证自己的猜测,这点是日志很难媲美的。魔鬼在细节中。有时候,日志反映的信息还是不够详细,需要你去”深入此山中“,找到自己想要的细节,这个时候就是 debugger 派上用场的时候了。

日志有日志的好处,debugger 有 debugger 的好处,而且,它们的优缺点基本上是互补的。为什么不两者结合起来用呢?没必要过于绝对地说日志好,debugger 不好,所以就只用日志不用 debugger。“思维绝对化”就像“依赖猜测”一样,是一个合格的工程师最好不要有的性格特点。

讨论还没有完。不要忘记了一个大前提:这句话是出于 Python 社区的。对于动态语言,因为语言本身实现的原因,使用 debugger 来进行调试(甚至实现一个 debugger)往往是一件费力不讨好的事情——进一步地,当一个用动态语言实现的项目的源代码量特别大,代码间关系特别复杂,依赖的环境(例如 web 应用中的缓存、队列,以及各种分布式基础设施等等)不再单一甚至可靠、可依赖时,用 debugger 来进行调试几乎就变成了一件不可能的事情。这个时候 debugger 就显现出了它的劣势了。所以说这一句话还是有一定的道理的——不要忘了抛出这个观点时的场景。当然,这句话的绝对论断,我是不敢苟同的。

最后:我一直相信,没有绝对优和绝对劣的工具。使用工具的是人。聪明的人在合适的场景下让一个为此场景而生的工具发挥效力提高生产力,这才是工具的意义。用螺丝刀钉钉子,然后说螺丝刀不好,是不明智的。 为什么要使用日志来诊断问题,而不是使用单步跟踪,是因为:
单步跟踪的前提是已经知道了如何对问题进行复现,然后在重现的场景中进行单步调试,但是很多情况下并没有这个条件。
比如说你的服务端程序挂了,这种bug 10w次query才出现1次,请问如何单步跟踪?
再比如说你写的客户端程序已经发版了,用户告诉你程序闪退,请问如何单步跟踪?

除此以外,使用日志来诊断问题,能强迫你把代码写得更加规范,更加容易理解。

一位著名的计算机科学家说过,好的程序,应该看日志就能对它的运作细节了如指掌 :)

说实话,有些时候单步跟踪根本没用,打log也是看得很痛苦的。我大四的毕业设计是一个简化后的haskell的实现。类型退到用了淬火算法,一层一层递归,不断地收敛,最后把类型推算出来。一个50行的haskell程序可以产生4M的log。我曾经单步进去,发现递归(不能改成循环的那种)多到根本没法知道当前的context在哪。后来只能看log,每次出了问题,都要打开4M的log,眼睛一行一行看,看看哪里推导的中间结果是错的,然后看看代码猜一下到底是为什么,不断地修改直到所有的test case都过了为止。


这个故事告诉我们,只要算法足够复杂,任何方法都是没用的,只能靠蛮力。

日志打得好是一门学问。
考虑分离几个层面的日志文件,core / model / logic / view / task / service / ext http。
即便在一个层面里面,也要考虑规划好 info / error / debug 基本日志层级。
好的日志可以在出现异常时候,帮助快速找出问题点。
我本人并不反对单步调试,平日用的也很多,不过仍然强调打日志水平的提高。 虽然我是日志派的.因为嫌调试麻烦. 可是还是要说,“以打印日志为荣 , 以单步跟踪为耻”说这话的人就是在装B. 我曾经一个星期 blind fix 过三个 crash bug。都是无法重现的。只能用用户发上来的 crash report。过程是这样的。

看 crash report 的 callstack ,使劲看。
各种假设。
用 debugger 研究代码,验证各种假设。

没有 log。狂用 debugger 单步。没有「必须重现问题」的前提。

说实话,log 这个东西,有用确实有用。但是:
  1. 没那么重要。其实问题发生的一刻,留下的证据就很多。
  2. 研究问题不仅仅是找证据,还有各种假设。即使无法完全重现问题,也要深入的验证各种假设。这必须要靠 debugger 单步。
  3. 日志和单步并不互斥。
不看场景与需求就谈论好坏全是瞎扯淡 显然不对,debugger能获得进程的全部信息、stack trace,还可以动态修改代码、重新运行走过的代码,岂是日志可比的

那个“八荣八耻”不要当真,一笑置之就好 静态调试拯救世界。
前提是你足够熟悉你的代码。
日志是最没用的。日志要建立在你已经能至少定位到出错的函数,才有意义。 因为小蛇做不好单步跟踪,这是一种*