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

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

  •  1
     
  •   mitiskysean · 68 天前 · 4484 次点击
    这是一个创建于 68 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

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

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

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

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

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

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


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

    这其实并不矛盾,以 xx 方法为主只是一种倾向,而不是完全摒弃另一方。
    Mohanson
        34
    Mohanson   68 天前 via Android   ❤️ 1
    大部分 CPU 在设计的时候都有个 debug 模块,它允许用户态程序完全接管 CPU 的运行,甚至允许运行过程中修改寄存器内的值,也就是全部 debug 工具的能力来源。

    但是 CPU 中 debug 模块的复杂程度甚至超过了 CPU 本身,非常不划算。

    所以后来提出了 tracing 模式,也可以理解为 CPU 层面下的 Log 模块,只负责记录。不过这东西造价高昂,cpu 每秒能产生海量数据,要能全部记录,压缩和存储。

    不过从大趋势上来讲,tracing 与 debug 两方的角逐我认为 tracing 未来可能会占优,现有的 debugger 工具也将逐渐退出(前提成立的情况下)
    taowen
        35
    taowen   68 天前
    业内比较先进的有 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 的概念 做 tracing 的时候都需要这样的东西。这种上下文关联的事情不是纯技术手段能底层解决的,要侵入到业务代码的编写方式里。
    vindurriel
        36
    vindurriel   68 天前 via iPhone
    能打断点的 debugger 侵入性太大 日志则可以控制输出级别和粒度 一种方案同时应对开发 测试 生产环境的需要 对正常逻辑的影响更可控
    holdmybeer
        37
    holdmybeer   68 天前
    @wuhx #4

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

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

    如我前面所说,日志查 bug 是一个系统化的工程,不是在遇到 bug 的时候才开始的,而是从开发阶段就已经 “留一手”。
    也正是因此,断点只能用一次,日志点可以保留,后续查用。
    fanchangyong
        40
    fanchangyong   68 天前
    基本没太用过调试工具,都是加日志查问题。
    现在做前端了,还是靠 log
    kayv
        41
    kayv   68 天前
    我是靠单测+log 。写代码之前先想清楚,service/logic 的函数基本都有单测,要调试就加日志运行单测。
    zhuangzhuang1988
        42
    zhuangzhuang1988   68 天前
    @wuhx
    相对的 windows 内核 从开始就支持 debuger
    基本 windbg 和 nt 内核时同步进行的.
    ifsclimbing
        43
    ifsclimbing   68 天前 via iPhone
    本地开发环境还可以断点,Prod 就难了,还是日志方便
    guyeu
        44
    guyeu   68 天前   ❤️ 1
    @also24 #33 我回顾了一下我的措辞,我觉得还是比较准确和中肯的。

    楼主原话是`改 bug 的方式`,已经发现了有 bug,甚至开始尝试定位,这种情况下断点调试的效率很高。

    我从没有说断点调试是优于日志的 debug 方式,只是在改 bug 的时候效率更高。

    楼上有很多人认为日志有助于提高系统的可维护性,很大程度上日志有变量监视器和注释的作用,我也并没有否认,我只是说,放弃使用调试器,想要单凭日志来 debug,甚至追求那些所谓的`额外收益`,是一件南辕北辙的事情。

    我看到有位仁兄 @ybw 觉得调试要一行一行看,觉得很难定位到一个问题存在的范围,可能代表了某些人的想法。可是能知道在那个地方添加日志,怎么就想不起来在那个地方下断点呢?断点相当于一个运行期间可以随时修改,完整打印所有变量内容甚至堆栈细节的日志,所以说 debugger 的效率比查日志高。

    而你所说的,基本上是废话,每个人都知道日志不可或缺,甚至在有些场景是唯一的方案。对代码熟悉的人,可以更精确的下断点,但只看日志就确定问题的人,一定熟悉代码。

    查 bug 的常规思路,知道某个地方有 bug,然后开始浏览日志试图定位问题,可能 40%的 bug 就能看出来了。看不到问题,开始复现 bug,剩余 90%以上的 bug 都是可以复现的,对可以复现的 bug 而言,断点调试是效率最高的调试方式了,剩下的 bug,属于疑难杂症,需要结合各种手段。

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

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

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

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


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

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

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

    我批的是有些人无打日志的习惯,甚至根本不知道日志跟踪定位。
    pkookp8
        69
    pkookp8   67 天前 via Android
    两者结合吧
    需要的关键信息加日志
    写的功能加单元测试或调试命令

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

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

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