github.com/haraldrudell/parl@v0.4.176/perrors/whynotpanic/why-not-panic.go (about) 1 /* 2 © 2022–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/) 3 ISC License 4 */ 5 6 package whynotpanic 7 8 import ( 9 "fmt" 10 "strings" 11 12 "github.com/haraldrudell/parl" 13 "github.com/haraldrudell/parl/perrors/errorglue" 14 "github.com/haraldrudell/parl/perrors/panicdetector" 15 ) 16 17 var whyTemplate = strings.Join([]string{ 18 " WHY_NOT_PANIC: isPanic: %t recoveryIndex: %d panicIndex: %d error-nil: %t stacks: %d", 19 "WhyNotPanic describes why a panic was not detected for an error value", 20 "— isPanic: false means the panic detector did not find a stack trace containing a Go panic", 21 "— if recoveryIndex or panicIndex is 0, it means that the line was not found in any stack trace", 22 "— error-nil: true means the error value was nil and did not contain an error", 23 "— stacks is the number of stack traces found in the errors’ error chain", 24 "— if stacks is 0, it means the error is not the result of any of parl’s recovery functions", 25 "— panicIndex is the stack trace line before a Go detected a panic. It is the code line causing panic", 26 "— the known runtime package reference invoked on Go panic: ‘%s’", 27 "— recoveryIndex is the stack frame after Go panic handling concludes", 28 "— the known runtime package reference invoking deferred functions after a panic is: ‘%s’", 29 "error message for last error with stack trace: %s", 30 "last stack trace: %s", 31 "— end WHY_NOT_PANIC", 32 }, "\n") 33 34 // WhyNotPanic returns a printble string explaining panic-data on err 35 func WhyNotPanic(err error) (s string) { 36 37 // find any panic stack trace in the err error chain 38 var isPanic, stack, recoveryIndex, panicIndex, numberOfStacks, errorWithStack = errorglue.FirstPanicStack(err) 39 if isPanic { 40 return // panic is detected return: empty string 41 } 42 43 var message string 44 if errorWithStack != nil { 45 message = "‘" + errorWithStack.Error() + "’" 46 } else { 47 message = "none" 48 } 49 var lastStack string 50 if st, ok := stack.(parl.Stack); ok { 51 if len(st.Frames()) > 0 { 52 lastStack = stack.String() 53 } 54 } 55 if lastStack == "" { 56 lastStack = "none" 57 } 58 59 var deferS, panicS = panicdetector.PanicDetectorValues() 60 61 s = fmt.Sprintf(whyTemplate, 62 isPanic, recoveryIndex, panicIndex, err == nil, numberOfStacks, 63 deferS, 64 panicS, 65 message, lastStack, 66 ) 67 return 68 }