Skip to content

Commit dc02879

Browse files
committed
Update documentation and readme
1 parent 1890639 commit dc02879

5 files changed

Lines changed: 62 additions & 63 deletions

File tree

README.md

Lines changed: 40 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,16 @@
22

33
[![Go Reference](https://pkg.go.dev/badge/github.com/mdobak/go-xerrors.svg)](https://pkg.go.dev/github.com/mdobak/go-xerrors) [![Go Report Card](https://goreportcard.com/badge/github.com/mdobak/go-xerrors)](https://goreportcard.com/report/github.com/mdobak/go-xerrors) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Coverage Status](https://coveralls.io/repos/github/MDobak/go-xerrors/badge.svg?branch=coverage)](https://coveralls.io/github/MDobak/go-xerrors?branch=coverage)
44

5-
`go-xerrors` is a simple, idiomatic, lightweight Go package that provides utilities for error handling. It offers functions and types to support stack traces, multi-errors, and simplified panic handling. The package is compatible with Go's standard error handling mechanisms, such as `errors.As`, `errors.Is`, and `errors.Unwrap`, including features from Go 1.13 and 1.20.
5+
`go-xerrors` is a small, idiomatic library that makes error handling in Go easier. It provides utilities for creating errors with stack traces, wrapping existing errors, aggregating multiple errors, and recovering from panics.
66

7-
**Main Features:**
7+
**Main features**
88

9-
- **Stack Traces**: Captures stack traces when creating errors to help locate the origin of issues during debugging
10-
- **Multi-Errors**: Aggregates multiple errors into a single error instance while maintaining individual error context
11-
- **Error Wrapping**: Wraps errors with additional context while preserving compatibility with `errors.Is`, `errors.As`, and `errors.Unwrap`
12-
- **Panic Handling**: Converts panic values to standard Go errors with stack traces for structured error recovery
13-
- **Zero Dependencies**: Implements error handling utilities with no external dependencies beyond the Go standard library
9+
- **Stack traces**: Capture stack traces when creating errors to pinpoint the source during debugging.
10+
- **Multi-errors**: Aggregate multiple errors into a single error while preserving individual context.
11+
- **Panic handling**: Convert panic values to standard Go errors with stack traces.
12+
- **Zero dependencies**: No external dependencies beyond the Go standard library.
1413

15-
> **Note:** This package is considered stable and will therefore be rarely updated, mostly for bug fixes and adding support for new Go versions and features. With the release of version 1.0, the API is frozen, and no breaking changes will be introduced in future releases.
14+
> Note: This package is stable. Updates are rare and limited to bug fixes and support for new Go versions or error-related features. Since 1.0, the API has been frozen. No breaking changes will be introduced in future releases.
1615
1716
---
1817

@@ -26,7 +25,7 @@ go get -u github.com/mdobak/go-xerrors
2625

2726
### Example
2827

29-
The following example demonstrates the basic usage of `go-xerrors` for creating and handling errors.
28+
Here’s a quick example of creating and handling errors with `go-xerrors`.
3029

3130
```go
3231
package main
@@ -50,12 +49,12 @@ func findUserByID(id int) error {
5049
func main() {
5150
err := findUserByID(123)
5251
if err != nil {
53-
// 1. The standard Error() method provides a concise, log-friendly message.
54-
fmt.Println("Concise log message:", err.Error())
55-
// Output: user 123 not found: sql: no rows in result set
52+
// 1) err.Error() returns a concise, log-friendly message.
53+
fmt.Println(err.Error())
54+
// Output:
55+
// user 123 not found: sql: no rows in result set
5656

57-
// 2. xerrors.Print provides a rich, multi-line report for developers,
58-
// including the stack trace from where the error was wrapped.
57+
// 2) xerrors.Print shows a detailed message with a stack trace.
5958
xerrors.Print(err)
6059
// Output:
6160
// Error: user 123 not found: sql: no rows in result set
@@ -72,18 +71,18 @@ func main() {
7271
The primary way to create an error in `go-xerrors` is by using the `xerrors.New` or `xerrors.Newf` functions:
7372

7473
```go
75-
// Create a new error with a stack trace
74+
// Create a new error with a stack trace.
7675
err := xerrors.New("something went wrong")
7776

78-
// Create a formatted error with a stack trace
77+
// Create a formatted error with a stack trace.
7978
err := xerrors.Newf("something went wrong: %s", reason)
8079
```
8180

82-
Calling the standard `Error()` method on `err` returns only the message ("something went wrong"), adhering to the Go convention of providing a concise error description.
81+
Calling `err.Error()` returns only the message ("something went wrong"), following the Go convention of keeping error strings concise.
8382

8483
### Displaying Detailed Errors
8584

86-
To display the error with the associated stack trace and additional details, use the `xerrors.Print`, `xerrors.Sprint`, or `xerrors.Fprint` functions:
85+
To print the error with its stack trace and details, use `xerrors.Print`, `xerrors.Sprint`, or `xerrors.Fprint`:
8786

8887
```go
8988
xerrors.Print(err)
@@ -115,16 +114,17 @@ at testing.tRunner (/home/user/go/src/testing/testing.go:1259)
115114
at runtime.goexit (/home/user/go/src/runtime/asm_arm64.s:1133)
116115
```
117116

118-
You can also explicitly add a stack trace to an existing error:
117+
You can also add a stack trace to an existing error with `xerrors.WithStackTrace`, and choose how many frames to skip. This is handy when a helper creates errors but you don’t want its own frame captured:
119118

120119
```go
121-
err := someFunction()
122-
errWithStack := xerrors.WithStackTrace(err, 0) // 0 skips no frames
120+
func errNotFound(path string) error {
121+
return xerrors.WithStackTrace(ErrNotFound{path: path}, 1) // skip one frame
122+
}
123123
```
124124

125125
### Wrapping Errors
126126

127-
The `xerrors.New` and `xerrors.Newf` functions can also wrap existing errors:
127+
You can also wrap existing errors:
128128

129129
```go
130130
output, err := json.Marshal(data)
@@ -142,11 +142,11 @@ if err != nil {
142142
}
143143
```
144144

145-
Note that wrapping multiple errors with `xerrors.Newf` is possible only in Go 1.20 and later.
145+
> Wrapping multiple errors with `xerrors.Newf` is possible only in Go 1.20 and later.
146146
147147
### Creating Error Chains Without Stack Traces
148148

149-
For situations where you don't need a stack trace (such as creating sentinel errors), use `xerrors.Join` and `xerrors.Joinf`:
149+
When you dont need a stack trace (for example, when creating sentinel errors), use `xerrors.Join` and `xerrors.Joinf`:
150150

151151
```go
152152
err := xerrors.Join("operation failed", otherErr)
@@ -158,7 +158,7 @@ With formatted messages:
158158
err := xerrors.Joinf("operation failed: %w", otherErr)
159159
```
160160

161-
Note that wrapping multiple errors with `xerrors.Joinf` is possible only in Go 1.20 and later.
161+
> Wrapping multiple errors with `xerrors.Joinf` is possible only in Go 1.20 and later.
162162
163163
The main difference between Go's `fmt.Errorf` and `xerrors.Newf`/`xerrors.Joinf` is that the latter functions preserve the error chain, whereas `fmt.Errorf` flattens it (i.e., its `Unwrap` method returns all underlying errors at once instead of just the next one in the chain).
164164

@@ -206,18 +206,24 @@ if len(input.Password) < 8 {
206206
}
207207

208208
if err != nil {
209-
fmt.Println(err.Error()) // [username cannot be empty, password must be at least 8 characters]
209+
fmt.Println(err.Error())
210+
// Output:
211+
// [username cannot be empty, password must be at least 8 characters]
210212

211213
// Detailed output using xerrors.Print:
212214
xerrors.Print(err)
213215
// Output:
214216
// Error: [username cannot be empty, password must be at least 8 characters]
215217
// 1. Error: username cannot be empty
216-
// at main.validateInput (/path/to/your/file.go:XX)
217-
// ... stack trace ...
218+
// at main.validateInput (/home/user/app/main.go:40)
219+
// at main.main (/home/user/app/main.go:20)
220+
// at runtime.main (/usr/local/go/src/runtime/proc.go:250)
221+
// at runtime.goexit (/usr/local/go/src/runtime/asm_amd64.s:1594)
218222
// 2. Error: password must be at least 8 characters
219-
// at main.validateInput (/path/to/your/file.go:YY)
220-
// ... stack trace ...
223+
// at main.validateInput (/home/user/app/main.go:43)
224+
// at main.main (/home/user/app/main.go:20)
225+
// at runtime.main (/usr/local/go/src/runtime/proc.go:250)
226+
// at runtime.goexit (/usr/local/go/src/runtime/asm_amd64.s:1594)
221227
}
222228
```
223229

@@ -271,7 +277,7 @@ The returned error implements the `PanicError` interface, which provides access
271277
While these functions can all be used to aggregate errors, they each serve distinct purposes:
272278

273279
- **`xerrors.New`**: Use this to create errors and attach stack traces, especially when wrapping existing errors to provide additional context.
274-
- **`xerrors.Join`**: Use this to chain errors together _without_ capturing stack traces. This is most appropriate for creating sentinel errors.
280+
- **`xerrors.Join`**: Use this to chain errors together _without_ capturing stack traces.
275281
- **`xerrors.Append`**: Use this to aggregate multiple, independent errors into a single multi-error. This is useful when several operations might fail, and you want to report all failures at once.
276282

277283
#### Examples
@@ -356,8 +362,8 @@ func (m *MyStruct) Validate() error {
356362

357363
- `xerrors.StackTrace(err error) Callers`: Extracts the stack trace from an error
358364
- `xerrors.WithStackTrace(err error, skip int) error`: Wraps an error with a stack trace
359-
- `DefaultCallersFormatter`: The default formatter for [Callers], used when printing stack traces.
360-
- `DefaultFrameFormatter`: The default formatter for [Frame], used when printing stack traces.
365+
- `DefaultCallersFormatter`: The default formatter for Callers, used when printing stack traces.
366+
- `DefaultFrameFormatter`: The default formatter for Frame, used when printing stack traces.
361367

362368
### Error printing
363369

@@ -372,7 +378,7 @@ func (m *MyStruct) Validate() error {
372378

373379
## Documentation
374380

375-
For comprehensive details on all functions and types, please refer to the full documentation available at:
381+
For full API details, see the documentation:
376382

377383
[https://pkg.go.dev/github.com/mdobak/go-xerrors](https://pkg.go.dev/github.com/mdobak/go-xerrors)
378384

doc.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
// Package go-xerrors is a simple, idiomatic, lightweight Go package that
2-
// provides utilities for error handling. It offers functions and types to
3-
// support stack traces, multi-errors, and simplified panic handling. The
4-
// package is compatible with Go's standard error handling mechanisms, such
5-
// as errors.As, errors.Is, and errors.Unwrap, including features from Go
6-
// 1.13 and 1.20.
1+
// Package xerrors is a small, idiomatic library that makes error handling in
2+
// Go easier. It provides utilities for creating errors with stack traces,
3+
// wrapping existing errors, aggregating multiple errors, and recovering
4+
// from panics.
75
package xerrors

format.go

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,10 @@ var errWriter io.Writer = os.Stderr
1212

1313
// Print writes a formatted error to stderr.
1414
//
15-
// If the error implements the [DetailedError] interface and returns
16-
// a non-empty string, the returned details are added to each error
17-
// in the chain.
15+
// If any error in the chain implements [DetailedError] and returns a non-empty
16+
// string, its details are appended to the error message.
1817
//
19-
// The formatted error can span multiple lines and always ends with
20-
// a newline.
18+
// The output may span multiple lines and always ends with a newline.
2119
func Print(err error) {
2220
buf := &strings.Builder{}
2321
writeErr(buf, err)
@@ -26,12 +24,10 @@ func Print(err error) {
2624

2725
// Sprint returns a formatted error as a string.
2826
//
29-
// If the error implements the [DetailedError] interface and returns
30-
// a non-empty string, the returned details are added to each error
31-
// in the chain.
27+
// If any error in the chain implements [DetailedError] and returns a non-empty
28+
// string, its details are appended to the error message.
3229
//
33-
// The formatted error can span multiple lines and always ends with
34-
// a newline.
30+
// The output may span multiple lines and always ends with a newline.
3531
func Sprint(err error) string {
3632
buf := &strings.Builder{}
3733
writeErr(buf, err)
@@ -40,12 +36,10 @@ func Sprint(err error) string {
4036

4137
// Fprint writes a formatted error to the provided [io.Writer].
4238
//
43-
// If the error implements the [DetailedError] interface and returns
44-
// a non-empty string, the returned details are added to each error
45-
// in the chain.
39+
// If any error in the chain implements [DetailedError] and returns a non-empty
40+
// string, its details are appended to the error message.
4641
//
47-
// The formatted error can span multiple lines and always ends with
48-
// a newline.
42+
// The output may span multiple lines and always ends with a newline.
4943
func Fprint(w io.Writer, err error) (int, error) {
5044
buf := &strings.Builder{}
5145
writeErr(buf, err)
@@ -78,7 +72,7 @@ func writeErr(buf *strings.Builder, err error) {
7872
} else {
7973
// If an error does not contain any details, do not print
8074
// it, except for the first one. This is to avoid printing
81-
// every wrapped error on a single line.
75+
// every wrapped error in the chain.
8276
if first {
8377
buf.WriteString(firstErrorPrefix)
8478
buf.WriteString(errMsg)

panic.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
// PanicError represents an error that occurs during a panic. It is
88
// returned by the [Recover] and [FromRecover] functions. It provides
99
// access to the original panic value via the [Panic] method.
10+
//
11+
// Use the standard [errors.As] function to convert an error to this interface.
1012
type PanicError interface {
1113
error
1214

@@ -16,11 +18,10 @@ type PanicError interface {
1618

1719
// Recover wraps the built-in `recover()` function, converting the
1820
// recovered value into an error with a stack trace. The provided `fn`
19-
// callback is only invoked when a panic occurs. The error passed to
20-
// `fn` implements [PanicError].
21+
// callback is only invoked when a panic occurs.
2122
//
2223
// This function must always be used directly with the `defer`
23-
// keyword; otherwise, it will not function correctly.
24+
// keyword.
2425
func Recover(fn func(err error)) {
2526
if r := recover(); r != nil {
2627
fn(&withStackTrace{

wrapper.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ import (
55
"strings"
66
)
77

8-
// withWrapper wraps an error with another error.
8+
// withWrapper wraps one error with another.
99
//
10-
// It is intended to be build error chains, e.g. if we have a
11-
// following error chain: `err1: err2: err3`, the wrapper is `err1`,
12-
// and the err is another withWrapper containing `err2` and `err3`.
10+
// It is intended to build error chains. For example, given an error chain
11+
// like `err1: err2: err3`, the wrapper is `err1`, and the err is another
12+
// withWrapper containing `err2` and `err3`.
1313
type withWrapper struct {
1414
wrapper error // wrapper is the error that wraps the next error in the chain, may be nil
1515
err error // err is the next error in the chain, must not be nil

0 commit comments

Comments
 (0)