前段时间和一位字节跳动开发长者,估计 40+,是个真开发长者了。底层计算系统开发负责人,佩服的是依然一线主力开发。当时聊到日常开发时,长者表示他开发过程基本上很少 debug,逻辑异常都是通过运行日志来定位。
大致原因是,通过 debug 工具单步断点调试,是非常低效的开发行为。因为一次 debug 后只解决了当前的 bug,并没有让系统更易于维护,而每次通过完善日志来定位问题,问题定位会逐渐清晰且容易。而且断点对于复杂系统调试是非常麻烦的,首先定位问题出现大致范围就很耗时,完全没有通过日志来得清晰,当然具体细节通过断点 debug 是没有问题,毕竟日志输出是整体逻辑,没有输出太多细节信息,细节处问题还是需要通过 debug 工具。
当时听完蛮惊讶的,不过后来想一下,觉得好像是这么一回事。出现问题-->输出完善清晰的日志-->定位问题-->辅助 debug 工具-->解决问题,同时完善信息-->再次出现问题....的确好像会让整个系统更为清晰。最近试了一下,自觉效果不错,只是过程感觉有点不适,总是不自觉想直接开点 debug 去调。但是从结果上,由于被调试目的驱使,输出的运行信息的确更为高效且清晰,也的确同一模块问题定位因为日志逐渐完善会加速。
不过我觉得这个方法有个使用前提:开发水平较高,bug 多是结构逻辑上的。比方说事务漏提交导致后续的问,改动通过调用某模块方法来解决。而是某个方法细节出了问题,比如某个方法资源没释放,导致另外一处的问题,那这通过 bug 通过日志定位的话,估计输出一大堆信息吧。
老铁们怎么看这个问题,业界是否已有类似的开发模式啊?
1
baoyexi 2020-03-21 10:58:11 +08:00
最近也在想日志这个事情, mark 一下
|
2
nightwitch 2020-03-21 11:06:15 +08:00
大系统里面日志越早实现越好。Debugger 有很多局限性,有的地方断不下来,有的比较隐晦的 bug 可能根本不知道断到哪里。细粒度的日志可以比较快的定位到异常的地方。 而且有的时候 debugger 真的很慢。。
|
3
optional 2020-03-21 11:11:12 +08:00
debugger 基本不会用啊, 除非写一个 util 工具方法。
|
4
wuhx 2020-03-21 11:19:57 +08:00
这就是为什么 Linus 一直反对给内核加调试器
https://lkml.org/lkml/2000/9/6/65 |
5
forestyuan 2020-03-21 11:48:30 +08:00 1
对于多线程的程序,那些线程之间交互的部分很难 debug,恐怕只能用日志了
|
6
402124773 2020-03-21 11:49:33 +08:00
windows 有个内置日志系统叫做 ETW,做的比较好,比较好用。内核和应用都可以使用。并不开源。
|
7
xsen 2020-03-21 11:55:03 +08:00
一直都是通过日志的方式。当然,对于随便就出问题(一分钟内,百分百重现),会利用 debug 调试
日志系统完善起来,可以提高效率很多的 |
8
secsilm 2020-03-21 11:58:03 +08:00 via Android
偏向日志,有目标性,后续还能持续输出,出问题好定位。但是感觉控制好日志粒度不是容易的事。https://i.loli.net/2020/03/21/HNlO9WTFKgZGido.png
|
9
mikicomo 2020-03-21 11:58:21 +08:00
能用日志不用 debug
|
10
hallDrawnel 2020-03-21 12:02:58 +08:00
debugger 感觉在刷题的时候还有用,其他地方确实是日志很好用。尤其是现在各种操作都是异步或者并发的,靠断点都没法复现。
|
11
littlewing 2020-03-21 12:26:20 +08:00 via iPhone
必须是日志啊,debug 是在看完日志后仍然无法确定问题时就用
|
12
guyeu 2020-03-21 12:28:50 +08:00
断点调试是很效率很高的 debug 方式,相当于在每一行代码执行之后都打日志。
日志本身也并不能让系统更易于维护,大量的日志反而会拖慢系统的性能。在关键结点准确清晰地打出易于追踪的日志是难度很高的事情,到最后往往是一百行代码几十行日志。 |
13
raphael008 2020-03-21 12:31:48 +08:00
现在都习惯去 splunk 看发生了啥啊。。。
|
14
qiyuey 2020-03-21 12:36:53 +08:00
肯定是日志
|
15
sleepm 2020-03-21 12:41:08 +08:00 via Android
打日志是最简单的 debug
|
16
ericgui 2020-03-21 12:44:31 +08:00
好消息,因为我都不会用断点,学过好几次,感觉没什么卵用,也不好用
|
18
Vegetable 2020-03-21 12:46:58 +08:00
debugger 真的用的很少,局限性太大了,换句话说,debugger 能做的事情,日志其实都能做
|
21
mywaiting 2020-03-21 12:58:01 +08:00
debugger 的方式也仅限于本地调试的时候用一下,线上产品,那必须是日志的方式
完善的 log 记录分析跟踪,是个好习惯,即使小项目也是可以接入 sentry 这样的异常记录工具的 |
27
felixlong 2020-03-21 13:03:45 +08:00
基本上自己熟悉的 code 用 log 比较方便。debugger 主要用来调不熟悉的 code.
|
28
mitu9527 2020-03-21 13:04:23 +08:00
生产只能是日志,开发时主要是通过日志定位问题所在的位置,然后再通过 debugger 调试,看看具体发生了什么,才会引发问题。
|
32
ybw 2020-03-21 13:09:23 +08:00 via Android
@guyeu 抱歉了,多年的开发经验告诉我,我没这个能力。你一定是大多数时候就"一猜就准"吧,真羡慕你的调试经历。
|
33
also24 2020-03-21 13:13:01 +08:00 1
@guyeu #26
你可能理解的过于偏激了,楼主的标题其实有个关键词是 “XX 为主” 以 debugger 为主的处理思路,更多的适用于 “一次性” 故障,是为了解决 bug 而做的。 以日志为主的思路是一整套动作,要掌握好日志的输出粒度,以及日志的格式化方便查找等。 之所以推荐日志为主的处理思路,则是因为它具有更好的 “整体性”,能在解决 bug 之外带来更多额外的收益。 至于是否一定能够 “快速” 定位问题,其实影响因素很多: 对代码熟悉的人,也许能够更精确的下断点;但也许遇到多线程的问题就会比较难受。 日志写的详细的人,也许能够只看日志就确定问题;但也许遇到日志盲区就不得不走调试。 这其实并不矛盾,以 xx 方法为主只是一种倾向,而不是完全摒弃另一方。 |
34
Mohanson 2020-03-21 13:27:36 +08:00 via Android 1
大部分 CPU 在设计的时候都有个 debug 模块,它允许用户态程序完全接管 CPU 的运行,甚至允许运行过程中修改寄存器内的值,也就是全部 debug 工具的能力来源。
但是 CPU 中 debug 模块的复杂程度甚至超过了 CPU 本身,非常不划算。 所以后来提出了 tracing 模式,也可以理解为 CPU 层面下的 Log 模块,只负责记录。不过这东西造价高昂,cpu 每秒能产生海量数据,要能全部记录,压缩和存储。 不过从大趋势上来讲,tracing 与 debug 两方的角逐我认为 tracing 未来可能会占优,现有的 debugger 工具也将逐渐退出(前提成立的情况下) |
35
taowen 2020-03-21 13:45:15 +08:00
业内比较先进的有 firefox 的 rr https://github.com/mozilla/rr/wiki/Recording-Firefox 和微软的 time travel debugging https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/time-travel-debugging-overview 之前在滴滴做过一个业务上用的简单的工具 https://github.com/didi/rdebug
难点还是比较多的,不仅仅是数据量和性能问题,还包括什么叫一个完整因果链的 session 的问题。React 有一个叫 Interaction 的概念 https://gist.github.com/bvaughn/8de925562903afd2e7a12554adcdda16 做 tracing 的时候都需要这样的东西。这种上下文关联的事情不是纯技术手段能底层解决的,要侵入到业务代码的编写方式里。 |
36
vindurriel 2020-03-21 14:12:48 +08:00 via iPhone
能打断点的 debugger 侵入性太大 日志则可以控制输出级别和粒度 一种方案同时应对开发 测试 生产环境的需要 对正常逻辑的影响更可控
|
37
holdmybeer 2020-03-21 14:21:54 +08:00
|
38
winterfell30 2020-03-21 14:30:10 +08:00
我有另一个疑问,我从大学开始我找 bug 就是二分法打日志来找的,一直感觉用 debug 的更专业,但是因为我 debug 效率一直不如打日志高所以一直也没有动力学怎么更高效的 debug,有什么打日志做不了但是很适合用 debug 的例子可以说说吗
|
39
also24 2020-03-21 14:51:22 +08:00 1
@winterfell30 #38
你用二分法打日志的过程,就不如直接使用 debugger, 用 debugger 大概率只需要跑一次…… 以及,你的二分法的日志点,其实就是你心目中使用 debugger 的断点位置。 在我的理解,你这样其实是在使用打日志的方式来进行 debugger 的工作。 如我前面所说,日志查 bug 是一个系统化的工程,不是在遇到 bug 的时候才开始的,而是从开发阶段就已经 “留一手”。 也正是因此,断点只能用一次,日志点可以保留,后续查用。 |
40
fancy2020 2020-03-21 15:04:12 +08:00
基本没太用过调试工具,都是加日志查问题。
现在做前端了,还是靠 log |
41
kayv 2020-03-21 15:47:06 +08:00
我是靠单测+log 。写代码之前先想清楚,service/logic 的函数基本都有单测,要调试就加日志运行单测。
|
42
zhuangzhuang1988 2020-03-21 15:51:52 +08:00
|
43
ifsclimbing 2020-03-21 15:53:39 +08:00 via iPhone
本地开发环境还可以断点,Prod 就难了,还是日志方便
|
44
guyeu 2020-03-21 15:57:02 +08:00 1
@also24 #33 我回顾了一下我的措辞,我觉得还是比较准确和中肯的。
楼主原话是`改 bug 的方式`,已经发现了有 bug,甚至开始尝试定位,这种情况下断点调试的效率很高。 我从没有说断点调试是优于日志的 debug 方式,只是在改 bug 的时候效率更高。 楼上有很多人认为日志有助于提高系统的可维护性,很大程度上日志有变量监视器和注释的作用,我也并没有否认,我只是说,放弃使用调试器,想要单凭日志来 debug,甚至追求那些所谓的`额外收益`,是一件南辕北辙的事情。 我看到有位仁兄 @ybw 觉得调试要一行一行看,觉得很难定位到一个问题存在的范围,可能代表了某些人的想法。可是能知道在那个地方添加日志,怎么就想不起来在那个地方下断点呢?断点相当于一个运行期间可以随时修改,完整打印所有变量内容甚至堆栈细节的日志,所以说 debugger 的效率比查日志高。 而你所说的,基本上是废话,每个人都知道日志不可或缺,甚至在有些场景是唯一的方案。对代码熟悉的人,可以更精确的下断点,但只看日志就确定问题的人,一定熟悉代码。 查 bug 的常规思路,知道某个地方有 bug,然后开始浏览日志试图定位问题,可能 40%的 bug 就能看出来了。看不到问题,开始复现 bug,剩余 90%以上的 bug 都是可以复现的,对可以复现的 bug 而言,断点调试是效率最高的调试方式了,剩下的 bug,属于疑难杂症,需要结合各种手段。 而你所谓`日志为主的处理思路`,对真正的疑难杂症毫无作用,所谓的`整体性`,是以程序运行的效率为代价的,`更多额外的收益`只是臆想,任何应用广泛的软件设施,对日志的使用都是很克制的。 |
45
hantsy 2020-03-21 15:58:31 +08:00
几乎没用过 Debug 。
1,实在不会用 IDE 的 Debug 功能 2,一般项目都要求写测试,一般的问题都是可以在测试中消除。 3,必要的跟踪日志不可缺少,项目一开始就会有要求 |
46
p1gd0g 2020-03-21 15:59:37 +08:00
debug 是啥,单元测试吗?
俺司都是用日志来查问题,为了方便,昨天俺刚把 pkg/errors 塞进项目里。 |
47
NeinChn 2020-03-21 16:22:21 +08:00
加日志只能解决一小部分问题
如果你用了别人的库,你还能加日志?中间过程就不 debug 了么,只看输入和输出有时候又解决不了问题 要是只会做黑盒调用那出问题就。。。 |
48
crayygy 2020-03-21 16:40:19 +08:00 via iPhone
offline 的情况下,log 是唯一的 debug 工具
|
49
learnshare 2020-03-21 16:40:34 +08:00
日志比较方便,也很直观,但要求有代码,而且对代码十分了解
Debug 一般针对摸不透的问题,逐步查找分析 |
50
wangxiaoaer 2020-03-21 16:53:12 +08:00 via Android
Bug 分很多种,业务逻辑的通过日志排查是个好办法,但如果是计算问题,难道还很有对象都重写 tostring 输出吗?这种情况明显 debug 更直观
|
51
zhuangzhuang1988 2020-03-21 17:21:38 +08:00 via Android 1
现在流行,反智么
|
52
yingo 2020-03-21 18:12:48 +08:00
那调试日志程序的 bug,该怎么办....
|
53
souths 2020-03-21 18:15:08 +08:00
并不冲突
|
54
liprais 2020-03-21 18:24:15 +08:00
不打日志有 bug 都发现不了
|
55
nicebird 2020-03-21 19:45:38 +08:00
做后端分布式系统的,没见过靠调试能定位好问题的。
|
56
laminux29 2020-03-21 20:35:08 +08:00
所以那个人到了 40+也只能呆在跳动字节的一线而已,因为他根本没考虑以下问题:
1.如果程序崩溃时,连日志组件也没能记录下,怎么办? 2.如果需要行级别的日志,才能找到问题,那前期开发时,如何进行日志输出?每一行代码就写个 Log()? 3.如果需要进行调试的地方,数据量极大,导致如果全部日志,会成为性能瓶颈。如果不全部日志,输出粒度又会造成关键信息不足,那怎么办? 真正的高手,会根据情况,来判断到底如何调试,通常是日志与调试进行两者结合。而不是拍脑袋觉得某种一定更好。 |
57
yunlzheng 2020-03-21 20:35:53 +08:00 1
个人习惯是如果线上有问题,会尽量通过单元测试的方式在本地复现。 既可以保证本地效率,写好的测试还可以避免问题的出现。
|
58
hoyixi 2020-03-21 21:16:33 +08:00
这是常识。
某些系统架构下,或者产品自身特点,很多 bug 是客户那里操作运行产生,比如客户跨国、客户自己部署你的产品,你作为开发,怎么 debug ?标准方式就是除了详细描述 bug,还要让客户把运行日志发给你分析。 为啥很多软件开发基本流程和基本常识,现在的从业者都不知道? 因为自从互联网泡沫以来,很多 IT 从业者,说好听点,在互联网公司上班,实质都在软件作坊里干活罢了。 没流程,烂管理,全靠加班。 |
59
zhuangzhuang1988 2020-03-21 21:42:53 +08:00
@hoyixi c++, c#的话
windows 上的 dump 文件了解下 可以记录 进程里的各种 dll, 当前系统各种信息, 堆栈信息, 日志文件只能看到 when, 不能知道 why. 而且 在复杂的客户环境下 exe 被各种注入了. |
60
hoyixi 2020-03-21 21:49:11 +08:00
@zhuangzhuang1988 #59
我知道可以利用 dump 来 debug,但是并不是一定会 dump,定位逻辑错误还是日志更便捷。 |
61
zhuangzhuang1988 2020-03-21 22:47:17 +08:00
@hoyixi 其实本身不是 非 A 即 B 得问题, 我代码里都用, 特别是动态调试别人的框架时候, 肯定上 debugger.
同意的人很多扯 , 静态语言 和 单元测试 都不是一个维度的, 比较. |
62
liango 2020-03-21 22:59:38 +08:00
哪个更快定位就用哪个
|
63
Inn0Vat10n 2020-03-21 23:56:05 +08:00
哪个方便用哪个,哪个能用用哪个,这么简单的问题还用的着争吗
|
64
123444a 2020-03-22 00:56:08 +08:00 via Android
coredump,很简单的
|
65
mingl0280 2020-03-22 04:04:47 +08:00 1
@hoyixi 还是被日志惯坏了,有时候(比方说驱动引起莫名其妙蓝屏、内核搞事什么的)你没法看日志的。那种情况只能挂调试器上去 debug,不然你看到的东西是好几个线程输出的不相关内容,根本没法用。
|
66
mingl0280 2020-03-22 04:09:22 +08:00 1
@hoyixi 正常人根本不会说只用某一种 debug 手段,挂调试器能解决日志有时候打不出来的问题,看日志有时候能看出调试器挂不了的问题,都是手段而已,怎么就这个高那个低了?
|
67
xuanbg 2020-03-22 09:15:08 +08:00
通过日志直接定位到关键点,如果发现代码明显写错了或者不完善,就直接改。如果发现结果和预期不符,但貌似代码逻辑没错,就打断点看看实际的数据是否符合预期。数据不符合预期肯定是别的地方写错了导致的。
|
68
hoyixi 2020-03-22 13:03:11 +08:00
|
69
pkookp8 2020-03-22 13:15:28 +08:00 via Android
两者结合吧
需要的关键信息加日志 写的功能加单元测试或调试命令 出现问题可以通过日志分析 辅助调试命令观察现象,辅助单元测试快速调试 具体也和环境,系统,设计框架,历史遗留的代码有关 这些事也没有绝对的好与坏,能有一定理由,符合公司的代码习惯即可 |
70
aguesuka 2020-03-22 21:26:39 +08:00
长者表示他开发过程基本上很少 debug,逻辑异常都是通过运行日志来定位。
就我个人在调试代码的时候,一般用 assert+debugger,生产环境用日志。idea 可以打 AssertionError 的断点,assert false 就相当于进入断点,就我而言效果比日志强太多 |
71
laball 2020-03-23 00:22:11 +08:00
Debug 效率确实比较低!而且系统越大越复杂,效率越低;
有的时候一次 Debug 需要的条件非常复杂,自己构造,还不如打日志跑一遍来得快,如果代码对于单元测试支持的好,会得到一些改善; 另外就是多线程的 Bug,调试可能没有打日志靠谱; 40+的一线开发,应该是什么都见过的主,而且,应该都是处理大型系统什么的,对他来说,日志,确实是一把利剑; 发现问题 ——> 日志打点 ——> 重现一遍 ——> 直接修复,或者只调试一小段代码; 对他来说,效率是第一位的; |
72
nmap 2020-03-23 10:16:08 +08:00
这不是常识么,你见过真正的生产环境么?能让你用 gdb 上去调?
|
73
Aresxue 2020-03-23 10:35:19 +08:00
生产远程 debug 模式又不能开, 出了问题当然主要就是靠日志。 但日志要做好解耦, 不然是一件十分消耗性能的事情。另外日志的输出是交错的, 有时候可能会比较难以区分,因此在日志之外 JVM 的监控工具也应该有效利用上, 比如 pinpoint 和 arthas
|
74
LouisGuo 2020-03-23 13:17:12 +08:00
大佬的思路还是很清晰的
|