Skip to content

Commit f905622

Browse files
committed
Zerolog formatter
1 parent e3d0bb6 commit f905622

File tree

11 files changed

+267
-20
lines changed

11 files changed

+267
-20
lines changed

Makefile

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ build:
44

55
test:
66
go test -race -v ./...
7+
go -C loggers/zerolog test -race -v ./...
78
watch-test:
8-
reflex -t 50ms -s -- sh -c 'gotest -race -v ./...'
9+
reflex -t 50ms -s -- sh -c 'gotest -race -v ./... && go -C loggers/zerolog test -race -v ./...'
910

1011
bench:
1112
go test -benchmem -count 3 -bench ./...

examples/zerolog/example.go

+4-16
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66

77
"github.com/rs/zerolog"
88
"github.com/samber/oops"
9+
oopszerolog "github.com/samber/oops/loggers/zerolog"
910
)
1011

1112
func d() error {
@@ -36,22 +37,9 @@ func a() error {
3637
return b()
3738
}
3839

39-
func WithOops(l zerolog.Logger, err error) *zerolog.Logger {
40-
if oopsErr, ok := oops.AsOops(err); ok {
41-
ctx := l.With()
42-
for k, v := range oopsErr.ToMap() {
43-
ctx = ctx.Interface(k, v)
44-
}
45-
46-
logger := ctx.Err(oopsErr).Logger()
47-
return &logger
48-
}
49-
50-
// Recursively call into ourself so we can at least get a stack trace for any error
51-
return WithOops(l, oops.Wrap(err))
52-
}
53-
5440
func main() {
41+
zerolog.ErrorStackMarshaler = oopszerolog.OopsStackMarshaller
42+
zerolog.ErrorMarshalFunc = oopszerolog.OopsMarshalFunc
5543
logger := zerolog.
5644
New(os.Stderr).
5745
With().
@@ -60,5 +48,5 @@ func main() {
6048

6149
err := a()
6250

63-
WithOops(logger, err).Error().Send()
51+
logger.Error().Stack().Err(err).Msg(err.Error())
6452
}

examples/zerolog/go.mod

+5-3
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@ go 1.21
44

55
require (
66
github.com/rs/zerolog v1.31.0
7-
github.com/samber/oops v1.9.2
7+
github.com/samber/oops v1.16.1
88
)
99

1010
require (
1111
github.com/mattn/go-colorable v0.1.13 // indirect
1212
github.com/mattn/go-isatty v0.0.19 // indirect
1313
github.com/oklog/ulid/v2 v2.1.0 // indirect
14-
github.com/samber/lo v1.38.1 // indirect
15-
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 // indirect
14+
github.com/samber/lo v1.49.1 // indirect
15+
go.opentelemetry.io/otel v1.29.0 // indirect
16+
go.opentelemetry.io/otel/trace v1.29.0 // indirect
1617
golang.org/x/sys v0.12.0 // indirect
18+
golang.org/x/text v0.22.0 // indirect
1719
)

examples/zerolog/go.sum

+10
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,21 @@ github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A=
1414
github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
1515
github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
1616
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
17+
github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew=
18+
github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o=
1719
github.com/samber/oops v1.9.2 h1:ph8WaOk5pEMetbtp+UTcdrdaggk8E8gKhpunShAKyIM=
1820
github.com/samber/oops v1.9.2/go.mod h1:xEXk4BLyqajkvCxzpxBnqfzHzRLFk3+g4E+tOJtOPZY=
21+
github.com/samber/oops v1.16.1 h1:XlKkXsWM5g8hE4C+sEV9n0X282fZn3XabVmAKU2RiHI=
22+
github.com/samber/oops v1.16.1/go.mod h1:8eXgMAJcDXRAijQsFRhfy/EHDOTiSvwkg6khFqFK078=
23+
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
24+
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
25+
go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
26+
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
1927
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 h1:5llv2sWeaMSnA3w2kS57ouQQ4pudlXrR0dCgw51QK9o=
2028
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
2129
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
2230
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
2331
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
2432
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
33+
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
34+
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=

go.work

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use (
1414

1515
// logger formatters
1616
./loggers/logrus
17+
./loggers/zerolog
1718

1819
// recovery middlewares
1920
./recovery/gin

go.work.sum

+45
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,43 @@
1+
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
2+
github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
13
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
4+
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
5+
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
26
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
7+
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
38
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
9+
github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA=
10+
github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
411
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
512
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
13+
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
14+
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
615
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
16+
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
17+
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
18+
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
19+
github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=
720
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
821
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
22+
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30 h1:BHT1/DKsYDGkUgQ2jmMaozVcdk+sVfz0+1ZJq4zkWgw=
23+
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A=
24+
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
25+
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
26+
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
27+
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
28+
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
29+
github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
30+
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
931
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
32+
github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE=
1033
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
34+
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
35+
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
36+
go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc=
1137
go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8=
1238
go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ=
39+
go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
40+
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
1341
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
1442
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
1543
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
@@ -18,29 +46,40 @@ golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
1846
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
1947
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
2048
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
49+
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
2150
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
51+
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
52+
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
2253
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
2354
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
2455
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
2556
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
2657
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
2758
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
59+
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
2860
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
2961
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
3062
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
3163
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
64+
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
3265
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
66+
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
67+
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
3368
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
3469
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
3570
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
3671
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
72+
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
73+
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2 h1:IRJeR9r1pYWsHKTRe/IInb7lYvbBVIqOgsX/u0mbOWY=
3774
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
75+
golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457 h1:zf5N6UOrA487eEFacMePxjXAJctxKmyjKUsjA11Uzuk=
3876
golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0=
3977
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
4078
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
4179
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
4280
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
4381
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
82+
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
4483
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
4584
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
4685
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
@@ -49,4 +88,10 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
4988
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
5089
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
5190
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
91+
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
5292
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
93+
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
94+
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
95+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
96+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
97+
rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4=

loggers/zerolog/README.md

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Zerolog formatter for Oops
2+
3+
```go
4+
import oopszerolog "github.com/samber/oops/loggers/zerolog"
5+
6+
func init() {
7+
zerolog.ErrorStackMarshaler = oopszerolog.OopsStackMarshaller
8+
zerolog.ErrorMarshalFunc = oopszerolog.OopsMarshalFunc
9+
}
10+
11+
func main() {
12+
err := oops.
13+
With("driver", "postgresql").
14+
With("query", query).
15+
With("query.duration", queryDuration).
16+
Errorf("could not fetch user")
17+
18+
if err != nil {
19+
zerolog.New(os.Stderr).Error().Stack().Err(err).Msg(err.Error())
20+
}
21+
}
22+
```

loggers/zerolog/formatter.go

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package oopszerolog
2+
3+
import (
4+
"github.com/rs/zerolog"
5+
"github.com/samber/oops"
6+
)
7+
8+
func OopsStackMarshaller(err error) interface{} {
9+
if typedErr, ok := oops.AsOops(err); ok {
10+
return typedErr.Stacktrace()
11+
}
12+
return err
13+
}
14+
15+
func OopsMarshalFunc(err error) interface{} {
16+
if typedErr, ok := oops.AsOops(err); ok {
17+
return zerologErrorMarshaller{err: typedErr}
18+
}
19+
return err
20+
}
21+
22+
type zerologErrorMarshaller struct {
23+
err oops.OopsError
24+
}
25+
26+
func (m zerologErrorMarshaller) MarshalZerologObject(e *zerolog.Event) {
27+
payload := m.err.ToMap()
28+
for k, v := range payload {
29+
switch k {
30+
case "stacktrace":
31+
case "context":
32+
if context, ok := v.(map[string]any); ok && len(context) > 0 {
33+
dict := zerolog.Dict()
34+
for k, v := range context {
35+
switch vTyped := v.(type) {
36+
case nil:
37+
case error:
38+
dict = dict.Str(k, vTyped.Error())
39+
default:
40+
dict = dict.Interface(k, vTyped)
41+
}
42+
}
43+
e.Dict(k, dict)
44+
}
45+
default:
46+
e.Any(k, v)
47+
}
48+
}
49+
}

loggers/zerolog/formatter_test.go

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package oopszerolog
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"github.com/rs/zerolog"
7+
"github.com/samber/oops"
8+
"github.com/stretchr/testify/assert"
9+
"github.com/stretchr/testify/require"
10+
"testing"
11+
)
12+
13+
type jsonLogEntryError struct {
14+
Error string
15+
Time string
16+
Domain string
17+
Trace string
18+
Context map[string]any
19+
}
20+
21+
type jsonLogEntry struct {
22+
Level string
23+
Stack string
24+
Message string
25+
Error jsonLogEntryError
26+
}
27+
28+
func TestZerologFormatter(t *testing.T) {
29+
zerolog.ErrorStackMarshaler = OopsStackMarshaller
30+
zerolog.ErrorMarshalFunc = OopsMarshalFunc
31+
32+
buffer := bytes.NewBuffer(make([]byte, 0, 1024))
33+
logger := zerolog.New(buffer).Level(zerolog.ErrorLevel)
34+
err := oops.
35+
In("test").
36+
With("driver", "postgresql").
37+
Errorf("could not fetch user")
38+
logger.Error().Stack().Err(err).Msg("something went wrong")
39+
40+
loggedError := jsonLogEntry{}
41+
err = json.Unmarshal(buffer.Bytes(), &loggedError)
42+
require.NoError(t, err)
43+
44+
assert.Contains(t, loggedError.Stack, "Oops: could not fetch user\n --- at ")
45+
assert.NotEmpty(t, loggedError.Error.Time)
46+
assert.NotEmpty(t, loggedError.Error.Trace)
47+
loggedError.Stack = ""
48+
loggedError.Error.Time = ""
49+
loggedError.Error.Trace = ""
50+
assert.EqualValues(t, jsonLogEntry{
51+
Level: "error",
52+
Message: "something went wrong",
53+
Error: jsonLogEntryError{
54+
Error: "could not fetch user",
55+
Domain: "test",
56+
Context: map[string]any{
57+
"driver": "postgresql",
58+
},
59+
},
60+
}, loggedError)
61+
}

loggers/zerolog/go.mod

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
module github.com/samber/oops/loggers/zerolog
2+
3+
go 1.21
4+
5+
require (
6+
github.com/rs/zerolog v1.31.0
7+
github.com/samber/oops v1.16.1
8+
github.com/stretchr/testify v1.10.0
9+
)
10+
11+
require (
12+
github.com/davecgh/go-spew v1.1.1 // indirect
13+
github.com/mattn/go-colorable v0.1.13 // indirect
14+
github.com/mattn/go-isatty v0.0.19 // indirect
15+
github.com/oklog/ulid/v2 v2.1.0 // indirect
16+
github.com/pmezard/go-difflib v1.0.0 // indirect
17+
github.com/samber/lo v1.49.1 // indirect
18+
go.opentelemetry.io/otel v1.29.0 // indirect
19+
go.opentelemetry.io/otel/trace v1.29.0 // indirect
20+
golang.org/x/sys v0.12.0 // indirect
21+
golang.org/x/text v0.21.0 // indirect
22+
gopkg.in/yaml.v3 v3.0.1 // indirect
23+
)

0 commit comments

Comments
 (0)