请教下日志打印的最佳实践 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
xrlin
V2EX    程序员

请教下日志打印的最佳实践

  •  
  •   xrlin 2018-05-24 01:17:04 +08:00 5000 次点击
    这是一个创建于 2751 天前的主题,其中的信息可能已经有所发展或是发生改变。

    无论是线上还是开发环境,log 打印对排查 bug 都很有帮助,但是这就遇到个问题,如果要打印详细的 log 就会侵入到方法的实现,特别是如果调用链很常的时候,比如

    controller -> validator -> serviceA -> serviceB -> model

    这时如果要打印出详细的日志就必须在 controller、service、model .... 中都要加上打印语句,这样显得很麻烦,有没有更好的实现方式?虽然可以用类似 AOP 的方法,但是如果要精细一些还是要在方法实现中主动调用。

    15 条回复    2018-12-11 03:56:17 +08:00
    kslr
        1
    kslr  
       2018-05-24 04:50:52 +08:00 via Android
    发出事件监听呢
    billwsy
        2
    billwsy  
       2018-05-24 05:43:09 +08:00 via iPhone
    glog https://github.com/google/glog 可以在某些时候打印 stack trace
    gaoyulong
        3
    gaoyulong  
       2018-05-24 07:19:41 +08:00
    mark
    ppyybb
        4
    ppyybb  
       2018-05-24 08:43:37 +08:00 via iPhone
    我在 rails 里面的简易做法是:
    抛出异常
    打出到 controller 层为止的 stack trace
    打出需要的当前环境的状态
    严重的发短信报警

    另外,你 log 的目的是针对可能出现的异常情况做记录,方便出问题的时候查找。
    还是已经发现比较奇怪的现象,但是找不到原因,准备打 log 排查?如果是后者,log 只是临时的,处理好有问题的调用链上的 log,专门写一个 logger 类来打出一整条链上的状态,事后清理即可
    ksupertu
        5
    ksupertu  
       2018-05-24 09:18:36 +08:00
    sentry 了解一下
    jorneyr
        6
    jorneyr  
       2018-05-24 09:54:19 +08:00
    很多日志都是根据业务逻辑进行打印,就必须侵入到不同层的代码里。AOP 只能打印一些通用的日志,例如访问方法的顺序,参数,执行的时间等。
        7
    hilow  
       2018-05-24 09:56:37 +08:00 via Android
    在每个函数中返回 自定义的 *exerror.Error 类型变量。
    此 err 变量中包含错误的上下文信息,如 userId, zerror 和 [email protected]:108 这样的 zcallstack
    在调用函数时,如果返回非 nil 的 err,就能打印日志,日志中包含所有上下文信息。
    实际业务中在不同代码中调用相同函数,可能出现同样错误,都返回了 err,这时能根据要求灵活决定是否打印出日志。
    日志打印格式推荐“结构化日志信息”,比如`level=info msg="Recv RestRequest"` ,主要优点是,方便使用 grep awk 等工具过滤日志,详情参考[logrus]( https://github.com/sirupsen/logrus)
    另外每行日志中增加一个`ReqId`,此 ID 全局唯一,用于关联同一会议的 ID

    ```log
    cat log/server.log | grep ExtHwyApi_QLlUyYd9To
    time="2018-05-24T09:42:02+08:00" level=info msg="Recv RestRequest" ReqHeader=map[Date:[2018-03-29T09:32:35+08:00] Accept:[application/json]] ReqId="ExtHwyApi_QLlUyYd9To" Url="/ext/api/product"
    time="2018-05-24T09:42:02+08:00" level=warning msg="AuthTimeOut Disable" AuthTimeOutSecOnds=0 ReqId="ExtHwyApi_QLlUyYd9To"
    time="2018-05-24T09:42:03+08:00" level=error msg="RestDispatch Fail" ReqBody="{"seq":"ExtHwyApi_QLlUyYd9To","var":1}}" ReqId="ExtHwyApi_QLlUyYd9To" ResBody="{"Code":"812018","Msg":"发送失败"}" Tag="out_ccm" zcallstack="[email protected]:43 Handler@ext_hwy_api.go:44" zerror="dial tcp 127.0.0.1:5010: connectex: No connection could be made because the target machine actively refused it."
    ```
    xrlin
        8
    xrlin  
    OP
       2018-05-24 11:40:15 +08:00
    @ppyybb 异常的话一般都会记录下,就是一些问题追踪比较难以排查,特别是遇到一些不常遇到的问题,这时如果没有记录下日志不好分析。
    xrlin
        9
    xrlin  
    OP
       2018-05-24 11:46:39 +08:00
    @ppyybb 不过再想想,遇到不是异常而是某些逻辑分支的情况,即便的打上 log,也是设定为 info,在线上也不会启用,遇到问题出现时才启用记录。
    lolizeppelin
        10
    lolizeppelin  
       2018-05-24 12:17:53 +08:00 via Android
    Python 可以看看 openstack 的做法

    配置里可以控制每个模块代码块的日志等级
    EmdeBoas
        11
    EmdeBoas  
       2018-05-24 12:42:28 +08:00
    平时都是无脑用 CAT...没想过这个问题..回头好好看看 CAT 里面怎么实现的
    ywind
        12
    ywind  
       2018-05-24 13:15:31 +08:00 via Android
    m
    zj299792458
        13
    zj299792458  
       2018-05-24 13:23:29 +08:00 via iPhone
    我想问问如果日志过多,比如播放视频的每一帧信息都记入日志,微秒级别记录,直接往文件操作符里写会阻塞正常逻辑么?还是一般自己实现 cache ?
    yhding
        14
    yhding  
       2018-05-24 13:35:08 +08:00
    我一直有个想法但是没有具体实现,就是在打印日志的时候写的详细一些,
    比如: 文件路径 + 行数 + 想输出的信息.
    大佬看如何啊
    lxml
        15
    lxml  
       2018-12-11 03:56:17 +08:00
    @yhding #14 调用 runtime 包就行了,缺点是性能差成狗
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5478 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 38ms UTC 03:19 PVG 11:19 LAX 19:19 JFK 22:19
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86