github.com/haraldrudell/parl@v0.4.176/pruntime/invocation-id.go (about) 1 /* 2 © 2021–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/) 3 ISC License 4 */ 5 6 package pruntime 7 8 import ( 9 "runtime/debug" 10 "strings" 11 ) 12 13 /* 14 A stack has a leading line with go routine ID, then two lines per frame: 15 goroutine 1 [running]: 16 runtime/debug.Stack(0x1, 0x1, 0x2) 17 18 /usr/local/Cellar/go/1.16.6/libexec/src/runtime/debug/stack.go:24 +0x9f 19 */ 20 const ( 21 // the number of lines debug.Stack produces for each stack frame 22 linesPerStackFrame = 2 23 // skip debug.Stack, that includes itself, and the Invocation stack frames 24 skipFrames = 2 25 ) 26 27 // Invocation returns an invocation stack trace for debug printing, empty string on troubles. 28 // The result is similar to the output from debug.Stack, but has some stack frames removed. 29 // tabs are replaced by two spaces. 30 // stackFramesToSkip 0 means first frame will be the caller of Invocation 31 // "goroutine 1 [running]:\ngithub.com/haraldrudell/parl/mains.(*Executable).AddErr(0x1809300, 0x158b620, 0xc000183800, 0x1) mains.(*Executable).AddErr-executable.go:302…" 32 func Invocation(stackFramesToSkip int) (stackTrace string) { 33 if stackFramesToSkip < 0 { 34 stackFramesToSkip = 0 35 } 36 37 // remove the first few stack frames 38 stackBytes := debug.Stack() 39 stackString := string(stackBytes) 40 stackTraceLines := strings.Split(stackString, "\n") 41 linesToSkip := (stackFramesToSkip + skipFrames) * linesPerStackFrame 42 copy(stackTraceLines[1:], stackTraceLines[1+linesToSkip:]) 43 stackTraceLines = stackTraceLines[:len(stackTraceLines)-linesToSkip] 44 stackTrace = strings.Join(stackTraceLines, "\n") 45 46 return strings.ReplaceAll(stackTrace, "\t", "\x20\x20") 47 }