Skip to content
This repository has been archived by the owner on Jul 28, 2021. It is now read-only.

Commit

Permalink
Merge pull request #97 from Microsoft/stack_trace_in_response
Browse files Browse the repository at this point in the history
Support responses with both error messages and stack traces
  • Loading branch information
soccerGB committed Aug 8, 2017
2 parents 7f54f58 + 891e7f7 commit c0a6db9
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 5 deletions.
9 changes: 5 additions & 4 deletions service/gcs/bridge/bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -407,13 +407,13 @@ func newResponseBase() *prot.MessageResponseBase {
// contain information pertaining to the given error.
func (b *bridge) setErrorForResponseBase(response *prot.MessageResponseBase, errForResponse error) {
errorMessage := errForResponse.Error()
stackString := ""
fileName := ""
lineNumber := -1
functionName := ""
if serr, ok := errForResponse.(gcserr.StackTracer); ok {
frames := serr.StackTrace()
bottomFrame := frames[0]
errorMessage = fmt.Sprintf("%+v", serr)
if stack := gcserr.BaseStackTrace(errForResponse); stack != nil {
bottomFrame := stack[0]
stackString = fmt.Sprintf("%+v", stack)
fileName = fmt.Sprintf("%s", bottomFrame)
lineNumberStr := fmt.Sprintf("%d", bottomFrame)
var err error
Expand All @@ -433,6 +433,7 @@ func (b *bridge) setErrorForResponseBase(response *prot.MessageResponseBase, err
newRecord := prot.ErrorRecord{
Result: int32(hresult),
Message: errorMessage,
StackTrace: stackString,
ModuleName: "gcs",
FileName: fileName,
Line: uint32(lineNumber),
Expand Down
27 changes: 27 additions & 0 deletions service/gcs/errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,33 @@ type StackTracer interface {
StackTrace() errors.StackTrace
}

// BaseStackTrace gets the earliest errors.StackTrace in the given error's
// cause stack. This will be the stack trace which reaches closest to the
// error's actual origin. It returns nil if no stack trace is found in the
// cause stack.
func BaseStackTrace(e error) errors.StackTrace {
type causer interface {
Cause() error
}
cause := e
var tracer StackTracer
for cause != nil {
serr, ok := cause.(StackTracer)
if ok {
tracer = serr
}
cerr, ok := cause.(causer)
if !ok {
break
}
cause = cerr.Cause()
}
if tracer == nil {
return nil
}
return tracer.StackTrace()
}

type baseHresultError struct {
hresult Hresult
}
Expand Down
51 changes: 51 additions & 0 deletions service/gcs/errors/errors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,57 @@ type stackTraceCauseError interface {

var _ = Describe("Errors", func() {
Describe("unittests", func() {
Describe("getting the base stack trace", func() {
Context("only one error in cause stack", func() {
var (
e error
stackTrace errors.StackTrace
)
BeforeEach(func() {
e = errors.New("test")
stackTrace = BaseStackTrace(e)
})
It("should return the same stack trace as the single error", func() {
se, ok := e.(StackTracer)
Expect(ok).To(BeTrue())
Expect(stackTrace).To(Equal(se.StackTrace()))
})
})
Context("multiple StackTracers in cause stack", func() {
var (
e1 error
e2 error
e3 error
e4 error
stackTrace errors.StackTrace
)
BeforeEach(func() {
e1 = fmt.Errorf("test")
e2 = errors.WithStack(e1)
e3 = errors.WithStack(e2)
e4 = errors.WithMessage(e3, "test2")
stackTrace = BaseStackTrace(e4)
})
It("should return the same stack trace as the bottom-most StackTracer", func() {
se, ok := e2.(StackTracer)
Expect(ok).To(BeTrue())
Expect(stackTrace).To(Equal(se.StackTrace()))
})
})
Context("no StackTracers in cause stack", func() {
var (
e error
stackTrace errors.StackTrace
)
BeforeEach(func() {
e = fmt.Errorf("test")
stackTrace = BaseStackTrace(e)
})
It("should return nil", func() {
Expect(stackTrace).To(BeNil())
})
})
})
Describe("constructing HRESULT errors", func() {
Context("with no wrapped error", func() {
var (
Expand Down
3 changes: 2 additions & 1 deletion service/gcs/prot/protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,10 +335,11 @@ func UnmarshalContainerModifySettings(b []byte) (*ContainerModifySettings, error

// ErrorRecord represents a single error to be reported back to the HCS. It
// allows for specifying information about the source of the error, as well as
// an error message.
// an error message and stack trace.
type ErrorRecord struct {
Result int32
Message string
StackTrace string `json:",omitempty"`
ModuleName string
FileName string
Line uint32
Expand Down

0 comments on commit c0a6db9

Please sign in to comment.