stoneerror/error.go
Rene Nochebuena 7f3dcfa1cd
All checks were successful
Go CI/CD / go-ci (push) Successful in 10m5s
Release v1.0.0 (#2)
Reviewed-on: #2
Reviewed-by: Cloud Administrator <cloud-admin@noreply.gitstormr.dev>
Co-authored-by: Rene Nochebuena <code-raider@noreply.gitstormr.dev>
Co-committed-by: Rene Nochebuena <code-raider@noreply.gitstormr.dev>
2025-04-12 18:39:22 -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)
}