对于golang
大家一般是怎么做错误日志记录的。
如果我的代码层级是controller->service->repo
层,在repo
层的错误一直往上抛,抛到最外层, 我的想法是用中间件errorMiddleware
统一处理error
并记录错误日志.
但有以下几个问题:
zap
内置的错误zap.Error(err)
, err
的堆栈信息如果原始err
不记录,会直接丢失。pkg/errors
记录stack
或者fmt.Errorf
去记录调用/逻辑栈,但如果我在错误处记录一些现场数据,用起来相比zap.Field
难用,
比如是个map
结构体,里面还带指针什么,用%#v
之类的也不能设置进去。error
处logger
记录, 那每一层的err
都会记录,导致重复logger
。不知道大家有什么好的方式去处理
1
dreampuf 234 天前
1. 不受控的 err 无法强制要求 traceback
2. https://github.com/davecgh/go-spew 3. 只在最外层 logger ,中间函数均使用 `fmt.Errorf` 相比成本高昂的 traceback ,我通常选择一个唯一的 ttl |
2
hailaz 234 天前
|
3
me1onsoda 234 天前 1
怎么这么 Java 味
|
4
kuanat 234 天前
我不确定我的做法是不是 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 对业务层面的日志和实现层面的日志做个关联。业务层面的日志要保留很久,但功能层面的日志一般三个月就可以清理了。 |
5
nobject OP @me1onsoda 这跟 java 与 go 好像没任何关系吧?你在业务处理的时候不记日志?既然记了日志,就会有碰到相关问题吧,函数调用链长,我的 err 的日志记在哪里合适
|
9
zzhaolei 233 天前
不是日志的问题,而是 controller->service->repo 层 一看就是 Java 转过来的。
楼主你就说你是不是 Java 转的?纯好奇 |
10
nobject OP @zzhaolei 这和 java 有啥关系呢,即使 php 古早的框架也有 controller 与 model 层呢。为啥重点放这里,难道你们代码都不需要分层?无论是 controller ,service 还是 repo ,model ,这只是个分层的名词而已。如果你们一点也不分层当我没说咯
|
11
dilu 233 天前
我的习惯是 repo 这一层打印日志,上面零星会打印一些关键日志。
|
13
yuhuai 233 天前
他们好奇楼主是 java 转过来的是因为 mvc+仓储,而 go 的框架大多是[注册路由和中间件-> 路由绑定函数 -> 函数内操作 dal 和 model]一般是这样
|
14
nobject OP @yuhuai 事实上,现在其他语言任何的成熟的框架都很少把业务逻辑层与数据访问层放在同一层或只整合成一层,这不仅仅是 java,php,c#主流的框架也一样,这是写业务代码,不是写中间件或一些基础组件啊。ps:我以前是写 php 的,并不写 java 的
|
15
nobject OP @zzhaolei 不太懂怎么按代码量来分层的,如果是按代码量,我宁愿不分层,多建个文件写业务就行了。如果我一个业务,写着写着本来只有 1000 行,我再加个接口就变 1200 行了,我就开始分层了?那这个分层过程还要做抽离呢,还是仅仅把新增的接口业务放在另一层?
|
16
zzhaolei 233 天前
@nobject 比如我有 a 、b 两个类型,如果围绕他俩的函数或其他方法的代码量很少,我就不会拆,大一点了就会拆成两个文件分别存。我是比较讨厌提前优化和过度优化的。go 本身也是不提倡严格分层的,而是提倡根据你的代码来
|
17
nobject OP @zzhaolei 对于三层架构,我并不觉得这是多过度优化,过度优化的是复杂的设计模式,依赖注入控制反转那些。三层架构在写业务代码的时候是有优势的,我觉得这无关语言。而且这也不是我想探讨的主题
|
19
xiaozirun 232 天前
|