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>
This commit is contained in:
Rene Nochebuena 2025-04-12 18:39:22 -06:00 committed by Gitstormr: Unleash the code storm
parent e65fc49b8e
commit df0f48d7cb
Signed by: Gitstormr: Unleash the code storm
GPG Key ID: A42842566C073B0A
4 changed files with 291 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 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"`
@ -11,3 +21,83 @@ 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)
}

79
error_test.go Normal file
View File

@ -0,0 +1,79 @@
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()
}
}

2
go.mod
View File

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