Source File
stack.go
Belonging Package
go.uber.org/zap/internal/stacktrace
// Copyright (c) 2023 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 stacktrace provides support for gathering stack traces// efficiently.package stacktraceimport ()var _stackPool = pool.New(func() *Stack {return &Stack{storage: make([]uintptr, 64),}})// Stack is a captured stack trace.type Stack struct {pcs []uintptr // program counters; always a subslice of storageframes *runtime.Frames// The size of pcs varies depending on requirements:// it will be one if the only the first frame was requested,// and otherwise it will reflect the depth of the call stack.//// storage decouples the slice we need (pcs) from the slice we pool.// We will always allocate a reasonably large storage, but we'll use// only as much of it as we need.storage []uintptr}// Depth specifies how deep of a stack trace should be captured.type Depth intconst (// First captures only the first frame.First Depth = iota// Full captures the entire call stack, allocating more// storage for it if needed.Full)// Capture captures a stack trace of the specified depth, skipping// the provided number of frames. skip=0 identifies the caller of// Capture.//// The caller must call Free on the returned stacktrace after using it.func ( int, Depth) *Stack {:= _stackPool.Get()switch {case First:.pcs = .storage[:1]case Full:.pcs = .storage}// Unlike other "skip"-based APIs, skip=0 identifies runtime.Callers// itself. +2 to skip captureStacktrace and runtime.Callers.:= runtime.Callers(+2,.pcs,)// runtime.Callers truncates the recorded stacktrace if there is no// room in the provided slice. For the full stack trace, keep expanding// storage until there are fewer frames than there is room.if == Full {:= .pcsfor == len() {= make([]uintptr, len()*2)= runtime.Callers(+2, )}// Discard old storage instead of returning it to the pool.// This will adjust the pool size over time if stack traces are// consistently very deep..storage =.pcs = [:]} else {.pcs = .pcs[:]}.frames = runtime.CallersFrames(.pcs)return}// Free releases resources associated with this stacktrace// and returns it back to the pool.func ( *Stack) () {.frames = nil.pcs = nil_stackPool.Put()}// Count reports the total number of frames in this stacktrace.// Count DOES NOT change as Next is called.func ( *Stack) () int {return len(.pcs)}// Next returns the next frame in the stack trace,// and a boolean indicating whether there are more after it.func ( *Stack) () ( runtime.Frame, bool) {return .frames.Next()}// Take returns a string representation of the current stacktrace.//// skip is the number of frames to skip before recording the stack trace.// skip=0 identifies the caller of Take.func ( int) string {:= Capture(+1, Full)defer .Free():= bufferpool.Get()defer .Free():= NewFormatter().FormatStack()return .String()}// Formatter formats a stack trace into a readable string representation.type Formatter struct {b *buffer.BuffernonEmpty bool // whehther we've written at least one frame already}// NewFormatter builds a new Formatter.func ( *buffer.Buffer) Formatter {return Formatter{b: }}// FormatStack formats all remaining frames in the provided stacktrace -- minus// the final runtime.main/runtime.goexit frame.func ( *Formatter) ( *Stack) {// Note: On the last iteration, frames.Next() returns false, with a valid// frame, but we ignore this frame. The last frame is a runtime frame which// adds noise, since it's only either runtime.main or runtime.goexit.for , := .Next(); ; , = .Next() {.FormatFrame()}}// FormatFrame formats the given frame.func ( *Formatter) ( runtime.Frame) {if .nonEmpty {.b.AppendByte('\n')}.nonEmpty = true.b.AppendString(.Function).b.AppendByte('\n').b.AppendByte('\t').b.AppendString(.File).b.AppendByte(':').b.AppendInt(int64(.Line))}
![]() |
The pages are generated with Golds v0.6.7. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |