-
Notifications
You must be signed in to change notification settings - Fork 3
/
werror.go
88 lines (79 loc) · 1.84 KB
/
werror.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package goxml
import (
"encoding/json"
"fmt"
"runtime"
"strings"
)
type Werror struct {
P []string // err msgs for public consumption
C []string
PC []uintptr `json:"-"`
Cause error
Xp *Xp `json:"-"`
}
// NewWerror allows us to make error that are list of semistructured messages "tag: message" to
// allow for textual error messages that can be interpreted by a program.
func NewWerror(ctx ...string) Werror {
x := Werror{C: ctx}
x.PC = make([]uintptr, 32)
n := runtime.Callers(2, x.PC)
x.PC = x.PC[:n]
return x
}
// Wrap a std error in a Werror
func Wrap(err error, ctx ...string) Werror {
switch x := err.(type) {
case Werror:
x.C = append(x.C, ctx...)
return x
default:
werr := NewWerror("cause:" + err.Error())
werr.Cause = err
return Wrap(werr, ctx...)
}
}
// WrapWithXp - keep the Xp to be able to debug
func WrapWithXp(err error, xp *Xp, ctx ...string) error {
werr := Wrap(err, ctx...)
werr.Xp = xp
return werr
}
// PublicError - append messages to a Werror
func PublicError(e Werror, ctx ...string) error {
e.P = append(e.P, ctx...)
return e
}
// Error downgrade an Werror to error
func (e Werror) Error() (err string) {
errjson, _ := json.Marshal(e.C)
if len(e.P) > 0 {
errjson, _ = json.Marshal(e.P)
}
err = string(errjson)
return
}
// FullError - convert to JSON
func (e Werror) FullError() (err string) {
errjson, _ := json.Marshal(append(e.C, e.P...))
err = string(errjson)
return
}
// Stack - get stack as string
func (e Werror) Stack(depth int) (st string) {
n := len(e.PC)
if n > 0 && depth < n {
pcs := e.PC[:n-depth]
frames := runtime.CallersFrames(pcs)
for {
frame, more := frames.Next()
function := frame.Function
file := strings.Split(frame.File, "/")
st += fmt.Sprintf(" %s %s %d\n", function, file[len(file)-1:][0], frame.Line)
if !more {
break
}
}
}
return
}