在Go语言中快速查找引发错误的文件和行号的技巧是什么?

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

Trick to quickly find file & line number throwing an error in Go?

问题

在我使用Go语言的过程中,我发现它没有堆栈跟踪。所以每当出现错误时,我们只能得到一个简单的字符串错误消息,没有任何信息告诉我们错误的来源。这与其他语言形成了鲜明对比,我习惯于看到详细的堆栈跟踪。

例如,下面是来自apex的错误消息:

$ cat event.json | apex invoke --logs webhook                                  
   ⨯ error parsing response: json: cannot unmarshal array into Go value of type map[string]interface {}

这里告诉我无法将event.json解析为一个映射类型的Go值,因为它是一个数组。我们必须将其解析为interface{}以支持数组和映射。然而,它没有告诉我哪个文件/行导致了这个错误。

问题:

  1. 有没有一种快速找到错误来源的方法?
  2. 一般来说,Go语言开发者有没有什么技巧可以从这个字符串错误消息中快速找到问题的源头?
  3. 大多数Go项目的堆栈跟踪是这样的吗?还是有一些应该遵循的最佳实践?
英文:

In my journey with go discovered that there are no stacktraces. so whenever something breaks, all we get an simple string error message without any information where is this is coming from. This is in stark contrast with other languages where I am used to seing detailed stacktraces

For example, below is the error message from apex

$ cat event.json | apex invoke --logs webhook                                  
   ⨯ error parsing response: json: cannot unmarshal array into Go value of type map[string]interface {}

here its telling me that unmarshal to a map ins't working because event.json is an array. We have unmarshal to interface{} to support both arrays & maps.However, it doesn't tell me which file/line is causing this error.

Questions:

  1. What is way to quickly find which file/line this error coming from?
  2. In General, Are there tips/tricks which gophers use to get to the source of problem quickly from this string error message?
  3. is this how stack traces are for most go projects or there are any best practices that should be followed?

答案1

得分: 5

寻找错误来源的快速方法是什么?

除非是未恢复的 panic,否则不会打印默认的堆栈信息。

一般来说,有几种方法可以快速找到问题的源代码。大多数情况下,你需要检查函数调用的错误返回值。有多种方法可以做到这一点。

我通常使用标准库中的 log 包,在简单的程序中打印带有文件和行号的错误日志,以便进行简单的调试。例如:

package main

import "log"
import "errors"

func init() { log.SetFlags(log.Lshortfile | log.LstdFlags) }

func callFunc() error {
    return errors.New("error")
}

func main() {
    if err := callFunc(); err != nil {
        log.Println(err)
    }
}

输出:

2009/11/10 23:00:00 main.go:14: error

此外,标准库中的 runtime/debug 包提供了一些函数,可以打印或获取当前的堆栈信息,例如:https://golang.org/pkg/runtime/debug/#PrintStack

还有许多社区努力致力于使错误处理更加简单,你可以在 GoDoc 中搜索错误处理相关的内容:https://godoc.org/?q=error

英文:

> What is way to quickly find which file/line this error coming from?

There are no default stacks printed unless it's an unrecovered panic.

> In General, Are there tips/tricks which gophers use to get to the source of problem quickly from this string error message? is this how stack traces are for most go projects or there are any best practices that should be followed?

In General, you need to check error returns from most of the function calls. There are more than one way to do that.
I usually use standard library package log to print out error logs with file and line numbers for easy debugging in simple programs. For example:

package main

import "log"
import "errors"

func init() { log.SetFlags(log.Lshortfile | log.LstdFlags) }

func callFunc() error {
	return errors.New("error")
}

func main() {
	if err := callFunc(); err != nil {
		log.Println(err)
	}
}

http://play.golang.org/p/0iytNw7eZ7

output:

2009/11/10 23:00:00 main.go:14: error

Also, there are functions for you to print or retrieve current stacks in standard library runtime/debug, e.g. https://golang.org/pkg/runtime/debug/#PrintStack

