stoneerror/error.go
Rene Nochebuena b42137701b
Some checks failed
Go CI/CD / go-ci (push) Failing after 5m34s
Go CI/CD / go-ci (pull_request) Failing after 5m29s
Refactor and document StoneError with enhanced features
Updated module path and significantly extended the StoneError implementation with new functionality, including metadata handling, error wrapping, JSON serialization, and utilities like `IsStoneError`. Enhanced README with detailed examples, usage guidelines, and a thematic introduction.
2025-04-12 17:24:44 -06:00

104 lines
2.8 KiB
Go

package stoneerror
import (
"encoding/json"
"errors"
"fmt"
"regexp"
"time"
)
// StoneError represents a structured error type with metadata and nested errors.
// Code indicates the error code for categorization.
// Message describes the error in a human-readable format.
// Time specifies when the error occurred.
// Metadata provides additional contextual data for the error.
// Err holds an underlying error causing the StoneError.
type StoneError struct {
Code int `json:"code"`
Message string `json:"message"`
Time time.Time `json:"time"`
Metadata map[string]interface{} `json:"metadata"`
Err error `json:"-"`
}
// Error returns the formatted string representation of the StoneError.
func (e *StoneError) Error() string {
var errorStr string
errorStr = fmt.Sprintf("[%d] %s", e.Code, e.Message)
if len(e.Metadata) > 0 {
errorStr += "\n Metadata:"
for k, v := range e.Metadata {
errorStr += fmt.Sprintf("\n %s: %v", k, v)
}
}
if e.Err != nil {
errorStr += fmt.Sprintf("\n Caused by: %v", e.Err)
var nestedStoneErr *StoneError
if errors.As(e.Err, &nestedStoneErr) {
errorStr += "\n" + indentString(nestedStoneErr.Error(), " ")
}
}
return errorStr
}
// New creates a new instance of StoneError with the provided code and message.
// It initializes the time to the current UTC time and sets Metadata as an empty map.
func New(code int, message string) *StoneError {
return &StoneError{
Code: code,
Message: message,
Time: time.Now().UTC(),
Metadata: make(map[string]interface{}),
}
}
// Wrap creates a new StoneError with a code, message, and wrapped error.
func Wrap(err error, code int, message string) *StoneError {
return &StoneError{
Code: code,
Message: message,
Time: time.Now().UTC(),
Err: err,
Metadata: make(map[string]interface{}),
}
}
// Unwrap returns the underlying error wrapped by the StoneError instance.
func (e *StoneError) Unwrap() error {
return e.Err
}
// WithMetadata adds a key-value pair to the error's metadata and returns the error.
func (e *StoneError) WithMetadata(key string, value interface{}) *StoneError {
if e.Metadata == nil {
e.Metadata = make(map[string]interface{})
}
e.Metadata[key] = value
return e
}
// ToJSON serializes the StoneError object into a JSON RawMessage.
func (e *StoneError) ToJSON() json.RawMessage {
jsonData, _ := json.Marshal(e)
return jsonData
}
// IsStoneError checks if the given error is of type *StoneError.
func IsStoneError(err error) bool {
var stoneError *StoneError
as := errors.As(err, &stoneError)
return as
}
// indentString prepends each line of string s with the given indent string.
func indentString(s string, indent string) string {
return indent + regexp.MustCompile("\n").ReplaceAllString(s, "\n"+indent)
}