Go 包是否应该使用 log.Fatal 以及何时使用?

新手上路,请多包涵

到目前为止,我一直避免使用 log.Fatal ,但我最近偶然发现了这些问题; code-coveragetests-using-log-fatal

100 个代码覆盖率问题的评论之一说:

…在绝大多数情况下 log.Fatal 应该只在 main 或 init 函数中使用(或者可能是一些只能直接从它们调用的东西)”

这让我开始思考,所以我开始查看 Go 提供的标准库代码。有很多示例,其中库中的 测试 代码使用了 log.Fatal 这看起来不错。在测试代码之外还有一些示例,例如 net/http ,如下所示:

 // net/http/transport.go
func (t *Transport) putIdleConn(pconn *persistConn) bool {
    ...
    for _, exist := range t.idleConn[key] {
        if exist == pconn {
            log.Fatalf("dup idle pconn %p in freelist", pconn)
        }
    }
    ...
}

如果最好的做法是避免使用 log.Fatal ,那么为什么在标准库中完全使用它,我本以为只会返回一个错误。调用 os.Exit 并且不为应用程序提供任何清理机会似乎对库的用户不公平。

我可能很天真,因此作为一种更好的做法,我的问题似乎是调用 log.Panic 可以恢复并且我理论上长期运行的稳定应用程序可能有机会从灰烬中重生。

那么 Go 的最佳实践是什么时候应该使用 log.Fatal 呢?

原文由 miltonb 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 645
2 个回答

可能只有我一个人,但这是我使用 log.Fatal 的方式。根据 UNIX 约定,遇到错误的进程应尽早失败并返回非零退出代码。这引导我遵循以下使用指南 log.Fatal 当……

  1. …我的任何 func init() 都发生了错误,因为这些错误分别发生在处理导入时或调用 main func 之前。相反,我只做不直接影响库或 cmd 应该做的工作单元的事情。例如,我设置日志记录并检查我们是否有一个健全的环境和参数。如果我们有无效的标志,就不需要运行 main 了,对吧?如果我们不能提供适当的反馈,我们应该尽早告知。
  2. ……发生了一个我知道无法挽回的错误。假设我们有一个程序可以创建命令行上给定的图像文件的缩略图。如果此文件不存在或由于权限不足而无法读取,则没有理由继续并且无法从中恢复此错误。所以我们遵守约定,失败了。
  3. …在可能不可逆的过程中发生错误。我知道,这是一种软定义。让我来说明一下。假设我们有一个 cp 的实现,它开始是非交互式的并递归地复制一个目录。现在,假设我们在目标目录中遇到一个与要复制到那里的文件同名(但内容不同)的文件。由于我们不能要求用户决定要做什么,而且我们不能复制这个文件,所以我们遇到了问题。因为当我们以退出代码零结束时,用户会假设源目录和目标目录是精确的副本,所以我们不能简单地跳过有问题的文件。但是,我们不能简单地覆盖它,因为这可能会破坏信息。这是我们无法根据用户的明确请求恢复的情况,因此我将使用 log.Fatal 来解释这种情况,在此遵守尽早失败的原则。

原文由 Markus W Mahlberg 发布,翻译遵循 CC BY-SA 3.0 许可协议

马库斯,我看到了你的回复,我认为它非常好而且很有见地,我倾向于同意你的分解。很难一概而论,尽管我一直在考虑这个问题,并且作为 Go 的新手。我认为在理论层面上,如果我们正在寻找计算中的最佳实践,无论操作系统、包框架或库如何,记录器的职责就是简单地记录。在任何级别上,记录器的职责:

  • 按照我选择的渠道一致地格式化和打印信息。
  • 分类、过滤、显示不同的日志级别[debug、info、warn、error]
  • 跨异步和并行作业处理和聚合日志条目

如果程序运行正常,日志包或任何包都没有也不应该有使程序崩溃的权限。任何中间件或库都应遵循抛出/捕获模式,抛出的 所有 异常都有机会被调用者捕获。这也是在应用程序中遵循的一个很好的模式,当您构建为应用程序的各个部分以及潜在的其他应用程序提供支持的基础和包时,它们不应该直接导致应用程序崩溃。相反,他们应该抛出一个致命异常,让程序来处理。我认为这也解决了你的一些观点,Marcus,因为它可以在未被捕获时立即提醒呼叫者,这是一个致命的崩溃。

在大多数情况下,为了直接面向用户的 cli 工具,我可以直接在 Go 中利用 log.Fatal,我认为这是它真正想要的简单性。我认为将其作为处理包间致命错误的长期方法没有什么意义。

原文由 moniecodes 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题