diff options
Diffstat (limited to 'vendor/github.com/hashicorp/go-hclog/stacktrace.go')
-rw-r--r-- | vendor/github.com/hashicorp/go-hclog/stacktrace.go | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/go-hclog/stacktrace.go b/vendor/github.com/hashicorp/go-hclog/stacktrace.go new file mode 100644 index 0000000..8af1a3b --- /dev/null +++ b/vendor/github.com/hashicorp/go-hclog/stacktrace.go | |||
@@ -0,0 +1,108 @@ | |||
1 | // Copyright (c) 2016 Uber Technologies, Inc. | ||
2 | // | ||
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy | ||
4 | // of this software and associated documentation files (the "Software"), to deal | ||
5 | // in the Software without restriction, including without limitation the rights | ||
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
7 | // copies of the Software, and to permit persons to whom the Software is | ||
8 | // furnished to do so, subject to the following conditions: | ||
9 | // | ||
10 | // The above copyright notice and this permission notice shall be included in | ||
11 | // all copies or substantial portions of the Software. | ||
12 | // | ||
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
19 | // THE SOFTWARE. | ||
20 | |||
21 | package hclog | ||
22 | |||
23 | import ( | ||
24 | "bytes" | ||
25 | "runtime" | ||
26 | "strconv" | ||
27 | "strings" | ||
28 | "sync" | ||
29 | ) | ||
30 | |||
31 | var ( | ||
32 | _stacktraceIgnorePrefixes = []string{ | ||
33 | "runtime.goexit", | ||
34 | "runtime.main", | ||
35 | } | ||
36 | _stacktracePool = sync.Pool{ | ||
37 | New: func() interface{} { | ||
38 | return newProgramCounters(64) | ||
39 | }, | ||
40 | } | ||
41 | ) | ||
42 | |||
43 | // A stacktrace gathered by a previous call to log.Stacktrace. If passed | ||
44 | // to a logging function, the stacktrace will be appended. | ||
45 | type CapturedStacktrace string | ||
46 | |||
47 | // Gather a stacktrace of the current goroutine and return it to be passed | ||
48 | // to a logging function. | ||
49 | func Stacktrace() CapturedStacktrace { | ||
50 | return CapturedStacktrace(takeStacktrace()) | ||
51 | } | ||
52 | |||
53 | func takeStacktrace() string { | ||
54 | programCounters := _stacktracePool.Get().(*programCounters) | ||
55 | defer _stacktracePool.Put(programCounters) | ||
56 | |||
57 | var buffer bytes.Buffer | ||
58 | |||
59 | for { | ||
60 | // Skip the call to runtime.Counters and takeStacktrace so that the | ||
61 | // program counters start at the caller of takeStacktrace. | ||
62 | n := runtime.Callers(2, programCounters.pcs) | ||
63 | if n < cap(programCounters.pcs) { | ||
64 | programCounters.pcs = programCounters.pcs[:n] | ||
65 | break | ||
66 | } | ||
67 | // Don't put the too-short counter slice back into the pool; this lets | ||
68 | // the pool adjust if we consistently take deep stacktraces. | ||
69 | programCounters = newProgramCounters(len(programCounters.pcs) * 2) | ||
70 | } | ||
71 | |||
72 | i := 0 | ||
73 | frames := runtime.CallersFrames(programCounters.pcs) | ||
74 | for frame, more := frames.Next(); more; frame, more = frames.Next() { | ||
75 | if shouldIgnoreStacktraceFunction(frame.Function) { | ||
76 | continue | ||
77 | } | ||
78 | if i != 0 { | ||
79 | buffer.WriteByte('\n') | ||
80 | } | ||
81 | i++ | ||
82 | buffer.WriteString(frame.Function) | ||
83 | buffer.WriteByte('\n') | ||
84 | buffer.WriteByte('\t') | ||
85 | buffer.WriteString(frame.File) | ||
86 | buffer.WriteByte(':') | ||
87 | buffer.WriteString(strconv.Itoa(int(frame.Line))) | ||
88 | } | ||
89 | |||
90 | return buffer.String() | ||
91 | } | ||
92 | |||
93 | func shouldIgnoreStacktraceFunction(function string) bool { | ||
94 | for _, prefix := range _stacktraceIgnorePrefixes { | ||
95 | if strings.HasPrefix(function, prefix) { | ||
96 | return true | ||
97 | } | ||
98 | } | ||
99 | return false | ||
100 | } | ||
101 | |||
102 | type programCounters struct { | ||
103 | pcs []uintptr | ||
104 | } | ||
105 | |||
106 | func newProgramCounters(size int) *programCounters { | ||
107 | return &programCounters{make([]uintptr, size)} | ||
108 | } | ||