Documentation
¶
Overview ¶
Package stacktrace captures and formats call stack information using the Go runtime. It provides GetStack to capture the current program stack, and Wrap / Extract to attach a StackTrace to an error. StackTrace implements slog.LogValuer for structured logging integration.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var Disabled atomic.Bool
Disabled disables stacktrace collection in Wrap when set to true.
Functions ¶
func Wrap ¶
Wrap extends err by attaching a StackTrace captured at the call site. If err is nil or Disabled is true, err is returned unchanged. If err already carries a StackTrace, it is not wrapped again.
Example ¶
package main
import (
"bytes"
"errors"
"fmt"
"log/slog"
"regexp"
"github.com/wood-jp/xerrors"
"github.com/wood-jp/xerrors/stacktrace"
)
func newLogger(buf *bytes.Buffer) *slog.Logger {
return slog.New(slog.NewJSONHandler(buf, &slog.HandlerOptions{
ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
if a.Key == slog.TimeKey && len(groups) == 0 {
return slog.Attr{}
}
return a
},
}))
}
var (
reSource = regexp.MustCompile(`"source":"[^"]*"`)
reLine = regexp.MustCompile(`"line":\d+`)
)
func normalizeStack(s string) string {
s = reSource.ReplaceAllString(s, `"source":"..."`)
s = reLine.ReplaceAllString(s, `"line":0`)
return s
}
func main() {
var buf bytes.Buffer
err := stacktrace.Wrap(errors.New("something failed"))
newLogger(&buf).Error("operation failed", xerrors.Log(err))
fmt.Print(normalizeStack(buf.String()))
}
Output: {"level":"ERROR","msg":"operation failed","error":{"error":"something failed","error_detail":{"stacktrace":[{"func":"github.com/wood-jp/xerrors/stacktrace_test.ExampleWrap","line":0,"source":"..."},{"func":"main.main","line":0,"source":"..."}]}}}
Types ¶
type Frame ¶
type Frame struct {
// File is the source file path of the frame.
File string `json:"source"`
// LineNumber is the line number within File where the call was made.
LineNumber int `json:"line"`
// Function is the fully-qualified function name of the frame.
Function string `json:"func"`
}
Frame represents human-readable information about a single frame in a stack trace.
type StackTrace ¶
type StackTrace []Frame
StackTrace represents a program stack trace as a series of frames.
func Extract ¶
func Extract(err error) StackTrace
Extract returns the StackTrace attached to err, or nil if none is present or err is nil.
Example (NoStack) ¶
package main
import (
"errors"
"fmt"
"github.com/wood-jp/xerrors/stacktrace"
)
func main() {
err := errors.New("plain error")
fmt.Println(stacktrace.Extract(err) == nil)
}
Output: true
func GetStack ¶
func GetStack(skipFrames int, skipRuntime bool) StackTrace
GetStack captures the current program stack trace and returns it as a StackTrace. skipFrames controls how many frames to skip: passing 1 makes GetStack itself the first captured frame. When skipRuntime is true, frames from the Go runtime (e.g. runtime.main, runtime.panic) and the testing package are omitted from the result.
func (StackTrace) LogValue ¶
func (st StackTrace) LogValue() slog.Value
LogValue implements slog.LogValuer. It returns a group containing a single "stacktrace" attr whose value is an array of frame objects, each with "func", "line", and "source" keys.
Each frame is represented as map[string]any rather than slog.GroupValue because slog handlers only resolve slog.LogValuer at the top level of an attribute value — they do not recursively resolve slog.Value elements nested inside a []slog.Value wrapped in slog.AnyValue. JSON and text handlers would encode those as empty objects ({}). map[string]any is handled correctly by encoding/json and produces the expected key-value output.