stacktrace

package module
v2.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 22, 2025 License: Apache-2.0 Imports: 6 Imported by: 3

README

stacktrace/v2

Package stacktrace provides utilities for capturing and inspecting stack traces associated with errors.

Go Reference Go Report Card

Features

  • Wraps errors with a single stack trace
    • Typically, a single error chain contains at most one stack trace
  • Extracts the stack trace from an error

Usage

Trace

The most basic way to create an error with a stack trace is to use the Trace function:

err := stacktrace.Trace(os.Chdir(target))

There are Trace2, Trace3, and Trace4: These are overloads of Trace that return the given values unchanged if err is nil. If err is not nil, it wraps err with stack trace information before returning.

file, err := stacktrace.Trace2(os.Open(file))
New and Errorf

For convenience, you can use New and Errorf as drop-in replacements for errors.New and fmt.Errorf:

err := stacktrace.New("some error")
err := stacktrace.Errorf("some error: %w", originalErr)

Extracting Stack Trace Information

As a string

To get a formatted string representation of stack trace information from an error:

// Get as a string.
// This is equivalent to calling `err.Error()`
// if `err` does not contain stack trace information.
// `s` is an empty string if `err` is nil.
s := stacktrace.Format(err)

Use Format. For example, the s contains multiline string like below:

chdir /no/such/dir: no such file or directory (run.go:10 main.run)
        example.com/hello/run.go:10 main.run
        example.com/hello/main.go:11 main.main
As a DebugInfo

To extract stack trace information from an error:

// Get as a DebugInfo instance
info := stacktrace.GetDebugInfo(err)

The DebugInfo type is compatible with google.golang.org/genproto/googleapis/rpc/errdetails.DebugInfo.

For example, the info contains information like below:

{
  "detail": "chdir /no/such/dir: no such file or directory (run.go:10 main.run)",
  "stack_entries": [
    "example.com/hello/run.go:10 main.run",
    "example.com/hello/main.go:11 main.main"
  ]
}
As StackTracers

Alternatively, you can use ListStackTracers to extract the StackTracer instances from an error chain. CallersFrames is available in Go 1.23 or later.

list := stacktrace.ListStackTracers(err)
for _, v := range list {
	for frame := range stacktrace.CallersFrames(v.StackTrace()) {
		_, _ = frame.File, frame.Line
	}
}

Performance Considerations

Adding stack traces to errors involves some overhead. In performance-critical sections, consider using traditional error handling and adding stack traces at higher levels of your application.

Documentation

Overview

Package stacktrace provides utilities for capturing and inspecting call stacks associated with errors.

This package allows you to create error objects that include information about where in the code the error occurred, which can be extremely useful for debugging. It includes methods to unwrap underlying errors, retrieve call stack frames, and generate string representations of errors with detailed stack trace information.

Example
if err := stacktrace.Trace(os.Chdir(".")); err != nil {
	fmt.Println("err.Error():", err.Error())
	info := stacktrace.GetDebugInfo(err)
	fmt.Println("info.Detail:", info.Detail)
	fmt.Printf("%d stack entries included.", len(info.StackEntries))
	panic(stacktrace.GetDebugInfo(err))
}
if file, err := stacktrace.Trace2(os.Open("./no/such/file")); err != nil {
	fmt.Println("err.Error():", err.Error())
	info := stacktrace.GetDebugInfo(err)
	fmt.Println("info.Detail:", info.Detail)
	fmt.Printf("%d stack entries included.", len(info.StackEntries))
} else {
	file.Close()
}
Output:

err.Error(): open ./no/such/file: no such file or directory (stacktrace_test.go:18 Example)
info.Detail: open ./no/such/file: no such file or directory (stacktrace_test.go:18 Example)
5 stack entries included.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Callers

func Callers(skip int) []uintptr

Callers returns the program counters (PCs) of function invocations on the calling goroutine's stack, skipping the specified number of stack frames.

The skip parameter determines how many initial stack frames to omit from the result. A skip value of 0 starts from the caller of Callers itself.

The returned slice contains the collected program counters, which can be further processed using runtime.CallersFrames to obtain function details.

func CallersFrames

func CallersFrames(callers []uintptr) iter.Seq[*runtime.Frame]

CallersFrames returns an iterator sequence of *runtime.Frame based on the given slice of program counters (PCs). It yields stack frames one by one, stopping if the iterator function returns false, or if there are no more frames.

The function utilizes runtime.CallersFrames to traverse the stack trace and provides each frame through the yield function.

func CallersLimit added in v2.4.0

func CallersLimit(skip, limit int) []uintptr

CallersLimit returns the program counters (PCs) of function invocations on the calling goroutine's stack, skipping the specified number of stack frames and limiting the number of returned frames.

The skip parameter determines how many initial stack frames to omit from the result. A skip value of 0 starts from the caller of CallersLimit itself.

The limit parameter specifies the maximum number of stack frames to return. If limit is 0, an empty slice is returned. If limit is negative, all available stack frames after skipping are returned (equivalent to calling Callers with skip + 1).

The returned slice contains the collected program counters, which can be further processed using runtime.CallerFrames to obtain function details.

func Errorf

func Errorf(format string, a ...any) error

Errorf returns an error formatted according to the format specifier, similar to fmt.Errorf, along with stack trace information in a concise way.

Example usage:

err := stacktrace.Errorf("failed to do %s", action)

This is equivalent to:

err := stacktrace.Trace(fmt.Errorf("failed to do %s", action))

stacktrace.Errorf is slightly more concise and efficient.

func Format

func Format(err error) string

Format returns a formatted string representation of the DebugInfo from err.

