From ddc9cd2c25e203571bdb30e6b10aa56ff5a281f8 Mon Sep 17 00:00:00 2001 From: Danny Date: Wed, 8 Jun 2022 08:59:59 -0400 Subject: [PATCH] Issue #144 Commit adds ability to add message id to errors (#151) * Issue #144 Commit adds ability to add message id to errors Commit related to Issue #140 to find cascading errors associated with the failures GraphConnector queries. * Issue 144: Update to go libraries to import multierror * Reduced error package to include certain multierror interface. * Issue #144: Added format interface for append. Added additional testing for multiple wrapping of error. --- src/go.mod | 2 + src/go.sum | 4 ++ src/internal/connector/errors.go | 93 +++++++++++++++++++++++++++ src/internal/connector/errors_test.go | 60 +++++++++++++++++ 4 files changed, 159 insertions(+) create mode 100644 src/internal/connector/errors.go create mode 100644 src/internal/connector/errors_test.go diff --git a/src/go.mod b/src/go.mod index 45aedb183..2b9efcc4c 100644 --- a/src/go.mod +++ b/src/go.mod @@ -41,6 +41,8 @@ require ( github.com/dustin/go-humanize v1.0.0 // indirect github.com/golang-jwt/jwt v3.2.1+incompatible // indirect github.com/golang/protobuf v1.5.2 // indirect + github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect diff --git a/src/go.sum b/src/go.sum index ec44463f5..dabd5477a 100644 --- a/src/go.sum +++ b/src/go.sum @@ -177,6 +177,10 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= diff --git a/src/internal/connector/errors.go b/src/internal/connector/errors.go new file mode 100644 index 000000000..da5305fc4 --- /dev/null +++ b/src/internal/connector/errors.go @@ -0,0 +1,93 @@ +package connector + +import ( + "fmt" + "strings" + + "github.com/pkg/errors" + + multierror "github.com/hashicorp/go-multierror" + msgraph_errors "github.com/microsoftgraph/msgraph-sdk-go/models/odataerrors" +) + +// WrapErrorAndAppend helper function used to attach identifying information to an error +// and return it as a mulitierror +func WrapAndAppend(identifier string, e error, previous error) error { + return multierror.Append(previous, errors.Wrap(e, identifier)) +} + +// WrapErrorAndAppendf format version of WrapErrorAndAppend +func WrapAndAppendf(identifier interface{}, e error, previous error) error { + return multierror.Append(previous, errors.Wrapf(e, "%v", identifier)) +} + +// ListErrors is a helper method used to return the string of errors when +// the multiError library is used. +// depends on ConnectorStackErrorTrace +func ListErrors(multi multierror.Error) string { + aString := "" + for idx, err := range multi.Errors { + detail := ConnectorStackErrorTrace(err) + if detail == "" { + detail = fmt.Sprintf("%v", err) + } + aString = aString + fmt.Sprintf("\n\tErr: %d %v", idx+1, detail) + } + return aString +} + +// concatenateStringFromPointers is a helper funtion that adds +// strings to the originalMessage iff the pointer is not nil +func concatenateStringFromPointers(orig string, pointers []*string) string { + for _, pointer := range pointers { + if pointer != nil { + orig = strings.Join([]string{orig, *pointer}, " ") + } + } + return orig +} + +// ConnectorStackErrorTrace is a helper function that wraps the +// stack trace for oDataError types from querying the M365 back store. +func ConnectorStackErrorTrace(e error) string { + eMessage := "" + if oDataError, ok := e.(msgraph_errors.ODataErrorable); ok { + // Get MainError + mainErr := oDataError.GetError() + // message *string + // target *string + // code *string + // details ErrorDetailsable + // Ignoring Additonal Detail + code := mainErr.GetCode() + subject := mainErr.GetMessage() + target := mainErr.GetTarget() + details := mainErr.GetDetails() + inners := mainErr.GetInnererror() + eMessage = concatenateStringFromPointers(eMessage, + []*string{code, subject, target}) + // Get Error Details + // code, message, target + if details != nil { + eMessage = eMessage + "\nDetails Section:" + for idx, detail := range details { + dMessage := fmt.Sprintf("Detail %d:", idx) + c := detail.GetCode() + m := detail.GetMessage() + t := detail.GetTarget() + dMessage = concatenateStringFromPointers(dMessage, + []*string{c, m, t}) + eMessage = eMessage + dMessage + } + } + if inners != nil { + fmt.Println("Inners not nil") + eMessage = eMessage + "\nConnector Section:" + client := inners.GetClientRequestId() + rId := inners.GetRequestId() + eMessage = concatenateStringFromPointers(eMessage, + []*string{client, rId}) + } + } + return eMessage +} diff --git a/src/internal/connector/errors_test.go b/src/internal/connector/errors_test.go new file mode 100644 index 000000000..88a04929f --- /dev/null +++ b/src/internal/connector/errors_test.go @@ -0,0 +1,60 @@ +package connector + +import ( + "errors" + "fmt" + "strings" + "testing" + + multierror "github.com/hashicorp/go-multierror" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +type GraphConnectorErrorSuite struct { + suite.Suite +} + +func TestGraphConnectorErrorSuite(t *testing.T) { + suite.Run(t, new(GraphConnectorErrorSuite)) +} + +func (suite *GraphConnectorErrorSuite) TestWrapAndAppend() { + err1 := fmt.Errorf("New Error") + err2 := errors.New("I have two") + returnErr := WrapAndAppend("arc376", err2, err1) + suite.True(strings.Contains(returnErr.Error(), "arc376")) + suite.Error(returnErr) + multi := &multierror.Error{Errors: []error{err1, err2}} + suite.True(strings.Contains(ListErrors(*multi), "two")) // Does not contain the wrapped information + suite.T().Log(ListErrors(*multi)) +} + +func (suite *GraphConnectorErrorSuite) TestWrapAndAppend_Add3() { + errOneTwo := WrapAndAppend("user1", assert.AnError, assert.AnError) + combined := WrapAndAppend("unix36", assert.AnError, errOneTwo) + allErrors := WrapAndAppend("fxi92874", assert.AnError, combined) + suite.True(strings.Contains(combined.Error(), "unix36")) + suite.True(strings.Contains(combined.Error(), "user1")) + suite.True(strings.Contains(allErrors.Error(), "fxi92874")) + +} + +func (suite *GraphConnectorErrorSuite) TestWrapAndAppendf() { + err1 := assert.AnError + err2 := assert.AnError + combined := WrapAndAppendf(134323, err2, err1) + suite.True(strings.Contains(combined.Error(), "134323")) +} + +func (suite *GraphConnectorErrorSuite) TestConcatenateStringFromPointers() { + var s1, s2, s3 *string + var outString string + v1 := "Corso" + v3 := "remains" + s1 = &v1 + s3 = &v3 + outString = concatenateStringFromPointers(outString, []*string{s1, s2, s3}) + suite.True(strings.Contains(outString, v1)) + suite.True(strings.Contains(outString, v3)) +}