【问题标题】:Where to log error in go在哪里记录错误
【发布时间】:2017-05-20 13:06:33
【问题描述】:

也许这是一种观点,或者它实际上是一个最佳实践,但我想正确地做到这一点。

考虑以下代码:

func main() {
    if err := doSomething(); err != nil {
        // log here and exit?
    }
}

func doSomething() {
    f, err := os.Open("filename.ext")
    if err != nil {
        // log here and return the error/exit?
    }
}

我很想知道应该在哪里记录错误以及应该在哪里退出程序(假设无法恢复)。一些可能性包括:在被调用者中记录和退出;登录被调用者,返回错误,并在调用者中退出;登录被调用者,返回错误,登录调用者,然后退出。所有这些方法似乎都有好处。例如,第二种方法允许细粒度的错误消息,但仍将错误传递给调用者。但是,它会产生两条日志消息。

谢谢!

【问题讨论】:

  • 将其放入日志文件或打印出来
  • dave.cheney.net/2016/04/27/… 提供了一些很好的 go 错误处理指导。
  • @captncraig 那是一篇有用的文章。看起来使用 errors.Wrap 可以在返回错误时为错误提供一些上下文。我喜欢这样。

标签: logging go error-handling error-logging


【解决方案1】:

这是一个有趣的话题,真的可以归结为很多意见,所以这可能会被关闭。我尝试遵循一些准则:

  1. 只“处理”一次错误。记录算作处理。如果你不知道需要采取什么行动,那就放弃吧。您绝对不希望每次出现多次记录错误。

  2. 如果你的调用者可能因为错误而改变他们的行为,你应该返回它。如果尽管出现错误,您仍然可以完成“工作”,也许您应该记录并继续。

  3. 有时,将上下文添加到错误最初进入系统的位置会有所帮助(因此日志行可以包括错误的来源,而不仅仅是最终记录的位置)。像https://github.com/pkg/errors 这样的东西可能对此很有用。

【讨论】:

  • 为了进一步补充这一点,通常不要使用os.Exit(),除非在您的main() 函数中。主要原因是,与panic() 不同,os.Exit() 不能被捕获,main() 确实应该有权决定进程何时终止以及如何终止。作为推论,os.Exit() 和扩展,log.Fatal()(它调用 os.Exit())应该绝对不用于打算由其他人导入的库中(我看到这ALL时间,这是可怕的做法)。如果它是致命的(在可导入的包中),panic(),不要os.Exit()log.Fatal()
【解决方案2】:

从单元测试的角度来看,最好返回错误。如果您为 fn() 返回错误,则更容易对其进行单元测试。

例如,

// p.go
func fn() error {
    ...
}

// p_test.go
func TestFn(t *testing.T) {
    // returning error makes easier to test fn() here.
    if err := fn(); err != nil {
        t.Error("fn(): got:%v, want:nil", err)
    }
}

如果fn() 直接记录错误并退出,则无法对其进行单元测试。

【讨论】:

    猜你喜欢
    • 2011-09-15
    • 2011-06-13
    • 1970-01-01
    • 2017-06-25
    • 1970-01-01
    • 2018-03-27
    • 1970-01-01
    • 1970-01-01
    • 2010-10-11
    相关资源
    最近更新 更多