Documentation
¶
Index ¶
- func GetTypedValue[T any](err error, key TypedKey[T]) (T, bool)
- func HasTag(err error, tag tag) bool
- func NewTag(value string) tag
- func Tags(err error) []string
- func TypedValues(err error) map[string]any
- func Values(err error) map[string]any
- type Builder
- type Error
- func (x *Error) Error() string
- func (x *Error) Format(s fmt.State, verb rune)
- func (x *Error) HasTag(tag tag) bool
- func (x *Error) Is(target error) bool
- func (x *Error) LogValue() slog.Value
- func (x *Error) MarshalJSON() ([]byte, error)
- func (x *Error) Printable() *Printable
- func (x *Error) StackTrace() StackTrace
- func (x *Error) Stacks() []*Stack
- func (x *Error) Tags() []string
- func (x *Error) TypedValues() map[string]any
- func (x *Error) Unstack() *Error
- func (x *Error) UnstackN(n int) *Error
- func (x *Error) Unwrap() error
- func (x *Error) Values() map[string]any
- func (x *Error) WithTags(tags ...tag) *Errordeprecated
- func (x *Error) Wrap(cause error, options ...Option) *Error
- type Errors
- func (x *Errors) As(target any) bool
- func (x *Errors) Error() string
- func (x *Errors) ErrorOrNil() error
- func (x *Errors) Errors() []error
- func (x *Errors) Format(s fmt.State, verb rune)
- func (x *Errors) HasTag(tag tag) bool
- func (x *Errors) Is(target error) bool
- func (x *Errors) IsEmpty() bool
- func (x *Errors) Len() int
- func (x *Errors) LogValue() slog.Value
- func (x *Errors) MarshalJSON() ([]byte, error)
- func (x *Errors) Unwrap() []error
- type ErrorsJSON
- type Option
- type Printable
- type Stack
- type StackTrace
- type TypedKey
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func GetTypedValue ¶
GetTypedValue returns value associated with the typed key from the error. It searches through the error chain.
Usage:
key := goerr.NewTypedKey[string]("user_id")
if userID, ok := goerr.GetTypedValue(err, key); ok {
fmt.Printf("User ID: %s", userID) // userID is guaranteed to be string
}
func NewTag ¶
func NewTag(value string) tag
NewTag creates a new Tag. The key will be empty.
Example ¶
package main
import (
"fmt"
"github.com/gaebalai/goerr/v2"
)
func main() {
t1 := goerr.NewTag("DB error")
err := goerr.New("error message", goerr.Tag(t1))
if goErr := goerr.Unwrap(err); goErr != nil {
if goErr.HasTag(t1) {
fmt.Println("DB error")
}
}
}
Output: DB error
func Tags ¶
Tags returns list of tags that is set by WithTags. All wrapped goerr.Error tags will be merged. Tags of wrapped error is overwritten by upper goerr.Error.
func TypedValues ¶
TypedValues returns map of key and value that is set by TypedValue. All wrapped goerr.Error typed key and values will be merged. Key and values of wrapped error is overwritten by upper goerr.Error.
Types ¶
type Builder ¶
type Builder struct {
// contains filtered or unexported fields
}
Builder keeps a set of key-value pairs and can create a new error and wrap error with the key-value pairs.
Example ¶
ExampleBuilder demonstrates using Builder pattern for creating errors with shared context. goerr.NewBuilder(options...) creates a builder, .With(options...) extends it, .New(msg) / .Wrap(err, msg) creates errors
package main
import (
"fmt"
"github.com/gaebalai/goerr/v2"
)
func main() {
// Create a builder with common context for a request
builder := goerr.NewBuilder(
goerr.V("service", "user-service"),
goerr.V("request_id", "req-12345"),
)
// Create errors using the builder - shared context is automatically included
err1 := builder.New("user not found")
err2 := builder.Wrap(fmt.Errorf("connection refused"), "database unavailable")
// All errors created by the builder include the shared context
fmt.Println("Error 1:", err1.Error())
fmt.Printf("Service: %s\n", goerr.Values(err1)["service"])
fmt.Println("Error 2:", err2.Error())
fmt.Printf("Request ID: %s\n", goerr.Values(err2)["request_id"])
// Extend the builder with additional context
extendedBuilder := builder.With(goerr.V("user_id", "user789"))
err3 := extendedBuilder.New("permission denied")
fmt.Println("Error 3:", err3.Error())
fmt.Printf("User ID: %s\n", goerr.Values(err3)["user_id"])
}
Output: Error 1: user not found Service: user-service Error 2: database unavailable: connection refused Request ID: req-12345 Error 3: permission denied User ID: user789
func NewBuilder ¶
NewBuilder creates a new Builder. A Builder is useful for creating multiple errors that share a common context, such as a request ID or service name, without repeatedly specifying the same options.
Usage:
builder := goerr.NewBuilder(goerr.V("service", "auth"), goerr.V("request_id", "req123"))
err1 := builder.New("user not found")
err2 := builder.Wrap(dbErr, "query failed")
// Both errors will include service and request_id context
Example ¶
package main
import (
"fmt"
"io"
"github.com/gaebalai/goerr/v2"
)
func main() {
// Create a builder with common context for a request.
builder := goerr.NewBuilder(
goerr.Value("service", "auth-service"),
goerr.Value("request_id", "req-9876"),
)
// Use the builder to create errors.
err1 := builder.New("user not found")
err2 := builder.Wrap(io.EOF, "failed to read body")
// The context from the builder is automatically included.
fmt.Println(goerr.Values(err1)["service"])
fmt.Println(goerr.Values(err2)["request_id"])
}
Output: auth-service req-9876
func (*Builder) New ¶
New creates a new error with message
Usage:
builder := goerr.NewBuilder(goerr.V("service", "auth"))
err := builder.New("authentication failed") // includes service context
func (*Builder) With ¶
With copies the current Builder and adds a new key-value pair.
Usage:
baseBuilder := goerr.NewBuilder(goerr.V("service", "auth"))
userBuilder := baseBuilder.With(goerr.V("user_id", "user123"))
err := userBuilder.New("access denied") // includes both service and user_id
type Error ¶
type Error struct {
// contains filtered or unexported fields
}
Error is error interface for deepalert to handle related variables
func Unwrap ¶
Unwrap returns unwrapped goerr.Error from err by errors.As. If no goerr.Error, returns nil NOTE: Do not receive error interface. It causes typed-nil problem.
var err error = goerr.New("error")
if err != nil { // always true
func With ¶
With adds contextual information to an error without modifying the original. It is useful when you want to enrich an error with more context in a middleware or a higher-level function without altering the original error value.
If err is a *goerr.Error, it creates a new *Error that preserves the original stacktrace and adds the new options. If err is a standard error, it wraps the error in a new *goerr.Error with a new stacktrace and adds the options.
Usage:
originalErr := goerr.New("validation failed")
enrichedErr := goerr.With(originalErr, goerr.V("user_id", "user123"))
// originalErr is unchanged, enrichedErr has additional context
Example ¶
ExampleWith demonstrates how to add context to errors without modifying the original error. goerr.With(err, options...) adds context without modifying the original error
package main
import (
"fmt"
"github.com/gaebalai/goerr/v2"
)
func main() {
// Create an original error
originalErr := goerr.New("database connection failed")
// Add context without modifying the original error
// Original error remains unchanged, new error with additional context is returned
enrichedErr := goerr.With(originalErr,
goerr.V("user_id", "user123"),
goerr.V("component", "auth-service"),
)
fmt.Println("Original:", originalErr.Error())
fmt.Println("Enriched:", enrichedErr.Error())
// Verify original error has no additional context
originalValues := goerr.Values(originalErr)
fmt.Printf("Original has %d values\n", len(originalValues))
// Verify enriched error has the context
enrichedValues := goerr.Values(enrichedErr)
fmt.Printf("Enriched has %d values\n", len(enrichedValues))
fmt.Printf("User ID: %s\n", enrichedValues["user_id"])
}
Output: Original: database connection failed Enriched: database connection failed Original has 0 values Enriched has 2 values User ID: user123
func Wrap ¶
Wrap creates a new Error and add message.
Usage:
baseErr := fmt.Errorf("connection failed")
err := goerr.Wrap(baseErr, "database operation failed",
goerr.V("host", "localhost"), goerr.V("port", 5432))
// Result: "database operation failed: connection failed" with context
Example ¶
ExampleWrap demonstrates wrapping errors with additional context. goerr.Wrap(cause, message, options...) wraps an existing error and adds additional information
package main
import (
"errors"
"fmt"
"github.com/gaebalai/goerr/v2"
)
func main() {
// Create a base error
baseErr := fmt.Errorf("connection timeout")
// Wrap the error with additional context
wrappedErr := goerr.Wrap(baseErr, "failed to connect to database",
goerr.V("host", "localhost"),
goerr.V("port", 5432),
goerr.V("timeout", "30s"),
)
fmt.Println("Error:", wrappedErr.Error())
// Access the wrapped values
values := goerr.Values(wrappedErr)
fmt.Printf("Host: %s\n", values["host"])
fmt.Printf("Port: %v\n", values["port"])
// Check if the original error is preserved
if errors.Is(wrappedErr, baseErr) {
fmt.Println("Original error is preserved")
}
}
Output: Error: failed to connect to database: connection timeout Host: localhost Port: 5432 Original error is preserved
func (*Error) Format ¶
Format returns: - %v, %s, %q: formatted message - %+v: formatted message with stack trace
func (*Error) Is ¶
Is returns true if the target error matches this error. It's for errors.Is. If both errors have IDs set via goerr.ID() option (non-empty), they are compared by ID. Otherwise, pointer equality is used for comparison. Empty ID values (default) are not used for comparison.
func (*Error) LogValue ¶
LogValue returns slog.Value for structured logging. It's implementation of slog.LogValuer. https://pkg.go.dev/log/slog#LogValuer
Usage:
err := goerr.New("operation failed", goerr.V("user_id", "user123"))
logger.Error("request failed", slog.Any("error", err))
// Automatically outputs structured log with error details, stack trace, and values
Example ¶
ExampleError_LogValue demonstrates structured logging with slog.LogValuer interface. goerr.Error automatically implements slog.LogValuer for structured logging with slog.Any("error", err)
package main
import (
"fmt"
"github.com/gaebalai/goerr/v2"
)
func main() {
// Create an error with context
err := goerr.New("operation failed",
goerr.V("user_id", "user123"),
goerr.V("operation", "delete_account"),
)
// The error implements slog.LogValuer interface automatically
// When err is passed to a slog logger (e.g. via slog.Any("error", err)), its LogValue() method is called automatically.
// We can inspect the returned slog.Value for demonstration.
logValue := err.LogValue()
// Extract some information from the log value for demonstration
attrs := logValue.Group()
var message, operation string
for _, attr := range attrs {
switch attr.Key {
case "message":
message = attr.Value.String()
case "values":
valueGroup := attr.Value.Group()
for _, valueAttr := range valueGroup {
if valueAttr.Key == "operation" {
operation = valueAttr.Value.String()
}
}
}
}
fmt.Printf("Message: %s\n", message)
fmt.Printf("Operation: %s\n", operation)
fmt.Println("Structured logging ready")
}
Output: Message: operation failed Operation: delete_account Structured logging ready
func (*Error) MarshalJSON ¶
MarshalJSON implements json.Marshaler interface for Error type. It provides comprehensive JSON serialization including message, ID, stack trace, values, tags, and cause information.
func (*Error) StackTrace ¶
func (x *Error) StackTrace() StackTrace
StackTrace returns stack trace that is compatible with pkg/errors
func (*Error) Tags ¶
Tags returns list of tags that is set by WithTags. All wrapped goerr.Error tags will be merged. Tags of wrapped error is overwritten by upper goerr.Error.
func (*Error) TypedValues ¶
TypedValues returns map of key and value that is set by TypedValue. All wrapped goerr.Error typed key and values will be merged. Key and values of wrapped error is overwritten by upper goerr.Error.
func (*Error) Unstack ¶
Unstack trims stack trace by 1. It can be used for internal helper or utility functions.
func (*Error) UnstackN ¶
UnstackN trims stack trace by n. It can be used for internal helper or utility functions.
func (*Error) Values ¶
Values returns map of key and value that is set by With. All wrapped goerr.Error key and values will be merged. Key and values of wrapped error is overwritten by upper goerr.Error.
type Errors ¶
type Errors struct {
// contains filtered or unexported fields
}
Errors represents multiple errors as a single error
func Append ¶
Append adds errors to existing Errors (inspired by go-multierror) If base is nil, creates a new Errors. Flattens nested Errors.
func AsErrors ¶
AsErrors extracts goerr.Errors from err by errors.As. If no goerr.Errors, returns nil Complementary to goerr.Unwrap() which only extracts goerr.Error
func (*Errors) ErrorOrNil ¶
ErrorOrNil returns the error if non-empty, nil otherwise (inspired by go-multierror) Nil-safe: (*goerr.Errors)(nil).ErrorOrNil() returns nil
func (*Errors) Errors ¶
Errors returns the slice of wrapped errors (inspired by go-multierror.WrappedErrors)
func (*Errors) MarshalJSON ¶
MarshalJSON implements json.Marshaler interface for Errors type
type ErrorsJSON ¶
type ErrorsJSON struct {
Errors []any `json:"errors"`
}
ErrorsJSON represents JSON structure for Errors
type Option ¶
type Option func(*Error)
func ID ¶
ID sets an error ID for Is() comparison. When an ID is set, errors.Is() will compare errors by their ID string instead of by pointer equality. This allows for creating sentinel-like errors that can be matched even if they are wrapped. An empty string ("") is treated as an invalid ID and will not be used for comparison.
Example ¶
package main
import (
"errors"
"fmt"
"github.com/gaebalai/goerr/v2"
)
func main() {
var ErrPermission = goerr.New("permission denied", goerr.ID("permission"))
err := goerr.Wrap(ErrPermission, "failed to open file")
if errors.Is(err, ErrPermission) {
fmt.Println("Error is a permission error")
}
}
Output: Error is a permission error
func TypedValue ¶
TypedValue sets typed key and value to the error
Usage:
key := goerr.NewTypedKey[string]("user_id")
err := goerr.New("error", goerr.TypedValue(key, "user123"))
// or using alias: goerr.TV(key, "user123")
Example ¶
ExampleTypedValue demonstrates type-safe error value handling. goerr.NewTypedKey[T](name) creates typed keys, goerr.TV(key, value) sets values, goerr.GetTypedValue(err, key) retrieves values
package main
import (
"fmt"
"github.com/gaebalai/goerr/v2"
)
func main() {
// Create typed keys for different types - keys provide compile-time type safety
userIDKey := goerr.NewTypedKey[string]("user_id")
retryCountKey := goerr.NewTypedKey[int]("retry_count")
enabledKey := goerr.NewTypedKey[bool]("enabled")
// Create error with typed values - compiler ensures type matching
err := goerr.New("operation failed",
goerr.TV(userIDKey, "user123"), // string value
goerr.TV(retryCountKey, 3), // int value
goerr.TV(enabledKey, true), // bool value
)
// Retrieve values with type safety - no type assertions needed
if userID, ok := goerr.GetTypedValue(err, userIDKey); ok {
fmt.Printf("User ID: %s\n", userID) // userID is guaranteed to be string
}
if retryCount, ok := goerr.GetTypedValue(err, retryCountKey); ok {
fmt.Printf("Retry count: %d\n", retryCount) // retryCount is guaranteed to be int
}
if enabled, ok := goerr.GetTypedValue(err, enabledKey); ok {
fmt.Printf("Enabled: %t\n", enabled) // enabled is guaranteed to be bool
}
// TypedValues() returns all typed values as map[string]any
typedValues := goerr.TypedValues(err)
fmt.Printf("Total typed values: %d\n", len(typedValues))
}
Output: User ID: user123 Retry count: 3 Enabled: true Total typed values: 3
Example (ErrorChain) ¶
ExampleTypedValue_errorChain demonstrates typed value propagation through error chains.
package main
import (
"fmt"
"github.com/gaebalai/goerr/v2"
)
func main() {
// Create typed keys
userIDKey := goerr.NewTypedKey[string]("user_id")
requestIDKey := goerr.NewTypedKey[int64]("request_id")
// Base error with user ID
baseErr := goerr.New("validation failed",
goerr.TV(userIDKey, "user456"),
)
// Wrapped error adds request ID - values propagate through the chain
wrappedErr := goerr.Wrap(baseErr, "request processing failed",
goerr.TV(requestIDKey, int64(789)),
)
// Both values are accessible from the wrapped error
if userID, ok := goerr.GetTypedValue(wrappedErr, userIDKey); ok {
fmt.Printf("User ID: %s\n", userID)
}
if requestID, ok := goerr.GetTypedValue(wrappedErr, requestIDKey); ok {
fmt.Printf("Request ID: %d\n", requestID)
}
}
Output: User ID: user456 Request ID: 789
type StackTrace ¶
type StackTrace []frame
StackTrace is array of frame. It's exported for compatibility with github.com/pkg/errors
type TypedKey ¶
type TypedKey[T any] struct { // contains filtered or unexported fields }
TypedKey represents a type-safe key for error values
func NewTypedKey ¶
NewTypedKey creates a new type-safe key with the given name. This key can then be used with TV() and GetTypedValue() to attach and retrieve strongly-typed values from an error, providing compile-time safety.
Usage:
var UserIDKey = goerr.NewTypedKey[string]("user_id")
var CountKey = goerr.NewTypedKey[int]("count")
err := goerr.New("error", goerr.TV(UserIDKey, "user123"))
if userID, ok := goerr.GetTypedValue(err, UserIDKey); ok { ... }
Example ¶
package main
import (
"fmt"
"github.com/gaebalai/goerr/v2"
)
func main() {
// Define typed keys at the package level for reuse.
var UserIDKey = goerr.NewTypedKey[string]("user_id")
var RequestIDKey = goerr.NewTypedKey[int]("request_id")
// Attach typed values when creating an error.
err := goerr.New("request failed",
goerr.TV(UserIDKey, "blue"),
goerr.TV(RequestIDKey, 12345),
)
// Retrieve the typed value later.
if userID, ok := goerr.GetTypedValue(err, UserIDKey); ok {
// The retrieved value has the correct type (string), no assertion needed.
fmt.Printf("User ID: %s\n", userID)
}
if reqID, ok := goerr.GetTypedValue(err, RequestIDKey); ok {
fmt.Printf("Request ID: %d\n", reqID)
}
}
Output: User ID: blue Request ID: 12345
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
basic
command
|
|
|
builder
command
|
|
|
errors_is
command
|
|
|
logging
command
|
|
|
stacktrace_extract
command
|
|
|
stacktrace_print
command
|
|
|
tag
command
|
|
|
typed_values
command
|
|
|
variables
command
|
|
|
with
command
|