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  }