Skip to content

Commit 22c1d57

Browse files
dannykoppingclaude
andcommitted
fix: render error types as strings in human log sink
`formatValue` checked `reflect.Struct` before checking the `error` interface, so struct-typed errors like `context.DeadlineExceeded` were serialized via `json.Marshal` as `{}` instead of their error string. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 348ac12 commit 22c1d57

File tree

6 files changed

+155
-30
lines changed

6 files changed

+155
-30
lines changed

go.mod

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
module cdr.dev/slog/v3
22

3-
go 1.20
3+
go 1.24.0
44

55
require (
66
cloud.google.com/go/compute/metadata v0.2.3
77
cloud.google.com/go/logging v1.8.1
88
github.com/charmbracelet/lipgloss v0.7.1
9-
github.com/google/go-cmp v0.5.9
9+
github.com/google/go-cmp v0.7.0
1010
github.com/muesli/termenv v0.15.2
11-
go.opentelemetry.io/otel/sdk v1.16.0
12-
go.opentelemetry.io/otel/trace v1.16.0
13-
go.uber.org/goleak v1.2.1
11+
go.opentelemetry.io/otel/sdk v1.40.0
12+
go.opentelemetry.io/otel/trace v1.40.0
13+
go.uber.org/goleak v1.3.0
1414
golang.org/x/term v0.11.0
1515
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2
1616
google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e
@@ -20,18 +20,21 @@ require (
2020
cloud.google.com/go/compute v1.23.0 // indirect
2121
cloud.google.com/go/longrunning v0.5.1 // indirect
2222
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
23-
github.com/go-logr/logr v1.2.4 // indirect
23+
github.com/cespare/xxhash/v2 v2.3.0 // indirect
24+
github.com/go-logr/logr v1.4.3 // indirect
2425
github.com/go-logr/stdr v1.2.2 // indirect
2526
github.com/golang/protobuf v1.5.3 // indirect
27+
github.com/google/uuid v1.6.0 // indirect
2628
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
2729
github.com/mattn/go-isatty v0.0.19 // indirect
2830
github.com/mattn/go-runewidth v0.0.15 // indirect
2931
github.com/muesli/reflow v0.3.0 // indirect
3032
github.com/rivo/uniseg v0.4.4 // indirect
31-
go.opentelemetry.io/otel v1.16.0 // indirect
32-
go.opentelemetry.io/otel/metric v1.16.0 // indirect
33+
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
34+
go.opentelemetry.io/otel v1.40.0 // indirect
35+
go.opentelemetry.io/otel/metric v1.40.0 // indirect
3336
golang.org/x/net v0.12.0 // indirect
34-
golang.org/x/sys v0.11.0 // indirect
37+
golang.org/x/sys v0.40.0 // indirect
3538
golang.org/x/text v0.11.0 // indirect
3639
google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130 // indirect
3740
google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130 // indirect

go.sum

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,25 @@ cloud.google.com/go/longrunning v0.5.1 h1:Fr7TXftcqTudoyRJa113hyaqlGdiBQkp0Gq7tE
88
cloud.google.com/go/longrunning v0.5.1/go.mod h1:spvimkwdz6SPWKEt/XBij79E9fiTkHSQl/fRUUQJYJc=
99
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
1010
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
11+
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
12+
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
1113
github.com/charmbracelet/lipgloss v0.7.1 h1:17WMwi7N1b1rVWOjMT+rCh7sQkvDU75B2hbZpc5Kc1E=
1214
github.com/charmbracelet/lipgloss v0.7.1/go.mod h1:yG0k3giv8Qj8edTCbbg6AlQ5e8KNWpFujkNawKNhE2c=
1315
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
16+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
1417
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
15-
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
16-
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
18+
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
19+
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
1720
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
1821
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
1922
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
2023
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
2124
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
2225
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
23-
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
24-
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
26+
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
27+
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
28+
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
29+
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
2530
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
2631
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
2732
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
@@ -34,26 +39,32 @@ github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKt
3439
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
3540
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
3641
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
42+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
3743
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
3844
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
3945
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
4046
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
41-
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
42-
go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s=
43-
go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4=
44-
go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo=
45-
go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4=
46-
go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE=
47-
go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4=
48-
go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs=
49-
go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0=
50-
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
51-
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
47+
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
48+
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
49+
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
50+
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
51+
go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms=
52+
go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g=
53+
go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g=
54+
go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc=
55+
go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8=
56+
go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE=
57+
go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw=
58+
go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg=
59+
go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw=
60+
go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA=
61+
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
62+
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
5263
golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
5364
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
5465
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
55-
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
56-
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
66+
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
67+
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
5768
golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0=
5869
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
5970
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
@@ -74,3 +85,4 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
7485
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
7586
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
7687
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
88+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

internal/entryhuman/entry.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ func formatValue(v interface{}) (string, error) {
6767
if v == nil {
6868
return "<nil>", nil
6969
}
70+
switch v.(type) {
71+
case error, fmt.Stringer:
72+
return quote(fmt.Sprintf("%+v", v)), nil
73+
}
7074
typ := reflect.TypeOf(v)
7175
switch typ.Kind() {
7276
case reflect.Struct, reflect.Map:

internal/entryhuman/entry_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ package entryhuman_test
22

33
import (
44
"bytes"
5+
"context"
56
"database/sql"
67
"flag"
78
"fmt"
89
"io"
910
"math"
1011
"os"
12+
"strings"
1113
"testing"
1214
"time"
1315

@@ -284,6 +286,51 @@ func TestEntry(t *testing.T) {
284286
})
285287
}
286288

289+
func TestContextErrorFormatting(t *testing.T) {
290+
t.Parallel()
291+
292+
tests := []struct {
293+
name string
294+
err error
295+
expected string
296+
}{
297+
{
298+
name: "DeadlineExceeded",
299+
err: context.DeadlineExceeded,
300+
expected: "context deadline exceeded",
301+
},
302+
{
303+
name: "Canceled",
304+
err: context.Canceled,
305+
expected: "context canceled",
306+
},
307+
{
308+
name: "WrappedDeadlineExceeded",
309+
err: fmt.Errorf("request failed: %w", context.DeadlineExceeded),
310+
expected: "request failed: context deadline exceeded",
311+
},
312+
}
313+
314+
for _, tc := range tests {
315+
t.Run(tc.name, func(t *testing.T) {
316+
t.Parallel()
317+
318+
var buf bytes.Buffer
319+
entryhuman.Fmt(&buf, io.Discard, slog.SinkEntry{
320+
Level: slog.LevelError,
321+
Message: "something failed",
322+
Fields: slog.M(
323+
slog.Error(tc.err),
324+
),
325+
})
326+
327+
got := buf.String()
328+
assert.False(t, "error not empty object", strings.Contains(got, "error={}"))
329+
assert.True(t, "error contains expected string", strings.Contains(got, tc.expected))
330+
})
331+
}
332+
}
333+
287334
func BenchmarkFmt(b *testing.B) {
288335
bench := func(b *testing.B, color bool) {
289336
nfs := []int{1, 4, 16}

map_test.go

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package slog_test
22

33
import (
44
"bytes"
5+
"context"
56
"encoding/json"
67
"io"
78
"runtime"
@@ -62,12 +63,12 @@ func TestMap(t *testing.T) {
6263
{
6364
"msg": "wrap1",
6465
"fun": "cdr.dev/slog/v3_test.TestMap.func2",
65-
"loc": "`+mapTestFile+`:41"
66+
"loc": "`+mapTestFile+`:42"
6667
},
6768
{
6869
"msg": "wrap2",
6970
"fun": "cdr.dev/slog/v3_test.TestMap.func2",
70-
"loc": "`+mapTestFile+`:42"
71+
"loc": "`+mapTestFile+`:43"
7172
},
7273
"EOF"
7374
],
@@ -220,6 +221,26 @@ func TestMap(t *testing.T) {
220221
"val": "{meow:hi bar:23 far:600}"
221222
}`)
222223
})
224+
225+
t.Run("contextDeadlineExceeded", func(t *testing.T) {
226+
t.Parallel()
227+
228+
test(t, slog.M(
229+
slog.Error(context.DeadlineExceeded),
230+
), `{
231+
"error": "context deadline exceeded"
232+
}`)
233+
})
234+
235+
t.Run("contextCanceled", func(t *testing.T) {
236+
t.Parallel()
237+
238+
test(t, slog.M(
239+
slog.Error(context.Canceled),
240+
), `{
241+
"error": "context canceled"
242+
}`)
243+
})
223244
}
224245

225246
func indentJSON(t *testing.T, j string) string {

sloggers/slogjson/slogjson_test.go

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"database/sql"
77
"fmt"
88
"runtime"
9+
"strings"
910
"testing"
1011

1112
sdktrace "go.opentelemetry.io/otel/sdk/trace"
@@ -34,7 +35,7 @@ func TestMake(t *testing.T) {
3435
l.Error(ctx, "line1\n\nline2", slog.F("wowow", "me\nyou"))
3536

3637
j := entryjson.Filter(b.String(), "ts")
37-
exp := fmt.Sprintf(`{"level":"ERROR","msg":"line1\n\nline2","caller":"%v:34","func":"cdr.dev/slog/v3/sloggers/slogjson_test.TestMake","logger_names":["named"],"trace":"%v","span":"%v","fields":{"wowow":"me\nyou"}}
38+
exp := fmt.Sprintf(`{"level":"ERROR","msg":"line1\n\nline2","caller":"%v:35","func":"cdr.dev/slog/v3/sloggers/slogjson_test.TestMake","logger_names":["named"],"trace":"%v","span":"%v","fields":{"wowow":"me\nyou"}}
3839
`, slogjsonTestFile, span.SpanContext().TraceID().String(), span.SpanContext().SpanID().String())
3940
assert.Equal(t, "entry", exp, j)
4041
}
@@ -60,7 +61,44 @@ func TestNoDriverValue(t *testing.T) {
6061
l.Error(bg, "error!", slog.F("inval", invalidField), slog.F("val", validField), slog.F("int", validInt))
6162

6263
j := entryjson.Filter(b.String(), "ts")
63-
exp := fmt.Sprintf(`{"level":"ERROR","msg":"error!","caller":"%v:60","func":"cdr.dev/slog/v3/sloggers/slogjson_test.TestNoDriverValue","logger_names":["named"],"fields":{"inval":null,"val":"cat","int":42}}
64+
exp := fmt.Sprintf(`{"level":"ERROR","msg":"error!","caller":"%v:61","func":"cdr.dev/slog/v3/sloggers/slogjson_test.TestNoDriverValue","logger_names":["named"],"fields":{"inval":null,"val":"cat","int":42}}
6465
`, slogjsonTestFile)
6566
assert.Equal(t, "entry", exp, j)
6667
}
68+
69+
func TestContextErrors(t *testing.T) {
70+
t.Parallel()
71+
72+
t.Run("DeadlineExceeded", func(t *testing.T) {
73+
t.Parallel()
74+
75+
b := &bytes.Buffer{}
76+
l := slog.Make(slogjson.Sink(b))
77+
l.Error(bg, "request failed", slog.Error(context.DeadlineExceeded))
78+
79+
j := entryjson.Filter(b.String(), "ts")
80+
assert.True(t, "error contains deadline exceeded", strings.Contains(j, `"error":"context deadline exceeded"`))
81+
})
82+
83+
t.Run("Canceled", func(t *testing.T) {
84+
t.Parallel()
85+
86+
b := &bytes.Buffer{}
87+
l := slog.Make(slogjson.Sink(b))
88+
l.Error(bg, "request failed", slog.Error(context.Canceled))
89+
90+
j := entryjson.Filter(b.String(), "ts")
91+
assert.True(t, "error contains context canceled", strings.Contains(j, `"error":"context canceled"`))
92+
})
93+
94+
t.Run("WrappedDeadlineExceeded", func(t *testing.T) {
95+
t.Parallel()
96+
97+
b := &bytes.Buffer{}
98+
l := slog.Make(slogjson.Sink(b))
99+
l.Error(bg, "request failed", slog.Error(fmt.Errorf("dial: %w", context.DeadlineExceeded)))
100+
101+
j := entryjson.Filter(b.String(), "ts")
102+
assert.True(t, "error contains dial: context deadline exceeded", strings.Contains(j, `"error":"dial: context deadline exceeded"`))
103+
})
104+
}

0 commit comments

Comments
 (0)