blob: bc29af1e4f50af8f0c2b2484feb09f74b1129ec3 [file] [log] [blame]
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package derrors defines internal error values to categorize the different
// types error semantics.
package derrors
import (
"errors"
"fmt"
"runtime"
"cloud.google.com/go/errorreporting"
)
// Wrap adds context to the error and allows
// unwrapping the result to recover the original error.
//
// Example:
//
// defer derrors.Wrap(&err, "copy(%s, %s)", dst, src)
// defer derrors.Wrap(&err, "copy(%s, %s)", src, dst)
//
// See Add for an equivalent function that does not allow
// the result to be unwrapped.
func Wrap(errp *error, format string, args ...interface{}) {
if *errp != nil {
*errp = fmt.Errorf("%s: %w", fmt.Sprintf(format, args...), *errp)
}
}
// WrapStack is like Wrap, but adds a stack trace if there isn't one already.
func WrapStack(errp *error, format string, args ...interface{}) {
if *errp != nil {
if se := (*StackError)(nil); !errors.As(*errp, &se) {
*errp = NewStackError(*errp)
}
Wrap(errp, format, args...)
}
}
// StackError wraps an error and adds a stack trace.
type StackError struct {
Stack []byte
err error
}
// NewStackError returns a StackError, capturing a stack trace.
func NewStackError(err error) *StackError {
// Limit the stack trace to 16K. Same value used in the errorreporting client,
// cloud.google.com/go@v0.66.0/errorreporting/errors.go.
var buf [16 * 1024]byte
n := runtime.Stack(buf[:], false)
return &StackError{
err: err,
Stack: buf[:n],
}
}
func (e *StackError) Error() string {
return e.err.Error() // ignore the stack
}
func (e *StackError) Unwrap() error {
return e.err
}
// WrapAndReport calls Wrap followed by Report.
func WrapAndReport(errp *error, format string, args ...interface{}) {
Wrap(errp, format, args...)
if *errp != nil {
Report(*errp)
}
}
var repClient *errorreporting.Client
// SetReportingClient sets an errorreporting client, for use by Report.
func SetReportingClient(c *errorreporting.Client) {
repClient = c
}
// Report uses the errorreporting API to report an error.
func Report(err error) {
if repClient != nil {
repClient.Report(errorreporting.Entry{Error: err})
}
}