mattermost-community-enterp.../vendor/github.com/getsentry/sentry-go/exception.go
Claude ec1f89217a Merge: Complete Mattermost Server with Community Enterprise
Full Mattermost server source with integrated Community Enterprise features.
Includes vendor directory for offline/air-gapped builds.

Structure:
- enterprise-impl/: Enterprise feature implementations
- enterprise-community/: Init files that register implementations
- enterprise/: Bridge imports (community_imports.go)
- vendor/: All dependencies for offline builds

Build (online):
  go build ./cmd/mattermost

Build (offline/air-gapped):
  go build -mod=vendor ./cmd/mattermost

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 23:59:07 +09:00

104 lines
2.7 KiB
Go

package sentry
import (
"fmt"
"reflect"
"slices"
)
const (
MechanismTypeGeneric string = "generic"
MechanismTypeChained string = "chained"
MechanismTypeUnwrap string = "unwrap"
MechanismSourceCause string = "cause"
)
func convertErrorToExceptions(err error, maxErrorDepth int) []Exception {
var exceptions []Exception
visited := make(map[error]bool)
convertErrorDFS(err, &exceptions, nil, "", visited, maxErrorDepth, 0)
// mechanism type is used for debugging purposes, but since we can't really distinguish the origin of who invoked
// captureException, we set it to nil if the error is not chained.
if len(exceptions) == 1 {
exceptions[0].Mechanism = nil
}
slices.Reverse(exceptions)
// Add a trace of the current stack to the top level(outermost) 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 len(exceptions) > 0 && exceptions[len(exceptions)-1].Stacktrace == nil {
exceptions[len(exceptions)-1].Stacktrace = NewStacktrace()
}
return exceptions
}
func convertErrorDFS(err error, exceptions *[]Exception, parentID *int, source string, visited map[error]bool, maxErrorDepth int, currentDepth int) {
if err == nil {
return
}
if visited[err] {
return
}
visited[err] = true
_, isExceptionGroup := err.(interface{ Unwrap() []error })
exception := Exception{
Value: err.Error(),
Type: reflect.TypeOf(err).String(),
Stacktrace: ExtractStacktrace(err),
}
currentID := len(*exceptions)
var mechanismType string
if parentID == nil {
mechanismType = MechanismTypeGeneric
source = ""
} else {
mechanismType = MechanismTypeChained
}
exception.Mechanism = &Mechanism{
Type: mechanismType,
ExceptionID: currentID,
ParentID: parentID,
Source: source,
IsExceptionGroup: isExceptionGroup,
}
*exceptions = append(*exceptions, exception)
if maxErrorDepth >= 0 && currentDepth >= maxErrorDepth {
return
}
switch v := err.(type) {
case interface{ Unwrap() []error }:
unwrapped := v.Unwrap()
for i := range unwrapped {
if unwrapped[i] != nil {
childSource := fmt.Sprintf("errors[%d]", i)
convertErrorDFS(unwrapped[i], exceptions, &currentID, childSource, visited, maxErrorDepth, currentDepth+1)
}
}
case interface{ Unwrap() error }:
unwrapped := v.Unwrap()
if unwrapped != nil {
convertErrorDFS(unwrapped, exceptions, &currentID, MechanismTypeUnwrap, visited, maxErrorDepth, currentDepth+1)
}
case interface{ Cause() error }:
cause := v.Cause()
if cause != nil {
convertErrorDFS(cause, exceptions, &currentID, MechanismSourceCause, visited, maxErrorDepth, currentDepth+1)
}
}
}