【问题标题】:How to suppress stack trace after `panic` in Go?如何在 Go 中的“恐慌”之后抑制堆栈跟踪?
【发布时间】:2020-07-19 17:47:12
【问题描述】:

我正在开发一个 CLI 工具,如果出现问题,我想记录自定义错误并恐慌退出。恐慌的问题是panic 的退出后面是我不想向用户显示的堆栈跟踪。有没有办法惊慌并有一个忍者般的隐秘/安静的出口?

(选择 panic 而不是 os.Exit() 因为这样可以处理任何 defer 并且看起来更干净。)

【问题讨论】:

标签: go


【解决方案1】:

嗯,直接回答是肯定的,有办法:

  1. panic 带有自定义“哨兵”类型的错误,或带有自定义“哨兵”值的错误,然后
  2. main 中有一个defer-red 调用recover()-s 恐慌并检查返回值是否为哨兵类型(或等于哨兵值——具体方法取决于你) .
    如果它检测到“已知”错误,它会以非零退出代码静默退出; 否则再次panics。

但老实说,我认为您的思维方式受到编程语言的影响太大了,但有例外:我还没有看到 CLI 应用程序在“以通常方式”处理错误时会遇到任何困难,或者实际上会从使用 panic 的救助中受益.

与您所渴望的方法的相反论点是:冒泡错误允许在展开的调用堆栈的每个级别上为其添加更多上下文,这是有意义的 - 产生尽可能有用的错误显示。 基本上,它是这样工作的:

func main() {

  ...

  err := DoStuff()
  if err != nil {
    log.Fatal("failed to do stuff: ", err)
  }

  ...
}

func DoStuff() error {
  foo, err := InitializeWhatever()
  if err != nil {
    return fmt.Errorf("failed to inialize whatever: %w", err)
  }

  ...

  return nil
}

func InitializeWhatever() (*Whatever, error) {
  handle, err := OpenWhateverElse()
  if err != nil {
    return nil, fmt.Errorf("failed to open whatever else: %w", err)
  }

  ...

  return whatever, nil
}

...这会产生类似的东西

failed to do stuff: failed to inialize whatever: failed to open whatever else: task failed successfully

...这清楚地表明是哪个事件序列导致了不希望的结果。

当然,像往常一样,YMMV,除了你最了解你的情况外,没有人知道,但这仍然是值得思考的事情。


这里是我上面所写内容的各种想法。

  • 使用已知值/已知类型的错误进行恐慌的方法实际上并不是什么新鲜事——例如,请参阅net/http.ErrAbortHandler
    encoding/json 包用于使用这种方法来打破多个嵌套循环(不过从那时起已经重新设计)。
  • 不过,一些专家 consider sentinel errors to be bad design 并建议改为断言(使用 Go 的类型断言)错误的行为——例如,您可以查看 net.Error 如何拥有允许不拥有的 TimeoutTemporary 方法临时错误、超时错误及其组合的具体导出类型,而是让它们都支持一组通用方法,使调用者能够理解错误的性质。
  • 从 1.13 开始,Go gained 对“包装”错误的高级支持 - 生成 matryoshka 样式的错误链,这允许一种位于上述两个极端之间的错误处理方法:一个可以创建特定的错误在第一次发现错误的地方键入,然后在调用堆栈冒泡时将其包装在上下文中,然后在处理错误的地方断言最里面的错误的类型。 A friendly explanation on how it works

好吧,我建议阅读this,因为,我必须承认,如果你已经这样做了,你可能一开始就不会问你的问题 ;-)

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-25
  • 2023-04-05
  • 2015-12-07
  • 2013-09-29
  • 1970-01-01
  • 2017-10-14
  • 1970-01-01
相关资源
最近更新 更多