feat(debugerror)
License: MIT Signed-off-by: Brian Tiger Chow <brian@perfmode.com> impl errorf License: MIT Signed-off-by: Brian Tiger Chow <brian@perfmode.com> return a debug error License: MIT Signed-off-by: Brian Tiger Chow <brian@perfmode.com>
Brian Tiger Chow committed
Nov 14, 2014 at 15:18 UTC
eb5bb1daa87df6be45ee2b9fd56e3b58e94b1825
8 files changed
+244
-2
Godeps/Godeps.json
+4
@@ -60,6 +60,10 @@
60
"ImportPath": "github.com/coreos/go-semver/semver",
61
"Rev": "6fe83ccda8fb9b7549c9ab4ba47f47858bc950aa"
62
},
63
+ {
64
+ "ImportPath": "github.com/facebookgo/stackerr",
65
+ "Rev": "060fbf9364c89acd41bf710e9e92915a90e7a5b5"
66
+ },
67
{
68
"ImportPath": "github.com/gonuts/flag",
69
"Rev": "741a6cbd37a30dedc93f817e7de6aaf0ca38a493"
Godeps/_workspace/src/github.com/facebookgo/stackerr/.travis.yml
new
+24
@@ -0,0 +1,24 @@
1
+language: go
2
+
3
+go:
4
+ - 1.2
5
+ - 1.3
6
+
7
+matrix:
8
+ fast_finish: true
9
+
10
+before_install:
11
+ - go get -v code.google.com/p/go.tools/cmd/vet
12
+ - go get -v github.com/golang/lint/golint
13
+ - go get -v code.google.com/p/go.tools/cmd/cover
14
+
15
+install:
16
+ - go install -race -v std
17
+ - go get -race -t -v ./...
18
+ - go install -race -v ./...
19
+
20
+script:
21
+ - go vet ./...
22
+ - $HOME/gopath/bin/golint .
23
+ - go test -cpu=2 -race -v ./...
24
+ - go test -cpu=2 -covermode=atomic ./...
Godeps/_workspace/src/github.com/facebookgo/stackerr/readme.md
new
+4
@@ -0,0 +1,4 @@
1
+stackerr [](http://travis-ci.org/facebookgo/stackerr)
2
+========
3
+
4
+Documentation: https://godoc.org/github.com/facebookgo/stackerr
Godeps/_workspace/src/github.com/facebookgo/stackerr/stackerr.go
new
+97
@@ -0,0 +1,97 @@
1
+// Package stackerr provides a way to augment errors with one or more stack
2
+// traces to allow for easier debugging.
3
+package stackerr
4
+
5
+import (
6
+ "errors"
7
+ "fmt"
8
+
9
+ "github.com/facebookgo/stack"
10
+)
11
+
12
+// Error provides the wrapper that adds multiple Stacks to an error. Each Stack
13
+// represents a location in code thru which this error was wrapped.
14
+type Error struct {
15
+ multiStack *stack.Multi
16
+ underlying error
17
+}
18
+
19
+// Error provides a multi line error string that includes the stack trace.
20
+func (e *Error) Error() string {
21
+ return fmt.Sprintf("%s\n%s", e.underlying, e.multiStack)
22
+}
23
+
24
+// MultiStack identifies the locations this error was wrapped at.
25
+func (e *Error) MultiStack() *stack.Multi {
26
+ return e.multiStack
27
+}
28
+
29
+// Underlying returns the error that is being wrapped.
30
+func (e *Error) Underlying() error {
31
+ return e.underlying
32
+}
33
+
34
+type hasMultiStack interface {
35
+ MultiStack() *stack.Multi
36
+}
37
+
38
+// WrapSkip the error and add the current Stack. The argument skip is the
39
+// number of stack frames to ascend, with 0 identifying the caller of Wrap. If
40
+// the error to be wrapped has a MultiStack, the current stack will be added to
41
+// it. If the error to be wrapped is nil, a nil error is returned.
42
+func WrapSkip(err error, skip int) error {
43
+ // nil errors are returned back as nil.
44
+ if err == nil {
45
+ return nil
46
+ }
47
+
48
+ // we're adding another Stack to an already wrapped error.
49
+ if se, ok := err.(hasMultiStack); ok {
50
+ se.MultiStack().AddCallers(skip + 1)
51
+ return err
52
+ }
53
+
54
+ // we're create a freshly wrapped error.
55
+ return &Error{
56
+ multiStack: stack.CallersMulti(skip + 1),
57
+ underlying: err,
58
+ }
59
+}
60
+
61
+// Wrap provides a convenience function that calls WrapSkip with skip=0. That
62
+// is, the Stack starts with the caller of Wrap.
63
+func Wrap(err error) error {
64
+ return WrapSkip(err, 1)
65
+}
66
+
67
+// New returns a new error that includes the Stack.
68
+func New(s string) error {
69
+ return WrapSkip(errors.New(s), 1)
70
+}
71
+
72
+// Newf formats and returns a new error that includes the Stack.
73
+func Newf(format string, args ...interface{}) error {
74
+ return WrapSkip(fmt.Errorf(format, args...), 1)
75
+}
76
+
77
+type hasUnderlying interface {
78
+ Underlying() error
79
+}
80
+
81
+// Underlying returns all the underlying errors by iteratively checking if the
82
+// error has an Underlying error. If e is nil, the returned slice will be nil.
83
+func Underlying(e error) []error {
84
+ var errs []error
85
+ for {
86
+ if e == nil {
87
+ return errs
88
+ }
89
+ errs = append(errs, e)
90
+
91
+ if eh, ok := e.(hasUnderlying); ok {
92
+ e = eh.Underlying()
93
+ } else {
94
+ e = nil
95
+ }
96
+ }
97
+}
Godeps/_workspace/src/github.com/facebookgo/stackerr/stackerr_test.go
new
+82
@@ -0,0 +1,82 @@
1
+package stackerr_test
2
+
3
+import (
4
+ "errors"
5
+ "fmt"
6
+ "regexp"
7
+ "strings"
8
+ "testing"
9
+
10
+ "github.com/facebookgo/stackerr"
11
+)
12
+
13
+func TestNew(t *testing.T) {
14
+ const errStr = "foo bar baz"
15
+ e := stackerr.New(errStr)
16
+ matches := []string{
17
+ errStr,
18
+ "^github.com/facebookgo/stackerr/stackerr_test.go:15 +TestNew$",
19
+ }
20
+ match(t, e.Error(), matches)
21
+}
22
+
23
+func TestNewf(t *testing.T) {
24
+ const fmtStr = "%s 42"
25
+ const errStr = "foo bar baz"
26
+ e := stackerr.Newf(fmtStr, errStr)
27
+ matches := []string{
28
+ fmt.Sprintf(fmtStr, errStr),
29
+ "^github.com/facebookgo/stackerr/stackerr_test.go:26 +TestNewf$",
30
+ }
31
+ match(t, e.Error(), matches)
32
+}
33
+
34
+func TestWrap(t *testing.T) {
35
+ const errStr = "foo bar baz"
36
+ e := stackerr.Wrap(errors.New(errStr))
37
+ matches := []string{
38
+ errStr,
39
+ "^github.com/facebookgo/stackerr/stackerr_test.go:36 +TestWrap$",
40
+ }
41
+ match(t, e.Error(), matches)
42
+}
43
+
44
+func TestNilWrap(t *testing.T) {
45
+ if stackerr.WrapSkip(nil, 1) != nil {
46
+ t.Fatal("did not get nil error")
47
+ }
48
+}
49
+
50
+func TestDoubleWrap(t *testing.T) {
51
+ e := stackerr.New("")
52
+ if stackerr.WrapSkip(e, 1) != e {
53
+ t.Fatal("double wrap failure")
54
+ }
55
+}
56
+
57
+func TestLog(t *testing.T) {
58
+ t.Log(stackerr.New("hello"))
59
+}
60
+
61
+func TestUnderlying(t *testing.T) {
62
+ e1 := errors.New("")
63
+ e2 := stackerr.Wrap(e1)
64
+ errs := stackerr.Underlying(e2)
65
+ if len(errs) != 2 || errs[0] != e2 || errs[1] != e1 {
66
+ t.Fatal("failed Underlying")
67
+ }
68
+}
69
+
70
+func match(t testing.TB, s string, matches []string) {
71
+ lines := strings.Split(s, "\n")
72
+ for i, m := range matches {
73
+ if !regexp.MustCompile(m).MatchString(lines[i]) {
74
+ t.Fatalf(
75
+ "did not find expected match \"%s\" on line %d in:\n%s",
76
+ m,
77
+ i,
78
+ s,
79
+ )
80
+ }
81
+ }
82
+}
cmd/ipfs2/main.go
+1
@@ -169,6 +169,7 @@ func (i *cmdInvocation) Parse(args []string) error {
169
if err != nil {
170
return err
171
}
172
+ log.Debugf("config path is %s", configPath)
173
174
// this sets up the function that will initialize the config lazily.
175
ctx := i.req.Context()
config/config.go
+2
-2
@@ -5,11 +5,11 @@ import (
5
"crypto"
6
"crypto/x509"
7
"encoding/base64"
8
- "errors"
8
"os"
9
"path/filepath"
10
11
u "github.com/jbenet/go-ipfs/util"
12
+ "github.com/jbenet/go-ipfs/util/debugerror"
13
)
14
15
var log = u.Logger("config")
@@ -129,7 +129,7 @@ func (i *Identity) DecodePrivateKey(passphrase string) (crypto.PrivateKey, error
129
func Load(filename string) (*Config, error) {
130
// if nothing is there, fail. User must run 'ipfs init'
131
if _, err := os.Stat(filename); os.IsNotExist(err) {
132
- return nil, errors.New("ipfs not initialized, please run 'ipfs init'")
132
+ return nil, debugerror.New("ipfs not initialized, please run 'ipfs init'")
133
}
134
135
var cfg Config
util/debugerror/debugerror.go
new
+30
@@ -0,0 +1,30 @@
1
+// package debugerror provides a way to augment errors with additional
2
+// information to allow for easier debugging.
3
+package debugerror
4
+
5
+import (
6
+ "errors"
7
+ "fmt"
8
+
9
+ "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/facebookgo/stackerr"
10
+ "github.com/jbenet/go-ipfs/util"
11
+)
12
+
13
+func Errorf(format string, a ...interface{}) error {
14
+ return Wrap(fmt.Errorf(format, a...))
15
+}
16
+
17
+// New returns an error that contains a stack trace (in debug mode)
18
+func New(s string) error {
19
+ if util.Debug {
20
+ return stackerr.New(s)
21
+ }
22
+ return errors.New(s)
23
+}
24
+
25
+func Wrap(err error) error {
26
+ if util.Debug {
27
+ return stackerr.Wrap(err)
28
+ }
29
+ return err
30
+}