refactor: make use of regexs for err parsing

Signed-off-by: Jesse Simpson <jesse.simpson36@gmail.com>
pull/13586/head
Jesse Simpson 7 months ago
parent daf4c34879
commit 13b232e061
No known key found for this signature in database
GPG Key ID: 237495C89AB0AAFC

@ -339,67 +339,22 @@ type TraceableError struct {
func (t TraceableError) String() string { func (t TraceableError) String() string {
return t.location + "\n " + t.executedFunction + "\n " + t.message + "\n" return t.location + "\n " + t.executedFunction + "\n " + t.message + "\n"
} }
func cleanupExecError(filename string, err error) error {
func (t TraceableError) ExtractExecutedFunction() (TraceableError, error) { if _, isExecError := err.(template.ExecError); !isExecError {
executionLocationRegex, regexFindErr := regexp.Compile(`executing "[^\"]*" at <[^\<\>]*>:?\s*`) return err
if regexFindErr != nil {
return t, regexFindErr
}
byteArrayMsg := []byte(t.message)
executionLocations := executionLocationRegex.FindAll(byteArrayMsg, -1)
if len(executionLocations) == 0 {
return t, nil
}
t.executedFunction = string(executionLocations[0])
t.message = strings.ReplaceAll(t.message, t.executedFunction, "")
return t, nil
}
func (t TraceableError) FilterLocation() TraceableError {
if strings.Contains(t.message, t.location) {
t.message = strings.ReplaceAll(t.message, t.location, "")
}
return t
}
func (t TraceableError) FilterUnnecessaryWords() TraceableError {
if strings.Contains(t.message, "template:") {
t.message = strings.TrimSpace(strings.ReplaceAll(t.message, "template:", ""))
}
if strings.HasPrefix(t.message, ": ") {
t.message = strings.TrimSpace(strings.TrimPrefix(t.message, ": "))
}
return t
}
// In the process of formatting the error, we want to ensure that the formatted version of the error
// is not losing any necessary information. This function will tokenize and compare the two strings
// and if the formatted error doesn't meet the threshold, it will fallback to the originalErr
func determineIfFormattedErrorIsAcceptable(formattedErr error, originalErr error) error {
formattedErrTokens := strings.Fields(formattedErr.Error())
originalErrTokens := strings.Fields(originalErr.Error())
tokenSet := make(map[string]struct{})
for _, token := range originalErrTokens {
tokenSet[token] = struct{}{}
} }
matchCount := 0 // taken from https://cs.opensource.google/go/go/+/refs/tags/go1.23.6:src/text/template/exec.go;l=138
for _, token := range formattedErrTokens { // > "template: %s: %s"
if _, exists := tokenSet[token]; exists { // taken from https://cs.opensource.google/go/go/+/refs/tags/go1.23.6:src/text/template/exec.go;l=141
matchCount++ // > "template: %s: executing %q at <%s>: %s"
}
}
equivalenceRating := (float64(matchCount) / float64(len(formattedErrTokens))) * 100 execErrFmt, compileErr := regexp.Compile(`^template: (?P<templateName>(?U).+): executing (?P<functionName>(?U).+) at (?P<location>(?U).+): (?P<errMsg>(?U).+)(?P<nextErr>( template:.*)?)$`)
if equivalenceRating >= 80 { if compileErr != nil {
return formattedErr return err
} }
return originalErr execErrFmtWithoutTemplate, compileErr := regexp.Compile(`^template: (?P<templateName>(?U).+): (?P<errMsg>.*)(?P<nextErr>( template:.*)?)$`)
} if compileErr != nil {
func cleanupExecError(filename string, err error) error {
if _, isExecError := err.(template.ExecError); !isExecError {
return err return err
} }
@ -424,16 +379,35 @@ func cleanupExecError(filename string, err error) error {
if current == nil { if current == nil {
break break
} }
tokens = strings.SplitN(current.Error(), ": ", 3)
if len(tokens) == 1 { var traceable TraceableError
// For cases where the error message doesn't contain a colon if execErrFmt.MatchString(current.Error()) {
location = tokens[0] matches := execErrFmt.FindStringSubmatch(current.Error())
templateIndex := execErrFmt.SubexpIndex("templateName")
templateName := matches[templateIndex]
functionNameIndex := execErrFmt.SubexpIndex("functionName")
functionName := matches[functionNameIndex]
locationNameIndex := execErrFmt.SubexpIndex("location")
locationName := matches[locationNameIndex]
errMsgIndex := execErrFmt.SubexpIndex("errMsg")
errMsg := matches[errMsgIndex]
traceable = TraceableError{
location: templateName,
message: errMsg,
executedFunction: "executing " + functionName + " at " + locationName + ":",
}
} else if execErrFmtWithoutTemplate.MatchString(current.Error()) {
matches := execErrFmt.FindStringSubmatch(current.Error())
templateIndex := execErrFmt.SubexpIndex("templateName")
templateName := matches[templateIndex]
errMsgIndex := execErrFmt.SubexpIndex("errMsg")
errMsg := matches[errMsgIndex]
traceable = TraceableError{
location: templateName,
message: errMsg,
}
} else { } else {
location = tokens[1] return err
}
traceable := TraceableError{
location: location,
message: current.Error(),
} }
fileLocations = append(fileLocations, traceable) fileLocations = append(fileLocations, traceable)
current = errors.Unwrap(current) current = errors.Unwrap(current)
@ -442,30 +416,18 @@ func cleanupExecError(filename string, err error) error {
return fmt.Errorf("%s", err.Error()) return fmt.Errorf("%s", err.Error())
} }
prevMessage := "" var prev TraceableError
for i := len(fileLocations) - 1; i >= 0; i-- { for i := len(fileLocations) - 1; i >= 0; i-- {
currentMsg := fileLocations[i].message current := fileLocations[i]
if i == len(fileLocations)-1 { if i == len(fileLocations)-1 {
prevMessage = currentMsg prev = current
continue continue
} }
if strings.Contains(currentMsg, prevMessage) { if current.message == prev.message && current.location == prev.location && current.executedFunction == prev.executedFunction {
fileLocations[i].message = strings.ReplaceAll(fileLocations[i].message, prevMessage, "") fileLocations[i].message = ""
}
prevMessage = currentMsg
}
for i, fileLocation := range fileLocations {
fileLocation = fileLocation.FilterLocation().FilterUnnecessaryWords()
if fileLocation.message == "" {
continue
}
t, extractionErr := fileLocation.ExtractExecutedFunction()
if extractionErr != nil {
continue
} }
fileLocations[i] = t prev = current
} }
finalErrorString := "" finalErrorString := ""
@ -480,7 +442,7 @@ func cleanupExecError(filename string, err error) error {
return fmt.Errorf("%s", err.Error()) return fmt.Errorf("%s", err.Error())
} }
return determineIfFormattedErrorIsAcceptable(fmt.Errorf("%s", finalErrorString), err) return fmt.Errorf("%s", finalErrorString)
} }
func sortTemplates(tpls map[string]renderable) []string { func sortTemplates(tpls map[string]renderable) []string {

Loading…
Cancel
Save