Where to log error in go

huangapple go评论70阅读模式
英文:

Where to log error in go

问题

也许这是一个观点,或者可能实际上是一种最佳实践,但我想要正确地做这件事。

考虑以下代码:

func main() {
    if err := doSomething(); err != nil {
        // 在这里记录日志并退出?
    }
}

func doSomething() {
    f, err := os.Open("filename.ext")
    if err != nil {
        // 在这里记录日志并返回错误/退出?
    }
}

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

谢谢!

英文:

Perhaps this is an opinion or maybe it's actually a best practice, but I want to do it correctly.

Consider the following code:

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?
    }
}

I am interested to know where the error should be logged and where the program should be exited (assuming recovery is impossible). Some possibilities include: logging and exiting in the callee; logging in the callee, returning the error, and exiting in the caller; logging in the callee, returning the error, logging in the caller, and exiting. There seem to be benefits to all of these approaches. The second approach, for instance, allows a fine grained error message but still passes the error on to the caller. However, it will result in two log messages.

Thanks!

答案1

得分: 21

这是一个有趣的话题,实际上很大程度上取决于个人观点,所以可能会被关闭。我尝试遵循以下几个准则:

  1. 只处理错误一次。记录日志也算作处理。如果你不知道需要采取什么措施,就将错误传递上去。你绝对不希望每次出现错误都记录多次日志。

  2. 如果调用者可能会因为错误而改变其行为,你应该返回错误。如果你仍然可以完成你的“工作”,尽管有错误,也许你应该记录下来并继续执行。

  3. 有时候在错误最初进入系统时添加上下文信息会有所帮助(这样日志行就可以包含错误的来源,而不仅仅是最终记录的位置)。类似于 https://github.com/pkg/errors 的工具可能会有用。

英文:

This is an interesting topic, and really boils down to a lot of opinion, so this may get closed. There are a few guidelines I try to follow:

  1. Only "handle" an error once. Logging counts as handling. If you do not know what action needs to be taken, just pass it up. You definitely don't want errors to be logged multiple times per occurrence.

  2. If your caller is likely to change their behavior because of the error, you should return it. If you can still do your "job" despite the error, maybe you should log it and continue.

  3. Sometimes it helps to add context to where the error initially entered your system (so the log line can include where the error came from, not just where it finally got logged). Something like https://github.com/pkg/errors can be useful for this.

答案2

得分: 2

从单元测试的角度来看,最好返回错误。如果对于一个 fn() 返回错误,那么对它进行单元测试会更容易。

例如,

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

// p_test.go
func TestFn(t *testing.T) {
    // 返回错误使得在这里测试 fn() 更容易。
    if err := fn(); err != nil {
        t.Error("fn(): got:%v, want:nil", err)
    }
}

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

英文:

From unit-tests standpoint, it's better to return error. If you return error for a fn(), it's easier to unit-test it.

For example,

// 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)
    }
}

If fn() directly logged error and exited, it would be impossible to unit-test it.

huangapple
  • 本文由 发表于 2017年1月6日 04:43:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/41494350.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定