Compare commits
No commits in common. "627cfa36f5355e632919e5925de3998915f64570" and "e65fc49b8efb3cfc9502cce0541fe5e1c8fb1336" have entirely different histories.
627cfa36f5
...
e65fc49b8e
123
README.md
123
README.md
@ -1,122 +1,3 @@
|
|||||||
# π₯ StoneError - 10 Billion Times Error Handling!
|
# stoneerror
|
||||||
|
|
||||||
The most scientifically precise error library from the Kingdom of Science!
|
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! π
|
||||||
|
|
||||||
[]()
|
|
||||||
[]()
|
|
||||||
[]()
|
|
||||||
|
|
||||||
## π 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,19 +1,9 @@
|
|||||||
package stoneerror
|
package stoneerror
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"regexp"
|
|
||||||
"time"
|
"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 {
|
type StoneError struct {
|
||||||
Code int `json:"code"`
|
Code int `json:"code"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
@ -21,83 +11,3 @@ type StoneError struct {
|
|||||||
Metadata map[string]interface{} `json:"metadata"`
|
Metadata map[string]interface{} `json:"metadata"`
|
||||||
Err error `json:"-"`
|
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)
|
|
||||||
}
|
|
||||||
|
@ -1,79 +0,0 @@
|
|||||||
package stoneerror
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_StoneErrorWithoutMetadata(t *testing.T) {
|
|
||||||
stoneError := New(1, "test")
|
|
||||||
|
|
||||||
t.Log(stoneError)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_StoneErrorWithMetadata(t *testing.T) {
|
|
||||||
stoneError := New(1, "test").
|
|
||||||
WithMetadata("key", "value").
|
|
||||||
WithMetadata("key2", "value2")
|
|
||||||
|
|
||||||
t.Log(stoneError)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_NormalWrap(t *testing.T) {
|
|
||||||
normalError := errors.New("test")
|
|
||||||
stoneError := Wrap(normalError, 1, "test")
|
|
||||||
t.Log(stoneError)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_StoneWrap(t *testing.T) {
|
|
||||||
originalError := New(1, "test").
|
|
||||||
WithMetadata("key", "value").
|
|
||||||
WithMetadata("key2", "value2")
|
|
||||||
stoneError := Wrap(originalError, 1, "test")
|
|
||||||
t.Log(stoneError)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_NormalUnwrap(t *testing.T) {
|
|
||||||
normalError := errors.New("test")
|
|
||||||
stoneError := Wrap(normalError, 1, "test")
|
|
||||||
|
|
||||||
unwrap := stoneError.Unwrap()
|
|
||||||
|
|
||||||
if IsStoneError(unwrap) {
|
|
||||||
t.Fail()
|
|
||||||
} else {
|
|
||||||
t.Log(stoneError)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_StoneUnwrap(t *testing.T) {
|
|
||||||
normalError := New(1, "test")
|
|
||||||
stoneError := Wrap(normalError, 1, "test")
|
|
||||||
|
|
||||||
unwrap := stoneError.Unwrap()
|
|
||||||
|
|
||||||
if !IsStoneError(unwrap) {
|
|
||||||
t.Fail()
|
|
||||||
} else {
|
|
||||||
t.Log(stoneError)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_ToJSON(t *testing.T) {
|
|
||||||
stoneError := New(1, "test").
|
|
||||||
WithMetadata("key", "value").
|
|
||||||
WithMetadata("key2", "value2")
|
|
||||||
jsonData := stoneError.ToJSON()
|
|
||||||
t.Log(string(jsonData))
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_IsStoneError(t *testing.T) {
|
|
||||||
stoneError := New(1, "test").
|
|
||||||
WithMetadata("key", "value")
|
|
||||||
|
|
||||||
if IsStoneError(stoneError) {
|
|
||||||
t.Log("Is stone error")
|
|
||||||
} else {
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
}
|
|
Loadingβ¦
x
Reference in New Issue
Block a user