|
7 | 7 | [](https://pkg.go.dev/github.com/bnkamalesh/errors?tab=doc)
|
8 | 8 | [](https://github.com/avelino/awesome-go#error-handling)
|
9 | 9 |
|
10 |
| -# Errors |
| 10 | +# Errors v0.9.0 |
11 | 11 |
|
12 | 12 | Errors package is a drop-in replacement of the built-in Go errors package with no external dependencies. It lets you create errors of 11 different types which should handle most of the use cases. Some of them are a bit too specific for web applications, but useful nonetheless. Following are the primary features of this package:
|
13 | 13 |
|
14 | 14 | 1. Multiple (11) error types
|
15 | 15 | 2. User friendly message
|
16 |
| -3. File & line number prefixed to errors |
17 |
| -4. HTTP status code and user friendly message (wrapped messages are concatenated) for all error types |
18 |
| -5. Helper functions to generate each error type |
19 |
| -6. Helper function to get error Type, error type as int, check if error type is wrapped anywhere in chain |
| 16 | +3. Stacktrace - formatted, unfromatted, custom format (refer tests in errors_test.go) |
| 17 | +4. Retrieve the Program Counters, for compatibility external libraries which generate their own stacktrace |
| 18 | +5. Retrieve *runtime.Frames using `errors.RuntimeFrames(err error)`, for compatibility external libraries which generate their own stacktrace |
| 19 | +6. HTTP status code and user friendly message (wrapped messages are concatenated) for all error types |
| 20 | +7. Helper functions to generate each error type |
| 21 | +8. Helper function to get error Type, error type as int, check if error type is wrapped anywhere in chain |
| 22 | +9. fmt.Formatter support |
20 | 23 |
|
21 | 24 | In case of nested errors, the messages & errors are also looped through the full chain of errors.
|
22 | 25 |
|
@@ -50,44 +53,72 @@ There are helper functions for all the error types, when in need of setting a fr
|
50 | 53 |
|
51 | 54 | ```golang
|
52 | 55 | package main
|
53 |
| -import( |
54 |
| - "fmt" |
55 |
| - "github.com/bnkamalesh/errors" |
| 56 | + |
| 57 | +import ( |
| 58 | + "fmt" |
| 59 | + |
| 60 | + "github.com/bnkamalesh/errors" |
56 | 61 | )
|
57 | 62 |
|
58 | 63 | func Bar() error {
|
59 |
| - return fmt.Errorf("hello %s", "world!") |
| 64 | + return fmt.Errorf("hello %s", "world!") |
60 | 65 | }
|
61 | 66 |
|
62 | 67 | func Foo() error {
|
63 |
| - err := Bar() |
64 |
| - if err != nil { |
65 |
| - return errors.InternalErr(err, "bar is not happy") |
66 |
| - } |
67 |
| - return nil |
| 68 | + err := Bar() |
| 69 | + if err != nil { |
| 70 | + return errors.InternalErr(err, "bar is not happy") |
| 71 | + } |
| 72 | + return nil |
68 | 73 | }
|
69 | 74 |
|
70 | 75 | func main() {
|
71 |
| - err := Foo() |
72 |
| - fmt.Println(err) |
73 |
| - _,msg,_ := errors.HTTPStatusCodeMessage(err) |
74 |
| - fmt.Println(msg) |
| 76 | + err := Foo() |
| 77 | + |
| 78 | + fmt.Println("err:", err) |
| 79 | + fmt.Println("\nerr.Error():", err.Error()) |
| 80 | + |
| 81 | + fmt.Printf("\nformatted +v: %+v\n", err) |
| 82 | + fmt.Printf("\nformatted v: %v\n", err) |
| 83 | + fmt.Printf("\nformatted +s: %+s\n", err) |
| 84 | + fmt.Printf("\nformatted s: %s\n", err) |
| 85 | + |
| 86 | + _, msg, _ := errors.HTTPStatusCodeMessage(err) |
| 87 | + fmt.Println("\nmsg:", msg) |
75 | 88 | }
|
76 | 89 | ```
|
77 | 90 |
|
| 91 | +Output |
| 92 | +``` |
| 93 | +err: bar is not happy |
| 94 | +
|
| 95 | +err.Error(): /path/to/file.go:16: bar is not happy |
| 96 | +hello world! |
| 97 | +
|
| 98 | +formatted +v: /path/to/file.go:16: bar is not happy |
| 99 | +hello world! |
| 100 | +
|
| 101 | +formatted v: bar is not happy |
| 102 | +
|
| 103 | +formatted +s: bar is not happy: hello world! |
| 104 | +
|
| 105 | +formatted s: bar is not happy |
| 106 | +
|
| 107 | +msg: bar is not happy |
| 108 | +``` |
| 109 | + |
| 110 | +[Playground link](https://go.dev/play/p/-WzDH46f_U5) |
| 111 | + |
78 | 112 | ### File & line number prefixed to errors
|
79 | 113 |
|
80 |
| -A common annoyance with Go errors which most people are aware of is, figuring out the origin of the error, especially when there are nested function calls. Ever since error annotation was introduced in Go, a lot of people have tried using it to trace out an errors origin by giving function names, contextual message etc in it. e.g. `fmt.Errorf("database query returned error %w", err)`. This errors package, whenever you call the Go error interface's `Error() string` function, it'll print the error prefixed by the filepath and line number. It'd look like `../Users/JohnDoe/apps/main.go:50 hello world` where 'hello world' is the error message. |
| 114 | +A common annoyance with Go errors which most people are aware of is, figuring out the origin of the error, especially when there are nested function calls. Ever since error annotation was introduced in Go, a lot of people have tried using it to trace out an errors origin by giving function names, contextual message etc in it. e.g. `fmt.Errorf("database query returned error %w", err)`. However this errors package, whenever you call the Go error interface's `Error() string` function, prints the error prefixed by the filepath and line number. It'd look like `../Users/JohnDoe/apps/main.go:50 hello world` where 'hello world' is the error message. |
81 | 115 |
|
82 | 116 | ### HTTP status code & message
|
83 | 117 |
|
84 |
| -The function `errors.HTTPStatusCodeMessage(error) (int, string, bool)` returns the HTTP status code, message, and a boolean value. The boolean is true, if the error is of type *Error from this package. |
85 |
| -If error is nested with multiple errors, it loops through all the levels and returns a single concatenated message. This is illustrated in the 'How to use?' section |
| 118 | +The function `errors.HTTPStatusCodeMessage(error) (int, string, bool)` returns the HTTP status code, message, and a boolean value. The boolean is true, if the error is of type *Error from this package. If error is nested, it unwraps and returns a single concatenated message. Sample described in the 'How to use?' section |
86 | 119 |
|
87 | 120 | ## How to use?
|
88 | 121 |
|
89 |
| -Before that, over the years I have tried error with stack trace, annotation, custom error package with error codes etc. Finally, I think this package gives the best of all worlds, for most generic usecases. |
90 |
| - |
91 | 122 | A sample was already shown in the user friendly message section, following one would show a few more scenarios.
|
92 | 123 |
|
93 | 124 | ```golang
|
@@ -179,34 +210,33 @@ And the `fmt.Println(err.Error())` generated output on stdout would be:
|
179 | 210 | /Users/username/go/src/errorscheck/main.go:28 /Users/username/go/src/errorscheck/main.go:20 sinking bar
|
180 | 211 | ```
|
181 | 212 |
|
182 |
| -## Benchmark |
| 213 | +## Benchmark [2021-12-13] |
183 | 214 |
|
184 |
| -Benchmark run on: |
185 |
| -<p><img width="320" alt="Screenshot 2020-07-18 at 6 25 22 PM" src="https://user-images.githubusercontent.com/1092882/87852981-241b5c80-c924-11ea-9d22-296acdead7cc.png"></p> |
186 |
| - |
187 |
| -Results |
188 | 215 | ```bash
|
189 | 216 | $ go version
|
190 |
| -go version go1.14.4 darwin/amd64 |
191 |
| -$ go test -bench=. |
192 |
| -goos: darwin |
| 217 | +go version go1.17.4 linux/amd64 |
| 218 | + |
| 219 | +$ go test -benchmem -bench . |
| 220 | +goos: linux |
193 | 221 | goarch: amd64
|
194 | 222 | pkg: github.com/bnkamalesh/errors
|
195 |
| -Benchmark_Internal-8 1874256 639 ns/op 368 B/op 5 allocs/op |
196 |
| -Benchmark_InternalErr-8 1612707 755 ns/op 368 B/op 5 allocs/op |
197 |
| -Benchmark_InternalGetError-8 1700966 706 ns/op 464 B/op 6 allocs/op |
198 |
| -Benchmark_InternalGetErrorWithNestedError-8 1458368 823 ns/op 464 B/op 6 allocs/op |
199 |
| -Benchmark_InternalGetMessage-8 1866562 643 ns/op 368 B/op 5 allocs/op |
200 |
| -Benchmark_InternalGetMessageWithNestedError-8 1656597 770 ns/op 400 B/op 6 allocs/op |
201 |
| -Benchmark_HTTPStatusCodeMessage-8 26003678 46.1 ns/op 16 B/op 1 allocs/op |
202 |
| -BenchmarkHasType-8 84689433 14.2 ns/op 0 B/op 0 allocs/op |
| 223 | +cpu: Intel(R) Core(TM) i7-10510U CPU @ 1.80GHz |
| 224 | +Benchmark_Internal-8 772088 1412 ns/op 1272 B/op 5 allocs/op |
| 225 | +Benchmark_Internalf-8 695674 1692 ns/op 1296 B/op 6 allocs/op |
| 226 | +Benchmark_InternalErr-8 822500 1404 ns/op 1272 B/op 5 allocs/op |
| 227 | +Benchmark_InternalGetError-8 881791 1319 ns/op 1368 B/op 6 allocs/op |
| 228 | +Benchmark_InternalGetErrorWithNestedError-8 712803 1488 ns/op 1384 B/op 6 allocs/op |
| 229 | +Benchmark_InternalGetMessage-8 927864 1237 ns/op 1272 B/op 5 allocs/op |
| 230 | +Benchmark_InternalGetMessageWithNestedError-8 761164 1675 ns/op 1296 B/op 6 allocs/op |
| 231 | +Benchmark_HTTPStatusCodeMessage-8 29116684 41.62 ns/op 16 B/op 1 allocs/op |
| 232 | +BenchmarkHasType-8 100000000 11.50 ns/op 0 B/op 0 allocs/op |
203 | 233 | PASS
|
204 |
| -ok github.com/bnkamalesh/errors 14.478s |
| 234 | +ok github.com/bnkamalesh/errors 10.604s |
205 | 235 | ```
|
206 | 236 |
|
207 | 237 | ## Contributing
|
208 | 238 |
|
209 |
| -More error types, customization etc; PRs & issues are welcome! |
| 239 | +More error types, customization, features etc; PRs & issues are welcome! |
210 | 240 |
|
211 | 241 | ## The gopher
|
212 | 242 |
|
|
0 commit comments