feat(util:context) add error logging to context
This commit... is a second attempt at: https://github.com/jbenet/go-ipfs/pull/68 partially addresses: https://github.com/jbenet/go-ipfs/issues/66 is the result of discussion at: https://gist.github.com/perfmode/f2951c1ed3a02c484d0b
Brian Tiger Chow committed
Sep 23, 2014 at 16:41 UTC
63a2855a49df0492090416004f8a56fa05845405
2 files changed
+63
util/context.go
new
+35
@@ -0,0 +1,35 @@
1
+package util
2
+
3
+import (
4
+ context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
5
+)
6
+
7
+// privateChanType protects the channel. Since this is a package-private type,
8
+// only methods defined in this package can get the error value from the
9
+// context.
10
+type privateChanType chan error
11
+
12
+const errLogKey = "the key used to extract the error log from the context"
13
+
14
+// ContextWithErrorLog returns a copy of parent and an error channel that can
15
+// be used to receive errors sent with the LogError method.
16
+func ContextWithErrorLog(parent context.Context) (context.Context, <-chan error) {
17
+ errs := make(privateChanType)
18
+ ctx := context.WithValue(parent, errLogKey, errs)
19
+ return ctx, errs
20
+}
21
+
22
+// LogError logs the error to the owner of the context.
23
+//
24
+// If this context was created with ContextWithErrorLog, then this method
25
+// passes the error to context creator over an unbuffered channel.
26
+//
27
+// If this context was created by other means, this method is a no-op.
28
+func LogError(ctx context.Context, err error) {
29
+ v := ctx.Value(errLogKey)
30
+ errs, ok := v.(privateChanType)
31
+ if !ok {
32
+ return
33
+ }
34
+ errs <- err
35
+}
util/context_test.go
new
+28
@@ -0,0 +1,28 @@
1
+package util
2
+
3
+import (
4
+ "errors"
5
+ "testing"
6
+
7
+ context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
8
+)
9
+
10
+func TestLogErrorDoesNotBlockWhenCtxIsNotSetUpForLogging(t *testing.T) {
11
+ ctx := context.Background()
12
+ LogError(ctx, errors.New("ignore me"))
13
+}
14
+
15
+func TestLogErrorReceivedByParent(t *testing.T) {
16
+
17
+ expected := errors.New("From child to parent")
18
+
19
+ ctx, errs := ContextWithErrorLog(context.Background())
20
+
21
+ go func() {
22
+ LogError(ctx, expected)
23
+ }()
24
+
25
+ if err := <-errs; err != expected {
26
+ t.Fatal("didn't receive the expected error")
27
+ }
28
+}