Skip to content

Commit

Permalink
feat: Export client.EventFromMessage, client.EventFromException, and …
Browse files Browse the repository at this point in the history
…event.SetException (#607)

Co-authored-by: Kevin Snyder <[email protected]>
Co-authored-by: Anton Ovchinnikov <[email protected]>
  • Loading branch information
3 people authored May 2, 2023
1 parent eb22fb5 commit eb7fca9
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 38 deletions.
52 changes: 14 additions & 38 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"math/rand"
"net/http"
"os"
"reflect"
"sort"
"strings"
"sync"
Expand Down Expand Up @@ -378,13 +377,13 @@ func (client Client) Options() ClientOptions {

// CaptureMessage captures an arbitrary message.
func (client *Client) CaptureMessage(message string, hint *EventHint, scope EventModifier) *EventID {
event := client.eventFromMessage(message, LevelInfo)
event := client.EventFromMessage(message, LevelInfo)
return client.CaptureEvent(event, hint, scope)
}

// CaptureException captures an error.
func (client *Client) CaptureException(exception error, hint *EventHint, scope EventModifier) *EventID {
event := client.eventFromException(exception, LevelError)
event := client.EventFromException(exception, LevelError)
return client.CaptureEvent(event, hint, scope)
}

Expand Down Expand Up @@ -439,11 +438,11 @@ func (client *Client) RecoverWithContext(
var event *Event
switch err := err.(type) {
case error:
event = client.eventFromException(err, LevelFatal)
event = client.EventFromException(err, LevelFatal)
case string:
event = client.eventFromMessage(err, LevelFatal)
event = client.EventFromMessage(err, LevelFatal)
default:
event = client.eventFromMessage(fmt.Sprintf("%#v", err), LevelFatal)
event = client.EventFromMessage(fmt.Sprintf("%#v", err), LevelFatal)
}
return client.CaptureEvent(event, hint, scope)
}
Expand All @@ -463,10 +462,11 @@ func (client *Client) Flush(timeout time.Duration) bool {
return client.Transport.Flush(timeout)
}

func (client *Client) eventFromMessage(message string, level Level) *Event {
// EventFromMessage creates an event from the given message string.
func (client *Client) EventFromMessage(message string, level Level) *Event {
if message == "" {
err := usageError{fmt.Errorf("%s called with empty message", callerFunctionName())}
return client.eventFromException(err, level)
return client.EventFromException(err, level)
}
event := NewEvent()
event.Level = level
Expand All @@ -483,41 +483,17 @@ func (client *Client) eventFromMessage(message string, level Level) *Event {
return event
}

func (client *Client) eventFromException(exception error, level Level) *Event {
err := exception
if err == nil {
err = usageError{fmt.Errorf("%s called with nil error", callerFunctionName())}
}

// EventFromException creates a new Sentry event from the given `error` instance.
func (client *Client) EventFromException(exception error, level Level) *Event {
event := NewEvent()
event.Level = level

for i := 0; i < client.options.MaxErrorDepth && err != nil; i++ {
event.Exception = append(event.Exception, Exception{
Value: err.Error(),
Type: reflect.TypeOf(err).String(),
Stacktrace: ExtractStacktrace(err),
})
switch previous := err.(type) {
case interface{ Unwrap() error }:
err = previous.Unwrap()
case interface{ Cause() error }:
err = previous.Cause()
default:
err = nil
}
}

// Add a trace of the current stack to the most recent error in a chain if
// it doesn't have a stack trace yet.
// We only add to the most recent error to avoid duplication and because the
// current stack is most likely unrelated to errors deeper in the chain.
if event.Exception[0].Stacktrace == nil {
event.Exception[0].Stacktrace = NewStacktrace()
err := exception
if err == nil {
err = usageError{fmt.Errorf("%s called with nil error", callerFunctionName())}
}

// event.Exception should be sorted such that the most recent error is last.
reverse(event.Exception)
event.SetException(err, client.options.MaxErrorDepth)

return event
}
Expand Down
39 changes: 39 additions & 0 deletions interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"net"
"net/http"
"reflect"
"strings"
"time"
)
Expand Down Expand Up @@ -313,6 +314,44 @@ type Event struct {
sdkMetaData SDKMetaData
}

// SetException appends the unwrapped errors to the event's exception list.
//
// maxErrorDepth is the maximum depth of the error chain we will look
// into while unwrapping the errors.
func (e *Event) SetException(exception error, maxErrorDepth int) {
err := exception
if err == nil {
return
}

for i := 0; i < maxErrorDepth && err != nil; i++ {
e.Exception = append(e.Exception, Exception{
Value: err.Error(),
Type: reflect.TypeOf(err).String(),
Stacktrace: ExtractStacktrace(err),
})
switch previous := err.(type) {
case interface{ Unwrap() error }:
err = previous.Unwrap()
case interface{ Cause() error }:
err = previous.Cause()
default:
err = nil
}
}

// Add a trace of the current stack to the most recent error in a chain if
// it doesn't have a stack trace yet.
// We only add to the most recent error to avoid duplication and because the
// current stack is most likely unrelated to errors deeper in the chain.
if e.Exception[0].Stacktrace == nil {
e.Exception[0].Stacktrace = NewStacktrace()
}

// event.Exception should be sorted such that the most recent error is last.
reverse(e.Exception)
}

// TODO: Event.Contexts map[string]interface{} => map[string]EventContext,
// to prevent accidentally storing T when we mean *T.
// For example, the TraceContext must be stored as *TraceContext to pick up the
Expand Down

0 comments on commit eb7fca9

Please sign in to comment.