If err is nil, it returns an empty string. If err's chain doesn't contain any stack trace information, it returns err.Error().

This is equivalent to:

stacktrace.GetDebugInfo(err).Format()

See DebugInfo.Format.

func HasStackTracer added in v2.3.0

func HasStackTracer(err error) bool

HasStackTracer returns true if there is at least one StackTracer in the error chain, false otherwise.

func New

func New(text string) error

New returns an error created with errors.New along with stack trace information in a concise way.

Example usage:

err := stacktrace.New("something went wrong")

This is equivalent to:

err := stacktrace.Trace(errors.New("something went wrong"))

stacktrace.New is slightly more concise and efficient.

func Trace

func Trace(err error) error

Trace returns the error along with stack frame information. It returns nil if the input error is nil.

func Trace2

func Trace2[T0 any](v0 T0, err error) (T0, error)

Trace2 returns the given values unchanged if err is nil. If err is not nil, it wraps err with stack trace information before returning.

The function name "Trace2" indicates that it takes two arguments (a value of any type and an error) and returns two values.

func Trace3

func Trace3[T0, T1 any](v0 T0, v1 T1, err error) (T0, T1, error)

Trace3 returns the given values unchanged if err is nil. If err is not nil, it wraps err with stack trace information before returning.

The function name "Trace3" indicates that it takes three arguments (two values of any type and an error) and returns three values.

func Trace4

func Trace4[T0, T1, T2 any](v0 T0, v1 T1, v2 T2, err error) (T0, T1, T2, error)

Trace4 returns the given values unchanged if err is nil. If err is not nil, it wraps err with stack trace information before returning.

The function name "Trace4" indicates that it takes four arguments (three values of any type and an error) and returns four values.

Types

type DebugInfo

type DebugInfo struct {
	// Detail provides a detailed error message.
	Detail string `json:"detail,omitempty"`

	// StackEntries contains a list of stack trace entries related to the error.
	StackEntries []string `json:"stack_entries,omitempty"`
}

DebugInfo represents debug information about an error.

This struct is compatible with google.golang.org/genproto/googleapis/rpc/errdetails.DebugInfo.

Example (Multiple)
ch := make(chan error)
go func() { ch <- stacktrace.New("hello") }()
go func() { ch <- stacktrace.New("world") }()
err1 := <-ch // error from the thread
err2 := <-ch // error from the other thread
if err1 != nil || err2 != nil {
	err := errors.Join(
		stacktrace.New("Two errors"), // error of this thread
		err1,
		err2,
	)
	info := stacktrace.GetDebugInfo(err)
	fmt.Println(info.Format()) // this prints 3 stack frames.
}
Output:

func GetDebugInfo

func GetDebugInfo(err error) DebugInfo

GetDebugInfo extracts debug information from an error. It collects stack trace frames and formats them as strings, then returns this information along with the detailed error message in a DebugInfo struct.

It returns a zero value if err is nil.

func (DebugInfo) Format

func (info DebugInfo) Format() string

Format returns a formatted string representation of the DebugInfo.

The output consists of the Detail message followed by the stack trace entries, each separated by a newline and a tab ("\n\t").

Example
err := stacktrace.Trace(os.Chdir("/no/such/dir"))
fmt.Println(stacktrace.Format(err))
Output:

Example (Nil)
err := stacktrace.Trace(nil)
fmt.Println(stacktrace.Format(err))
Output:

type Error

type Error struct {
	// Err holds the original error that occurred.
	Err error

	// Callers contains the program counters (PCs) of the function call stack
	// at the time the error was captured. These can be used to retrieve stack traces.
	Callers []uintptr
}

Error wraps an error and adds a call stack indicating where it occurred.

It is recommended to use the following functions to create an instance of Error:

  • Trace: Adds a call stack indicating where Trace was executed to the given error and returns it.
  • Trace2, Trace3, Trace4: Variants of Trace that accept multiple arbitrary arguments along with an error and return them. The trailing number represents the number of additional arguments other than the error.
  • Errorf: A function that wraps `fmt.Errorf` with `Trace`.
  • New: A function that wraps `errors.New` with `Trace`.

If `nil` is passed to Trace and its variants, they return `nil` as an error.

Trace, Trace2, Trace3, Trace4, and Errorf do not add a new call stack if the given error already has one, meaning that if an `Error` instance is already present in the error chain, the original error is returned as-is.

New always returns an error with a newly added call stack.

func NewError

func NewError(err error, callers []uintptr) *Error

NewError returns a new Error instance with the given error and caller stack information.

func (Error) Error

func (err Error) Error() string

Error returns a string representation of the custom error, including the original error message. If the call stack information is available, it appends the information about the first frame of the stack trace to the error message.

The format of the returned string is: "<original error message> (<file name>:<line> <function name>)"

func (Error) StackTrace added in v2.1.0

func (err Error) StackTrace() []uintptr

StackTrace returns a slice of program counters representing the call stack.

func (Error) Unwrap

func (err Error) Unwrap() error

Unwrap returns the wrapped error, allowing for further inspection using errors.Unwrap.

type StackTracer added in v2.1.0

type StackTracer interface {
	// StackTracer extends the error interface.
	error

	// StackTrace returns a slice of program counters representing the call stack.
	StackTrace() []uintptr
}

StackTracer represents an error that provides stack trace information.

func ListStackTracers added in v2.3.0

func ListStackTracers(err error) []StackTracer

ListStackTracers returns all the StackTracers in the error chain.

Example
var err error
for _, v := range stacktrace.ListStackTracers(err) {
	for frame := range stacktrace.CallersFrames(v.StackTrace()) {
		_, _ = frame.File, frame.Line
	}
}
Output:

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL