gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

parse_panic.go (3009B)


      1 package errors
      2 
      3 import (
      4 	"strconv"
      5 	"strings"
      6 )
      7 
      8 type uncaughtPanic struct{ message string }
      9 
     10 func (p uncaughtPanic) Error() string {
     11 	return p.message
     12 }
     13 
     14 // ParsePanic allows you to get an error object from the output of a go program
     15 // that panicked. This is particularly useful with https://github.com/mitchellh/panicwrap.
     16 func ParsePanic(text string) (*Error, error) {
     17 	lines := strings.Split(text, "\n")
     18 
     19 	state := "start"
     20 
     21 	var message string
     22 	var stack []StackFrame
     23 
     24 	for i := 0; i < len(lines); i++ {
     25 		line := lines[i]
     26 
     27 		if state == "start" {
     28 			if strings.HasPrefix(line, "panic: ") {
     29 				message = strings.TrimPrefix(line, "panic: ")
     30 				state = "seek"
     31 			} else {
     32 				return nil, Errorf("bugsnag.panicParser: Invalid line (no prefix): %s", line)
     33 			}
     34 
     35 		} else if state == "seek" {
     36 			if strings.HasPrefix(line, "goroutine ") && strings.HasSuffix(line, "[running]:") {
     37 				state = "parsing"
     38 			}
     39 
     40 		} else if state == "parsing" {
     41 			if line == "" {
     42 				state = "done"
     43 				break
     44 			}
     45 			createdBy := false
     46 			if strings.HasPrefix(line, "created by ") {
     47 				line = strings.TrimPrefix(line, "created by ")
     48 				createdBy = true
     49 			}
     50 
     51 			i++
     52 
     53 			if i >= len(lines) {
     54 				return nil, Errorf("bugsnag.panicParser: Invalid line (unpaired): %s", line)
     55 			}
     56 
     57 			frame, err := parsePanicFrame(line, lines[i], createdBy)
     58 			if err != nil {
     59 				return nil, err
     60 			}
     61 
     62 			stack = append(stack, *frame)
     63 			if createdBy {
     64 				state = "done"
     65 				break
     66 			}
     67 		}
     68 	}
     69 
     70 	if state == "done" || state == "parsing" {
     71 		return &Error{Err: uncaughtPanic{message}, frames: stack}, nil
     72 	}
     73 	return nil, Errorf("could not parse panic: %v", text)
     74 }
     75 
     76 // The lines we're passing look like this:
     77 //
     78 //     main.(*foo).destruct(0xc208067e98)
     79 //             /0/go/src/github.com/bugsnag/bugsnag-go/pan/main.go:22 +0x151
     80 func parsePanicFrame(name string, line string, createdBy bool) (*StackFrame, error) {
     81 	idx := strings.LastIndex(name, "(")
     82 	if idx == -1 && !createdBy {
     83 		return nil, Errorf("bugsnag.panicParser: Invalid line (no call): %s", name)
     84 	}
     85 	if idx != -1 {
     86 		name = name[:idx]
     87 	}
     88 	pkg := ""
     89 
     90 	if lastslash := strings.LastIndex(name, "/"); lastslash >= 0 {
     91 		pkg += name[:lastslash] + "/"
     92 		name = name[lastslash+1:]
     93 	}
     94 	if period := strings.Index(name, "."); period >= 0 {
     95 		pkg += name[:period]
     96 		name = name[period+1:]
     97 	}
     98 
     99 	name = strings.Replace(name, "ยท", ".", -1)
    100 
    101 	if !strings.HasPrefix(line, "\t") {
    102 		return nil, Errorf("bugsnag.panicParser: Invalid line (no tab): %s", line)
    103 	}
    104 
    105 	idx = strings.LastIndex(line, ":")
    106 	if idx == -1 {
    107 		return nil, Errorf("bugsnag.panicParser: Invalid line (no line number): %s", line)
    108 	}
    109 	file := line[1:idx]
    110 
    111 	number := line[idx+1:]
    112 	if idx = strings.Index(number, " +"); idx > -1 {
    113 		number = number[:idx]
    114 	}
    115 
    116 	lno, err := strconv.ParseInt(number, 10, 32)
    117 	if err != nil {
    118 		return nil, Errorf("bugsnag.panicParser: Invalid line (bad line number): %s", line)
    119 	}
    120 
    121 	return &StackFrame{
    122 		File:       file,
    123 		LineNumber: int(lno),
    124 		Package:    pkg,
    125 		Name:       name,
    126 	}, nil
    127 }