File: stack_tracer.go

package info (click to toggle)
golang-github-jarcoal-httpmock 1.3.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 332 kB
  • sloc: makefile: 2
file content (91 lines) | stat: -rw-r--r-- 1,892 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package internal

import (
	"bytes"
	"fmt"
	"net/http"
	"runtime"
	"strings"
)

type StackTracer struct {
	CustomFn func(...interface{})
	Err      error
}

// Error implements error interface.
func (s StackTracer) Error() string {
	if s.Err == nil {
		return ""
	}
	return s.Err.Error()
}

// Unwrap implements the interface needed by errors.Unwrap.
func (s StackTracer) Unwrap() error {
	return s.Err
}

// CheckStackTracer checks for specific error returned by
// NewNotFoundResponder function or Trace Responder method.
func CheckStackTracer(req *http.Request, err error) error {
	if nf, ok := err.(StackTracer); ok {
		if nf.CustomFn != nil {
			pc := make([]uintptr, 128)
			npc := runtime.Callers(2, pc)
			pc = pc[:npc]

			var mesg bytes.Buffer
			var netHTTPBegin, netHTTPEnd bool

			// Start recording at first net/http call if any...
			for {
				frames := runtime.CallersFrames(pc)

				var lastFn string
				for {
					frame, more := frames.Next()

					if !netHTTPEnd {
						if netHTTPBegin {
							netHTTPEnd = !strings.HasPrefix(frame.Function, "net/http.")
						} else {
							netHTTPBegin = strings.HasPrefix(frame.Function, "net/http.")
						}
					}

					if netHTTPEnd {
						if lastFn != "" {
							if mesg.Len() == 0 {
								if nf.Err != nil {
									mesg.WriteString(nf.Err.Error())
								} else {
									fmt.Fprintf(&mesg, "%s %s", req.Method, req.URL)
								}
								mesg.WriteString("\nCalled from ")
							} else {
								mesg.WriteString("\n  ")
							}
							fmt.Fprintf(&mesg, "%s()\n    at %s:%d", lastFn, frame.File, frame.Line)
						}
					}
					lastFn = frame.Function

					if !more {
						break
					}
				}

				// At least one net/http frame found
				if mesg.Len() > 0 {
					break
				}
				netHTTPEnd = true // retry without looking at net/http frames
			}

			nf.CustomFn(mesg.String())
		}
		err = nf.Err
	}
	return err
}