Refactor and document StoneError with enhanced features
Some checks failed
Go CI/CD / go-ci (push) Failing after 5m34s
Go CI/CD / go-ci (pull_request) Failing after 5m29s

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.
This commit is contained in:
Rene Nochebuena 2025-04-12 17:24:44 -06:00
parent e65fc49b8e
commit b42137701b
Signed by: Rene Nochebuena
GPG Key ID: A9FD83117EA538D8
3 changed files with 212 additions and 3 deletions

123
README.md
View File

@ -1,3 +1,122 @@
# stoneerror
# πŸ”₯ StoneError - 10 Billion Times Error Handling!
Ultimate Go error toolkit! πŸ’Ž Standardized errors with custom codes, rich metadata & JSON superpowers. Perfect for APIs & microservices. Part of stone-utils ecosystem. Error handling, evolved! πŸš€
The most scientifically precise error library from the Kingdom of Science!
[![Kingdom of Science Approved](https://img.shields.io/badge/Approved%20By-Kingdom%20of%20Science-blueviolet)]()
[![SO BADASS](https://img.shields.io/badge/Science-SO_BADASS!-blueviolet)]()
[![10 BILLION](https://img.shields.io/badge/10_Billion%25-Reliable-blueviolet)]()
## πŸš€ Why StoneError?
- Dr.Stone-themed error handling that would make Senku proud
- Dramatic error traces worthy of a laboratory explosion
- Scientific metadata attached to every error case
- 10 billion percent more organized than standard errors
## πŸ’₯ Installation
```bash
go get gitstormr.dev/stone-utils/stoneerror@latest
```
## ⚑ Basic Usage
```go
package main
import (
"errors"
"fmt"
"gitstormr.dev/stone-utils/stoneerror"
)
func main() {
// Create new scientific error
err := stoneerror.New(4001, "Invalid chemical formula").
WithMetadata("element", "H2O2").
WithMetadata("expected", "H2O")
// Wrap existing errors with scientific precision
dbErr := errors.New("connection timeout")
wrappedErr := stoneerror.Wrap(dbErr, 5001, "Database experiment failed").
WithMetadata("query", "SELECT * FROM chemical_elements")
}
```
## πŸ”¬ Error Output Format
```text
StoneError [4001]
β”œβ”€ Message: Invalid chemical formula
β”œβ”€ Time: 2023-07-15T14:30:45Z
β”œβ”€ Metadata:
β”‚ β”œβ”€ element: H2O2
β”‚ β”œβ”€ expected: H2O
└─ Caused by:
StoneError [5001]
β”œβ”€ Message: Database experiment failed
β”œβ”€ Time: 2023-07-15T14:30:45Z
β”œβ”€ Metadata:
β”‚ β”œβ”€ query: SELECT * FROM chemical_elements
└─ Caused by:
connection timeout
```
## πŸ§ͺ Core Features
### Scientific Error Codes
```go
const (
LAB_FAILURE = 5000 // Critical experiment failure
BAD_CHEMISTRY = 4001 // Invalid formula or mixture
EQUIPMENT_FAIL = 5002 // Tools malfunction
)
```
### Advanced Error Wrapping
```go
// Wrap any error with scientific context
result := performExperiment()
if err != nil {
return stoneerror.Wrap(err, LAB_FAILURE, "Voltaic pile test failed")
.WithMetadata("voltage", "3.7V")
.WithMetadata("materials", []string{"zinc", "copper"})
}
```
### JSON Output
```go
jsonError := err.ToJSON()
// {
// "code": 4001,
// "message": "Invalid chemical formula",
// "time": "2023-07-15T14:30:45Z",
// "metadata": {
// "element": "H2O2",
// "expected": "H2O"
// }
// }
```
```go
stonelog.InitStoneLab(stonelog.STONE_DEBUG, true, false) // true = JSON, false = Keep suffixes
// Output: {"time":"2023-07-15T12:00:00Z","level":"OBSERVATION","message":"βœ… Experiment successful: System ready","caller":"main.go:15"}
```
## βš—οΈ Scientific Best Practices
1. Always use specific error codes - Each experiment needs proper labeling!
2. Attach relevant metadata - A good scientist documents everything
3. Wrap underlying errors - Trace the full chain of causality
4. Combine related failures - Multiple data points lead to better conclusions
**Join the Scientific Revolution!**
> "With StoneError, we're 10 billion percent prepared for any failure!" - Senku Ishigami
Kingdom of Science Approved
(Now with 100% more Chrome screaming "SO BADASS!")

View File

@ -1,9 +1,19 @@
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"`
@ -11,3 +21,83 @@ type StoneError struct {
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)
}

2
go.mod
View File

@ -1,3 +1,3 @@
module stoneerror
module gitstormr.dev/stone-utils/stoneerror
go 1.24