]>
Commit | Line | Data |
---|---|---|
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 | } |