diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 169efd540..412c11080 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -20,7 +20,7 @@ }, { "ImportPath": "github.com/minio-io/iodine", - "Rev": "2843626767a878d03d02acd4d2bc3790eb325b64" + "Rev": "8c8985d5a45e388dccb5ca280c897672abb18278" }, { "ImportPath": "gopkg.in/check.v1", diff --git a/Godeps/_workspace/src/github.com/minio-io/iodine/iodine.go b/Godeps/_workspace/src/github.com/minio-io/iodine/iodine.go index 458e10df2..a1fd95b2e 100644 --- a/Godeps/_workspace/src/github.com/minio-io/iodine/iodine.go +++ b/Godeps/_workspace/src/github.com/minio-io/iodine/iodine.go @@ -28,9 +28,9 @@ import ( "sync" ) -// Error is the iodine error which contains a pointer to the original error +// WrappedError is the iodine error which contains a pointer to the original error // and stack traces. -type Error struct { +type WrappedError struct { EmbeddedError error `json:"-"` ErrorMessage string @@ -88,19 +88,33 @@ func GetGlobalStateKey(k string) string { return result } -// New - instantiate an error, turning it into an iodine error. +// Error - instantiate an error, turning it into an iodine error. // Adds an initial stack trace. -func New(err error, data map[string]string) *Error { +func Error(err error, data map[string]string) error { if err != nil { entry := createStackEntry() + var newErr WrappedError + + // check if error is wrapped + switch typedError := err.(type) { + case WrappedError: + { + newErr = typedError + } + default: + { + newErr = WrappedError{ + EmbeddedError: err, + ErrorMessage: err.Error(), + Stack: []StackEntry{}, + } + } + } for k, v := range data { entry.Data[k] = v } - return &Error{ - EmbeddedError: err, - ErrorMessage: err.Error(), - Stack: []StackEntry{entry}, - } + newErr.Stack = append(newErr.Stack, entry) + return newErr } return nil } @@ -146,24 +160,24 @@ func getSystemData() map[string]string { } // Annotate an error with a stack entry and returns itself -func (err *Error) Annotate(info map[string]string) *Error { - entry := createStackEntry() - for k, v := range info { - entry.Data[k] = v - } - err.Stack = append(err.Stack, entry) - return err -} +//func (err *WrappedError) Annotate(info map[string]string) *WrappedError { +// entry := createStackEntry() +// for k, v := range info { +// entry.Data[k] = v +// } +// err.Stack = append(err.Stack, entry) +// return err +//} // EmitJSON writes JSON output for the error -func (err Error) EmitJSON() ([]byte, error) { +func (err WrappedError) EmitJSON() ([]byte, error) { return json.Marshal(err) } // EmitHumanReadable returns a human readable error message -func (err Error) EmitHumanReadable() string { +func (err WrappedError) EmitHumanReadable() string { var errorBuffer bytes.Buffer - fmt.Fprintln(&errorBuffer, err.Error()) + fmt.Fprintln(&errorBuffer, err.ErrorMessage) for i, entry := range err.Stack { fmt.Fprintln(&errorBuffer, "-", i, entry.Host+":"+entry.File+":"+strconv.Itoa(entry.Line), entry.Data) } @@ -171,8 +185,8 @@ func (err Error) EmitHumanReadable() string { } // Emits the original error message -func (err Error) Error() string { - return err.EmbeddedError.Error() +func (err WrappedError) Error() string { + return err.EmitHumanReadable() } func init() { diff --git a/Godeps/_workspace/src/github.com/minio-io/iodine/iodine_test.go b/Godeps/_workspace/src/github.com/minio-io/iodine/iodine_test.go index 5a1ce1eb3..3aa7b39f4 100644 --- a/Godeps/_workspace/src/github.com/minio-io/iodine/iodine_test.go +++ b/Godeps/_workspace/src/github.com/minio-io/iodine/iodine_test.go @@ -24,21 +24,30 @@ import ( ) func TestIodine(t *testing.T) { - iodineError := New(errors.New("Hello"), nil) - iodineError.Annotate(nil) - iodineError.Annotate(nil) - iodineError.Annotate(nil) - if len(iodineError.Stack) != 4 { - t.Fail() - } - jsonResult, err := iodineError.EmitJSON() - if err != nil { - t.Fail() - } - var prettyBuffer bytes.Buffer - json.Indent(&prettyBuffer, jsonResult, "", " ") - if prettyBuffer.String() == "" { - t.Fail() + iodineError := Error(errors.New("Hello"), nil) + iodineError = Error(iodineError, nil) + iodineError = Error(iodineError, nil) + iodineError = Error(iodineError, nil) + switch typedError := iodineError.(type) { + case WrappedError: + { + if len(typedError.Stack) != 4 { + t.Fail() + } + jsonResult, err := typedError.EmitJSON() + if err != nil { + t.Fail() + } + var prettyBuffer bytes.Buffer + json.Indent(&prettyBuffer, jsonResult, "", " ") + if prettyBuffer.String() == "" { + t.Fail() + } + } + default: + { + t.Fail() + } } } @@ -54,36 +63,41 @@ func TestState(t *testing.T) { t.Fail() } SetGlobalState("foo", "bar") - err := New(errors.New("a simple error"), nil) - if res, ok := err.Stack[0].Data["foo"]; ok { - if res != "bar" { - t.Error("global state not set: foo->bar") + err := Error(errors.New("a simple error"), nil) + switch typedError := err.(type) { + case WrappedError: + { + if res, ok := typedError.Stack[0].Data["foo"]; ok { + if res != "bar" { + t.Error("global state not set: foo->bar") + } + } else { + t.Fail() + } + typedError = Error(typedError, map[string]string{"foo2": "bar2"}).(WrappedError) + if res, ok := typedError.Stack[0].Data["foo"]; ok { + if res != "bar" { + t.Error("annotate should not modify previous data entries") + } + } else { + t.Error("annotate should not remove previous data entries") + } + if res, ok := typedError.Stack[1].Data["foo"]; ok { + if res != "bar" { + t.Error("global state should set value properly in annotate") + } + } else { + t.Error("global state should set key properly in annotate") + } + if res, ok := typedError.Stack[1].Data["foo2"]; ok { + if res != "bar2" { + // typedError = Error(typedError, nil).(WrappedError) + t.Error("foo2 -> bar should be set") + } + } else { + // typedError = Error(typedError, nil).(WrappedError) + t.Error("foo2 should be set") + } } - } else { - t.Fail() - } - err.Annotate(map[string]string{"foo2": "bar2"}) - if res, ok := err.Stack[0].Data["foo"]; ok { - if res != "bar" { - t.Error("annotate should not modify previous data entries") - } - } else { - t.Error("annotate should not remove previous data entries") - } - if res, ok := err.Stack[1].Data["foo"]; ok { - if res != "bar" { - t.Error("global state should set value properly in annotate") - } - } else { - t.Error("global state should set key properly in annotate") - } - if res, ok := err.Stack[1].Data["foo2"]; ok { - if res != "bar2" { - err.Annotate(nil) - t.Error("foo2 -> bar should be set") - } - } else { - err.Annotate(nil) - t.Error("foo2 should be set") } } diff --git a/main.go b/main.go index 1e533a43f..e408f6a2e 100644 --- a/main.go +++ b/main.go @@ -137,7 +137,7 @@ func main() { app.Action = runCmd err := app.Run(os.Args) switch typedErr := err.(type) { - case *iodine.Error: + case *iodine.WrappedError: { log.Errorln(typedErr.EmitHumanReadable()) } diff --git a/pkg/drivers/donut/donut.go b/pkg/drivers/donut/donut.go index 185895324..a3b4f7809 100644 --- a/pkg/drivers/donut/donut.go +++ b/pkg/drivers/donut/donut.go @@ -46,13 +46,11 @@ func Start(path string) (chan<- string, <-chan error, drivers.Driver) { s := new(donutDriver) // TODO donut driver should be passed in as Start param and driven by config - var err *iodine.Error + var err error s.donut, err = donut.NewDonut(path) + err = iodine.Error(err, map[string]string{"path": path}) if err != nil { - err = err.Annotate(map[string]string{"path": path}) - if err != nil { - log.Println(err.EmitHumanReadable()) - } + log.Println(err) } go start(ctrlChannel, errorChannel, s) diff --git a/pkg/server/server.go b/pkg/server/server.go index b71bce5c0..8bdb95616 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -110,8 +110,8 @@ func getHTTPChannels(configs []Config) (ctrlChans []chan<- string, statusChans [ } default: { - err := iodine.New(errors.New("Invalid API type"), nil) - log.Fatal(err.EmitHumanReadable()) + err := iodine.Error(errors.New("Invalid API type"), nil) + log.Fatal(err) } } } @@ -142,7 +142,7 @@ func getDriverChannels(driverType DriverType) (ctrlChans []chan<- string, status { u, err := user.Current() if err != nil { - log.Errorln(iodine.New(err, nil).EmitHumanReadable()) + log.Errorln(iodine.Error(err, nil)) return nil, nil, nil } root := path.Join(u.HomeDir, "minio-storage", "file") @@ -154,7 +154,7 @@ func getDriverChannels(driverType DriverType) (ctrlChans []chan<- string, status { u, err := user.Current() if err != nil { - log.Errorln(iodine.New(err, nil).EmitHumanReadable()) + log.Errorln(iodine.Error(err, nil)) return nil, nil, nil } root := path.Join(u.HomeDir, "minio-driver", "donut") @@ -164,8 +164,7 @@ func getDriverChannels(driverType DriverType) (ctrlChans []chan<- string, status } default: // should never happen { - err := iodine.New(errors.New("No driver found"), nil) - log.Fatal(err.EmitHumanReadable()) + log.Fatal(iodine.Error(errors.New("No driver found"), nil)) } } return diff --git a/pkg/storage/donut/bucket.go b/pkg/storage/donut/bucket.go index 9e027d98d..e372b71ad 100644 --- a/pkg/storage/donut/bucket.go +++ b/pkg/storage/donut/bucket.go @@ -13,7 +13,7 @@ type donutBucket struct { } // GetNodes - get list of associated nodes for a given bucket -func (b donutBucket) GetNodes() ([]string, *iodine.Error) { +func (b donutBucket) GetNodes() ([]string, error) { var nodes []string for _, node := range b.nodes { nodes = append(nodes, node) @@ -21,17 +21,22 @@ func (b donutBucket) GetNodes() ([]string, *iodine.Error) { return nodes, nil } -func (b donutBucket) AddNode(nodeID, bucketID string) *iodine.Error { +// AddNode - adds a node to a bucket +func (b donutBucket) AddNode(nodeID, bucketID string) error { tokens := strings.Split(bucketID, ":") if len(tokens) != 3 { - return iodine.New(errors.New("Bucket ID malformed: "+bucketID), map[string]string{"nodeID": nodeID, "bucketID": bucketID}) + var err error + err = iodine.Error(nil, nil) + return err + // return iodine.Error(errors.New("Bucket ID malformed: "+bucketID), map[string]string{"nodeID": nodeID, "bucketID": bucketID}) + } // bucketName := tokens[0] // aggregate := tokens[1] // aggregate := "0" part, err := strconv.Atoi(tokens[2]) if err != nil { - return iodine.New(errors.New("Part malformed: "+tokens[2]), map[string]string{"nodeID": nodeID, "bucketID": bucketID}) + return iodine.Error(errors.New("Part malformed: "+tokens[2]), map[string]string{"nodeID": nodeID, "bucketID": bucketID}) } b.nodes[part] = nodeID return nil diff --git a/pkg/storage/donut/donut.go b/pkg/storage/donut/donut.go index 2db0e3268..133c0d4e0 100644 --- a/pkg/storage/donut/donut.go +++ b/pkg/storage/donut/donut.go @@ -16,7 +16,7 @@ type donut struct { } // NewDonut - instantiate new donut driver -func NewDonut(root string) (Donut, *iodine.Error) { +func NewDonut(root string) (Donut, error) { nodes := make(map[string]Node) nodes["localhost"] = &localDirectoryNode{root: root} driver := &donut{ @@ -26,7 +26,7 @@ func NewDonut(root string) (Donut, *iodine.Error) { for nodeID, node := range nodes { bucketIDs, err := node.GetBuckets() if err != nil { - return nil, iodine.New(err, map[string]string{"root": root}) + return nil, iodine.Error(err, map[string]string{"root": root}) } for _, bucketID := range bucketIDs { tokens := strings.Split(bucketID, ":") @@ -38,7 +38,7 @@ func NewDonut(root string) (Donut, *iodine.Error) { driver.buckets[tokens[0]] = bucket } if err = driver.buckets[tokens[0]].AddNode(nodeID, bucketID); err != nil { - return nil, iodine.New(err, map[string]string{"root": root}) + return nil, iodine.Error(err, map[string]string{"root": root}) } } } diff --git a/pkg/storage/donut/interfaces.go b/pkg/storage/donut/interfaces.go index 658f0e3ce..dcd822e45 100644 --- a/pkg/storage/donut/interfaces.go +++ b/pkg/storage/donut/interfaces.go @@ -1,7 +1,6 @@ package donut import ( - "github.com/minio-io/iodine" "io" ) @@ -19,8 +18,8 @@ type Donut interface { // Bucket interface type Bucket interface { - GetNodes() ([]string, *iodine.Error) - AddNode(nodeID, bucketID string) *iodine.Error + GetNodes() ([]string, error) + AddNode(nodeID, bucketID string) error } // Node interface