github.com/anishathalye/periscope@v0.3.5/internal/herror/herror.go (about) 1 package herror 2 3 import ( 4 "bytes" 5 "fmt" 6 "runtime" 7 "strings" 8 ) 9 10 const maxStackDepth = 50 11 12 type Interface interface { 13 error 14 Herror(debug bool) string 15 } 16 17 type base struct { 18 stackTrace string 19 } 20 21 func newBase() base { 22 stackBuf := make([]uintptr, maxStackDepth) 23 length := runtime.Callers(3, stackBuf[:]) 24 stack := stackBuf[:length] 25 frames := runtime.CallersFrames(stack) 26 buf := new(bytes.Buffer) 27 for { 28 frame, more := frames.Next() 29 fn := frame.Function 30 if fn == "" { 31 fn = "???" 32 } 33 fmt.Fprintf(buf, "%s\n\t%s:%d\n", fn, frame.File, frame.Line) 34 if !more { 35 break 36 } 37 } 38 return base{buf.String()} 39 } 40 41 type silent struct { 42 base 43 } 44 45 func (s *silent) Error() string { 46 return "" 47 } 48 49 func (s *silent) Herror(debug bool) string { 50 if !debug { 51 return "" 52 } 53 return fmt.Sprintf("<silent error>\n--------\n%s--------\n", s.stackTrace) 54 } 55 56 func Silent() Interface { 57 return &silent{base: newBase()} 58 } 59 60 func IsSilent(e Interface) bool { 61 _, ok := e.(*silent) 62 return ok 63 } 64 65 type user struct { 66 base 67 err error 68 message string 69 } 70 71 func (u *user) Error() string { 72 if u.err != nil { 73 return fmt.Sprintf("%s (%s)", u.message, u.err.Error()) 74 } 75 return u.message 76 } 77 78 func (u *user) Herror(debug bool) string { 79 buf := new(bytes.Buffer) 80 fmt.Fprint(buf, u.message) 81 if u.err != nil { 82 fmt.Fprintf(buf, " (%s)", u.err.Error()) 83 } 84 fmt.Fprintf(buf, "\n") 85 if debug { 86 fmt.Fprintf(buf, "--------\n%s--------\n", u.stackTrace) 87 } 88 return buf.String() 89 } 90 91 func User(err error, message string) Interface { 92 return &user{base: newBase(), err: err, message: strings.TrimSpace(message)} 93 } 94 95 func UserF(err error, message string, a ...interface{}) Interface { 96 return User(err, fmt.Sprintf(message, a...)) 97 } 98 99 type unlikely struct { 100 base 101 err error 102 short string 103 long string 104 } 105 106 func (u *unlikely) Error() string { 107 if u.err != nil { 108 return fmt.Sprintf("%s (%s)", u.short, u.err.Error()) 109 } 110 return u.short 111 } 112 113 func (u *unlikely) Herror(debug bool) string { 114 buf := new(bytes.Buffer) 115 fmt.Fprint(buf, u.short) 116 if u.err != nil { 117 fmt.Fprintf(buf, " (%s)", u.err.Error()) 118 } 119 fmt.Fprint(buf, "\n") 120 if len(u.long) > 0 { 121 fmt.Fprintf(buf, "\n%s\n", u.long) 122 } 123 if debug { 124 fmt.Fprintf(buf, "--------\n%s--------\n", u.stackTrace) 125 } 126 return buf.String() 127 } 128 129 func Unlikely(err error, short string, long string) Interface { 130 return &unlikely{base: newBase(), short: strings.TrimSpace(short), err: err, long: strings.TrimSpace(long)} 131 } 132 133 type internal struct { 134 base 135 err error 136 message string 137 } 138 139 func (i *internal) Error() string { 140 if i.message != "" { 141 return fmt.Sprintf("%s (%s)", i.message, i.err.Error()) 142 } 143 return i.err.Error() 144 } 145 146 func (i *internal) Herror(debug bool) string { 147 buf := new(bytes.Buffer) 148 fmt.Fprint(buf, "internal error: ") 149 if i.message != "" { 150 fmt.Fprintf(buf, "%s (%s)\n", i.message, i.err.Error()) 151 } else { 152 fmt.Fprintf(buf, "%s\n", i.err.Error()) 153 } 154 if !debug { 155 fmt.Fprintf(buf, "\nThis might be a bug in periscope.\n\nRun with --debug to see a stack trace, and please consider opening a GitHub issue to report this occurrence.\n") 156 } else { 157 fmt.Fprintf(buf, "--------\n%s--------\n", i.stackTrace) 158 } 159 return buf.String() 160 } 161 162 func Internal(err error, message string) Interface { 163 return &internal{base: newBase(), message: strings.TrimSpace(message), err: err} 164 }