There are many community efforts on bringing error handling easier, you can search error in GoDoc: https://godoc.org/?q=error

答案2

得分: 2

你尝试的解决方案: 找到产生错误的代码片段来修复代码。

你实际的问题: event.json 的内容。

<sub>这被称为X-Y-Problem</sub>


Invoke 期望一个 JSON 对象,而你传递了一个 JSON 数组。修复这个问题,你的问题就解决了!

$ echo -n '{ "value": "Tobi the ferret" }' | apex invoke uppercase

相关文档的部分内容:调用函数

这是产生错误的代码片段:Github


是的,Go 有堆栈跟踪!阅读Dave Cheney关于错误和异常的博文

英文:

Your attempted solution: Finding the piece of code that produces the error to fix the code.

Your actual problem: The content of event.json.

<sub>This is called the X-Y-Problem</sub>


Invoke expects a json object, you are passing a json array. Fix that and your problem is gone!

$ echo -n &#39;{ &quot;value&quot;: &quot;Tobi the ferret&quot; }&#39; | apex invoke uppercase

Relevant part of the documentation: Invoking Functions

And that's the piece of code that produces the error: Github


And yes, Go does have stack traces! Read Dave Cheneys blog post on errors and exceptions.

答案3

得分: 1

Go在发生panic时确实会生成堆栈跟踪并使程序崩溃。这种情况通常发生在代码直接调用panic()的情况下,比如:

if err != nil {
    panic("it broke")
}

或者在运行时发生错误的情况下,比如:

a := []int{1, 2, 3}
b := a[12] // 超出索引范围

以下是一个最简示例:

package main

func main() {
    panic("wtf?!")
}

输出结果:

panic: wtf?!

goroutine 1 [running]:
panic(0x94e60, 0x1030a040)
    /usr/local/go/src/runtime/panic.go:464 +0x700
main.main()
    /tmp/sandbox366642315/main.go:4 +0x80

请注意main.go:4,它指示了文件名和行号。

在你的示例中,程序没有发生panic,而是选择调用(我猜)os.Exit(1)log.Fatal("error message")(它调用os.Exit(1))。或者,panic在调用函数中被恢复了。如果你不是代码的作者,对此你无能为力。

我建议阅读Golang博客上的Defer, Panic, and Recover以了解更多信息。

英文:

Go does produce stack traces when a panic happens, crashing the program. This will happen if the code calls panic() directly, typically in cases like:

if err != nil {
    panic(&quot;it broke&quot;)
}

or, when a runtime error happens:

a := []int{1, 2, 3}
b := a[12] // index out of range

Here's a minimal example:

package main

func main() {
	panic(&quot;wtf?!&quot;)
}

Output:

panic: wtf?!

goroutine 1 [running]:
panic(0x94e60, 0x1030a040)
    /usr/local/go/src/runtime/panic.go:464 +0x700
main.main()
    /tmp/sandbox366642315/main.go:4 +0x80

Note the main.go:4 indicating the filename and line number.

In your example, the program did not panic, instead opting to call (I'm guessing) os.Exit(1) or log.Fatal(&quot;error message&quot;) (which calls os.Exit(1)). Or, the panic was simply recovered from in the calling function. Unfortunately, there's nothing you can do about this if you aren't the author of the code.

I would recommend reading Defer, Panic, and Recover on the Golang blog for more about this.

答案4

得分: 0

在main()函数中设置log.SetFlags(log.LstdFlags | log.Lshortfile)即可。

例如,log.Printf("Deadline!")将打印:

03/11/2020 23:59:59 liberty_test.go:42: Deadline!

英文:

Setting log.SetFlags(log.LstdFlags | log.Lshortfile) in main() should do it.

For example, log.Printf(&quot;Deadline!&quot;) would print:

> 03/11/2020 23:59:59 liberty_test.go:42: Deadline!

huangapple
  • 本文由 发表于 2016年2月28日 14:46:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/35679647.html
匿名

发表评论

匿名网友

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

确定