github.com/artisanhe/tools@v1.0.1-0.20210607022958-19a8fef2eb04/catgo/cat-go/cat/stacktrace.go (about)

     1  package cat
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"go/build"
     7  	"path/filepath"
     8  	"runtime"
     9  	"strings"
    10  )
    11  
    12  var trimPaths []string
    13  
    14  func init() {
    15  	for _, prefix := range build.Default.SrcDirs() {
    16  		if prefix[len(prefix)-1] != filepath.Separator {
    17  			prefix += string(filepath.Separator)
    18  		}
    19  		trimPaths = append(trimPaths, prefix)
    20  	}
    21  }
    22  
    23  func trimPath(filename string) string {
    24  	for _, prefix := range trimPaths {
    25  		if trimmed := strings.TrimPrefix(filename, prefix); len(trimmed) < len(filename) {
    26  			return trimmed
    27  		}
    28  	}
    29  	return filename
    30  }
    31  
    32  func functionName(pc uintptr) string {
    33  	fn := runtime.FuncForPC(pc)
    34  	if fn == nil {
    35  		return "unknown"
    36  	}
    37  	return fn.Name()
    38  }
    39  
    40  func newStacktrace(skip int, err error) (buf *bytes.Buffer) {
    41  	buf = bytes.NewBuffer([]byte{})
    42  	buf.WriteString(err.Error())
    43  	buf.WriteRune('\n')
    44  	for i := skip; ; i++ {
    45  		pc, file, line, ok := runtime.Caller(i)
    46  		if !ok {
    47  			break
    48  		}
    49  		file = trimPath(file)
    50  		name := functionName(pc)
    51  		// `runtime.goexit` is bootstrap loader and is meaningless in tracing.
    52  		if name == "runtime.goexit" {
    53  			continue
    54  		}
    55  		buf.WriteString(fmt.Sprintf("at %s(%s:%d)\n", name, file, line))
    56  	}
    57  	return buf
    58  }