1
+ # err2
2
+
1
3
[ ![ test] ( https://github.com/lainio/err2/actions/workflows/test.yml/badge.svg?branch=master )] ( https://github.com/lainio/err2/actions/workflows/test.yml )
2
4
![ Go Version] ( https://img.shields.io/badge/go%20version-%3E=1.18-61CFDD.svg?style=flat-square )
3
5
[ ![ PkgGoDev] ( https://pkg.go.dev/badge/mod/github.com/lainio/err2 )] ( https://pkg.go.dev/mod/github.com/lainio/err2 )
4
6
[ ![ Go Report Card] ( https://goreportcard.com/badge/github.com/lainio/err2?style=flat-square )] ( https://goreportcard.com/report/github.com/lainio/err2 )
5
7
6
- # err2
8
+ <img src =" https://github.com/lainio/err2/raw/bench-tests/logo/logo.png " width =" 100 " >
9
+
10
+ ----
7
11
8
12
The package extends Go's error handling with ** fully automatic error checking
9
13
and propagation** like other modern programming languages: ** Zig** , Rust, Swift,
@@ -28,6 +32,8 @@ func CopyFile(src, dst string) (err error) {
28
32
}
29
33
```
30
34
35
+ ----
36
+
31
37
` go get github.com/lainio/err2 `
32
38
33
39
- [ Structure] ( #structure )
@@ -37,7 +43,6 @@ func CopyFile(src, dst string) (err error) {
37
43
- [ Error Stack Tracing] ( #error-stack-tracing )
38
44
- [ Error Checks] ( #error-checks )
39
45
- [ Filters for non-errors like io.EOF] ( #filters-for-non-errors-like-ioeof )
40
- - [ Backwards Compatibility Promise for the API] ( #backwards-compatibility-promise-for-the-api )
41
46
- [ Assertion] ( #assertion )
42
47
- [ Asserters] ( #asserters )
43
48
- [ Assertion Package for Runtime Use] ( #assertion-package-for-runtime-use )
@@ -75,17 +80,15 @@ run `benchmarks` in the project repo and see yourself.
75
80
76
81
## Automatic Error Propagation
77
82
78
- The current version of Go tends to produce too much error checking and too
79
- little error handling. But most importantly, it doesn't help developers with
80
- ** automatic** error propagation, which would have the same benefits as, e.g.,
81
- ** automated** garbage collection or automatic testing:
82
-
83
83
Automatic error propagation is crucial because it makes your * code change
84
- tolerant* . And, of course, it helps to make your code error-safe:
84
+ tolerant* . And, of course, it helps to make your code error-safe.
85
85
86
86
![ Never send a human to do a machine's job] ( https://www.magicalquote.com/wp-content/uploads/2013/10/Never-send-a-human-to-do-a-machines-job.jpg )
87
87
88
- The err2 package is your automation buddy:
88
+
89
+ <details >
90
+ <summary >The err2 package is your automation buddy:</summary >
91
+ <br />
89
92
90
93
1 . It helps to declare error handlers with ` defer ` . If you're familiar with [ Zig
91
94
language] ( https://ziglang.org/ ) , you can think ` defer err2.Handle(&err,...) `
@@ -101,31 +104,47 @@ You can use all of them or just the other. However, if you use `try` for error
101
104
checks, you must remember to use Go's ` recover() ` by yourself, or your error
102
105
isn't transformed to an ` error ` return value at any point.
103
106
104
- ## Error handling
107
+ </ details >
105
108
106
- The ` err2 ` relies on Go's declarative programming structure ` defer ` . The
107
- ` err2 ` helps to set deferred functions (error handlers) which are only called if
108
- ` err != nil ` .
109
+ ## Error Handling
109
110
110
- Every function which uses err2 for error-checking should have at least one error
111
- handler. The current function panics if there are no error handlers and an error
112
- occurs. However, if * any* function above in the call stack has an err2 error
113
- handler, it will catch the error.
111
+ The err2 relies on Go's declarative programming structure ` defer ` . The
112
+ err2 helps to set deferred error handlers which are only called if an error
113
+ occurs.
114
114
115
- This is the simplest form of ` err2 ` automatic error handler:
115
+ This is the simplest form of an automatic error handler:
116
116
117
117
``` go
118
118
func doSomething () (err error ) {
119
- // below: if err != nil { return ftm.Errorf("%s: %w", CUR_FUNC_NAME, err) }
120
119
defer err2.Handle (&err)
121
120
` ` `
122
121
122
+ <details>
123
+ <summary>The explanation of the above code and its error handler:</summary>
124
+ <br/>
125
+
126
+ Simplest rule for err2 error handlers are:
127
+ 1. Use named error return value: ` (..., err error )`
128
+ 1. Add at least one error handler at the beginning of your function (see the
129
+ above code block). *Handlers are called only if error ≠ nil.*
130
+ 1. Use ` err2.handle ` functions different calling schemes to achieve needed
131
+ behaviour. For example, without no extra arguments ` err2.Handle `
132
+ automatically annotates your errors by building annotations string from the
133
+ function's current name: ` doSomething → " do something" ` . Default is decamel
134
+ and add spaces. See ` err2.SetFormatter ` for more information.
135
+ 1. Every function which uses err2 for error-checking should have at least one
136
+ error handler. The current function panics if there are no error handlers and
137
+ an error occurs. However, if *any* function above in the call stack has an
138
+ err2 error handler, it will catch the error.
139
+
123
140
See more information from ` err2.Handle ` 's documentation. It supports several
124
141
error-handling scenarios. And remember that you can have as many error handlers
125
142
per function as you need, as well as you can chain error handling functions per
126
143
` err2.Handle ` that allows you to build new error handling middleware for your
127
144
own purposes.
128
145
146
+ </details>
147
+
129
148
#### Error Stack Tracing
130
149
131
150
The err2 offers optional stack tracing. It's automatic and optimized. Optimized
@@ -134,7 +153,10 @@ trace starts from where the actual error/panic is occurred, not where the error
134
153
is caught. You don't need to search for the line where the pointer was nil or
135
154
received an error. That line is in the first one you are seeing:
136
155
137
- ` ` ` console
156
+ <details>
157
+ <summary>The example of the optimized call stack:</summary>
158
+
159
+ ` ` ` sh
138
160
---
139
161
runtime error : index out of range [0 ] with length 0
140
162
---
@@ -145,6 +167,8 @@ main.main()
145
167
/home/.../go /src/github.com /lainio/ic/main.go :77 +0x248
146
168
` ` `
147
169
170
+ </details><br/>
171
+
148
172
Just set the ` err2.SetErrorTracer ` or ` err2.SetPanicTracer ` to the stream you
149
173
want traces to be written:
150
174
@@ -197,7 +221,7 @@ handling.
197
221
198
222
Nevertheless, there might be cases where you might want to:
199
223
1. Suppress the error and use some default value.
200
- 1. Just write a logline and continue without a break .
224
+ 1. Just write logging output and continue without breaking the execution .
201
225
1. Annotate the specific error value even when you have a general error handler.
202
226
1. You want to handle the specific error value, let's say, at the same line
203
227
or statement.
@@ -229,6 +253,7 @@ actual errors we have functions like `try.Is` and even `try.IsEOF` for
229
253
convenience.
230
254
231
255
With these you can write code where error is translated to boolean value:
256
+
232
257
` ` ` go
233
258
notExist := try.Is (r2.err , plugin.ErrNotExist )
234
259
@@ -245,23 +270,8 @@ notExist := try.Is(r2.err, plugin.ErrNotExist)
245
270
> 3. Finally, it calls ` try.To ` for the non nil error, and we already know what then
246
271
> happens: nearest ` err2.Handle ` gets it first.
247
272
248
- These ` try.Is ` functions help cleanup mess idiomatic Go, i.e. mixing happy and
249
- error path, leads to.
250
-
251
273
For more information see the examples in the documentation of both functions.
252
274
253
- ## Backwards Compatibility Promise for the API
254
-
255
- The ` err2` package's API will be **backward compatible**. Before version
256
- 1.0.0 is released, the API changes occasionally, but **we promise to offer
257
- automatic conversion scripts for your repos to update them for the latest API.**
258
- We also mark functions deprecated before they become obsolete. Usually, one
259
- released version before. We have tested this with a large code base in our
260
- systems, and it works wonderfully.
261
-
262
- More information can be found in the ` scripts/` directory [readme
263
- file](./scripts/README.md).
264
-
265
275
## Assertion
266
276
267
277
The ` assert` package is meant to be used for *design-by-contract-* type of
@@ -282,17 +292,15 @@ assert.SetDefault(assert.Production)
282
292
` ` `
283
293
284
294
If you want to suppress the caller info (source file name, line number, etc.)
285
- and get just the plain panics from the asserts, you should set the
286
- default asserter with the following line:
295
+ from certain asserts, you can do that per a goroutine or a function. You should
296
+ set the asserter with the following line for the current function :
287
297
288
298
` ` ` go
289
- assert.SetDefault (assert.Debug )
299
+ defer assert.PushAsserter (assert.Plain )( )
290
300
` ` `
291
301
292
- For certain type of programs this is the best way. It allows us to keep all the
293
- error messages as simple as possible. And by offering option to turn additional
294
- information on, which allows super users and developers get more technical
295
- information when needed.
302
+ This is especially good if you want to use assert functions for CLI's flag
303
+ validation or you want your app behave like legacy Go programs.
296
304
297
305
> [!NOTE]
298
306
> Since v0.9.5 you can set these asserters through Go's standard flag package
@@ -305,10 +313,10 @@ Following is example of use of the assert package:
305
313
306
314
` ` ` go
307
315
func marshalAttestedCredentialData (json []byte , data *protocol.AuthenticatorData ) []byte {
308
- assert.SLen (data.AttData .AAGUID , 16 , " wrong AAGUID length" )
309
- assert.NotEmpty (data.AttData .CredentialID , " empty credential id" )
310
- assert.SNotEmpty (data.AttData .CredentialPublicKey , " empty credential public key" )
311
- ...
316
+ assert.SLen (data.AttData .AAGUID , 16 , " wrong AAGUID length" )
317
+ assert.NotEmpty (data.AttData .CredentialID , " empty credential id" )
318
+ assert.SNotEmpty (data.AttData .CredentialPublicKey , " empty credential public key" )
319
+ ...
312
320
` ` `
313
321
314
322
We have now described design-by-contract for development and runtime use. What
@@ -317,7 +325,11 @@ automatic testing as well.
317
325
318
326
#### Assertion Package for Unit Testing
319
327
320
- The same asserts can be used **and shared** during the unit tests:
328
+ The same asserts can be used **and shared** during the unit tests.
329
+
330
+ <details>
331
+ <summary>The unit test code example:</summary>
332
+
321
333
322
334
` ` ` go
323
335
func TestWebOfTrustInfo (t *testing.T ) {
@@ -345,6 +357,8 @@ of the actual Test function, **it's reported as a standard test failure.** That
345
357
means we don't need to open our internal pre- and post-conditions just for
346
358
testing.
347
359
360
+ </details><br/>
361
+
348
362
**We can share the same assertions between runtime and test execution.**
349
363
350
364
The err2 ` assert` package integration to the Go ` testing` package is completed at
@@ -365,9 +379,12 @@ have an option to automatically support for err2 configuration flags through
365
379
Go's standard ` flag` package. See more information about err2 settings from
366
380
[Error Stack Tracing](#error-stack-tracing) and [Asserters](#asserters).
367
381
368
- Now you can always deploy your applications and services with the simple
369
- end-user friendly error messages and no stack traces, **but you can switch them
370
- on when ever you need**.
382
+ You can deploy your applications and services with the simple *end-user friendly
383
+ error messages and no stack traces.*
384
+
385
+ <details>
386
+ <summary>You can switch them on when ever you need them again.</summary>
387
+ <br/>
371
388
372
389
Let's say you have build CLI (` your-app` ) tool with the support for Go's flag
373
390
package, and the app returns an error. Let's assume you're a developer. You can
@@ -389,12 +406,17 @@ That adds more information to the assertion statement, which in default is in
389
406
production (` Prod` ) mode, i.e., outputs a single-line assertion message.
390
407
391
408
All you need to do is to add ` flag.Parse ` to your ` main` function.
409
+ </details>
392
410
393
411
#### Support for Cobra Flags
394
412
395
413
If you are using [cobra](https://github.com/spf13/cobra) you can still easily
396
414
support packages like ` err2` and ` glog` and their flags.
397
415
416
+ <details>
417
+ <summary>Add cobra support:</summary>
418
+ <br/>
419
+
398
420
1. Add std flag package to imports in ` cmd/root.go ` :
399
421
400
422
` ` ` go
@@ -442,17 +464,28 @@ Flags:
442
464
...
443
465
` ` `
444
466
467
+ </details>
468
+
445
469
## Code Snippets
446
470
447
- Most of the repetitive code blocks are offered as code snippets. They are in
448
- ` ./snippets` in VC code format, which is well supported e.g. neovim, etc.
471
+ <details>
472
+ <summary>Most of the repetitive code blocks are offered as code snippets.</summary>
473
+ <br/>
474
+
475
+ They are in ` ./snippets` in VC code format, which is well supported e.g. neovim,
476
+ etc.
449
477
450
478
The snippets must be installed manually to your preferred IDE/editor. During the
451
479
installation you can modify the according your style or add new ones. We would
452
480
prefer if you could contribute some of the back to the err2 package.
481
+ </details>
453
482
454
483
## Background
455
484
485
+ <details>
486
+ <summary>Why this repo exists?</summary>
487
+ <br/>
488
+
456
489
` err2` implements similar error handling mechanism as drafted in the original
457
490
[check/handle
458
491
proposal](https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling-overview.md).
@@ -492,14 +525,15 @@ help:
492
525
background) to projects,
493
526
- and most importantly, **it keeps your code more refactorable** because you
494
527
don't have to repeat yourself.
495
-
496
- <details>
497
- <summary>Learnings...</summary>
528
+ </details>
498
529
499
530
## Learnings by so far
500
531
501
- We have used the ` err2` and ` assert` packages in several projects. The results
502
- have been so far very encouraging:
532
+ <details>
533
+ <summary>We have used the err2 and assert packages in several projects. </summary>
534
+ <br/>
535
+
536
+ The results have been so far very encouraging:
503
537
504
538
- If you forget to use handler, but you use checks from the package, you will
505
539
get panics on errors (and optimized stack traces that can be suppressed). That
@@ -517,7 +551,7 @@ been much easier.** There is an excellent [blog post](https://jesseduffield.com/
517
551
about the issues you are facing with Go's error handling without the help of
518
552
the err2 package.
519
553
520
- </details><br/>
554
+ </details>
521
555
522
556
## Support And Contributions
523
557
0 commit comments