Skip to content

Commit 4401525

Browse files
Merge pull request #7 from scality/enhance-go-errors
fix: enhance Wrap and Wrapf + correct README
2 parents edfaa72 + 5888155 commit 4401525

3 files changed

Lines changed: 43 additions & 38 deletions

File tree

README.md

Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ import (
2828
)
2929

3030
func main() {
31-
err := errors.New("database error").
31+
var ErrDB = errors.New("database error")
32+
err := errors.From(ErrDB).
3233
WithIdentifier(1001).
3334
WithDetail("connection timeout").
3435
WithProperty("host", "localhost").
@@ -40,45 +41,40 @@ func main() {
4041

4142
## Usage Examples
4243

43-
### Creating Basic Errors
44-
45-
```go
46-
// Simple error
47-
err := errors.New("validation failed").Throw()
48-
49-
// Error with identifier
50-
err := errors.New("not found").
51-
WithIdentifier(404).
52-
Throw()
53-
```
54-
5544
### Adding Details and Properties
5645

5746
```go
47+
// Initializing Domain errors
48+
var (
49+
ErrValidationFailed = errors.New("validation failed")
50+
ErrRequestFailed = errors.New("request failed")
51+
ErrDatabaseError = errors.New("database error")
52+
)
53+
5854
// Multiple details
5955
// Each WithDetail() call appends to the Details slice
60-
err := errors.New("validation failed").
56+
err1 := errors.From(ErrValidationFailed).
6157
WithDetail("email is required").
6258
WithDetail("password must be at least 8 characters").
6359
Throw()
6460

6561
// Details can also be formatted
66-
err := errors.New("request failed").
62+
err2 := errors.From(ErrRequestFailed).
6763
WithDetailf("failed to connect to %s:%d", "api.example.com", 443).
6864
WithDetail("timeout after 30 seconds").
6965
Throw()
7066

7167
// Single property
72-
err := errors.New("request failed").
68+
err3 := errors.From(ErrRequestFailed).
7369
WithProperty("url", "https://api.example.com").
7470
WithProperty("status_code", 500).
7571
Throw()
7672

7773
// Multiple properties at once
78-
err := errors.New("database error").
74+
err4 := errors.From(ErrDatabaseError).
7975
WithProperties(map[string]any{
80-
"host": "localhost",
81-
"port": 5432,
76+
"host": "localhost",
77+
"port": 5432,
8278
"database": "myapp",
8379
}).
8480
Throw()
@@ -87,11 +83,13 @@ err := errors.New("database error").
8783
### Error Wrapping
8884

8985
```go
90-
func getUserByID(id int) (*User, error) {
86+
var ErrUserNotFound = errors.New("user not found")
87+
88+
func getUserByID(id string) (*User, error) {
9189
user, err := db.Query(id)
9290
if err != nil {
93-
return nil, errors.New("user not found").
94-
WithIdentifier(404).
91+
return nil, errors.From(ErrUserNotFound).
92+
WithIdentifier(404000).
9593
CausedBy(err).
9694
Throw()
9795
}
@@ -120,16 +118,18 @@ func getUser(id int) (*User, error) {
120118
### Stack Traces
121119

122120
```go
121+
var ErrSomethingWentWrong = errors.New("something went wrong")
122+
123123
func layer3() error {
124-
return errors.New("something went wrong").Throw()
124+
return errors.From(ErrSomethingWentWrong).Throw()
125125
}
126126

127127
func layer2() error {
128-
err := layer3()
129-
if err != nil {
130-
return errors.Stamp(err) // Adds layer2's location to stack
131-
}
132-
return nil
128+
err := layer3()
129+
if err != nil {
130+
return errors.Stamp(err) // Adds layer2's location to stack
131+
}
132+
return nil
133133
}
134134

135135
func layer1() error {
@@ -147,7 +147,7 @@ func layer1() error {
147147

148148
```go
149149
// Using errors.Is for comparison
150-
notFoundErr := errors.New("not found").WithIdentifier(404)
150+
notFoundErr := errors.New("not found")
151151

152152
if errors.Is(err, notFoundErr) {
153153
// Handle not found error
@@ -165,9 +165,6 @@ if errors.As(err, &e) {
165165
fmt.Printf(" Detail %d: %s\n", i, detail)
166166
}
167167
}
168-
169-
// Unwrapping errors
170-
cause := errors.Unwrap(err)
171168
```
172169

173170
### Converting Standard Errors
@@ -179,7 +176,7 @@ err := errors.From(stdErr).
179176
WithDetail("additional context").
180177
Throw()
181178

182-
// Using Intercept() when you're unsure of the error type
179+
// Using Intercept() to complete the error
183180
func handleError(err error) error {
184181
e := errors.Intercept(err)
185182
e.WithProperty("handled_at", time.Now())

errors.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,14 @@ func New(title string) error {
6262

6363
// Wrap wraps an error with a message.
6464
func Wrap(err error, msg string) error {
65-
return From(err).WithDetail(msg).Throw()
65+
trace := trace()
66+
return from(err, true).WithDetail(msg).throw(trace)
6667
}
6768

6869
// Wrapf wraps an error with a formatted message.
6970
func Wrapf(err error, format string, args ...any) error {
70-
return From(err).WithDetailf(format, args...).Throw()
71+
trace := trace()
72+
return from(err, true).WithDetailf(format, args...).throw(trace)
7173
}
7274

7375
// From creates a new *Error from any error type.
@@ -76,6 +78,10 @@ func Wrapf(err error, format string, args ...any) error {
7678
// If the error is an *Error, it returns a copy of the original error with the same
7779
// title, identifier, details, properties.
7880
func From(err error) *Error {
81+
return from(err, false)
82+
}
83+
84+
func from(err error, copyStack bool) *Error {
7985
var t *Error
8086

8187
ok := errors.As(err, &t)
@@ -89,6 +95,9 @@ func From(err error) *Error {
8995
Details: t.Details,
9096
Properties: t.Properties,
9197
}
98+
if copyStack {
99+
e.Stack = t.Stack
100+
}
92101

93102
if !ok {
94103
e.Cause = err

errors_test.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ var _ = Describe("Errors", func() {
365365
e := Intercept(err2)
366366
// From() only preserves title, so only the latest detail is kept
367367
Expect(e.Details).To(Equal([]string{"database query failed", "user service error"}))
368-
Expect(e.Stack).To(HaveLen(1))
368+
Expect(e.Stack).To(HaveLen(2))
369369
// From() on *Error doesn't set cause
370370
Expect(e.Cause).To(BeNil())
371371
})
@@ -424,8 +424,7 @@ var _ = Describe("Errors", func() {
424424
err2 := Wrap(err1, "duplicate entry detected")
425425
e := Intercept(err2)
426426
Expect(e.Details).To(Equal([]string{"database error: code 1062", "duplicate entry detected"}))
427-
Expect(e.Stack).To(HaveLen(1))
428-
// From() on *Error doesn't set cause
427+
Expect(e.Stack).To(HaveLen(2))
429428
Expect(e.Cause).To(BeNil())
430429
})
431430

0 commit comments

Comments
 (0)