zeebo/errs

GitHub: zeebo/errs

errs 是一个 Go 语言的错误处理库,通过 Class 分组、按需 stack trace、多层 Wrap 和 Group 收集等机制,让错误的创建、分类与诊断更加友好高效。

Stars: 57 | Forks: 7

# errs [![GoDoc](https://godoc.org/github.com/zeebo/errs?status.svg)](https://godoc.org/github.com/zeebo/errs) [![Sourcegraph](https://sourcegraph.com/github.com/zeebo/errs/-/badge.svg)](https://sourcegraph.com/github.com/zeebo/errs?badge) [![Go Report Card](https://goreportcard.com/badge/github.com/zeebo/errs)](https://goreportcard.com/report/github.com/zeebo/errs) errs 是一个用于让错误变得更友好、更易于处理的 package。 ### 创建错误 最简单的使用方式是使用 package 级的 [New][New] 函数。 它非常类似于 `fmt.Errorf`,但更好用。例如: ``` func checkThing() error { return errs.New("what's up with %q?", "zeebo") } ``` 为什么说它更好?因为它自带的 stack trace 仅在格式化字符串中使用了 `"+"` 字符时才会打印。 这样既能保留诊断错误发生位置和原因的优势,又避免了在所有情况下都打印 stack trace 所产生的冗余信息。例如: ``` func doSomeRealWork() { err := checkThing() if err != nil { fmt.Printf("%+v\n", err) // contains stack trace if it's a errs error. fmt.Printf("%v\n", err) // does not contain a stack trace return } } ``` ### 错误 Class 你可以创建一个错误的 [Class][Class],并检查是否有任何错误是由该 class 创建的。 该 class 的名称会作为它所创建的所有错误的前缀。例如: ``` var Unauthorized = errs.Class("unauthorized") func checkUser(username, password string) error { if username != "zeebo" { return Unauthorized.New("who is %q?", username) } if password != "hunter2" { return Unauthorized.New("that's not a good password, jerkmo!") } return nil } func handleRequest() { if err := checkUser("zeebo", "hunter3"); Unauthorized.Has(err) { fmt.Println(err) } // output: // unauthorized: that's not a good password, jerkmo! } ``` Class 还可以 [Wrap][ClassWrap] 其他错误,并且错误可以被多次 wrap。例如: ``` var ( Error = errs.Class("mypackage") Unauthorized = errs.Class("unauthorized") ) func deep3() error { return fmt.Errorf("ouch") } func deep2() error { return Unauthorized.Wrap(deep3()) } func deep1() error { return Error.Wrap(deep2()) } func deep() { fmt.Println(deep1()) // output: // mypackage: unauthorized: ouch } ``` 在上面的例子中,`Error.Has(deep1())` 和 `Unauthorized.Has(deep1())` 都会返回 `true`,并且 stack trace 只会在 `deep2` 调用时被记录一次。 此外,当一个错误已经被 wrap 后,再次使用相同的 class 去 wrap 它将不会产生任何效果。例如: ``` func doubleWrap() { fmt.Println(Error.Wrap(Error.New("foo"))) // output: // mypackage: foo } ``` 这样做是为了让你在决定是否应该 wrap 时更加轻松(你应该去 wrap)。 ### 实用工具 [Classes][Classes] 是一个辅助函数,用于获取一个错误所包含的 class 的 slice。在这个 slice 中,最近一次 wrap 的排在最前面。例如: ``` func getClasses() { classes := errs.Classes(deep1()) fmt.Println(classes[0] == &Error) fmt.Println(classes[1] == &Unauthorized) // output: // true // true } ``` 最后,提供了一个名为 [Unwrap][Unwrap] 的辅助函数,用于在你可能想要检查详细信息时获取被 wrap 的错误。例如: ``` var Error = errs.Class("mypackage") func getHandle() (*os.File, error) { fh, err := os.Open("neat_things") if err != nil { return nil, Error.Wrap(err) } return fh, nil } func checkForNeatThings() { fh, err := getHandle() if os.IsNotExist(errs.Unwrap(err)) { panic("no neat things?!") } if err != nil { panic("phew, at least there are neat things, even if i can't see them") } fh.Close() } ``` 它支持社区中常用的 `Unwrap() error` 和 `Unwrap() []error` 方法,并且会尽可能多地调用它们。 ### Defer 该 package 还提供了 [Wrap][Wrap] 的 [WrapP][WrapP] 版本,这在 defer 上下文中非常有用。例如: ``` func checkDefer() (err error) { defer Error.WrapP(&err) fh, err := os.Open("secret_stash") if err != nil { return nil, err } return fh.Close() } ``` ### Group [Groups][Group] 允许你收集一组错误。例如: ``` func tonsOfErrors() error { var group errs.Group for _, work := range someWork { group.Add(maybeErrors(work)) } return group.Err() } ``` 需要注意的几点: - [Add][GroupAdd] 方法仅在传入的错误为非 nil 时才会将其添加到 group 中。 - [Err][GroupErr] 方法仅在添加了非 nil 错误时才返回一个错误;此外,如果只添加了一个错误,它会直接返回该错误。因此,我们始终可以保证,如果你只调用了 `group.Add(err)`,那么 `group.Err() == err`。 返回的错误会以类似如下的方式进行格式化: ``` func groupFormat() { var group errs.Group group.Add(errs.New("first")) group.Add(errs.New("second")) err := group.Err() fmt.Printf("%v\n", err) fmt.Println() fmt.Printf("%+v\n", err) // output: // first; second // // group: // --- first // ... stack trace // --- second // ... stack trace } ``` ### 贡献 errs 是基于 MIT 许可证发布的。如果你想做出贡献,请务必将你自己添加到 AUTHORS 列表中。
标签:EVTX分析, Go, Ruby工具, SOC Prime, 堆栈跟踪, 开发工具, 日志审计, 编程库, 错误处理