summaryrefslogtreecommitdiffstats
path: root/vendor/go.uber.org/zap/stacktrace.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/go.uber.org/zap/stacktrace.go')
-rw-r--r--vendor/go.uber.org/zap/stacktrace.go126
1 files changed, 126 insertions, 0 deletions
diff --git a/vendor/go.uber.org/zap/stacktrace.go b/vendor/go.uber.org/zap/stacktrace.go
new file mode 100644
index 00000000..100fac21
--- /dev/null
+++ b/vendor/go.uber.org/zap/stacktrace.go
@@ -0,0 +1,126 @@
+// Copyright (c) 2016 Uber Technologies, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package zap
+
+import (
+ "runtime"
+ "strings"
+ "sync"
+
+ "go.uber.org/zap/internal/bufferpool"
+)
+
+const _zapPackage = "go.uber.org/zap"
+
+var (
+ _stacktracePool = sync.Pool{
+ New: func() interface{} {
+ return newProgramCounters(64)
+ },
+ }
+
+ // We add "." and "/" suffixes to the package name to ensure we only match
+ // the exact package and not any package with the same prefix.
+ _zapStacktracePrefixes = addPrefix(_zapPackage, ".", "/")
+ _zapStacktraceVendorContains = addPrefix("/vendor/", _zapStacktracePrefixes...)
+)
+
+func takeStacktrace() string {
+ buffer := bufferpool.Get()
+ defer buffer.Free()
+ programCounters := _stacktracePool.Get().(*programCounters)
+ defer _stacktracePool.Put(programCounters)
+
+ var numFrames int
+ for {
+ // Skip the call to runtime.Counters and takeStacktrace so that the
+ // program counters start at the caller of takeStacktrace.
+ numFrames = runtime.Callers(2, programCounters.pcs)
+ if numFrames < len(programCounters.pcs) {
+ break
+ }
+ // Don't put the too-short counter slice back into the pool; this lets
+ // the pool adjust if we consistently take deep stacktraces.
+ programCounters = newProgramCounters(len(programCounters.pcs) * 2)
+ }
+
+ i := 0
+ skipZapFrames := true // skip all consecutive zap frames at the beginning.
+ frames := runtime.CallersFrames(programCounters.pcs[:numFrames])
+
+ // Note: On the last iteration, frames.Next() returns false, with a valid
+ // frame, but we ignore this frame. The last frame is a a runtime frame which
+ // adds noise, since it's only either runtime.main or runtime.goexit.
+ for frame, more := frames.Next(); more; frame, more = frames.Next() {
+ if skipZapFrames && isZapFrame(frame.Function) {
+ continue
+ } else {
+ skipZapFrames = false
+ }
+
+ if i != 0 {
+ buffer.AppendByte('\n')
+ }
+ i++
+ buffer.AppendString(frame.Function)
+ buffer.AppendByte('\n')
+ buffer.AppendByte('\t')
+ buffer.AppendString(frame.File)
+ buffer.AppendByte(':')
+ buffer.AppendInt(int64(frame.Line))
+ }
+
+ return buffer.String()
+}
+
+func isZapFrame(function string) bool {
+ for _, prefix := range _zapStacktracePrefixes {
+ if strings.HasPrefix(function, prefix) {
+ return true
+ }
+ }
+
+ // We can't use a prefix match here since the location of the vendor
+ // directory affects the prefix. Instead we do a contains match.
+ for _, contains := range _zapStacktraceVendorContains {
+ if strings.Contains(function, contains) {
+ return true
+ }
+ }
+
+ return false
+}
+
+type programCounters struct {
+ pcs []uintptr
+}
+
+func newProgramCounters(size int) *programCounters {
+ return &programCounters{make([]uintptr, size)}
+}
+
+func addPrefix(prefix string, ss ...string) []string {
+ withPrefix := make([]string, len(ss))
+ for i, s := range ss {
+ withPrefix[i] = prefix + s
+ }
+ return withPrefix
+}