github.com/pinpoint-apm/pinpoint-go-agent@v1.4.1-0.20240110120318-a50c2eb18c8c/errors.go (about) 1 package pinpoint 2 3 import ( 4 "runtime" 5 "strings" 6 "sync/atomic" 7 "time" 8 "unsafe" 9 10 pkgError "github.com/pkg/errors" 11 ) 12 13 type pkgErrorStackTracer interface { 14 StackTrace() pkgError.StackTrace 15 } 16 17 type causer interface { 18 Cause() error 19 } 20 21 type errorWithCallStack struct { 22 err error 23 errorTime time.Time 24 callstack []uintptr 25 } 26 27 func (e *errorWithCallStack) stackTrace() []frame { 28 f := make([]frame, len(e.callstack)) 29 for i := 0; i < len(f); i++ { 30 f[i] = newFrame(e.callstack[i]) 31 } 32 return f 33 } 34 35 type frame struct { 36 moduleName string 37 funcName string 38 file string 39 line int32 40 } 41 42 func newFrame(f uintptr) frame { 43 moduleName := "unknown" 44 funcName := "unknown" 45 file := "unknown" 46 line := 0 47 48 pc := uintptr(f) - 1 49 if fn := runtime.FuncForPC(pc); fn != nil { 50 file, line = fn.FileLine(pc) 51 moduleName, funcName = splitName(fn.Name()) 52 } 53 54 return frame{moduleName, funcName, file, int32(line)} 55 } 56 57 func splitName(fullName string) (string, string) { 58 lastIdx := strings.LastIndex(fullName, ".") 59 return fullName[:lastIdx], fullName[lastIdx+1:] 60 } 61 62 func (span *span) findError(err error) *exception { 63 for _, chain := range span.errorChains { 64 if chain.callstack.err == err { 65 return chain 66 } 67 } 68 return nil 69 } 70 71 func (span *span) getExceptionChainId(err error) (int64, bool) { 72 if _, ok := err.(pkgErrorStackTracer); ok { 73 if ec := span.findError(err); ec != nil { 74 return ec.exceptionId, false 75 } 76 77 for e := err; e != nil; { 78 if c, ok := e.(causer); ok { 79 e = c.Cause() 80 if ec := span.findError(e); ec != nil { 81 return ec.exceptionId, true 82 } 83 } else { 84 break 85 } 86 } 87 } 88 89 return atomic.AddInt64(&exceptionIdGen, 1), true 90 } 91 92 func (span *span) addCauserCallStack(err error, eid int64) { 93 for e := err; e != nil; { 94 c, ok := e.(causer) 95 if !ok { 96 break 97 } 98 99 e = c.Cause() 100 if t := span.findError(e); t == nil { 101 if pkgErr, ok := e.(pkgErrorStackTracer); ok { 102 st := pkgErr.StackTrace() 103 chain := &exception{ 104 callstack: &errorWithCallStack{ 105 err: e, 106 errorTime: time.Now(), 107 callstack: *(*[]uintptr)(unsafe.Pointer(&st)), 108 }, 109 exceptionId: eid, 110 } 111 span.errorChains = append(span.errorChains, chain) 112 } 113 } 114 } 115 } 116 117 func (span *span) traceCallStack(err error, depth int) int64 { 118 var callstack []uintptr 119 120 eid, newId := span.getExceptionChainId(err) 121 if newId { 122 if pkgErr, ok := err.(pkgErrorStackTracer); ok { 123 span.addCauserCallStack(err, eid) 124 st := pkgErr.StackTrace() 125 callstack = *(*[]uintptr)(unsafe.Pointer(&st)) 126 } else { 127 pcs := make([]uintptr, depth+3) 128 n := runtime.Callers(3, pcs) 129 callstack = pcs[0:n] 130 } 131 132 chain := &exception{ 133 callstack: &errorWithCallStack{ 134 err: err, 135 errorTime: time.Now(), 136 callstack: callstack, 137 }, 138 exceptionId: eid, 139 } 140 span.errorChains = append(span.errorChains, chain) 141 } 142 return eid 143 }