Updating iodine to support new iodine.Error(error, map[string]string) error method

This commit is contained in:
Frederick F. Kautz IV 2015-03-25 19:12:39 -07:00
parent 68f36f5e08
commit 40e311a919
9 changed files with 119 additions and 90 deletions

2
Godeps/Godeps.json generated
View File

@ -20,7 +20,7 @@
}, },
{ {
"ImportPath": "github.com/minio-io/iodine", "ImportPath": "github.com/minio-io/iodine",
"Rev": "2843626767a878d03d02acd4d2bc3790eb325b64" "Rev": "8c8985d5a45e388dccb5ca280c897672abb18278"
}, },
{ {
"ImportPath": "gopkg.in/check.v1", "ImportPath": "gopkg.in/check.v1",

View File

@ -28,9 +28,9 @@ import (
"sync" "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. // and stack traces.
type Error struct { type WrappedError struct {
EmbeddedError error `json:"-"` EmbeddedError error `json:"-"`
ErrorMessage string ErrorMessage string
@ -88,19 +88,33 @@ func GetGlobalStateKey(k string) string {
return result 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. // 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 { if err != nil {
entry := createStackEntry() 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 { for k, v := range data {
entry.Data[k] = v entry.Data[k] = v
} }
return &Error{ newErr.Stack = append(newErr.Stack, entry)
EmbeddedError: err, return newErr
ErrorMessage: err.Error(),
Stack: []StackEntry{entry},
}
} }
return nil return nil
} }
@ -146,24 +160,24 @@ func getSystemData() map[string]string {
} }
// Annotate an error with a stack entry and returns itself // Annotate an error with a stack entry and returns itself
func (err *Error) Annotate(info map[string]string) *Error { //func (err *WrappedError) Annotate(info map[string]string) *WrappedError {
entry := createStackEntry() // entry := createStackEntry()
for k, v := range info { // for k, v := range info {
entry.Data[k] = v // entry.Data[k] = v
} // }
err.Stack = append(err.Stack, entry) // err.Stack = append(err.Stack, entry)
return err // return err
} //}
// EmitJSON writes JSON output for the error // EmitJSON writes JSON output for the error
func (err Error) EmitJSON() ([]byte, error) { func (err WrappedError) EmitJSON() ([]byte, error) {
return json.Marshal(err) return json.Marshal(err)
} }
// EmitHumanReadable returns a human readable error message // EmitHumanReadable returns a human readable error message
func (err Error) EmitHumanReadable() string { func (err WrappedError) EmitHumanReadable() string {
var errorBuffer bytes.Buffer var errorBuffer bytes.Buffer
fmt.Fprintln(&errorBuffer, err.Error()) fmt.Fprintln(&errorBuffer, err.ErrorMessage)
for i, entry := range err.Stack { for i, entry := range err.Stack {
fmt.Fprintln(&errorBuffer, "-", i, entry.Host+":"+entry.File+":"+strconv.Itoa(entry.Line), entry.Data) 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 // Emits the original error message
func (err Error) Error() string { func (err WrappedError) Error() string {
return err.EmbeddedError.Error() return err.EmitHumanReadable()
} }
func init() { func init() {

View File

@ -24,21 +24,30 @@ import (
) )
func TestIodine(t *testing.T) { func TestIodine(t *testing.T) {
iodineError := New(errors.New("Hello"), nil) iodineError := Error(errors.New("Hello"), nil)
iodineError.Annotate(nil) iodineError = Error(iodineError, nil)
iodineError.Annotate(nil) iodineError = Error(iodineError, nil)
iodineError.Annotate(nil) iodineError = Error(iodineError, nil)
if len(iodineError.Stack) != 4 { switch typedError := iodineError.(type) {
t.Fail() case WrappedError:
} {
jsonResult, err := iodineError.EmitJSON() if len(typedError.Stack) != 4 {
if err != nil { t.Fail()
t.Fail() }
} jsonResult, err := typedError.EmitJSON()
var prettyBuffer bytes.Buffer if err != nil {
json.Indent(&prettyBuffer, jsonResult, "", " ") t.Fail()
if prettyBuffer.String() == "" { }
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() t.Fail()
} }
SetGlobalState("foo", "bar") SetGlobalState("foo", "bar")
err := New(errors.New("a simple error"), nil) err := Error(errors.New("a simple error"), nil)
if res, ok := err.Stack[0].Data["foo"]; ok { switch typedError := err.(type) {
if res != "bar" { case WrappedError:
t.Error("global state not set: foo->bar") {
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")
} }
} }

View File

@ -137,7 +137,7 @@ func main() {
app.Action = runCmd app.Action = runCmd
err := app.Run(os.Args) err := app.Run(os.Args)
switch typedErr := err.(type) { switch typedErr := err.(type) {
case *iodine.Error: case *iodine.WrappedError:
{ {
log.Errorln(typedErr.EmitHumanReadable()) log.Errorln(typedErr.EmitHumanReadable())
} }

View File

@ -46,13 +46,11 @@ func Start(path string) (chan<- string, <-chan error, drivers.Driver) {
s := new(donutDriver) s := new(donutDriver)
// TODO donut driver should be passed in as Start param and driven by config // 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) s.donut, err = donut.NewDonut(path)
err = iodine.Error(err, map[string]string{"path": path})
if err != nil { if err != nil {
err = err.Annotate(map[string]string{"path": path}) log.Println(err)
if err != nil {
log.Println(err.EmitHumanReadable())
}
} }
go start(ctrlChannel, errorChannel, s) go start(ctrlChannel, errorChannel, s)

View File

@ -110,8 +110,8 @@ func getHTTPChannels(configs []Config) (ctrlChans []chan<- string, statusChans [
} }
default: default:
{ {
err := iodine.New(errors.New("Invalid API type"), nil) err := iodine.Error(errors.New("Invalid API type"), nil)
log.Fatal(err.EmitHumanReadable()) log.Fatal(err)
} }
} }
} }
@ -142,7 +142,7 @@ func getDriverChannels(driverType DriverType) (ctrlChans []chan<- string, status
{ {
u, err := user.Current() u, err := user.Current()
if err != nil { if err != nil {
log.Errorln(iodine.New(err, nil).EmitHumanReadable()) log.Errorln(iodine.Error(err, nil))
return nil, nil, nil return nil, nil, nil
} }
root := path.Join(u.HomeDir, "minio-storage", "file") root := path.Join(u.HomeDir, "minio-storage", "file")
@ -154,7 +154,7 @@ func getDriverChannels(driverType DriverType) (ctrlChans []chan<- string, status
{ {
u, err := user.Current() u, err := user.Current()
if err != nil { if err != nil {
log.Errorln(iodine.New(err, nil).EmitHumanReadable()) log.Errorln(iodine.Error(err, nil))
return nil, nil, nil return nil, nil, nil
} }
root := path.Join(u.HomeDir, "minio-driver", "donut") root := path.Join(u.HomeDir, "minio-driver", "donut")
@ -164,8 +164,7 @@ func getDriverChannels(driverType DriverType) (ctrlChans []chan<- string, status
} }
default: // should never happen default: // should never happen
{ {
err := iodine.New(errors.New("No driver found"), nil) log.Fatal(iodine.Error(errors.New("No driver found"), nil))
log.Fatal(err.EmitHumanReadable())
} }
} }
return return

View File

@ -13,7 +13,7 @@ type donutBucket struct {
} }
// GetNodes - get list of associated nodes for a given bucket // 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 var nodes []string
for _, node := range b.nodes { for _, node := range b.nodes {
nodes = append(nodes, node) nodes = append(nodes, node)
@ -21,17 +21,22 @@ func (b donutBucket) GetNodes() ([]string, *iodine.Error) {
return nodes, nil 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, ":") tokens := strings.Split(bucketID, ":")
if len(tokens) != 3 { 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] // bucketName := tokens[0]
// aggregate := tokens[1] // aggregate := tokens[1]
// aggregate := "0" // aggregate := "0"
part, err := strconv.Atoi(tokens[2]) part, err := strconv.Atoi(tokens[2])
if err != nil { 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 b.nodes[part] = nodeID
return nil return nil

View File

@ -16,7 +16,7 @@ type donut struct {
} }
// NewDonut - instantiate new donut driver // NewDonut - instantiate new donut driver
func NewDonut(root string) (Donut, *iodine.Error) { func NewDonut(root string) (Donut, error) {
nodes := make(map[string]Node) nodes := make(map[string]Node)
nodes["localhost"] = &localDirectoryNode{root: root} nodes["localhost"] = &localDirectoryNode{root: root}
driver := &donut{ driver := &donut{
@ -26,7 +26,7 @@ func NewDonut(root string) (Donut, *iodine.Error) {
for nodeID, node := range nodes { for nodeID, node := range nodes {
bucketIDs, err := node.GetBuckets() bucketIDs, err := node.GetBuckets()
if err != nil { 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 { for _, bucketID := range bucketIDs {
tokens := strings.Split(bucketID, ":") tokens := strings.Split(bucketID, ":")
@ -38,7 +38,7 @@ func NewDonut(root string) (Donut, *iodine.Error) {
driver.buckets[tokens[0]] = bucket driver.buckets[tokens[0]] = bucket
} }
if err = driver.buckets[tokens[0]].AddNode(nodeID, bucketID); err != nil { 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})
} }
} }
} }

View File

@ -1,7 +1,6 @@
package donut package donut
import ( import (
"github.com/minio-io/iodine"
"io" "io"
) )
@ -19,8 +18,8 @@ type Donut interface {
// Bucket interface // Bucket interface
type Bucket interface { type Bucket interface {
GetNodes() ([]string, *iodine.Error) GetNodes() ([]string, error)
AddNode(nodeID, bucketID string) *iodine.Error AddNode(nodeID, bucketID string) error
} }
// Node interface // Node interface