1
0
mirror of https://github.com/imgproxy/imgproxy.git synced 2025-12-28 22:21:10 +02:00
Files
imgproxy/errctx/wrapped_error.go
Sergei Aleksandrovich e33254005d Refactored errors (#1578)
* Refactored errors

* Make monitoring and errorreport accept `errctx.Error` instead of `error`

* Add server.Error; Remove category from errctx; Make HTTP handlers respond with *server.Error

* Remove stackSkip from errctx.Wrap; Add errctx.WrapWithStackSkip
2025-11-20 01:26:21 +06:00

98 lines
2.8 KiB
Go

package errctx
// WrappedError is an implementation of [Error] that wraps another error.
//
// It also implements the Unwrap and Cause methods to retrieve the wrapped error.
//
// When implementing a custom error type that wraps another error,
// embed [WrappedError] to provide standard behavior.
type WrappedError struct {
error
*ErrorContext
}
// NewWrappedError creates a new [WrappedError] with the given error and options.
// It wraps the provided even if it already is an [WrappedError] and always
// creates a new context.
// To avoid double wrapping and reuse existing context, use [Wrap] instead.
func NewWrappedError(err error, stackSkip int, opts ...Option) *WrappedError {
return &WrappedError{
error: err,
ErrorContext: newErrorContext(stackSkip+1, opts...),
}
}
// Wrap creates a new [WrappedError] with the given error and options.
// It gets the stack trace from the call site.
//
// If the provided error already an [Error], it clones its context and applies
// the new options to it.
//
// If the provided error is already an [WrappedError], it rewraps its inner error
// to avoid double wrapping.
func Wrap(err error, opts ...Option) Error {
return WrapWithStackSkip(err, 1, opts...)
}
// WrapWithStackSkip creates a new [WrappedError] with the given error and options.
// It the first stackSkip frames from the call stack.
//
// If the provided error already an [Error], it clones its context and applies
// the new options to it.
//
// If the provided error is already an [WrappedError], it rewraps its inner error
// to avoid double wrapping.
func WrapWithStackSkip(err error, stackSkip int, opts ...Option) Error {
if err == nil {
return nil
}
var ec *ErrorContext
// Check if the error already has context
if ewc, ok := err.(Error); ok {
// If the error already has context and no new options are provided,
// we don't need to wrap it again and can return it as is.
if len(opts) == 0 {
return ewc
}
// Clone the existing context to avoid modifying the original one
// and apply new options
ec = ewc.CloneErrorContext(opts...)
// If the error is already an WrappedError, get its inner error
// to avoid double wrapping
if ew, ok := err.(*WrappedError); ok {
err = ew.Unwrap()
}
} else {
// If the error does not have context, create a new one
ec = newErrorContext(stackSkip+1, opts...)
}
return &WrappedError{
error: err,
ErrorContext: ec,
}
}
// Error returns the error message with prefix if set.
func (e *WrappedError) Error() string {
if len(e.prefix) > 0 {
return e.prefix + ": " + e.error.Error()
}
return e.error.Error()
}
// Unwrap returns the wrapped error.
func (e *WrappedError) Unwrap() error {
return e.error
}
// Cause returns the wrapped error.
// This method is provided for compatibility with github.com/pkg/errors.
func (e *WrappedError) Cause() error {
return e.error
}