An errors package that will help you handle them gracefully. It allows you to add additional data to your errors, to wrap it and you even get a stack trace. Inspired by the github.com/pkg/errors package and Node.js' verror module.
- Add additional data to error values preventing long and hard to read error messages
- Wrap existing error values into new ones
- Stack traces for each error value
- MultiError, wrap multiple errors values into a single one; great for concurrent workflows that may generate multiple errors
- Pretty print of the whole error value and support JSON marshalling to ease the serialization (check the "Quick demo" section)
go get -u github.com/zignd/errorsFor a better understanding of the features provided by the package check the documentation at: pkg.go.dev/github.com/zignd/errors
There's an example at examples/example1/example1.go that shows how to use the package.
Here's the code for the example:
package main import ( "encoding/json""fmt""github.com/zignd/errors" ) funccreateTransaction(idstring) error{bank:="bank_123456"iferr:=updateDatabase(); err!=nil{returnerrors.Wrapdf(err, errors.Data{"transactionId": id, "userId": "67890", }, "failed to complete the transaction on %s", bank) } returnnil } funcupdateDatabase() error{iferr:=createConnection(); err!=nil{returnerrors.Wrapd(err, errors.Data{"tableName": "transactions", "operation": "update", }, "failed to update the database") } returnnil } funccreateConnection() error{iferr:=open(); err!=nil{returnerrors.Wrapd(err, errors.Data{"server": "db-server-01", "timeoutSeconds": 30, }, "connection timeout") } returnnil } funcopen() error{returnerrors.Errord(errors.Data{"network": "internal", "severity": "high", }, "network instability detected") } funcmain(){iferr:=createTransaction("tx_123456"); err!=nil{b, _:=json.MarshalIndent(err, "", " ") fmt.Println("Error logged as a JSON structure using the json.MarshalIndent:") fmt.Printf("%s\n", b) b, _=json.Marshal(err) fmt.Println("\nError logged as a JSON structure using the json.Marshal:") fmt.Printf("%s\n", b) fmt.Println("\nError logged using the s format specifier:") fmt.Printf("%s\n", err) fmt.Println("\nError logged using the +v format specifier:") fmt.Printf("%+v\n", err) } }Here's the execution of the example:
$ go run examples/example1/example1.go Error logged as a JSON structure using the json.MarshalIndent: [{"data":{"transactionId": "tx_123456", "userId": "67890" }, "message": "failed to complete the transaction on bank_123456", "stack": [ "main.createTransaction @ /root/hack/errors/examples/example1/example1.go:13", "main.main @ /root/hack/errors/examples/example1/example1.go:52", "runtime/internal/atomic.(*Uint32).Load @ /root/go/version/go1.21.0/src/runtime/internal/atomic/types.go:194", "runtime.goexit @ /root/go/version/go1.21.0/src/runtime/asm_amd64.s:1651" ] },{"data":{"operation": "update", "tableName": "transactions" }, "message": "failed to update the database", "stack": [ "main.updateDatabase @ /root/hack/errors/examples/example1/example1.go:24", "main.createTransaction @ /root/hack/errors/examples/example1/example1.go:12", "main.main @ /root/hack/errors/examples/example1/example1.go:52", "runtime/internal/atomic.(*Uint32).Load @ /root/go/version/go1.21.0/src/runtime/internal/atomic/types.go:194", "runtime.goexit @ /root/go/version/go1.21.0/src/runtime/asm_amd64.s:1651" ] },{"data":{"server": "db-server-01", "timeoutSeconds": 30 }, "message": "connection timeout", "stack": [ "main.createConnection @ /root/hack/errors/examples/example1/example1.go:35", "main.updateDatabase @ /root/hack/errors/examples/example1/example1.go:23", "main.createTransaction @ /root/hack/errors/examples/example1/example1.go:12", "main.main @ /root/hack/errors/examples/example1/example1.go:52", "runtime/internal/atomic.(*Uint32).Load @ /root/go/version/go1.21.0/src/runtime/internal/atomic/types.go:194", "runtime.goexit @ /root/go/version/go1.21.0/src/runtime/asm_amd64.s:1651" ] },{"data":{"network": "internal", "severity": "high" }, "message": "network instability detected", "stack": [ "main.open @ /root/hack/errors/examples/example1/example1.go:45", "main.createConnection @ /root/hack/errors/examples/example1/example1.go:34", "main.updateDatabase @ /root/hack/errors/examples/example1/example1.go:23", "main.createTransaction @ /root/hack/errors/examples/example1/example1.go:12", "main.main @ /root/hack/errors/examples/example1/example1.go:52", "runtime/internal/atomic.(*Uint32).Load @ /root/go/version/go1.21.0/src/runtime/internal/atomic/types.go:194", "runtime.goexit @ /root/go/version/go1.21.0/src/runtime/asm_amd64.s:1651" ] } ] Error logged as a JSON structure using the json.Marshal: [{"data":{"transactionId":"tx_123456","userId":"67890"},"message":"failed to complete the transaction on bank_123456","stack":["main.createTransaction @ /root/hack/errors/examples/example1/example1.go:13","main.main @ /root/hack/errors/examples/example1/example1.go:52","runtime/internal/atomic.(*Uint32).Load @ /root/go/version/go1.21.0/src/runtime/internal/atomic/types.go:194","runtime.goexit @ /root/go/version/go1.21.0/src/runtime/asm_amd64.s:1651"]},{"data":{"operation":"update","tableName":"transactions"},"message":"failed to update the database","stack":["main.updateDatabase @ /root/hack/errors/examples/example1/example1.go:24","main.createTransaction @ /root/hack/errors/examples/example1/example1.go:12","main.main @ /root/hack/errors/examples/example1/example1.go:52","runtime/internal/atomic.(*Uint32).Load @ /root/go/version/go1.21.0/src/runtime/internal/atomic/types.go:194","runtime.goexit @ /root/go/version/go1.21.0/src/runtime/asm_amd64.s:1651"]},{"data":{"server":"db-server-01","timeoutSeconds":30},"message":"connection timeout","stack":["main.createConnection @ /root/hack/errors/examples/example1/example1.go:35","main.updateDatabase @ /root/hack/errors/examples/example1/example1.go:23","main.createTransaction @ /root/hack/errors/examples/example1/example1.go:12","main.main @ /root/hack/errors/examples/example1/example1.go:52","runtime/internal/atomic.(*Uint32).Load @ /root/go/version/go1.21.0/src/runtime/internal/atomic/types.go:194","runtime.goexit @ /root/go/version/go1.21.0/src/runtime/asm_amd64.s:1651"]},{"data":{"network":"internal","severity":"high"},"message":"network instability detected","stack":["main.open @ /root/hack/errors/examples/example1/example1.go:45","main.createConnection @ /root/hack/errors/examples/example1/example1.go:34","main.updateDatabase @ /root/hack/errors/examples/example1/example1.go:23","main.createTransaction @ /root/hack/errors/examples/example1/example1.go:12","main.main @ /root/hack/errors/examples/example1/example1.go:52","runtime/internal/atomic.(*Uint32).Load @ /root/go/version/go1.21.0/src/runtime/internal/atomic/types.go:194","runtime.goexit @ /root/go/version/go1.21.0/src/runtime/asm_amd64.s:1651"]}] Error logged using the s format specifier: failed to complete the transaction on bank_123456: failed to update the database: connection timeout: network instability detected Error logged using the +v format specifier: message: "failed to complete the transaction on bank_123456" data: userId: 67890 transactionId: tx_123456 stack: main.createTransaction @ /root/hack/errors/examples/example1/example1.go:13 main.main @ /root/hack/errors/examples/example1/example1.go:52 runtime/internal/atomic.(*Uint32).Load @ /root/go/version/go1.21.0/src/runtime/internal/atomic/types.go:194 runtime.goexit @ /root/go/version/go1.21.0/src/runtime/asm_amd64.s:1651 cause: message: "failed to update the database" data: tableName: transactions operation: update stack: main.updateDatabase @ /root/hack/errors/examples/example1/example1.go:24 main.createTransaction @ /root/hack/errors/examples/example1/example1.go:12 main.main @ /root/hack/errors/examples/example1/example1.go:52 runtime/internal/atomic.(*Uint32).Load @ /root/go/version/go1.21.0/src/runtime/internal/atomic/types.go:194 runtime.goexit @ /root/go/version/go1.21.0/src/runtime/asm_amd64.s:1651 cause: message: "connection timeout" data: server: db-server-01 timeoutSeconds: 30 stack: main.createConnection @ /root/hack/errors/examples/example1/example1.go:35 main.updateDatabase @ /root/hack/errors/examples/example1/example1.go:23 main.createTransaction @ /root/hack/errors/examples/example1/example1.go:12 main.main @ /root/hack/errors/examples/example1/example1.go:52 runtime/internal/atomic.(*Uint32).Load @ /root/go/version/go1.21.0/src/runtime/internal/atomic/types.go:194 runtime.goexit @ /root/go/version/go1.21.0/src/runtime/asm_amd64.s:1651 cause: message: "network instability detected" data: severity: high network: internal stack: main.open @ /root/hack/errors/examples/example1/example1.go:45 main.createConnection @ /root/hack/errors/examples/example1/example1.go:34 main.updateDatabase @ /root/hack/errors/examples/example1/example1.go:23 main.createTransaction @ /root/hack/errors/examples/example1/example1.go:12 main.main @ /root/hack/errors/examples/example1/example1.go:52 runtime/internal/atomic.(*Uint32).Load @ /root/go/version/go1.21.0/src/runtime/internal/atomic/types.go:194 runtime.goexit @ /root/go/version/go1.21.0/src/runtime/asm_amd64.s:1651