@@ -75,88 +75,128 @@ func NewNotFoundError() error {
7575and returns the string as a value that satisfies error. You can wrap an error using ` %w ` modifier.
7676
7777` errors.Errorf() ` also records the stack trace at the point it was called. If the wrapped error
78- contains a stack trace then a new one will not be added to a chain. Also, you can pass
79- options to set structured attributes or to skip a caller in a stack trace.
80- Options must be specified after formatting arguments.
78+ contains a stack trace then a new one will not be added to a chain.
79+
80+ You can pass options to set structured attributes or to skip a caller in a stack trace.
81+ Both helper functions like ` errors.String() ` and ` slog.Attr ` directly are supported.
82+ Options/attributes must be specified after formatting arguments.
8183
8284``` golang
8385row := repository.db .QueryRow (ctx, findSQL, id)
8486var product Product
8587err := row.Scan (&product.ID , &product.Name )
8688if err != nil {
87- // Use errors.Errorf to wrap the library error with the message context and
88- // error attributes to be used for structured logging.
89+ // Option 1: Use helper functions
8990 return nil , errors.Errorf (
9091 " % w: %v " , errSQLError, err.Error (),
9192 errors.String (" sql" , findSQL),
9293 errors.Int (" productID" , id),
9394 )
95+
96+ // Option 2: Use slog.Attr directly (more idiomatic)
97+ return nil , errors.Errorf (
98+ " % w: %v " , errSQLError, err.Error (),
99+ slog.String (" sql" , findSQL),
100+ slog.Int (" productID" , id),
101+ )
94102}
95103```
96104
97105### ` errors.Wrap() ` for wrapping errors with attributes and stack trace
98106
99107` errors.Wrap() ` returns an error annotating err with a stack trace at the point ` errors.Wrap() ` is called.
100108If the wrapped error contains a stack trace then a new one will not be added to a chain.
101- If err is nil, Wrap returns nil. Also, you can pass options to set structured attributes or to skip a caller
102- in a stack trace.
109+ If err is nil, Wrap returns nil.
110+
111+ You can pass options to set structured attributes or to skip a caller in a stack trace.
112+ Both helper functions like ` errors.String() ` and ` slog.Attr ` directly are supported.
103113
104114``` golang
105115data , err := service.Handle (ctx, userID, message)
106116if err != nil {
107- // Adds a stack trace to the line that was called (if there is no stack trace in the chain already)
108- // and adds attributes for structured logging.
117+ // Option 1: Use helper functions
109118 return nil , errors.Wrap (
110119 err,
111120 errors.Int (" userID" , userID),
112121 errors.String (" userMessage" , message),
113122 )
123+
124+ // Option 2: Use slog.Attr directly (recommended)
125+ return nil , errors.Wrap (
126+ err,
127+ slog.Int (" userID" , userID),
128+ slog.String (" userMessage" , message),
129+ )
130+
131+ // Option 3: Mix both styles
132+ return nil , errors.Wrap (
133+ err,
134+ errors.SkipCaller (), // Option for stack trace
135+ slog.String (" userMessage" , message), // slog.Attr for logging
136+ )
114137}
115138```
116139
117- ### Working with grouped attributes
140+ ### Working with slog attributes
118141
119- The package supports grouped attributes via ` slog.Group ` , allowing you to organize related attributes :
142+ The package has native slog integration - you can pass ` slog.Attr ` directly to ` Wrap() ` and ` Errorf() ` :
120143
121144``` golang
145+ // Use slog attributes directly (recommended)
122146err := errors.Wrap (
123147 dbErr,
124- errors.Group (" request" ,
125- slog.String (" method" , " POST" ),
126- slog.String (" path" , " /api/users" ),
127- slog.Int (" status" , 500 ),
128- ),
129- errors.Group (" database" ,
130- slog.String (" query" , " INSERT INTO users..." ),
131- slog.Duration (" duration" , 150 *time.Millisecond ),
132- ),
148+ slog.String (" table" , " users" ),
149+ slog.Int (" id" , 123 ),
150+ slog.Duration (" query_time" , 50 *time.Millisecond ),
133151)
134- ```
135152
136- You can use all slog attribute types directly:
153+ // Or use helper functions (equivalent)
154+ err := errors.Wrap (
155+ dbErr,
156+ errors.String (" table" , " users" ),
157+ errors.Int (" id" , 123 ),
158+ errors.Duration (" query_time" , 50 *time.Millisecond ),
159+ )
137160
138- ``` golang
161+ // All slog types are supported
139162err := errors.Wrap (
140163 err,
141- errors.Int64 (" timestamp" , time.Now ().Unix ()),
142- errors.Uint64 (" bytes_written" , uint64 (1024 *1024 *500 )),
143- errors.Float64 (" cpu_usage" , 0.85 ),
144- errors.Any (" metadata" , map [string ]interface {}{
164+ slog.Bool (" cached" , false ),
165+ slog.Int64 (" timestamp" , time.Now ().Unix ()),
166+ slog.Uint64 (" bytes_written" , uint64 (1024 *1024 *500 )),
167+ slog.Float64 (" cpu_usage" , 0.85 ),
168+ slog.Any (" metadata" , map [string ]interface {}{
145169 " version" : " v1.2.3" ,
146170 " region" : " us-west-1" ,
147171 }),
148172)
149173```
150174
151- Or pass ` slog.Attr ` directly for maximum flexibility:
175+ ### Working with grouped attributes
176+
177+ Organize related attributes using ` slog.Group ` directly:
152178
153179``` golang
154180err := errors.Wrap (
155- err,
156- errors.Attr (slog.Group (" metadata" ,
157- slog.String (" version" , " v1.2.3" ),
158- slog.Bool (" production" , true ),
159- )),
181+ dbErr,
182+ slog.Group (" request" ,
183+ slog.String (" method" , " POST" ),
184+ slog.String (" path" , " /api/users" ),
185+ slog.Int (" status" , 500 ),
186+ ),
187+ slog.Group (" database" ,
188+ slog.String (" query" , " INSERT INTO users..." ),
189+ slog.Duration (" duration" , 150 *time.Millisecond ),
190+ ),
191+ )
192+
193+ // Or use the errors.Group helper
194+ err := errors.Wrap (
195+ dbErr,
196+ errors.Group (" request" ,
197+ slog.String (" method" , " POST" ),
198+ slog.String (" path" , " /api/users" ),
199+ ),
160200)
161201```
162202
0 commit comments