来源:cyningsun.github.io/09-27-2019/…html
本文受 Nate Finch started on the Go Forum 的一个话题启发。本文专一于 Go,可是若是你能看透,我认为这里提出的想法是普遍适用的。git
Go 的 log package 没有日志级别,你必须本身手动添加 debug、info、warn 和 error 等前缀。另外,Go 的 日志类型没法以包为基础打开或者关闭这些不一样级别。经过比较,让咱们看一些第三方的替代品:程序员
Google 的 glog 提供如下级别:github
看看另一个库, 咱们为 Juju 开发的 loggo,提供如下级别:golang
Loggo 还提供了根据每一个包调整日志的详细程度的功能。app
所以,以上两个示例显然受到其余语言的其余日志库的影响。实际上,它们的命令行能够追溯到 syslog(3),甚至更早。我认为他们是错的。函数
我站相反的立场。我认为_全部_日志库都很差,由于它提供了_太多_的功能。一系列使人困惑的选择,使程序员必须清楚地思考如何与将来的读者沟通,而读者将要使用他们的日志。oop
我认为成功的日志包须要的功能要少得多,固然须要的级别也更少。ui
咱们从最简单的一个开始。没有人须要 warning 的日志级别。this
没有人阅读 warning,由于按照定义,没有出错。也许未来会出问题,但这听起来像是别人的问题。
此外,若是你在使用某种分级日志,那么为何将级别设置为 warning? 你能够将级别设置为 info 或 error。将级别设置为 warning 是认可你可能正在以 warninng 级别打印错误日志
消除 warning 级别,由于它既多是信息性的消息,也多是错误的状况。(潜台词:语义不明确)
Fatal 级别,有效打印消息日志,而后调用 os.Exit(1)
。原则上,这意味着:
实际上,log.Fatal
的详细程度要比 panic
少,但在语义上却等同于它。
广泛认为,库不该该使用 panic1,可是若是调用 log.Fatal2 具备相同的效果,那么固然也应该将其定为非法。
解决此清理问题的建议是,能够经过在日志系统中注册 shutdown handler,但如此致使日志系统与发生清理操做的每一个位置之间紧密耦合。它也违反了关注点分离。
不要以 Fatal
级别写日志,而要将错误返回给调用方。若是错误一直冒泡到 main.main
, 那么退出以前,是处理全部清理操做的正确位置。
错误处理和日志密切相关,所以从表面上看,以 error 级别进行日志打印应该很容易解释。但,我不一样意。
在 Go 中,若是函数或方法调用返回错误值,实际上您有两个选择:
若是您选择经过打印日志来处理错误,那么按照定义,你已经处理了它,错误就不存在了。打印错误处理错误的行为,意味着再也不适合将其打印为错误日志。
让我尝试用如下代码片断说服您:
err := somethingHard()
if err != nil {
log.Error("oops, something was too hard", err)
return err // what is this, Java ?
}
复制代码
您永远不该该在 error 级别打印任何内容的日志,由于您应该处理错误,或者将其传递回调用方。
准确地说,我并非说您不该该将发生的状况打印日志
if err := planA(); err != nil {
log.Infof("could't open the foo file, continuing with plan b: %v", err)
planB()
}
复制代码
但实际上 log.Info
和 log.Error
有殊途同归之妙。
我并非说不要打印错误日志!相反,问题是,最小的日志API是什么?当提到错误时,我相信绝大多数打印日志为 error 级别的项目,都是经过这种简单地方式完成的,由于它们与错误相关。实际上,它们只是提供信息,意味着能够从API中删除以 error 级别打印日志。
咱们已经排除了 warning,认为不该该以 error 级别打印任何内容的日志,而且代表只有应用程序的顶层应该具备某种 log.Fatal
行为。还剩什么 ?
我认为只有两种东西您应该打印日志:
显然,分别是 debug 和 info 级别。
log.Info
应该简单地将该行写入日志输出。不该有将其关闭的选项,由于仅应告知用户对他们有用的事情。若是发生_没法_处理的错误,它将冒泡到 main.main
, 程序终止的地方。必须在最后一条日志消息前面插入 FATAL 前缀,或直接用 fmt.Fprintf
写入 os.Stderr
所带来的小小不便,不足以解释日志包须要添加 log.Fatal
方法。
log.Debug
,则彻底不一样。由开发人员或支持工程师控制。在开发过程当中,调试语句应足够多,而没必要求助于 trace 或 debug2 级别。日志包应支持细粒度的控制,以启用或禁用调试,而且仅在该包或可能更精细的范围内的语句调试。
若是这是推特民意调查,请您选择
可是事实是,打印日志是二者兼而有之。解决这个问题的方法_必须_是解构和残酷地消除没必要要的干扰。
你怎么看?这仅仅是疯狂到足以工做,仍是纯粹是疯狂的?
panic
/recover
做为内部控制流机制,但最重要的原则是它们必定不能让这些控制流操做泄漏到程序包边界以外。Fatal
和 Panic
功能。在此程序包中,致使程序忽然退出的功能数量超过了没有退出功能的数量。