golang 日志记录 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
nobject
V2EX    Go 编程语言

golang 日志记录

  •  
  •   nobject 2024-05-07 11:23:41 +08:00 2447 次点击
    这是一个创建于 529 天前的主题,其中的信息可能已经有所发展或是发生改变。

    对于golang大家一般是怎么做错误日志记录的。

    如果我的代码层级是controller->service->repo层,在repo层的错误一直往上抛,抛到最外层, 我的想法是用中间件errorMiddleware统一处理error并记录错误日志.

    但有以下几个问题:

    1. 使用zap内置的错误zap.Error(err), err的堆栈信息如果原始err不记录,会直接丢失。
    2. 使用pkg/errors记录stack或者fmt.Errorf去记录调用/逻辑栈,但如果我在错误处记录一些现场数据,用起来相比zap.Field难用, 比如是个map结构体,里面还带指针什么,用%#v之类的也不能设置进去。
    3. 直接在errorlogger记录, 那每一层的err都会记录,导致重复logger

    不知道大家有什么好的方式去处理

    19 条回复    2024-05-09 15:54:43 +08:00
    dreampuf
        1
    dreampuf  
       2024-05-07 11:34:40 +08:00
    1. 不受控的 err 无法强制要求 traceback
    2. https://github.com/davecgh/go-spew
    3. 只在最外层 logger ,中间函数均使用 `fmt.Errorf`

    相比成本高昂的 traceback ,我通常选择一个唯一的 ttl
    hailaz
        2
    hailaz  
       2024-05-07 11:46:40 +08:00
    me1onsoda
        3
    me1onsoda  
       2024-05-07 12:17:50 +08:00   1
    怎么这么 Java 味
    kuanat
        4
    kuanat  
       2024-05-07 13:11:39 +08:00
    我不确定我的做法是不是 idiomatic 只是简单描述一下我的思路。毕竟 slog 进标准库也没多久,看 api 也是受 zap 影响很大。

    大的逻辑方面我比较倾向于全局只有一个唯一 logger ,中间调用过程只传递。另外我习惯把业务层面的日志和功能实现层面的日志分开,然后两者用不同的方式来处理。

    业务层面的日志我倾向于用格式化的字符串:一方面它是给运维用的,需要一眼看明白在哪个环节出了问题,但并不需要知道出问题的细节;另一方面这类日志要进日志服务器做后续统计等功能,需要方便处理。

    对应的就是你的描述里 controller->service->repo 这个部分,我会用 errors 传递字符串,每个环节用 errorf 来 wrap 上一个环节的错误,起到简单的 stack trace 的功能。这里一般不建议用 runtime 来获取完整的 stack trace ,主要是性能开销的问题。

    包或者实现层面的日志,一般是给开发者方便调试用的,比如看到底是什么入参触发了什么样的边界条件导致出错。这个信息在开发和测试环节比较有用,实际线上是相对冗余的信息。

    日志记录这个信息我用的是自定义的 context ,因为标准库里的 context 实际上只有下文没有上文。可以看这个帖子 https://s.v2ex.com/t/1012453 我的回复。

    用 context 的话可以自定义数据结构,能够比较好处理那些复杂的结构体,也就是你说的第二条里的麻烦。

    对于 context 信息的记录就没有必要走业务层面的 logger 了。对于不太敏感又注重性能的业务,我的处理是加一个开关,当线上出现的问题无法复现的时候,开启开关再记录完整的 runtime stack trace 信息。对于相对敏感的业务,会单独用一个 logger 导出到日志服务器单独的表中,使用 traceId 对业务层面的日志和实现层面的日志做个关联。业务层面的日志要保留很久,但功能层面的日志一般三个月就可以清理了。
    nobject
        5
    nobject  
    OP
       2024-05-07 13:11:43 +08:00
    @me1onsoda 这跟 java 与 go 好像没任何关系吧?你在业务处理的时候不记日志?既然记了日志,就会有碰到相关问题吧,函数调用链长,我的 err 的日志记在哪里合适
    nobject
        6
    nobject  
    OP
       2024-05-07 13:12:10 +08:00
    @hailaz 谢谢啦,一会去看看
    nobject
        7
    nobject  
    OP
       2024-05-07 13:24:29 +08:00
    @dreampuf 嗯,谢谢了,我看看第二个库满足不满足我的需求。我也觉得记录 fmt.Errorf 这种逻辑栈记录下来好像也够了
    nobject
        8
    nobject  
    OP
       2024-05-07 13:27:25 +08:00
    @kuanat 非常感谢,感觉给我了很大的启发。特别是使用 ctx 的方式去记录复杂的一些数据结构,感觉是个不错的思路
    zzhaolei
        9
    zzhaolei  
       2024-05-07 18:32:24 +08:00
    不是日志的问题,而是 controller->service->repo 层 一看就是 Java 转过来的。

    楼主你就说你是不是 Java 转的?纯好奇
    nobject
        10
    nobject  
    OP
       2024-05-07 19:46:11 +08:00   1
    @zzhaolei 这和 java 有啥关系呢,即使 php 古早的框架也有 controller 与 model 层呢。为啥重点放这里,难道你们代码都不需要分层?无论是 controller ,service 还是 repo ,model ,这只是个分层的名词而已。如果你们一点也不分层当我没说咯
    dilu
        11
    dilu  
       2024-05-07 20:24:11 +08:00
    我的习惯是 repo 这一层打印日志,上面零星会打印一些关键日志。
    yuhuai
        13
    yuhuai  
       2024-05-08 10:11:43 +08:00
    他们好奇楼主是 java 转过来的是因为 mvc+仓储,而 go 的框架大多是[注册路由和中间件-> 路由绑定函数 -> 函数内操作 dal 和 model]一般是这样
    nobject
        14
    nobject  
    OP
       2024-05-08 10:32:37 +08:00
    @yuhuai 事实上,现在其他语言任何的成熟的框架都很少把业务逻辑层与数据访问层放在同一层或只整合成一层,这不仅仅是 java,php,c#主流的框架也一样,这是写业务代码,不是写中间件或一些基础组件啊。ps:我以前是写 php 的,并不写 java 的
    nobject
        15
    nobject  
    OP
       2024-05-08 10:37:29 +08:00
    @zzhaolei 不太懂怎么按代码量来分层的,如果是按代码量,我宁愿不分层,多建个文件写业务就行了。如果我一个业务,写着写着本来只有 1000 行,我再加个接口就变 1200 行了,我就开始分层了?那这个分层过程还要做抽离呢,还是仅仅把新增的接口业务放在另一层?
    zzhaolei
        16
    zzhaolei  
       2024-05-08 10:56:39 +08:00
    @nobject 比如我有 a 、b 两个类型,如果围绕他俩的函数或其他方法的代码量很少,我就不会拆,大一点了就会拆成两个文件分别存。我是比较讨厌提前优化和过度优化的。go 本身也是不提倡严格分层的,而是提倡根据你的代码来
    nobject
        17
    nobject  
    OP
       2024-05-08 11:20:58 +08:00
    @zzhaolei 对于三层架构,我并不觉得这是多过度优化,过度优化的是复杂的设计模式,依赖注入控制反转那些。三层架构在写业务代码的时候是有优势的,我觉得这无关语言。而且这也不是我想探讨的主题
    zzhaolei
        18
    zzhaolei  
       2024-05-08 11:42:07 +08:00
    @nobject 嗯,你用起来就完事儿了,反正咱俩又不一起写代码
    xiaozirun
        19
    xiaozirun  
       2024-05-09 15:54:43 +08:00
    关于记录一些数据,需要像 php 封装异常一样,去实现一些错误类型,例如:

    还有一些指针想获得对应值可以使用反射
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     900 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 22:14 PVG 06:14 LAX 15:14 JFK 18:14
    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