V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
mitiskysean
V2EX  ›  Java

讨论一下改 bug 的方式,日志输出为主代替 debug 工具为主的优缺点

  •  1
     
  •   mitiskysean · 2020-03-21 10:54:32 +08:00 · 7269 次点击
    这是一个创建于 1700 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前段时间和一位字节跳动开发长者,估计 40+,是个真开发长者了。底层计算系统开发负责人,佩服的是依然一线主力开发。当时聊到日常开发时,长者表示他开发过程基本上很少 debug,逻辑异常都是通过运行日志来定位。

    大致原因是,通过 debug 工具单步断点调试,是非常低效的开发行为。因为一次 debug 后只解决了当前的 bug,并没有让系统更易于维护,而每次通过完善日志来定位问题,问题定位会逐渐清晰且容易。而且断点对于复杂系统调试是非常麻烦的,首先定位问题出现大致范围就很耗时,完全没有通过日志来得清晰,当然具体细节通过断点 debug 是没有问题,毕竟日志输出是整体逻辑,没有输出太多细节信息,细节处问题还是需要通过 debug 工具。

    当时听完蛮惊讶的,不过后来想一下,觉得好像是这么一回事。出现问题-->输出完善清晰的日志-->定位问题-->辅助 debug 工具-->解决问题,同时完善信息-->再次出现问题....的确好像会让整个系统更为清晰。最近试了一下,自觉效果不错,只是过程感觉有点不适,总是不自觉想直接开点 debug 去调。但是从结果上,由于被调试目的驱使,输出的运行信息的确更为高效且清晰,也的确同一模块问题定位因为日志逐渐完善会加速。

    不过我觉得这个方法有个使用前提:开发水平较高,bug 多是结构逻辑上的。比方说事务漏提交导致后续的问,改动通过调用某模块方法来解决。而是某个方法细节出了问题,比如某个方法资源没释放,导致另外一处的问题,那这通过 bug 通过日志定位的话,估计输出一大堆信息吧。

    老铁们怎么看这个问题,业界是否已有类似的开发模式啊?

    74 条回复    2020-03-23 13:17:12 +08:00
    baoyexi
        1
    baoyexi  
       2020-03-21 10:58:11 +08:00
    最近也在想日志这个事情, mark 一下
    nightwitch
        2
    nightwitch  
       2020-03-21 11:06:15 +08:00
    大系统里面日志越早实现越好。Debugger 有很多局限性,有的地方断不下来,有的比较隐晦的 bug 可能根本不知道断到哪里。细粒度的日志可以比较快的定位到异常的地方。 而且有的时候 debugger 真的很慢。。
    optional
        3
    optional  
       2020-03-21 11:11:12 +08:00
    debugger 基本不会用啊, 除非写一个 util 工具方法。
    wuhx
        4
    wuhx  
       2020-03-21 11:19:57 +08:00
    这就是为什么 Linus 一直反对给内核加调试器
    https://lkml.org/lkml/2000/9/6/65
    forestyuan
        5
    forestyuan  
       2020-03-21 11:48:30 +08:00   ❤️ 1
    对于多线程的程序,那些线程之间交互的部分很难 debug,恐怕只能用日志了
    402124773
        6
    402124773  
       2020-03-21 11:49:33 +08:00
    windows 有个内置日志系统叫做 ETW,做的比较好,比较好用。内核和应用都可以使用。并不开源。
    xsen
        7
    xsen  
       2020-03-21 11:55:03 +08:00
    一直都是通过日志的方式。当然,对于随便就出问题(一分钟内,百分百重现),会利用 debug 调试
    日志系统完善起来,可以提高效率很多的
    secsilm
        8
    secsilm  
       2020-03-21 11:58:03 +08:00 via Android
    偏向日志,有目标性,后续还能持续输出,出问题好定位。但是感觉控制好日志粒度不是容易的事。https://i.loli.net/2020/03/21/HNlO9WTFKgZGido.png
    mikicomo
        9
    mikicomo  
       2020-03-21 11:58:21 +08:00
    能用日志不用 debug
    hallDrawnel
        10
    hallDrawnel  
       2020-03-21 12:02:58 +08:00
    debugger 感觉在刷题的时候还有用,其他地方确实是日志很好用。尤其是现在各种操作都是异步或者并发的,靠断点都没法复现。
    littlewing
        11
    littlewing  
       2020-03-21 12:26:20 +08:00 via iPhone
    必须是日志啊,debug 是在看完日志后仍然无法确定问题时就用
    guyeu
        12
    guyeu  
       2020-03-21 12:28:50 +08:00
    断点调试是很效率很高的 debug 方式,相当于在每一行代码执行之后都打日志。

    日志本身也并不能让系统更易于维护,大量的日志反而会拖慢系统的性能。在关键结点准确清晰地打出易于追踪的日志是难度很高的事情,到最后往往是一百行代码几十行日志。
    raphael008
        13
    raphael008  
       2020-03-21 12:31:48 +08:00
    现在都习惯去 splunk 看发生了啥啊。。。
    qiyuey
        14
    qiyuey  
       2020-03-21 12:36:53 +08:00
    肯定是日志
    sleepm
        15
    sleepm  
       2020-03-21 12:41:08 +08:00 via Android
    打日志是最简单的 debug
    ericgui
        16
    ericgui  
       2020-03-21 12:44:31 +08:00
    好消息,因为我都不会用断点,学过好几次,感觉没什么卵用,也不好用
    ybw
        17
    ybw  
       2020-03-21 12:46:42 +08:00 via Android
    @guyeu 每一行都停下,也是缺点。
    Vegetable
        18
    Vegetable  
       2020-03-21 12:46:58 +08:00
    debugger 真的用的很少,局限性太大了,换句话说,debugger 能做的事情,日志其实都能做
    guyeu
        19
    guyeu  
       2020-03-21 12:51:53 +08:00
    @ybw #17 可以自己决定在哪一行停下的。
    ybw
        20
    ybw  
       2020-03-21 12:54:39 +08:00 via Android
    @guyeu 事实是,你不能。因为你不知道问题出在哪一行,所以你要一行行去确定。
    mywaiting
        21
    mywaiting  
       2020-03-21 12:58:01 +08:00
    debugger 的方式也仅限于本地调试的时候用一下,线上产品,那必须是日志的方式

    完善的 log 记录分析跟踪,是个好习惯,即使小项目也是可以接入 sentry 这样的异常记录工具的
    guyeu
        22
    guyeu  
       2020-03-21 12:58:26 +08:00
    @ybw #20 事实是,你可以。你总能把问题定位到一个范围,然后在几十行代码里跳转。
    ybw
        23
    ybw  
       2020-03-21 12:59:52 +08:00 via Android
    @guyeu 所以你要一行行去停下来啊。
    ybw
        24
    ybw  
       2020-03-21 13:00:53 +08:00 via Android
    @guyeu 另一个事实是,比如程序崩溃了,崩溃点和问题所在点,会差的很远。尤其是多线程。
    guyeu
        25
    guyeu  
       2020-03-21 13:01:33 +08:00
    @ybw #24 所以没必要一行行停下来啊。。停在你认为可能出问题的代码就行了啊。。。
    guyeu
        26
    guyeu  
       2020-03-21 13:02:10 +08:00
    @ybw #24 另一个事实是,如果程序崩溃了,崩溃点和问题所在点也不见得有日志,因为日志系统是程序的一部分。
    felixlong
        27
    felixlong  
       2020-03-21 13:03:45 +08:00
    基本上自己熟悉的 code 用 log 比较方便。debugger 主要用来调不熟悉的 code.
    mitu9527
        28
    mitu9527  
       2020-03-21 13:04:23 +08:00
    生产只能是日志,开发时主要是通过日志定位问题所在的位置,然后再通过 debugger 调试,看看具体发生了什么,才会引发问题。
    ybw
        29
    ybw  
       2020-03-21 13:04:55 +08:00 via Android
    @guyeu 真的行吗?要是我猜错了呢?
    ybw
        30
    ybw  
       2020-03-21 13:06:23 +08:00 via Android
    @guyeu 我已经不理解你试图表达什么了? 一行行逐行调试,跳进跳出函数,不是常规流程吗?
    guyeu
        31
    guyeu  
       2020-03-21 13:07:24 +08:00
    @ybw #29 真的行,用自己的脑子重新思考一下,结合日志,你可以的。
    ybw
        32
    ybw  
       2020-03-21 13:09:23 +08:00 via Android
    @guyeu 抱歉了,多年的开发经验告诉我,我没这个能力。你一定是大多数时候就"一猜就准"吧,真羡慕你的调试经历。
    also24
        33
    also24  
       2020-03-21 13:13:01 +08:00   ❤️ 1
    @guyeu #26
    你可能理解的过于偏激了,楼主的标题其实有个关键词是 “XX 为主”

    以 debugger 为主的处理思路,更多的适用于 “一次性” 故障,是为了解决 bug 而做的。

    以日志为主的思路是一整套动作,要掌握好日志的输出粒度,以及日志的格式化方便查找等。
    之所以推荐日志为主的处理思路,则是因为它具有更好的 “整体性”,能在解决 bug 之外带来更多额外的收益。


    至于是否一定能够 “快速” 定位问题,其实影响因素很多:
    对代码熟悉的人,也许能够更精确的下断点;但也许遇到多线程的问题就会比较难受。
    日志写的详细的人,也许能够只看日志就确定问题;但也许遇到日志盲区就不得不走调试。

    这其实并不矛盾,以 xx 方法为主只是一种倾向,而不是完全摒弃另一方。
    Mohanson
        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 工具也将逐渐退出(前提成立的情况下)
    taowen
        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 的时候都需要这样的东西。这种上下文关联的事情不是纯技术手段能底层解决的,要侵入到业务代码的编写方式里。
    vindurriel
        36
    vindurriel  
       2020-03-21 14:12:48 +08:00 via iPhone
    能打断点的 debugger 侵入性太大 日志则可以控制输出级别和粒度 一种方案同时应对开发 测试 生产环境的需要 对正常逻辑的影响更可控
    holdmybeer
        37
    holdmybeer  
       2020-03-21 14:21:54 +08:00
    @wuhx #4

    哈哈哈,看到了那句 'To me, it's not a bug, it's a feature.'
    winterfell30
        38
    winterfell30  
       2020-03-21 14:30:10 +08:00
    我有另一个疑问,我从大学开始我找 bug 就是二分法打日志来找的,一直感觉用 debug 的更专业,但是因为我 debug 效率一直不如打日志高所以一直也没有动力学怎么更高效的 debug,有什么打日志做不了但是很适合用 debug 的例子可以说说吗
    also24
        39
    also24  
       2020-03-21 14:51:22 +08:00   ❤️ 1
    @winterfell30 #38
    你用二分法打日志的过程,就不如直接使用 debugger, 用 debugger 大概率只需要跑一次……
    以及,你的二分法的日志点,其实就是你心目中使用 debugger 的断点位置。

    在我的理解,你这样其实是在使用打日志的方式来进行 debugger 的工作。

    如我前面所说,日志查 bug 是一个系统化的工程,不是在遇到 bug 的时候才开始的,而是从开发阶段就已经 “留一手”。
    也正是因此,断点只能用一次,日志点可以保留,后续查用。
    fancy2020
        40
    fancy2020  
       2020-03-21 15:04:12 +08:00
    基本没太用过调试工具,都是加日志查问题。
    现在做前端了,还是靠 log
    kayv
        41
    kayv  
       2020-03-21 15:47:06 +08:00
    我是靠单测+log 。写代码之前先想清楚,service/logic 的函数基本都有单测,要调试就加日志运行单测。
    zhuangzhuang1988
        42
    zhuangzhuang1988  
       2020-03-21 15:51:52 +08:00
    @wuhx
    相对的 windows 内核 从开始就支持 debuger
    基本 windbg 和 nt 内核时同步进行的.
    ifsclimbing
        43
    ifsclimbing  
       2020-03-21 15:53:39 +08:00 via iPhone
    本地开发环境还可以断点,Prod 就难了,还是日志方便
    guyeu
        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,属于疑难杂症,需要结合各种手段。

    而你所谓`日志为主的处理思路`,对真正的疑难杂症毫无作用,所谓的`整体性`,是以程序运行的效率为代价的,`更多额外的收益`只是臆想,任何应用广泛的软件设施,对日志的使用都是很克制的。
    hantsy
        45
    hantsy  
       2020-03-21 15:58:31 +08:00
    几乎没用过 Debug 。
    1,实在不会用 IDE 的 Debug 功能
    2,一般项目都要求写测试,一般的问题都是可以在测试中消除。
    3,必要的跟踪日志不可缺少,项目一开始就会有要求
    p1gd0g
        46
    p1gd0g  
       2020-03-21 15:59:37 +08:00
    debug 是啥,单元测试吗?
    俺司都是用日志来查问题,为了方便,昨天俺刚把 pkg/errors 塞进项目里。
    NeinChn
        47
    NeinChn  
       2020-03-21 16:22:21 +08:00
    加日志只能解决一小部分问题
    如果你用了别人的库,你还能加日志?中间过程就不 debug 了么,只看输入和输出有时候又解决不了问题
    要是只会做黑盒调用那出问题就。。。
    crayygy
        48
    crayygy  
       2020-03-21 16:40:19 +08:00 via iPhone
    offline 的情况下,log 是唯一的 debug 工具
    learnshare
        49
    learnshare  
       2020-03-21 16:40:34 +08:00
    日志比较方便,也很直观,但要求有代码,而且对代码十分了解
    Debug 一般针对摸不透的问题,逐步查找分析
    wangxiaoaer
        50
    wangxiaoaer  
       2020-03-21 16:53:12 +08:00 via Android
    Bug 分很多种,业务逻辑的通过日志排查是个好办法,但如果是计算问题,难道还很有对象都重写 tostring 输出吗?这种情况明显 debug 更直观
    zhuangzhuang1988
        51
    zhuangzhuang1988  
       2020-03-21 17:21:38 +08:00 via Android   ❤️ 1
    现在流行,反智么
    yingo
        52
    yingo  
       2020-03-21 18:12:48 +08:00
    那调试日志程序的 bug,该怎么办....
    souths
        53
    souths  
       2020-03-21 18:15:08 +08:00
    并不冲突
    liprais
        54
    liprais  
       2020-03-21 18:24:15 +08:00
    不打日志有 bug 都发现不了
    nicebird
        55
    nicebird  
       2020-03-21 19:45:38 +08:00
    做后端分布式系统的,没见过靠调试能定位好问题的。
    laminux29
        56
    laminux29  
       2020-03-21 20:35:08 +08:00
    所以那个人到了 40+也只能呆在跳动字节的一线而已,因为他根本没考虑以下问题:

    1.如果程序崩溃时,连日志组件也没能记录下,怎么办?

    2.如果需要行级别的日志,才能找到问题,那前期开发时,如何进行日志输出?每一行代码就写个 Log()?

    3.如果需要进行调试的地方,数据量极大,导致如果全部日志,会成为性能瓶颈。如果不全部日志,输出粒度又会造成关键信息不足,那怎么办?


    真正的高手,会根据情况,来判断到底如何调试,通常是日志与调试进行两者结合。而不是拍脑袋觉得某种一定更好。
    yunlzheng
        57
    yunlzheng  
       2020-03-21 20:35:53 +08:00   ❤️ 1
    个人习惯是如果线上有问题,会尽量通过单元测试的方式在本地复现。 既可以保证本地效率,写好的测试还可以避免问题的出现。
    hoyixi
        58
    hoyixi  
       2020-03-21 21:16:33 +08:00
    这是常识。

    某些系统架构下,或者产品自身特点,很多 bug 是客户那里操作运行产生,比如客户跨国、客户自己部署你的产品,你作为开发,怎么 debug ?标准方式就是除了详细描述 bug,还要让客户把运行日志发给你分析。

    为啥很多软件开发基本流程和基本常识,现在的从业者都不知道? 因为自从互联网泡沫以来,很多 IT 从业者,说好听点,在互联网公司上班,实质都在软件作坊里干活罢了。 没流程,烂管理,全靠加班。
    zhuangzhuang1988
        59
    zhuangzhuang1988  
       2020-03-21 21:42:53 +08:00
    @hoyixi c++, c#的话
    windows 上的 dump 文件了解下
    可以记录 进程里的各种 dll,
    当前系统各种信息, 堆栈信息, 日志文件只能看到 when, 不能知道 why.
    而且 在复杂的客户环境下 exe 被各种注入了.
    hoyixi
        60
    hoyixi  
       2020-03-21 21:49:11 +08:00
    @zhuangzhuang1988 #59
    我知道可以利用 dump 来 debug,但是并不是一定会 dump,定位逻辑错误还是日志更便捷。
    zhuangzhuang1988
        61
    zhuangzhuang1988  
       2020-03-21 22:47:17 +08:00
    @hoyixi 其实本身不是 非 A 即 B 得问题, 我代码里都用, 特别是动态调试别人的框架时候, 肯定上 debugger.
    同意的人很多扯 , 静态语言 和 单元测试 都不是一个维度的, 比较.
    liango
        62
    liango  
       2020-03-21 22:59:38 +08:00
    哪个更快定位就用哪个
    Inn0Vat10n
        63
    Inn0Vat10n  
       2020-03-21 23:56:05 +08:00
    哪个方便用哪个,哪个能用用哪个,这么简单的问题还用的着争吗
    123444a
        64
    123444a  
       2020-03-22 00:56:08 +08:00 via Android
    coredump,很简单的
    mingl0280
        65
    mingl0280  
       2020-03-22 04:04:47 +08:00   ❤️ 1
    @hoyixi 还是被日志惯坏了,有时候(比方说驱动引起莫名其妙蓝屏、内核搞事什么的)你没法看日志的。那种情况只能挂调试器上去 debug,不然你看到的东西是好几个线程输出的不相关内容,根本没法用。
    mingl0280
        66
    mingl0280  
       2020-03-22 04:09:22 +08:00   ❤️ 1
    @hoyixi 正常人根本不会说只用某一种 debug 手段,挂调试器能解决日志有时候打不出来的问题,看日志有时候能看出调试器挂不了的问题,都是手段而已,怎么就这个高那个低了?
    xuanbg
        67
    xuanbg  
       2020-03-22 09:15:08 +08:00
    通过日志直接定位到关键点,如果发现代码明显写错了或者不完善,就直接改。如果发现结果和预期不符,但貌似代码逻辑没错,就打断点看看实际的数据是否符合预期。数据不符合预期肯定是别的地方写错了导致的。
    hoyixi
        68
    hoyixi  
       2020-03-22 13:03:11 +08:00
    @mingl0280
    不好意思,我有说过 高低 吗,我也说了“某些”,你自己也提了 “有时候”

    我批的是有些人无打日志的习惯,甚至根本不知道日志跟踪定位。
    pkookp8
        69
    pkookp8  
       2020-03-22 13:15:28 +08:00 via Android
    两者结合吧
    需要的关键信息加日志
    写的功能加单元测试或调试命令

    出现问题可以通过日志分析
    辅助调试命令观察现象,辅助单元测试快速调试
    具体也和环境,系统,设计框架,历史遗留的代码有关
    这些事也没有绝对的好与坏,能有一定理由,符合公司的代码习惯即可
    aguesuka
        70
    aguesuka  
       2020-03-22 21:26:39 +08:00
    长者表示他开发过程基本上很少 debug,逻辑异常都是通过运行日志来定位。

    就我个人在调试代码的时候,一般用 assert+debugger,生产环境用日志。idea 可以打 AssertionError 的断点,assert false 就相当于进入断点,就我而言效果比日志强太多
    laball
        71
    laball  
       2020-03-23 00:22:11 +08:00
    Debug 效率确实比较低!而且系统越大越复杂,效率越低;
    有的时候一次 Debug 需要的条件非常复杂,自己构造,还不如打日志跑一遍来得快,如果代码对于单元测试支持的好,会得到一些改善;
    另外就是多线程的 Bug,调试可能没有打日志靠谱;

    40+的一线开发,应该是什么都见过的主,而且,应该都是处理大型系统什么的,对他来说,日志,确实是一把利剑;
    发现问题 ——> 日志打点 ——> 重现一遍 ——> 直接修复,或者只调试一小段代码;
    对他来说,效率是第一位的;
    nmap
        72
    nmap  
       2020-03-23 10:16:08 +08:00
    这不是常识么,你见过真正的生产环境么?能让你用 gdb 上去调?
    Aresxue
        73
    Aresxue  
       2020-03-23 10:35:19 +08:00
    生产远程 debug 模式又不能开, 出了问题当然主要就是靠日志。 但日志要做好解耦, 不然是一件十分消耗性能的事情。另外日志的输出是交错的, 有时候可能会比较难以区分,因此在日志之外 JVM 的监控工具也应该有效利用上, 比如 pinpoint 和 arthas
    LouisGuo
        74
    LouisGuo  
       2020-03-23 13:17:12 +08:00
    大佬的思路还是很清晰的
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   970 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 35ms · UTC 20:22 · PVG 04:22 · LAX 12:22 · JFK 15:22
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.