github.com/thanos-io/thanos@v0.32.5/pkg/errors/stacktrace.go (about) 1 // Copyright (c) The Thanos Authors. 2 // Licensed under the Apache License 2.0. 3 4 package errors 5 6 import ( 7 "fmt" 8 "runtime" 9 "strings" 10 ) 11 12 // stacktrace holds a snapshot of program counters. 13 type stacktrace []uintptr 14 15 // newStackTrace captures a stack trace. It skips first 3 frames to record the 16 // snapshot of the stack trace at the origin of a particular error. It tries to 17 // record maximum 16 frames (if available). 18 func newStackTrace() stacktrace { 19 const stackDepth = 16 // record maximum 16 frames (if available). 20 21 pc := make([]uintptr, stackDepth) 22 // using skip=3 for not to count the program counter address of 23 // 1. the respective function from errors package (eg. errors.New) 24 // 2. newStacktrace itself 25 // 3. the function used in runtime.Callers 26 n := runtime.Callers(3, pc) 27 28 // this approach is taken to reduce long term memory footprint (obtained through escape analysis). 29 // We are returning a new slice by re-slicing the pc with the required length and capacity (when the 30 // no of returned callFrames is less that stackDepth). This uses less memory compared to pc[:n] as 31 // the capacity of new slice is inherited from the parent slice if not specified. 32 return stacktrace(pc[:n:n]) 33 } 34 35 // String implements the fmt.Stringer interface to provide formatted text output. 36 func (s stacktrace) String() string { 37 var buf strings.Builder 38 39 // CallersFrames takes the slice of Program Counter addresses returned by Callers to 40 // retrieve function/file/line information. 41 cf := runtime.CallersFrames(s) 42 for { 43 // more indicates if the next call will be successful or not. 44 frame, more := cf.Next() 45 // used formatting scheme <`>`space><function name><tab><filepath><:><line><newline> for example: 46 // > testing.tRunner /home/go/go1.17.8/src/testing/testing.go:1259 47 buf.WriteString(fmt.Sprintf("> %s\t%s:%d\n", frame.Func.Name(), frame.File, frame.Line)) 48 if !more { 49 break 50 } 51 } 52 return buf.String() 53 }