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  }