Skip to content

Instantly share code, notes, and snippets.

@shovanmaity
Created April 11, 2019 09:32
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shovanmaity/bd5b6317d9fc9ab9df810cb79e641a1a to your computer and use it in GitHub Desktop.
Save shovanmaity/bd5b6317d9fc9ab9df810cb79e641a1a to your computer and use it in GitHub Desktop.
package main
import (
"encoding/json"
"fmt"
"log"
"github.com/pkg/errors"
)
func jsonIndent(ctx string, obj interface{}) string {
if obj == nil {
return ""
}
b, _ := json.MarshalIndent(obj, "", ".")
return fmt.Sprintf("%s %s", ctx, string(b))
}
func newTypea() *Typea {
return &Typea{Item: 1}
}
func newTypeb() *Typeb {
return &Typeb{Item: 2}
}
func newTypec() *Typec {
return &Typec{Item: 3}
}
// Struct typea with GoString and String implementation
type Typea struct {
Item int
}
func (a *Typea) String() string {
return jsonIndent("struct Typea", a)
}
func (a *Typea) GoString() string {
return a.String()
}
func (a *Typea) errorFunc1() error {
b := newTypeb()
return b.errorFunc1()
}
func (a *Typea) errorFunc2() error {
b := newTypeb()
return errors.Wrapf(b.errorFunc2(), "object: %+v", a)
}
func (a *Typea) errorFunc3() error {
b := newTypeb()
return errors.WithMessagef(b.errorFunc3(), "object: %+v", a)
}
func (a *Typea) errorFunc4() error {
b := newTypeb()
return errors.WithMessagef(b.errorFunc4(), "object: %+v", a)
}
func (a *Typea) errorFunc5() error {
b := newTypeb()
return errors.WithMessagef(b.errorFunc5(), "object: %+v", a)
}
// Struct typeb with GoString and String implementation
type Typeb struct {
Item int
}
func (b *Typeb) String() string {
return jsonIndent("struct Typeb", b)
}
func (b *Typeb) GoString() string {
return b.String()
}
func (b *Typeb) errorFunc1() error {
c := newTypec()
return c.errorFunc1()
}
func (b *Typeb) errorFunc2() error {
c := newTypec()
return errors.Wrapf(c.errorFunc1(), "object: %+v", b)
}
func (b *Typeb) errorFunc3() error {
c := newTypec()
return errors.WithMessagef(c.errorFunc1(), "object: %+v", b)
}
func (b *Typeb) errorFunc4() error {
c := newTypec()
return errors.WithMessagef(c.errorFunc2(), "object: %+v", b)
}
func (b *Typeb) errorFunc5() error {
c := newTypec()
return errors.WithMessagef(c.errorFunc3(), "object: %+v", b)
}
// Struct typec with GoString and String implementation
type Typec struct {
Item int
}
func (c *Typec) String() string {
return jsonIndent("struct Typec", c)
}
func (c *Typec) GoString() string {
return c.String()
}
func (c *Typec) errorFunc1() error {
return errors.Errorf("new error %+v", c)
}
func (c *Typec) errorFunc2() error {
return fmt.Errorf("new error %+v", c)
}
func (c *Typec) errorFunc3() error {
err := fmt.Errorf("new error")
// return errors.Wrapf(err, "%+v", c)
return errors.Errorf("%s %+v", err, c)
}
// main function
func main() {
a := newTypea()
log.Printf(`------------------------------Example-1------------------------------
This is a basic example of printing StackTrace. I have 4 functions main, func1, func2,
func3. Here source of error(func3) returns an error and func2 and func3 returns same error.
func func3() err{
return errors.New("new error")
}
func func2() err{
return func3()
}
func func1() err{
return func2()
}
func main(){
log.Println(func1())
}
--------------------------------------------------------------------------------------------`)
log.Printf("\n\n\nerror: %+v\n\n\n", a.errorFunc1())
log.Printf(`------------------------------Example-2------------------------------
Now question how can I add some more extra details in every function calls?
=> we can use errors.Wraf to add more info in every function calls.
func func3() err{
return errors.New("new error")
}
func func2() err{
return errors.Wraf(func3(),"function2")
}
func func1() err{
return errors.Wraf(func2(),"function1")
}
func main(){
log.Println(func1())
}
--------------------------------------------------------------------------------------------`)
log.Printf("\n\n\nerror: %+v\n\n", a.errorFunc2())
log.Printf(`------------------------------Example-3------------------------------
Now question my StackTrace is printing multiple time. why and how can I avoid this?
Why?
=> errors.Wrapf creates a new instance of error also new StackTrace for it. Thats why we
are getting StackTrace multiple times.
How to avoid?
=> we can use errors.WithMessagef to avoid this. errors.WithMessagef will add only extra
message in that error.
func func3() err{
return errors.New("new error")
}
func func2() err{
return errors.WithMessagef(func3(),"function2")
}
func func1() err{
return errors.WithMessagef(func2(),"function1")
}
func main(){
log.Println(func1())
}
--------------------------------------------------------------------------------------------`)
log.Printf("\n\n\nerror: %+v\n\n\n", a.errorFunc3())
log.Printf(`------------------------------Example-4------------------------------
Now question what happen if my error is generated by some external package and it
does not have StackTrace.
=> It will not print StackTrace
func func3() err{
return fmt.Errorf("new error")
}
func func2() err{
return errors.WithMessagef(func3(),"function2")
}
func func1() err{
return errors.WithMessagef(func2(),"function1")
}
func main(){
log.Println(func1())
}
--------------------------------------------------------------------------------------------`)
log.Printf("\n\n\nerror: %+v\n\n\n", a.errorFunc4())
log.Printf(`------------------------------Example-5------------------------------
Now question How to solve this?
=> Wraping external error will solve this problem
func func3() err{
return errors.Wrapf(fmt.Errorf("new error"),"function3")
}
func func2() err{
return errors.WithMessagef(func3(),"function2")
}
func func1() err{
return errors.WithMessagef(func2(),"function1")
}
func main(){
log.Println(func1())
}
--------------------------------------------------------------------------------------------`)
log.Printf("\n\n\nerror: %+v\n\n\n", a.errorFunc5())
log.Println(`
-----------------------------------------------------------------------------------------
Q- how we are printing StackTrace?
=> Here I copied some comments from github.com/pkg/errors package.
All error values returned from this package implement fmt.Formatter and can
be formatted by the fmt package. The following verbs are supported:
%s => print the error. If the error has a Cause it will be printed recursively.
%v => see %s
%+v => extended format. Each Frame of the error's StackTrace will be printed in detail.
-----------------------------------------------------------------------------------------
Q- What does errors.WithMessagef() do?
=> Here I copied some comments and code from github.com/pkg/errors package.
type withMessage struct {
cause error
msg string
}
func (w *withMessage) Cause() error { return w.cause }
// WithMessagef annotates err with the format specifier.
func WithMessagef(err error, format string, args ...interface{}) error {
if err == nil {
return nil
}
return &withMessage{
cause: err,
msg: fmt.Sprintf(format, args...),
}
}
-----------------------------------------------------------------------------------------
Q- What does errors.Wrapf() do?
=> Here I copied some comments and code from github.com/pkg/errors package.
type withStack struct {
error
*stack
}
func (w *withStack) Cause() error { return w.error }
// Wrapf returns an error annotating err with a stack trace
// at the point Wrapf is called, and the format specifier.
func Wrapf(err error, format string, args ...interface{}) error {
if err == nil {
return nil
}
err = &withMessage{
cause: err,
msg: fmt.Sprintf(format, args...),
}
return &withStack{
err,
callers(),
}
}
-----------------------------------------------------------------------------------------`)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment