乐趣区

关于go:go错误处理工程化实践

1) 背景

    不相熟代码的状况下, 拿到一个谬误排查, 无奈串起来整个代码的调用链路, 谬误产生堆栈, 排查艰难、迟缓, 依据 trace 只能看见服务调用链

2) 现状

1) 反复解决

// 反复: 逐层返回谬误, 各层记录日志

func foo() error{return errors.New("foo")
}
 
func bar() error{err := foo()
 
    if err != nil {log.Error(err)
 
        return err    // handle error once, 应该记日志或者返回
 
    }
 
    return nil
}
 
func handle() error {err := bar()
 
    if err != nil {log.Error(err)
 
        return err    // handle error once, 应该记日志或者返回
 
    }
 
    return nil
}

2) 没有堆栈

// 没有谬误链(堆栈): 当谬误达到利用下层, 不好跟踪本源

func foo() error {return errors.New("foo")
 
}
 
func test() error{err := foo()
 
    if err != nil {log.Error(err)
 
        return err
 
    }
 
    return nil
}
 
func main(){err := test()
 
    if err := nil {fmt.Println("%+v",err)    // foo, 没有从 main->test->foo 的堆栈

    }
}

3) 如何处理错误

1) 指标

  • 谬误被日志记录, 不重复记录
  • 下层利用处理错误, 珍重 100% 的完整性
  • 能够增加上下文信息

2) 办法

“github.com/pkg/errors”

  • errors.Wrapf(): Wrapf returns an error annotating err with a stack trace (带有堆栈, 反复会有屡次堆栈)
  • errors.WithMessagef(): WithMessagef annotates err with the format specifier (不带堆栈, 可携带信息)

3) 最佳实际

  • 最底层 (比方公共库) 返回原始谬误, 无需 wrap
  • 利用上层流转谬误, 应用 wrap 带上堆栈
  • 利用内办法相互调用, 防止反复 wrap 导致反复堆栈, withMessage 携带信息即可

4) 成果

在打印或者记录谬误, 个别由日志中间件在最上层实现, 应用占位符 %+v, 比方

// log error with stack

fmt.Printf("err:%+v", err)

4) Q&A

1) ecode 为自定义错误信息构造体, 是否会扭转前端提醒?

前端可能正确展现对应的提醒是基于返回的 ecode 中的 code 和 message, 前端展现 message 信息。

  • wrap 之前: 利用返回原始 error(即为根因 error), 如果该 error 为 ecode, 领有对应的 code 和 message, 则前端能失常展现, 否则则不能
  • wrap 之后: 应用层通用返回原始 error(即为根因 error), wrap 加上堆栈, 出口处框架会主动 cause 寻找根因, 之后和 wrap 之前逻辑统一

也就是说, 重点在于返回的原始 error 是否为 ecode 才是重点, 与是否 wrap 没有关系

2) 每一层 error 向上抛时如何携带上下文信息?

pkg/errors 包提供了以下办法

  • errors.Wrap(),
  • errors.Wrapf(),
  • errors.WithMessage(),
  • errors.WithMessagef()

应用注意事项

  • Wrap类会携带堆栈, 利用上层调用一次即可, 防止屡次调用造成堆栈屡次打印
  • WithMessage类不会携带堆栈, 只会包装一层
  • f 类占位符的函数, 能够携带一些参数等上下文信息

5) references

  • go-exceptions
  • why-go-error-handling-is-awesome
  • stack-traces-and-the-errors
退出移动版