Remove BPA from Makefile
[icn.git] / cmd / bpa-operator / vendor / go.uber.org / zap / stacktrace.go
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 zap
22
23 import (
24         "runtime"
25         "strings"
26         "sync"
27
28         "go.uber.org/zap/internal/bufferpool"
29 )
30
31 const _zapPackage = "go.uber.org/zap"
32
33 var (
34         _stacktracePool = sync.Pool{
35                 New: func() interface{} {
36                         return newProgramCounters(64)
37                 },
38         }
39
40         // We add "." and "/" suffixes to the package name to ensure we only match
41         // the exact package and not any package with the same prefix.
42         _zapStacktracePrefixes       = addPrefix(_zapPackage, ".", "/")
43         _zapStacktraceVendorContains = addPrefix("/vendor/", _zapStacktracePrefixes...)
44 )
45
46 func takeStacktrace() string {
47         buffer := bufferpool.Get()
48         defer buffer.Free()
49         programCounters := _stacktracePool.Get().(*programCounters)
50         defer _stacktracePool.Put(programCounters)
51
52         var numFrames int
53         for {
54                 // Skip the call to runtime.Counters and takeStacktrace so that the
55                 // program counters start at the caller of takeStacktrace.
56                 numFrames = runtime.Callers(2, programCounters.pcs)
57                 if numFrames < len(programCounters.pcs) {
58                         break
59                 }
60                 // Don't put the too-short counter slice back into the pool; this lets
61                 // the pool adjust if we consistently take deep stacktraces.
62                 programCounters = newProgramCounters(len(programCounters.pcs) * 2)
63         }
64
65         i := 0
66         skipZapFrames := true // skip all consecutive zap frames at the beginning.
67         frames := runtime.CallersFrames(programCounters.pcs[:numFrames])
68
69         // Note: On the last iteration, frames.Next() returns false, with a valid
70         // frame, but we ignore this frame. The last frame is a a runtime frame which
71         // adds noise, since it's only either runtime.main or runtime.goexit.
72         for frame, more := frames.Next(); more; frame, more = frames.Next() {
73                 if skipZapFrames && isZapFrame(frame.Function) {
74                         continue
75                 } else {
76                         skipZapFrames = false
77                 }
78
79                 if i != 0 {
80                         buffer.AppendByte('\n')
81                 }
82                 i++
83                 buffer.AppendString(frame.Function)
84                 buffer.AppendByte('\n')
85                 buffer.AppendByte('\t')
86                 buffer.AppendString(frame.File)
87                 buffer.AppendByte(':')
88                 buffer.AppendInt(int64(frame.Line))
89         }
90
91         return buffer.String()
92 }
93
94 func isZapFrame(function string) bool {
95         for _, prefix := range _zapStacktracePrefixes {
96                 if strings.HasPrefix(function, prefix) {
97                         return true
98                 }
99         }
100
101         // We can't use a prefix match here since the location of the vendor
102         // directory affects the prefix. Instead we do a contains match.
103         for _, contains := range _zapStacktraceVendorContains {
104                 if strings.Contains(function, contains) {
105                         return true
106                 }
107         }
108
109         return false
110 }
111
112 type programCounters struct {
113         pcs []uintptr
114 }
115
116 func newProgramCounters(size int) *programCounters {
117         return &programCounters{make([]uintptr, size)}
118 }
119
120 func addPrefix(prefix string, ss ...string) []string {
121         withPrefix := make([]string, len(ss))
122         for i, s := range ss {
123                 withPrefix[i] = prefix + s
124         }
125         return withPrefix
126 }