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.
This commit is contained in:
parent
e65fc49b8e
commit
b42137701b
123
README.md
123
README.md
@ -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!
|
||||
|
||||
[]()
|
||||
[]()
|
||||
[]()
|
||||
|
||||
## π 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!")
|
90
error.go
90
error.go
@ -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)
|
||||
}
|
||||
|
Loadingβ¦
x
Reference in New Issue
Block a user