-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Moved project from the Nordcloud private repository
- Loading branch information
Showing
10 changed files
with
1,013 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package errors | ||
|
||
import ( | ||
"github.com/aws/aws-sdk-go/aws/awserr" | ||
"github.com/aws/aws-sdk-go/service/dynamodb" | ||
"github.com/aws/aws-sdk-go/service/redshift" | ||
"github.com/aws/aws-sdk-go/service/s3" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
const ( | ||
AWSAccessDenied = "AccessDenied" | ||
AWSAccessDeniedException = "AccessDeniedException" | ||
|
||
AWSDynamoTableNotFound = dynamodb.ErrCodeTableNotFoundException | ||
AWSS3BucketNotFound = s3.ErrCodeNoSuchBucket | ||
|
||
AWSRedshiftClusterSnapsotQuotaExceeded = redshift.ErrCodeClusterSnapshotQuotaExceededFault | ||
) | ||
|
||
//GetAWSErrorCode returns the underlying AWS error code from the error. | ||
func GetAWSErrorCode(err error) string { | ||
nativeError := errors.Cause(err) | ||
if nativeError == nil { | ||
return "" | ||
} | ||
if ncError, ok := nativeError.(NCError); ok { | ||
nativeError = errors.Cause(ncError.RootError) | ||
} | ||
if nativeError == nil { | ||
return "" | ||
} | ||
|
||
if awsError, ok := nativeError.(awserr.Error); ok { | ||
return awsError.Code() | ||
} | ||
|
||
return "" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package errors | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/pkg/errors" | ||
|
||
"github.com/aws/aws-sdk-go/aws/awserr" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestGetAWSErrorCode_Standard(t *testing.T) { | ||
cause := errors.New("std except") | ||
errCode := GetAWSErrorCode(cause) | ||
assert.Equal(t, "", errCode) | ||
} | ||
|
||
func TestGetAWSErrorCode_AWSErr(t *testing.T) { | ||
cause := awserr.New("code", "aws error", nil) | ||
errCode := GetAWSErrorCode(cause) | ||
assert.Equal(t, "code", errCode) | ||
} | ||
|
||
func TestGetAWSErrorCode_Context(t *testing.T) { | ||
cause := WithContext(awserr.New("code1", "aws error", nil), "context1", nil) | ||
errCode := GetAWSErrorCode(cause) | ||
assert.Equal(t, "code1", errCode) | ||
} | ||
|
||
func TestGetAWSErrorCode_Wrap(t *testing.T) { | ||
cause := WithContext(errors.Wrap(awserr.New("code1", "aws error", nil), "wrap"), "context1", nil) | ||
errCode := GetAWSErrorCode(cause) | ||
assert.Equal(t, "code1", errCode) | ||
} | ||
|
||
func TestGetAWSErrorCode_MultilevelContext(t *testing.T) { | ||
cause := WithContext(WithContext(errors.Wrap(awserr.New("code1", "aws error", nil), "wrap"), "context0", nil), "context1", nil) | ||
errCode := GetAWSErrorCode(cause) | ||
assert.Equal(t, "code1", errCode) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
package errors | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
) | ||
|
||
type LogSeverity string | ||
|
||
const ( | ||
//ERROR Severity - logged with error level | ||
ERROR LogSeverity = "error" | ||
//WARN Severity warn - logged with warning level | ||
WARN LogSeverity = "warning" | ||
//INFO Severity - logged with info level | ||
INFO LogSeverity = "info" | ||
//DEBUG Severity - logged with Debug level | ||
DEBUG LogSeverity = "debug" | ||
) | ||
|
||
// ListToError converts errors list to single error | ||
func ListToError(errs []error) error { | ||
if len(errs) == 0 { | ||
return nil | ||
} | ||
var errorMessages []string | ||
for _, err := range errs { | ||
errorMessages = append(errorMessages, err.Error()) | ||
} | ||
return fmt.Errorf("[%s]", strings.Join(errorMessages[:], ", ")) | ||
} | ||
|
||
// Fields keeps context. | ||
type Fields map[string]interface{} | ||
|
||
// Cause keeps the context information about the error | ||
type Cause struct { | ||
Message string | ||
Fields Fields | ||
FuncName string | ||
FileName string | ||
Line int | ||
Severity LogSeverity | ||
} | ||
|
||
// NCError basic error structure | ||
type NCError struct { | ||
Causes []Cause | ||
// Contains stack trace from the initial place when the error | ||
// was raised. | ||
Stack []string | ||
//The root error at the base level. | ||
RootError error | ||
} | ||
|
||
func (n NCError) Error() string { | ||
var messages []string | ||
for _, cause := range n.Causes { | ||
messages = append(messages, cause.Message) | ||
} | ||
return strings.Join(messages, ": ") | ||
} | ||
|
||
//New error with context. | ||
func New(message string, fields Fields) error { | ||
fileName, funcName, lineNumber := GetRuntimeContext() | ||
newCause := Cause{ | ||
Message: message, | ||
Fields: fields, | ||
FuncName: funcName, | ||
FileName: fileName, | ||
Line: lineNumber, | ||
Severity: ERROR} | ||
return NCError{ | ||
Causes: []Cause{newCause}, | ||
Stack: GetTrace()} | ||
} | ||
|
||
func NewWithSeverity(message string, fields Fields, severity LogSeverity) error { | ||
fileName, funcName, lineNumber := GetRuntimeContext() | ||
newCause := Cause{ | ||
Message: message, | ||
Fields: fields, | ||
FuncName: funcName, | ||
FileName: fileName, | ||
Line: lineNumber, | ||
Severity: severity, | ||
} | ||
return NCError{ | ||
Causes: []Cause{newCause}, | ||
Stack: GetTrace(), | ||
} | ||
} | ||
|
||
//WithContext set new error wrapped with message and error context. | ||
func WithContext(err error, message string, fields Fields) error { | ||
// Attach message to the list of causes. | ||
fileName, funcName, lineNumber := GetRuntimeContext() | ||
newCause := Cause{ | ||
Message: message, | ||
Fields: fields, | ||
FuncName: funcName, | ||
FileName: fileName, | ||
Line: lineNumber, | ||
Severity: ERROR, | ||
} | ||
//If we wrap existing NCError at the higher layer. Here we only append causes. | ||
//and do not touch stack trace and root error. | ||
if ncError, ok := err.(NCError); ok { | ||
ncError.Causes = append([]Cause{newCause}, ncError.Causes...) | ||
return ncError | ||
} | ||
|
||
return NCError{ | ||
Causes: []Cause{newCause, Cause{Message: err.Error()}}, | ||
Stack: GetTrace(), | ||
RootError: err} | ||
} | ||
|
||
//WithContextAndSeverity set new error wrapped with message, severity and error context. | ||
func WithContextAndSeverity(err error, message string, severity LogSeverity, fields Fields) error { | ||
// Attach message to the list of causes. | ||
fileName, funcName, lineNumber := GetRuntimeContext() | ||
newCause := Cause{ | ||
Message: message, | ||
Fields: fields, | ||
FuncName: funcName, | ||
FileName: fileName, | ||
Line: lineNumber, | ||
Severity: severity, | ||
} | ||
//If we wrap existing NCError at the higher layer. Here we only append causes. | ||
//and do not touch stack trace and root error. | ||
if ncError, ok := err.(NCError); ok { | ||
ncError.Causes = append([]Cause{newCause}, ncError.Causes...) | ||
return ncError | ||
} | ||
|
||
return NCError{ | ||
Causes: []Cause{newCause, Cause{Message: err.Error()}}, | ||
Stack: GetTrace(), | ||
RootError: err, | ||
} | ||
} | ||
|
||
// GetContext returns fields from the error (with attached stack and causes fields) | ||
// This will be used for logrus.WithFields method. | ||
func (n *NCError) GetContext() Fields { | ||
return Fields{ | ||
"stack": n.Stack, | ||
"causes": n.Causes} | ||
} | ||
|
||
// GetMergedFields returns fields from the error. | ||
// The custom fields are merged from every error's cause's fields (as defined by WithContext invocations). | ||
// If the field with the same name is present in multiple causes the value from the outermost cause is taken. | ||
// This will be used for logrus.WithFields method. | ||
func (n *NCError) GetMergedFields() Fields { | ||
errFields := Fields{} | ||
for _, cause := range n.Causes { | ||
for k, v := range cause.Fields { | ||
if _, exists := errFields[k]; !exists { | ||
errFields[k] = v | ||
} | ||
} | ||
} | ||
|
||
return errFields | ||
} | ||
|
||
// GetMergedFieldsContext returns error stack and merged fields. | ||
func (n *NCError) GetMergedFieldsContext() Fields { | ||
return Fields{ | ||
"stack": n.Stack, | ||
"fields": n.GetMergedFields(), | ||
} | ||
} | ||
|
||
//GetErrorSeverity returns outermost NCError severity or ERROR level. | ||
func GetErrorSeverity(err error) LogSeverity { | ||
if ncError, ok := err.(NCError); ok { | ||
if len(ncError.Causes) > 0 { | ||
return ncError.Causes[0].Severity | ||
} | ||
return ERROR | ||
} | ||
return ERROR | ||
} | ||
|
||
// GetRootError returns root error. | ||
func GetRootError(err error) error { | ||
if ncError, ok := err.(NCError); ok && ncError.RootError != nil { | ||
return ncError.RootError | ||
} | ||
return err | ||
} |
Oops, something went wrong.