Sentry integration (#591)

Use sentry echo integration to send errors

Only capture errors not already handled by echo

Add sentry panic handler

Add sentry library

Add sentry init

Add sentry config

Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#591
This commit is contained in:
konrad 2020-06-19 18:47:15 +00:00
parent c51662c270
commit d02d413c5e
31 changed files with 4547 additions and 0 deletions

View File

@ -32,6 +32,8 @@ service:
enabletaskcomments: true
# Whether totp is enabled. In most cases you want to leave that enabled.
enabletotp: true
# If not empty, enables logging of crashes and unhandled errors in sentry.
sentrydsn: ''
database:
# Database type to use. Supported types are mysql, postgres and sqlite.

View File

@ -75,6 +75,8 @@ service:
enabletaskcomments: true
# Whether totp is enabled. In most cases you want to leave that enabled.
enabletotp: true
# If not empty, enables logging of crashes and unhandled errors in sentry.
sentrydsn: ''
database:
# Database type to use. Supported types are mysql, postgres and sqlite.

1
go.mod
View File

@ -31,6 +31,7 @@ require (
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/fzipp/gocyclo v0.0.0-20150627053110-6acd4345c835
github.com/getsentry/sentry-go v0.6.1
github.com/go-openapi/jsonreference v0.19.3 // indirect
github.com/go-openapi/spec v0.19.4 // indirect
github.com/go-redis/redis/v7 v7.4.0

82
go.sum
View File

@ -28,9 +28,14 @@ gitea.com/xorm/tests v0.7.0 h1:pFcaxTGGAWw3rDuVfhBdyr+mX1uzdTtncyAKxkCQ/IE=
gitea.com/xorm/tests v0.7.0/go.mod h1:ngmhQrSBgihBbOqw1hdReSQJAnTlbStYTn0vruUFwDc=
gitea.com/xorm/xorm-redis-cache v0.2.0 h1:qglRHt6/7vJmDeld6j+n10M9PmruAh+Le2lgNraFu3g=
gitea.com/xorm/xorm-redis-cache v0.2.0/go.mod h1:juYdjkmIKvLbPkdfBVKGVJ2daFQIJAgKsn4mL4ZK8Zk=
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw=
github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w=
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
@ -41,8 +46,10 @@ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tN
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@ -58,6 +65,7 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs=
github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
@ -80,12 +88,16 @@ github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJ
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
@ -101,13 +113,21 @@ github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4 h1:YcpmyvADG
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
@ -116,6 +136,9 @@ github.com/fzipp/gocyclo v0.0.0-20150627053110-6acd4345c835 h1:roDmqJ4Qes7hrDOsW
github.com/fzipp/gocyclo v0.0.0-20150627053110-6acd4345c835/go.mod h1:BjL/N0+C+j9uNX+1xcNuM9vdSIcXCZrQZUYbXOFbgN8=
github.com/garyburd/redigo v1.6.0 h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc=
github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
github.com/getsentry/sentry-go v0.6.1 h1:K84dY1/57OtWhdyr5lbU78Q/+qgzkEyGc/ud+Sipi5k=
github.com/getsentry/sentry-go v0.6.1/go.mod h1:0yZBuzSvbZwBnvaF9VwZIMen3kXscY8/uasKtAX1qG8=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w=
@ -125,11 +148,15 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm
github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
github.com/gin-gonic/gin v1.6.2/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
github.com/go-openapi/jsonpointer v0.17.0 h1:nH6xp8XdXHx8dqveo0ZuJBluCO2qGrPbDNZ0dwoRHP0=
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
@ -165,6 +192,9 @@ github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-testfixtures/testfixtures/v3 v3.2.0 h1:FGAW3z5UzmrZGjR/dZp1u3Tbld0SDmirLO4RrR5++7Q=
github.com/go-testfixtures/testfixtures/v3 v3.2.0/go.mod h1:RZctY24ixituGC73XlAV1gkCwYMVwiSwPm26MNlQIhE=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@ -195,6 +225,7 @@ github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pO
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
@ -203,6 +234,7 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@ -237,6 +269,7 @@ github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@ -250,8 +283,13 @@ github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334 h1:VHgatEHNcBFE
github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg=
github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI=
github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0=
github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI=
github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc=
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
github.com/jackc/pgx v3.6.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
@ -281,10 +319,19 @@ github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk=
github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U=
github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw=
github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.9.6/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/kolaente/caldav-go v3.0.1-0.20190524174923-9e5cd1688227+incompatible h1:PkEEpmbrFXlMul8cOplR8nkcIM/NDbx+H6fq2+vaKAA=
@ -304,6 +351,7 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/labstack/echo/v4 v4.1.7-0.20190627175217-8fb7b5be270f h1:fNJtR+TNyxTdYCZU40fc8Or8RyBqMOKYNv+Zay5gjvk=
github.com/labstack/echo/v4 v4.1.7-0.20190627175217-8fb7b5be270f/go.mod h1:kU/7PwzgNxZH4das4XNsSpBSOD09XIF5YEPzjpkGnGE=
github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g=
github.com/labstack/echo/v4 v4.1.16 h1:8swiwjE5Jkai3RPfZoahp8kjVCRNq+y7Q0hPji2Kz0o=
github.com/labstack/echo/v4 v4.1.16/go.mod h1:awO+5TzAjvL8XpibdsfXxPgHr+orhtXZJZIQCVjogKI=
github.com/labstack/gommon v0.2.9 h1:heVeuAYtevIQVYkGj6A41dtfT91LrvFG220lavpWhrU=
@ -355,8 +403,12 @@ github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71
github.com/mattn/go-sqlite3 v2.0.2+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg=
github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ=
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
@ -371,7 +423,11 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM=
github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
@ -381,6 +437,7 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU=
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
@ -399,6 +456,8 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9
github.com/pelletier/go-toml v1.4.0 h1:u3Z1r+oOXJIkxqw34zVhyPgjBsm6X2wn21NWs/HfSeg=
github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
@ -446,10 +505,14 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shopspring/decimal v0.0.0-20191009025716-f1972eb1d1f5/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 h1:bUGsEnyNbVPw06Bs80sCeARAlK8lhwqGyi6UT8ymuGk=
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
@ -471,6 +534,7 @@ github.com/spf13/afero v1.3.0 h1:Ysnmjh1Di8EaWaBv40CYR4IdaIsBc5996Gh1oZzCBKk=
github.com/spf13/afero v1.3.0/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
@ -481,6 +545,7 @@ github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
@ -513,6 +578,7 @@ github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGr
github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v0.0.0-20181022190402-e5e69e061d4f/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/ulule/limiter/v3 v3.5.0 h1:QRAebbswjlezHIfiSQgM8+jMxaz/zsrxGRuiUJ43MHo=
@ -521,16 +587,25 @@ github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
github.com/valyala/fasthttp v1.9.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/fasttemplate v1.1.0 h1:RZqt0yGBsps8NGvLSGW804QQqCUYYLsaOjTVHy1Ocw4=
github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
@ -544,6 +619,7 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@ -551,6 +627,7 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4 h1:ydJNl0ENAG67pFbB+9tfhiL2pYqLhfoaZFw/cjLhY4A=
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@ -595,6 +672,7 @@ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c h1:uOCk1iQW6Vc18bnC13MfzScl+wdKBmM9Y9kU7Z83/lw=
@ -634,6 +712,7 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -675,11 +754,13 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
@ -768,6 +849,7 @@ gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eR
gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4=
gopkg.in/jcmturner/gokrb5.v7 v7.5.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM=
gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=

View File

@ -49,6 +49,7 @@ const (
ServiceTimeZone Key = `service.timezone`
ServiceEnableTaskComments Key = `service.enabletaskcomments`
ServiceEnableTotp Key = `service.enabletotp`
ServiceSentryDsn Key = `service.sentrydsn`
DatabaseType Key = `database.type`
DatabaseHost Key = `database.host`

View File

@ -59,13 +59,17 @@ import (
"code.vikunja.io/api/pkg/routes/caldav"
_ "code.vikunja.io/api/pkg/swagger" // To generate swagger docs
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/api/pkg/version"
"code.vikunja.io/web"
"code.vikunja.io/web/handler"
"github.com/asaskevich/govalidator"
"github.com/getsentry/sentry-go"
sentryecho "github.com/getsentry/sentry-go/echo"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
elog "github.com/labstack/gommon/log"
"strings"
"time"
)
// CustomValidator is a dummy struct to use govalidator with echo
@ -116,6 +120,42 @@ func NewEcho() *echo.Echo {
}))
}
// panic recover
e.Use(middleware.Recover())
if config.ServiceSentryDsn.GetString() != "" {
if err := sentry.Init(sentry.ClientOptions{
Dsn: config.ServiceSentryDsn.GetString(),
AttachStacktrace: true,
Release: version.Version,
}); err != nil {
log.Criticalf("Sentry init failed: %s", err)
}
defer sentry.Flush(5 * time.Second)
e.Use(sentryecho.New(sentryecho.Options{
Repanic: true,
}))
e.HTTPErrorHandler = func(err error, c echo.Context) {
// Only capture errors not already handled by echo
if _, ok := err.(*echo.HTTPError); !ok {
hub := sentryecho.GetHubFromContext(c)
if hub != nil {
hub.WithScope(func(scope *sentry.Scope) {
scope.SetExtra("url", c.Request().URL)
hub.CaptureException(err)
})
} else {
sentry.CaptureException(err)
log.Debugf("Could not add context for sending error '%s' to sentry", err.Error())
}
log.Debugf("Error '%s' sent to sentry", err.Error())
}
e.DefaultHTTPErrorHandler(err, c)
}
}
// Validation
e.Validator = &CustomValidator{}

19
vendor/github.com/getsentry/sentry-go/.craft.yml generated vendored Normal file
View File

@ -0,0 +1,19 @@
minVersion: '0.9.2'
github:
owner: getsentry
repo: sentry-go
preReleaseCommand: bash scripts/craft-pre-release.sh
changelogPolicy: simple
statusProvider:
name: github
config:
contexts:
- Travis CI - Branch
targets:
- name: github
includeNames: /none/
tagPrefix: v
- name: registry
type: sdk
config:
canonical: "github:getsentry/sentry-go"

6
vendor/github.com/getsentry/sentry-go/.gitignore generated vendored Normal file
View File

@ -0,0 +1,6 @@
coverage.txt
# Just my personal way of tracking stuff — Kamil
FIXME.md
TODO.md
!NOTES.md

50
vendor/github.com/getsentry/sentry-go/.golangci.yml generated vendored Normal file
View File

@ -0,0 +1,50 @@
linters:
disable-all: true
enable:
- bodyclose
- deadcode
- depguard
- dogsled
- dupl
- errcheck
- gochecknoglobals
- gochecknoinits
- goconst
- gocritic
- gocyclo
- gofmt
- goimports
- golint
- gosec
- gosimple
- govet
- ineffassign
- interfacer
- lll
- maligned
- misspell
- nakedret
- prealloc
- scopelint
- staticcheck
- structcheck
- typecheck
- unconvert
- unparam
- unused
- varcheck
run:
skip-dirs:
- echo
- example/echo
issues:
exclude:
- "not declared by package utf8"
- "unicode/utf8/utf8.go"
exclude-rules:
- path: _test\.go
linters:
- prealloc
- path: errors_test\.go
linters:
- unused

49
vendor/github.com/getsentry/sentry-go/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,49 @@
language: go
go:
- 1.12.x
- 1.13.x
- 1.14.x
- master
env:
- GO111MODULE=on GOFLAGS=-mod=readonly
- GO111MODULE=off
jobs:
include:
- name: "Module support outside of GOPATH"
go: stable
before_script: >-
mv $GOPATH/src/github.com/getsentry/sentry-go ~/sentry-go &&
cd ~/sentry-go &&
export GOPATH= &&
go env GOPATH
script: >-
go test ./... &&
go test ./... -race
allow_failures:
- go: master
fast_finish: true
before_install:
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/v1.19.1/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.19.1
# Fetch origin/master. This is required for `git merge-base` when testing a
# branch, since Travis clones only the target branch.
- git fetch origin master:remotes/origin/master
script:
- golangci-lint run --new-from-rev=$(git merge-base origin/master HEAD)
- go build ./...
- go test ./...
- go test ./... -race
notifications:
webhooks:
urls:
- https://zeus.ci/hooks/befe9810-9285-11e9-b01a-0a580a281808/public/provider/travis/webhook
on_success: always
on_failure: always
on_start: always
on_cancel: always
on_error: always

226
vendor/github.com/getsentry/sentry-go/CHANGELOG.md generated vendored Normal file
View File

@ -0,0 +1,226 @@
# Changelog
## Unreleased
- "I am running away from my responsibilities. And it feels good." Michael Scott, Season 4, "Money"
## v0.6.1
- fix: Use NewEvent to init Event struct (#220)
_NOTE:_
A change introduced in v0.6.0 with the intent of avoiding allocations made a
pattern used in official examples break in certain circumstances (attempting
to write to a nil map).
This release reverts the change such that maps in the Event struct are always
allocated.
## v0.6.0
- feat: Read module dependencies from runtime/debug (#199)
- feat: Support chained errors using Unwrap (#206)
- feat: Report chain of errors when available (#185)
- **[breaking]** fix: Accept http.RoundTripper to customize transport (#205)
Before the SDK accepted a concrete value of type `*http.Transport` in
`ClientOptions`, now it accepts any value implementing the `http.RoundTripper`
interface. Note that `*http.Transport` implements `http.RoundTripper`, so most
code bases will continue to work unchanged.
Users of custom transport gain the ability to pass in other implementations of
`http.RoundTripper` and may be able to simplify their code bases.
- fix: Do not panic when scope event processor drops event (#192)
- **[breaking]** fix: Use time.Time for timestamps (#191)
Users of sentry-go typically do not need to manipulate timestamps manually.
For those who do, the field type changed from `int64` to `time.Time`, which
should be more convenient to use. The recommended way to get the current time
is `time.Now().UTC()`.
- fix: Report usage error including stack trace (#189)
- feat: Add Exception.ThreadID field (#183)
- ci: Test against Go 1.14, drop 1.11 (#170)
- feat: Limit reading bytes from request bodies (#168)
- **[breaking]** fix: Rename fasthttp integration package sentryhttp => sentryfasthttp
The current recommendation is to use a named import, in which case existing
code should not require any change:
```go
package main
import (
"fmt"
"github.com/getsentry/sentry-go"
sentryfasthttp "github.com/getsentry/sentry-go/fasthttp"
"github.com/valyala/fasthttp"
)
```
_NOTE:_
This version includes some new features and a few breaking changes, none of
which should pose troubles with upgrading. Most code bases should be able to
upgrade without any changes.
## v0.5.1
- fix: Ignore err.Cause() when it is nil (#160)
## v0.5.0
- fix: Synchronize access to HTTPTransport.disabledUntil (#158)
- docs: Update Flush documentation (#153)
- fix: HTTPTransport.Flush panic and data race (#140)
_NOTE:_
This version changes the implementation of the default transport, modifying the
behavior of `sentry.Flush`. The previous behavior was to wait until there were
no buffered events; new concurrent events kept `Flush` from returning. The new
behavior is to wait until the last event prior to the call to `Flush` has been
sent or the timeout; new concurrent events have no effect. The new behavior is
inline with the [Unified API
Guidelines](https://docs.sentry.io/development/sdk-dev/unified-api/).
We have updated the documentation and examples to clarify that `Flush` is meant
to be called typically only once before program termination, to wait for
in-flight events to be sent to Sentry. Calling `Flush` after every event is not
recommended, as it introduces unnecessary latency to the surrounding function.
Please verify the usage of `sentry.Flush` in your code base.
## v0.4.0
- fix(stacktrace): Correctly report package names (#127)
- fix(stacktrace): Do not rely on AbsPath of files (#123)
- build: Require github.com/ugorji/go@v1.1.7 (#110)
- fix: Correctly store last event id (#99)
- fix: Include request body in event payload (#94)
- build: Reset go.mod version to 1.11 (#109)
- fix: Eliminate data race in modules integration (#105)
- feat: Add support for path prefixes in the DSN (#102)
- feat: Add HTTPClient option (#86)
- feat: Extract correct type and value from top-most error (#85)
- feat: Check for broken pipe errors in Gin integration (#82)
- fix: Client.CaptureMessage accept nil EventModifier (#72)
## v0.3.1
- feat: Send extra information exposed by the Go runtime (#76)
- fix: Handle new lines in module integration (#65)
- fix: Make sure that cache is locked when updating for contextifyFramesIntegration
- ref: Update Iris integration and example to version 12
- misc: Remove indirect dependencies in order to move them to separate go.mod files
## v0.3.0
- feat: Retry event marshalling without contextual data if the first pass fails
- fix: Include `url.Parse` error in `DsnParseError`
- fix: Make more `Scope` methods safe for concurrency
- fix: Synchronize concurrent access to `Hub.client`
- ref: Remove mutex from `Scope` exported API
- ref: Remove mutex from `Hub` exported API
- ref: Compile regexps for `filterFrames` only once
- ref: Change `SampleRate` type to `float64`
- doc: `Scope.Clear` not safe for concurrent use
- ci: Test sentry-go with `go1.13`, drop `go1.10`
_NOTE:_
This version removes some of the internal APIs that landed publicly (namely `Hub/Scope` mutex structs) and may require (but shouldn't) some changes to your code.
It's not done through major version update, as we are still in `0.x` stage.
## v0.2.1
- fix: Run `Contextify` integration on `Threads` as well
## v0.2.0
- feat: Add `SetTransaction()` method on the `Scope`
- feat: `fasthttp` framework support with `sentryfasthttp` package
- fix: Add `RWMutex` locks to internal `Hub` and `Scope` changes
## v0.1.3
- feat: Move frames context reading into `contextifyFramesIntegration` (#28)
_NOTE:_
In case of any performance issues due to source contexts IO, you can let us know and turn off the integration in the meantime with:
```go
sentry.Init(sentry.ClientOptions{
Integrations: func(integrations []sentry.Integration) []sentry.Integration {
var filteredIntegrations []sentry.Integration
for _, integration := range integrations {
if integration.Name() == "ContextifyFrames" {
continue
}
filteredIntegrations = append(filteredIntegrations, integration)
}
return filteredIntegrations
},
})
```
## v0.1.2
- feat: Better source code location resolution and more useful inapp frames (#26)
- feat: Use `noopTransport` when no `Dsn` provided (#27)
- ref: Allow empty `Dsn` instead of returning an error (#22)
- fix: Use `NewScope` instead of literal struct inside a `scope.Clear` call (#24)
- fix: Add to `WaitGroup` before the request is put inside a buffer (#25)
## v0.1.1
- fix: Check for initialized `Client` in `AddBreadcrumbs` (#20)
- build: Bump version when releasing with Craft (#19)
## v0.1.0
- First stable release! \o/
## v0.0.1-beta.5
- feat: **[breaking]** Add `NewHTTPTransport` and `NewHTTPSyncTransport` which accepts all transport options
- feat: New `HTTPSyncTransport` that blocks after each call
- feat: New `Echo` integration
- ref: **[breaking]** Remove `BufferSize` option from `ClientOptions` and move it to `HTTPTransport` instead
- ref: Export default `HTTPTransport`
- ref: Export `net/http` integration handler
- ref: Set `Request` instantly in the package handlers, not in `recoverWithSentry` so it can be accessed later on
- ci: Add craft config
## v0.0.1-beta.4
- feat: `IgnoreErrors` client option and corresponding integration
- ref: Reworked `net/http` integration, wrote better example and complete readme
- ref: Reworked `Gin` integration, wrote better example and complete readme
- ref: Reworked `Iris` integration, wrote better example and complete readme
- ref: Reworked `Negroni` integration, wrote better example and complete readme
- ref: Reworked `Martini` integration, wrote better example and complete readme
- ref: Remove `Handle()` from frameworks handlers and return it directly from New
## v0.0.1-beta.3
- feat: `Iris` framework support with `sentryiris` package
- feat: `Gin` framework support with `sentrygin` package
- feat: `Martini` framework support with `sentrymartini` package
- feat: `Negroni` framework support with `sentrynegroni` package
- feat: Add `Hub.Clone()` for easier frameworks integration
- feat: Return `EventID` from `Recovery` methods
- feat: Add `NewScope` and `NewEvent` functions and use them in the whole codebase
- feat: Add `AddEventProcessor` to the `Client`
- fix: Operate on requests body copy instead of the original
- ref: Try to read source files from the root directory, based on the filename as well, to make it work on AWS Lambda
- ref: Remove `gocertifi` dependence and document how to provide your own certificates
- ref: **[breaking]** Remove `Decorate` and `DecorateFunc` methods in favor of `sentryhttp` package
- ref: **[breaking]** Allow for integrations to live on the client, by passing client instance in `SetupOnce` method
- ref: **[breaking]** Remove `GetIntegration` from the `Hub`
- ref: **[breaking]** Remove `GlobalEventProcessors` getter from the public API
## v0.0.1-beta.2
- feat: Add `AttachStacktrace` client option to include stacktrace for messages
- feat: Add `BufferSize` client option to configure transport buffer size
- feat: Add `SetRequest` method on a `Scope` to control `Request` context data
- feat: Add `FromHTTPRequest` for `Request` type for easier extraction
- ref: Extract `Request` information more accurately
- fix: Attach `ServerName`, `Release`, `Dist`, `Environment` options to the event
- fix: Don't log events dropped due to full transport buffer as sent
- fix: Don't panic and create an appropriate event when called `CaptureException` or `Recover` with `nil` value
## v0.0.1-beta
- Initial release

53
vendor/github.com/getsentry/sentry-go/CONTRIBUTING.md generated vendored Normal file
View File

@ -0,0 +1,53 @@
## Community
The public-facing channels for support and development of Sentry SDKs can be found on [Discord](https://discord.gg/Ww9hbqr).
## Testing
```console
$ go test
```
### Watch mode
Use: https://github.com/cespare/reflex
```console
$ reflex -g '*.go' -d "none" -- sh -c 'printf "\n"; go test'
```
### With data race detection
```console
$ go test -race
```
### Coverage
```console
$ go test -race -coverprofile=coverage.txt -covermode=atomic && go tool cover -html coverage.txt
```
## Linting
```console
$ golangci-lint run
```
## Release
1. Update `CHANGELOG.md` with new version in `vX.X.X` format title and list of changes.
The command below can be used to get a list of changes since the last tag, with the format used in `CHANGELOG.md`:
```console
$ git log --no-merges --format=%s $(git describe --abbrev=0).. | sed 's/^/- /'
```
2. Commit with `misc: vX.X.X changelog` commit message and push to `master`.
3. Let [`craft`](https://github.com/getsentry/craft) do the rest:
```console
$ craft prepare X.X.X
$ craft publish X.X.X
```

9
vendor/github.com/getsentry/sentry-go/LICENSE generated vendored Normal file
View File

@ -0,0 +1,9 @@
Copyright (c) 2019 Sentry (https://sentry.io) and individual contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

392
vendor/github.com/getsentry/sentry-go/MIGRATION.md generated vendored Normal file
View File

@ -0,0 +1,392 @@
# `raven-go` to `sentry-go` Migration Guide
## Installation
raven-go
```go
go get github.com/getsentry/raven-go
```
sentry-go
```go
go get github.com/getsentry/sentry-go@v0.0.1
```
## Configuration
raven-go
```go
import "github.com/getsentry/raven-go"
func main() {
raven.SetDSN("___PUBLIC_DSN___")
}
```
sentry-go
```go
import (
"fmt"
"github.com/getsentry/sentry-go"
)
func main() {
err := sentry.Init(sentry.ClientOptions{
Dsn: "___PUBLIC_DSN___",
})
if err != nil {
fmt.Printf("Sentry initialization failed: %v\n", err)
}
}
```
raven-go
```go
SetDSN()
SetDefaultLoggerName()
SetDebug()
SetEnvironment()
SetRelease()
SetSampleRate()
SetIgnoreErrors()
SetIncludePaths()
```
sentry-go
```go
sentry.Init(sentry.ClientOptions{
Dsn: "___PUBLIC_DSN___",
DebugWriter: os.Stderr,
Debug: true,
Environment: "environment",
Release: "release",
SampleRate: 0.5,
// IgnoreErrors: TBD,
// IncludePaths: TBD
})
```
Available options: see [Configuration](https://docs.sentry.io/platforms/go/config/) section.
### Providing SSL Certificates
By default, TLS uses the host's root CA set. If you don't have `ca-certificates` (which should be your go-to way of fixing the issue of missing certificates) and want to use `gocertifi` instead, you can provide pre-loaded cert files as one of the options to the `sentry.Init` call:
```go
package main
import (
"log"
"github.com/certifi/gocertifi"
"github.com/getsentry/sentry-go"
)
sentryClientOptions := sentry.ClientOptions{
Dsn: "___PUBLIC_DSN___",
}
rootCAs, err := gocertifi.CACerts()
if err != nil {
log.Println("Couldn't load CA Certificates: %v\n", err)
} else {
sentryClientOptions.CaCerts = rootCAs
}
sentry.Init(sentryClientOptions)
```
## Usage
### Capturing Errors
raven-go
```go
f, err := os.Open("filename.ext")
if err != nil {
raven.CaptureError(err, nil)
}
```
sentry-go
```go
f, err := os.Open("filename.ext")
if err != nil {
sentry.CaptureException(err)
}
```
### Capturing Panics
raven-go
```go
raven.CapturePanic(func() {
// do all of the scary things here
}, nil)
```
sentry-go
```go
func() {
defer sentry.Recover()
// do all of the scary things here
}()
```
### Capturing Messages
raven-go
```go
raven.CaptureMessage("Something bad happened and I would like to know about that")
```
sentry-go
```go
sentry.CaptureMessage("Something bad happened and I would like to know about that")
```
### Capturing Events
raven-go
```go
packet := &raven.Packet{
Message: "Hand-crafted event",
Extra: &raven.Extra{
"runtime.Version": runtime.Version(),
"runtime.NumCPU": runtime.NumCPU(),
},
}
raven.Capture(packet)
```
sentry-go
```go
event := &sentry.NewEvent()
event.Message = "Hand-crafted event"
event.Extra["runtime.Version"] = runtime.Version()
event.Extra["runtime.NumCPU"] = runtime.NumCPU()
sentry.CaptureEvent(event)
```
### Additional Data
See Context section.
### Event Sampling
raven-go
```go
raven.SetSampleRate(0.25)
```
sentry-go
```go
sentry.Init(sentry.ClientOptions{
SampleRate: 0.25,
})
```
### Awaiting the response (not recommended)
```go
raven.CaptureMessageAndWait("Something bad happened and I would like to know about that")
```
sentry-go
```go
sentry.CaptureMessage("Something bad happened and I would like to know about that")
if sentry.Flush(time.Second * 2) {
// event delivered
} else {
// timeout reached
}
```
## Context
### Per-event
raven-go
```go
raven.CaptureError(err, map[string]string{"browser": "Firefox"}, &raven.Http{
Method: "GET",
URL: "https://example.com/raven-go"
})
```
sentry-go
```go
sentry.WithScope(func(scope *sentry.Scope) {
scope.SetTag("browser", "Firefox")
scope.SetContext("Request", map[string]string{
"Method": "GET",
"URL": "https://example.com/raven-go",
})
sentry.CaptureException(err)
})
```
### Globally
#### SetHttpContext
raven-go
```go
raven.SetHttpContext(&raven.Http{
Method: "GET",
URL: "https://example.com/raven-go",
})
```
sentry-go
```go
sentry.ConfigureScope(func(scope *sentry.Scope) {
scope.SetContext("Request", map[string]string{
"Method": "GET",
"URL": "https://example.com/raven-go",
})
})
```
#### SetTagsContext
raven-go
```go
t := map[string]string{"day": "Friday", "sport": "Weightlifting"}
raven.SetTagsContext(map[string]string{"day": "Friday", "sport": "Weightlifting"})
```
sentry-go
```go
sentry.ConfigureScope(func(scope *sentry.Scope) {
scope.SetTags(map[string]string{"day": "Friday", "sport": "Weightlifting"})
})
```
#### SetUserContext
raven-go
```go
raven.SetUserContext(&raven.User{
ID: "1337",
Username: "kamilogorek",
Email: "kamil@sentry.io",
IP: "127.0.0.1",
})
```
sentry-go
```go
sentry.ConfigureScope(func(scope *sentry.Scope) {
scope.SetUser(sentry.User{
ID: "1337",
Username: "kamilogorek",
Email: "kamil@sentry.io",
IPAddress: "127.0.0.1",
})
})
```
#### ClearContext
raven-go
```go
raven.ClearContext()
```
sentry-go
```go
sentry.ConfigureScope(func(scope *sentry.Scope) {
scope.Clear()
})
```
#### WrapWithExtra
raven-go
```go
path := "filename.ext"
f, err := os.Open(path)
if err != nil {
err = raven.WrapWithExtra(err, map[string]string{"path": path, "cwd": os.Getwd()}
raven.CaptureError(err, nil)
}
```
sentry-go
```go
// use `sentry.WithScope`, see "Context / Per-event Section"
path := "filename.ext"
f, err := os.Open(path)
if err != nil {
sentry.WithScope(func(scope *sentry.Scope) {
sentry.SetExtras(map[string]interface{}{"path": path, "cwd": os.Getwd())
sentry.CaptureException(err)
})
}
```
## Integrations
### net/http
raven-go
```go
mux := http.NewServeMux
http.Handle("/", raven.Recoverer(mux))
// or
func root(w http.ResponseWriter, r *http.Request) {}
http.HandleFunc("/", raven.RecoveryHandler(root))
```
sentry-go
```go
sentryHandler := sentryhttp.New(sentryhttp.Options{
Repanic: false,
WaitForDelivery: true,
})
mux := http.NewServeMux
http.Handle("/", sentryHandler.Handle(mux))
// or
func root(w http.ResponseWriter, r *http.Request) {}
http.HandleFunc("/", sentryHandler.HandleFunc(root))
```

190
vendor/github.com/getsentry/sentry-go/README.md generated vendored Normal file
View File

@ -0,0 +1,190 @@
<p align="center">
<a href="https://sentry.io" target="_blank" align="center">
<img src="https://sentry-brand.storage.googleapis.com/sentry-logo-black.png" width="280">
</a>
<br />
</p>
# Official Sentry SDK for Go
[![Build Status](https://travis-ci.com/getsentry/sentry-go.svg?branch=master)](https://travis-ci.com/getsentry/sentry-go)
[![Go Report Card](https://goreportcard.com/badge/github.com/getsentry/sentry-go)](https://goreportcard.com/report/github.com/getsentry/sentry-go)
[![Discord](https://img.shields.io/discord/621778831602221064)](https://discord.gg/Ww9hbqr)
[![GoDoc](https://godoc.org/github.com/getsentry/sentry-go?status.svg)](https://godoc.org/github.com/getsentry/sentry-go)
[![go.dev](https://img.shields.io/badge/go.dev-pkg-007d9c.svg?style=flat)](https://pkg.go.dev/github.com/getsentry/sentry-go)
`sentry-go` provides a Sentry client implementation for the Go programming
language. This is the next line of the Go SDK for [Sentry](https://sentry.io/),
intended to replace the `raven-go` package.
> Looking for the old `raven-go` SDK documentation? See the Legacy client section [here](https://docs.sentry.io/clients/go/).
> If you want to start using sentry-go instead, check out the [migration guide](https://docs.sentry.io/platforms/go/migration/).
## Requirements
The only requirement is a Go compiler.
We verify this package against the 3 most recent releases of Go. Those are the
supported versions. The exact versions are defined in
[`.travis.yml`](.travis.yml).
In addition, we run tests against the current master branch of the Go toolchain,
though support for this configuration is best-effort.
## Installation
`sentry-go` can be installed like any other Go library through `go get`:
```console
$ go get github.com/getsentry/sentry-go
```
Or, if you are already using
[Go Modules](https://github.com/golang/go/wiki/Modules), you may specify a
version number as well:
```console
$ go get github.com/getsentry/sentry-go@latest
```
Check out the [list of released versions](https://pkg.go.dev/github.com/getsentry/sentry-go?tab=versions).
## Configuration
To use `sentry-go`, youll need to import the `sentry-go` package and initialize
it with your DSN and other [options](https://godoc.org/github.com/getsentry/sentry-go#ClientOptions).
If not specified in the SDK initialization, the
[DSN](https://docs.sentry.io/error-reporting/configuration/?platform=go#dsn),
[Release](https://docs.sentry.io/workflow/releases/?platform=go) and
[Environment](https://docs.sentry.io/enriching-error-data/environments/?platform=go)
are read from the environment variables `SENTRY_DSN`, `SENTRY_RELEASE` and
`SENTRY_ENVIRONMENT`, respectively.
More on this in the [Configuration](https://docs.sentry.io/platforms/go/config/)
section of the official Sentry documentation.
## Usage
The SDK must be initialized with a call to `sentry.Init`. The default transport
is asynchronous and thus most programs should call `sentry.Flush` to wait until
buffered events are sent to Sentry right before the program terminates.
Typically, `sentry.Init` is called in the beginning of `func main` and
`sentry.Flush` is [deferred](https://golang.org/ref/spec#Defer_statements) right
after.
> Note that if the program terminates with a call to
> [`os.Exit`](https://golang.org/pkg/os/#Exit), either directly or indirectly
> via another function like `log.Fatal`, deferred functions are not run.
>
> In that case, and if it is important for you to report outstanding events
> before terminating the program, arrange for `sentry.Flush` to be called before
> the program terminates.
Example:
```go
// This is an example program that makes an HTTP request and prints response
// headers. Whenever a request fails, the error is reported to Sentry.
//
// Try it by running:
//
// go run main.go
// go run main.go https://sentry.io
// go run main.go bad-url
//
// To actually report events to Sentry, set the DSN either by editing the
// appropriate line below or setting the environment variable SENTRY_DSN to
// match the DSN of your Sentry project.
package main
import (
"fmt"
"log"
"net/http"
"os"
"time"
"github.com/getsentry/sentry-go"
)
func main() {
if len(os.Args) < 2 {
log.Fatalf("usage: %s URL", os.Args[0])
}
err := sentry.Init(sentry.ClientOptions{
// Either set your DSN here or set the SENTRY_DSN environment variable.
Dsn: "",
// Enable printing of SDK debug messages.
// Useful when getting started or trying to figure something out.
Debug: true,
})
if err != nil {
log.Fatalf("sentry.Init: %s", err)
}
// Flush buffered events before the program terminates.
// Set the timeout to the maximum duration the program can afford to wait.
defer sentry.Flush(2 * time.Second)
resp, err := http.Get(os.Args[1])
if err != nil {
sentry.CaptureException(err)
log.Printf("reported to Sentry: %s", err)
return
}
defer resp.Body.Close()
for header, values := range resp.Header {
for _, value := range values {
fmt.Printf("%s=%s\n", header, value)
}
}
}
```
For your convenience, this example is available at
[`example/basic/main.go`](example/basic/main.go).
There are also more examples in the
[example](example) directory.
For more detailed information about how to get the most out of `sentry-go`,
checkout the official documentation:
- [Configuration](https://docs.sentry.io/platforms/go/config)
- [Error Reporting](https://docs.sentry.io/error-reporting/quickstart?platform=go)
- [Enriching Error Data](https://docs.sentry.io/enriching-error-data/context?platform=go)
- [Transports](https://docs.sentry.io/platforms/go/transports)
- [Integrations](https://docs.sentry.io/platforms/go/integrations)
- [net/http](https://docs.sentry.io/platforms/go/http)
- [echo](https://docs.sentry.io/platforms/go/echo)
- [fasthttp](https://docs.sentry.io/platforms/go/fasthttp)
- [gin](https://docs.sentry.io/platforms/go/gin)
- [iris](https://docs.sentry.io/platforms/go/iris)
- [martini](https://docs.sentry.io/platforms/go/martini)
- [negroni](https://docs.sentry.io/platforms/go/negroni)
## Resources
- [Bug Tracker](https://github.com/getsentry/sentry-go/issues)
- [GitHub Project](https://github.com/getsentry/sentry-go)
- [![GoDoc](https://godoc.org/github.com/getsentry/sentry-go?status.svg)](https://godoc.org/github.com/getsentry/sentry-go)
- [![go.dev](https://img.shields.io/badge/go.dev-pkg-007d9c.svg?style=flat)](https://pkg.go.dev/github.com/getsentry/sentry-go)
- [![Documentation](https://img.shields.io/badge/documentation-sentry.io-green.svg)](https://docs.sentry.io/platforms/go/)
- [![Forum](https://img.shields.io/badge/forum-sentry-green.svg)](https://forum.sentry.io/c/sdks)
- [![Discord](https://img.shields.io/discord/621778831602221064)](https://discord.gg/Ww9hbqr)
- [![Stack Overflow](https://img.shields.io/badge/stack%20overflow-sentry-green.svg)](http://stackoverflow.com/questions/tagged/sentry)
- [![Twitter Follow](https://img.shields.io/twitter/follow/getsentry?label=getsentry&style=social)](https://twitter.com/intent/follow?screen_name=getsentry)
## License
Licensed under
[The 2-Clause BSD License](https://opensource.org/licenses/BSD-2-Clause), see
[`LICENSE`](LICENSE).
## Community
Join Sentry's [`#go` channel on Discord](https://discord.gg/Ww9hbqr) to get
involved and help us improve the SDK!

487
vendor/github.com/getsentry/sentry-go/client.go generated vendored Normal file
View File

@ -0,0 +1,487 @@
package sentry
import (
"context"
"crypto/x509"
"fmt"
"io"
"io/ioutil"
"log"
"math/rand"
"net/http"
"os"
"reflect"
"sort"
"time"
)
// maxErrorDepth is the maximum number of errors reported in a chain of errors.
// This protects the SDK from an arbitrarily long chain of wrapped errors.
//
// An additional consideration is that arguably reporting a long chain of errors
// is of little use when debugging production errors with Sentry. The Sentry UI
// is not optimized for long chains either. The top-level error together with a
// stack trace is often the most useful information.
const maxErrorDepth = 10
// usageError is used to report to Sentry an SDK usage error.
//
// It is not exported because it is never returned by any function or method in
// the exported API.
type usageError struct {
error
}
// Logger is an instance of log.Logger that is use to provide debug information about running Sentry Client
// can be enabled by either using `Logger.SetOutput` directly or with `Debug` client option
var Logger = log.New(ioutil.Discard, "[Sentry] ", log.LstdFlags) //nolint: gochecknoglobals
type EventProcessor func(event *Event, hint *EventHint) *Event
type EventModifier interface {
ApplyToEvent(event *Event, hint *EventHint) *Event
}
var globalEventProcessors []EventProcessor //nolint: gochecknoglobals
func AddGlobalEventProcessor(processor EventProcessor) {
globalEventProcessors = append(globalEventProcessors, processor)
}
// Integration allows for registering a functions that modify or discard captured events.
type Integration interface {
Name() string
SetupOnce(client *Client)
}
// ClientOptions that configures a SDK Client
type ClientOptions struct {
// The DSN to use. If the DSN is not set, the client is effectively disabled.
Dsn string
// In debug mode, the debug information is printed to stdout to help you understand what
// sentry is doing.
Debug bool
// Configures whether SDK should generate and attach stacktraces to pure capture message calls.
AttachStacktrace bool
// The sample rate for event submission (0.0 - 1.0, defaults to 1.0).
SampleRate float64
// List of regexp strings that will be used to match against event's message
// and if applicable, caught errors type and value.
// If the match is found, then a whole event will be dropped.
IgnoreErrors []string
// Before send callback.
BeforeSend func(event *Event, hint *EventHint) *Event
// Before breadcrumb add callback.
BeforeBreadcrumb func(breadcrumb *Breadcrumb, hint *BreadcrumbHint) *Breadcrumb
// Integrations to be installed on the current Client, receives default integrations
Integrations func([]Integration) []Integration
// io.Writer implementation that should be used with the `Debug` mode
DebugWriter io.Writer
// The transport to use.
// This is an instance of a struct implementing `Transport` interface.
// Defaults to `httpTransport` from `transport.go`
Transport Transport
// The server name to be reported.
ServerName string
// The release to be sent with events.
Release string
// The dist to be sent with events.
Dist string
// The environment to be sent with events.
Environment string
// Maximum number of breadcrumbs.
MaxBreadcrumbs int
// An optional pointer to `http.Client` that will be used with a default HTTPTransport.
// Using your own client will make HTTPTransport, HTTPProxy, HTTPSProxy and CaCerts options ignored.
HTTPClient *http.Client
// An optional pointer to `http.Transport` that will be used with a default HTTPTransport.
// Using your own transport will make HTTPProxy, HTTPSProxy and CaCerts options ignored.
HTTPTransport http.RoundTripper
// An optional HTTP proxy to use.
// This will default to the `http_proxy` environment variable.
// or `https_proxy` if that one exists.
HTTPProxy string
// An optional HTTPS proxy to use.
// This will default to the `HTTPS_PROXY` environment variable
// or `http_proxy` if that one exists.
HTTPSProxy string
// An optional CaCerts to use.
// Defaults to `gocertifi.CACerts()`.
CaCerts *x509.CertPool
}
// Client is the underlying processor that's used by the main API and `Hub` instances.
type Client struct {
options ClientOptions
dsn *Dsn
eventProcessors []EventProcessor
integrations []Integration
Transport Transport
}
// NewClient creates and returns an instance of `Client` configured using `ClientOptions`.
func NewClient(options ClientOptions) (*Client, error) {
if options.Debug {
debugWriter := options.DebugWriter
if debugWriter == nil {
debugWriter = os.Stdout
}
Logger.SetOutput(debugWriter)
}
if options.Dsn == "" {
options.Dsn = os.Getenv("SENTRY_DSN")
}
if options.Release == "" {
options.Release = os.Getenv("SENTRY_RELEASE")
}
if options.Environment == "" {
options.Environment = os.Getenv("SENTRY_ENVIRONMENT")
}
var dsn *Dsn
if options.Dsn != "" {
var err error
dsn, err = NewDsn(options.Dsn)
if err != nil {
return nil, err
}
}
client := Client{
options: options,
dsn: dsn,
}
client.setupTransport()
client.setupIntegrations()
return &client, nil
}
func (client *Client) setupTransport() {
transport := client.options.Transport
if transport == nil {
if client.options.Dsn == "" {
transport = new(noopTransport)
} else {
transport = NewHTTPTransport()
}
}
transport.Configure(client.options)
client.Transport = transport
}
func (client *Client) setupIntegrations() {
integrations := []Integration{
new(contextifyFramesIntegration),
new(environmentIntegration),
new(modulesIntegration),
new(ignoreErrorsIntegration),
}
if client.options.Integrations != nil {
integrations = client.options.Integrations(integrations)
}
for _, integration := range integrations {
if client.integrationAlreadyInstalled(integration.Name()) {
Logger.Printf("Integration %s is already installed\n", integration.Name())
continue
}
client.integrations = append(client.integrations, integration)
integration.SetupOnce(client)
Logger.Printf("Integration installed: %s\n", integration.Name())
}
}
// AddEventProcessor adds an event processor to the client.
func (client *Client) AddEventProcessor(processor EventProcessor) {
client.eventProcessors = append(client.eventProcessors, processor)
}
// Options return `ClientOptions` for the current `Client`.
func (client Client) Options() ClientOptions {
return client.options
}
// CaptureMessage captures an arbitrary message.
func (client *Client) CaptureMessage(message string, hint *EventHint, scope EventModifier) *EventID {
event := client.eventFromMessage(message, LevelInfo)
return client.CaptureEvent(event, hint, scope)
}
// CaptureException captures an error.
func (client *Client) CaptureException(exception error, hint *EventHint, scope EventModifier) *EventID {
event := client.eventFromException(exception, LevelError)
return client.CaptureEvent(event, hint, scope)
}
// CaptureEvent captures an event on the currently active client if any.
//
// The event must already be assembled. Typically code would instead use
// the utility methods like `CaptureException`. The return value is the
// event ID. In case Sentry is disabled or event was dropped, the return value will be nil.
func (client *Client) CaptureEvent(event *Event, hint *EventHint, scope EventModifier) *EventID {
return client.processEvent(event, hint, scope)
}
// Recover captures a panic.
// Returns `EventID` if successfully, or `nil` if there's no error to recover from.
func (client *Client) Recover(err interface{}, hint *EventHint, scope EventModifier) *EventID {
if err == nil {
err = recover()
}
if err != nil {
if err, ok := err.(error); ok {
event := client.eventFromException(err, LevelFatal)
return client.CaptureEvent(event, hint, scope)
}
if err, ok := err.(string); ok {
event := client.eventFromMessage(err, LevelFatal)
return client.CaptureEvent(event, hint, scope)
}
}
return nil
}
// Recover captures a panic and passes relevant context object.
// Returns `EventID` if successfully, or `nil` if there's no error to recover from.
func (client *Client) RecoverWithContext(
ctx context.Context,
err interface{},
hint *EventHint,
scope EventModifier,
) *EventID {
if err == nil {
err = recover()
}
if err != nil {
if hint.Context == nil && ctx != nil {
hint.Context = ctx
}
if err, ok := err.(error); ok {
event := client.eventFromException(err, LevelFatal)
return client.CaptureEvent(event, hint, scope)
}
if err, ok := err.(string); ok {
event := client.eventFromMessage(err, LevelFatal)
return client.CaptureEvent(event, hint, scope)
}
}
return nil
}
// Flush waits until the underlying Transport sends any buffered events to the
// Sentry server, blocking for at most the given timeout. It returns false if
// the timeout was reached. In that case, some events may not have been sent.
//
// Flush should be called before terminating the program to avoid
// unintentionally dropping events.
//
// Do not call Flush indiscriminately after every call to CaptureEvent,
// CaptureException or CaptureMessage. Instead, to have the SDK send events over
// the network synchronously, configure it to use the HTTPSyncTransport in the
// call to Init.
func (client *Client) Flush(timeout time.Duration) bool {
return client.Transport.Flush(timeout)
}
func (client *Client) eventFromMessage(message string, level Level) *Event {
event := NewEvent()
event.Level = level
event.Message = message
if client.Options().AttachStacktrace {
event.Threads = []Thread{{
Stacktrace: NewStacktrace(),
Crashed: false,
Current: true,
}}
}
return event
}
func (client *Client) eventFromException(exception error, level Level) *Event {
err := exception
if err == nil {
err = usageError{fmt.Errorf("%s called with nil error", callerFunctionName())}
}
event := NewEvent()
event.Level = level
for i := 0; i < maxErrorDepth && err != nil; i++ {
event.Exception = append(event.Exception, Exception{
Value: err.Error(),
Type: reflect.TypeOf(err).String(),
Stacktrace: ExtractStacktrace(err),
})
switch previous := err.(type) {
case interface{ Unwrap() error }:
err = previous.Unwrap()
case interface{ Cause() error }:
err = previous.Cause()
default:
err = nil
}
}
// Add a trace of the current stack to the most recent error in a chain if
// it doesn't have a stack trace yet.
// We only add to the most recent error to avoid duplication and because the
// current stack is most likely unrelated to errors deeper in the chain.
if event.Exception[0].Stacktrace == nil {
event.Exception[0].Stacktrace = NewStacktrace()
}
// event.Exception should be sorted such that the most recent error is last.
reverse(event.Exception)
return event
}
// reverse reverses the slice a in place.
func reverse(a []Exception) {
for i := len(a)/2 - 1; i >= 0; i-- {
opp := len(a) - 1 - i
a[i], a[opp] = a[opp], a[i]
}
}
func (client *Client) processEvent(event *Event, hint *EventHint, scope EventModifier) *EventID {
options := client.Options()
// TODO: Reconsider if its worth going away from default implementation
// of other SDKs. In Go zero value (default) for float32 is 0.0,
// which means that if someone uses ClientOptions{} struct directly
// and we would not check for 0 here, we'd skip all events by default
if options.SampleRate != 0.0 {
randomFloat := rand.New(rand.NewSource(time.Now().UnixNano())).Float64()
if randomFloat > options.SampleRate {
Logger.Println("Event dropped due to SampleRate hit.")
return nil
}
}
if event = client.prepareEvent(event, hint, scope); event == nil {
return nil
}
if options.BeforeSend != nil {
h := &EventHint{}
if hint != nil {
h = hint
}
if event = options.BeforeSend(event, h); event == nil {
Logger.Println("Event dropped due to BeforeSend callback.")
return nil
}
}
client.Transport.SendEvent(event)
return &event.EventID
}
func (client *Client) prepareEvent(event *Event, hint *EventHint, scope EventModifier) *Event {
if event.EventID == "" {
event.EventID = EventID(uuid())
}
if event.Timestamp.IsZero() {
event.Timestamp = time.Now().UTC()
}
if event.Level == "" {
event.Level = LevelInfo
}
if event.ServerName == "" {
if client.Options().ServerName != "" {
event.ServerName = client.Options().ServerName
} else if hostname, err := os.Hostname(); err == nil {
event.ServerName = hostname
}
}
if event.Release == "" && client.Options().Release != "" {
event.Release = client.Options().Release
}
if event.Dist == "" && client.Options().Dist != "" {
event.Dist = client.Options().Dist
}
if event.Environment == "" && client.Options().Environment != "" {
event.Environment = client.Options().Environment
}
event.Platform = "go"
event.Sdk = SdkInfo{
Name: "sentry.go",
Version: Version,
Integrations: client.listIntegrations(),
Packages: []SdkPackage{{
Name: "sentry-go",
Version: Version,
}},
}
if scope != nil {
event = scope.ApplyToEvent(event, hint)
if event == nil {
return nil
}
}
for _, processor := range client.eventProcessors {
id := event.EventID
event = processor(event, hint)
if event == nil {
Logger.Printf("Event dropped by one of the Client EventProcessors: %s\n", id)
return nil
}
}
for _, processor := range globalEventProcessors {
id := event.EventID
event = processor(event, hint)
if event == nil {
Logger.Printf("Event dropped by one of the Global EventProcessors: %s\n", id)
return nil
}
}
return event
}
func (client Client) listIntegrations() []string {
integrations := make([]string, 0, len(client.integrations))
for _, integration := range client.integrations {
integrations = append(integrations, integration.Name())
}
sort.Strings(integrations)
return integrations
}
func (client Client) integrationAlreadyInstalled(name string) bool {
for _, integration := range client.integrations {
if integration.Name() == name {
return true
}
}
return false
}

188
vendor/github.com/getsentry/sentry-go/dsn.go generated vendored Normal file
View File

@ -0,0 +1,188 @@
package sentry
import (
"encoding/json"
"fmt"
"net/url"
"strconv"
"strings"
"time"
)
type scheme string
const (
schemeHTTP scheme = "http"
schemeHTTPS scheme = "https"
)
func (scheme scheme) defaultPort() int {
switch scheme {
case schemeHTTPS:
return 443
case schemeHTTP:
return 80
default:
return 80
}
}
type DsnParseError struct {
Message string
}
func (e DsnParseError) Error() string {
return "[Sentry] DsnParseError: " + e.Message
}
// Dsn is used as the remote address source to client transport.
type Dsn struct {
scheme scheme
publicKey string
secretKey string
host string
port int
path string
projectID int
}
// NewDsn creates an instance of `Dsn` by parsing provided url in a `string` format.
// If Dsn is not set the client is effectively disabled.
func NewDsn(rawURL string) (*Dsn, error) {
// Parse
parsedURL, err := url.Parse(rawURL)
if err != nil {
return nil, &DsnParseError{fmt.Sprintf("invalid url: %v", err)}
}
// Scheme
var scheme scheme
switch parsedURL.Scheme {
case "http":
scheme = schemeHTTP
case "https":
scheme = schemeHTTPS
default:
return nil, &DsnParseError{"invalid scheme"}
}
// PublicKey
publicKey := parsedURL.User.Username()
if publicKey == "" {
return nil, &DsnParseError{"empty username"}
}
// SecretKey
var secretKey string
if parsedSecretKey, ok := parsedURL.User.Password(); ok {
secretKey = parsedSecretKey
}
// Host
host := parsedURL.Hostname()
if host == "" {
return nil, &DsnParseError{"empty host"}
}
// Port
var port int
if parsedURL.Port() != "" {
parsedPort, err := strconv.Atoi(parsedURL.Port())
if err != nil {
return nil, &DsnParseError{"invalid port"}
}
port = parsedPort
} else {
port = scheme.defaultPort()
}
// ProjectID
if len(parsedURL.Path) == 0 || parsedURL.Path == "/" {
return nil, &DsnParseError{"empty project id"}
}
pathSegments := strings.Split(parsedURL.Path[1:], "/")
projectID, err := strconv.Atoi(pathSegments[len(pathSegments)-1])
if err != nil {
return nil, &DsnParseError{"invalid project id"}
}
// Path
var path string
if len(pathSegments) > 1 {
path = "/" + strings.Join(pathSegments[0:len(pathSegments)-1], "/")
}
return &Dsn{
scheme: scheme,
publicKey: publicKey,
secretKey: secretKey,
host: host,
port: port,
path: path,
projectID: projectID,
}, nil
}
// String formats Dsn struct into a valid string url
func (dsn Dsn) String() string {
var url string
url += fmt.Sprintf("%s://%s", dsn.scheme, dsn.publicKey)
if dsn.secretKey != "" {
url += fmt.Sprintf(":%s", dsn.secretKey)
}
url += fmt.Sprintf("@%s", dsn.host)
if dsn.port != dsn.scheme.defaultPort() {
url += fmt.Sprintf(":%d", dsn.port)
}
if dsn.path != "" {
url += dsn.path
}
url += fmt.Sprintf("/%d", dsn.projectID)
return url
}
// StoreAPIURL returns assembled url to be used in the transport.
// It points to configures Sentry instance.
func (dsn Dsn) StoreAPIURL() *url.URL {
var rawURL string
rawURL += fmt.Sprintf("%s://%s", dsn.scheme, dsn.host)
if dsn.port != dsn.scheme.defaultPort() {
rawURL += fmt.Sprintf(":%d", dsn.port)
}
if dsn.path != "" {
rawURL += dsn.path
}
rawURL += fmt.Sprintf("/api/%d/store/", dsn.projectID)
parsedURL, _ := url.Parse(rawURL)
return parsedURL
}
// RequestHeaders returns all the necessary headers that have to be used in the transport.
func (dsn Dsn) RequestHeaders() map[string]string {
auth := fmt.Sprintf("Sentry sentry_version=%s, sentry_timestamp=%d, "+
"sentry_client=sentry.go/%s, sentry_key=%s", apiVersion, time.Now().Unix(), Version, dsn.publicKey)
if dsn.secretKey != "" {
auth = fmt.Sprintf("%s, sentry_secret=%s", auth, dsn.secretKey)
}
return map[string]string{
"Content-Type": "application/json",
"X-Sentry-Auth": auth,
}
}
func (dsn Dsn) MarshalJSON() ([]byte, error) {
return json.Marshal(dsn.String())
}
func (dsn *Dsn) UnmarshalJSON(data []byte) error {
var str string
_ = json.Unmarshal(data, &str)
newDsn, err := NewDsn(str)
if err != nil {
return err
}
*dsn = *newDsn
return nil
}

135
vendor/github.com/getsentry/sentry-go/echo/README.md generated vendored Normal file
View File

@ -0,0 +1,135 @@
<p align="center">
<a href="https://sentry.io" target="_blank" align="center">
<img src="https://sentry-brand.storage.googleapis.com/sentry-logo-black.png" width="280">
</a>
<br />
</p>
# Official Sentry Echo Handler for Sentry-go SDK
**Godoc:** https://godoc.org/github.com/getsentry/sentry-go/echo
**Example:** https://github.com/getsentry/sentry-go/tree/master/example/echo
## Installation
```sh
go get github.com/getsentry/sentry-go/echo
```
```go
import (
"fmt"
"net/http"
"github.com/getsentry/sentry-go"
sentryecho "github.com/getsentry/sentry-go/echo"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
// To initialize Sentry's handler, you need to initialize Sentry itself beforehand
if err := sentry.Init(sentry.ClientOptions{
Dsn: "your-public-dsn",
}); err != nil {
fmt.Printf("Sentry initialization failed: %v\n", err)
}
// Then create your app
app := echo.New()
app.Use(middleware.Logger())
app.Use(middleware.Recover())
// Once it's done, you can attach the handler as one of your middleware
app.Use(sentryecho.New(sentryecho.Options{}))
// Set up routes
app.GET("/", func(ctx echo.Context) error {
return ctx.String(http.StatusOK, "Hello, World!")
})
// And run it
app.Logger.Fatal(app.Start(":3000"))
```
## Configuration
`sentryecho` accepts a struct of `Options` that allows you to configure how the handler will behave.
Currently it respects 3 options:
```go
// Repanic configures whether Sentry should repanic after recovery, in most cases it should be set to true,
// as echo includes its own Recover middleware that handles http responses.
Repanic bool
// WaitForDelivery configures whether you want to block the request before moving forward with the response.
// Because Echo's `Recover` handler doesn't restart the application,
// it's safe to either skip this option or set it to `false`.
WaitForDelivery bool
// Timeout for the event delivery requests.
Timeout time.Duration
```
## Usage
`sentryecho` attaches an instance of `*sentry.Hub` (https://godoc.org/github.com/getsentry/sentry-go#Hub) to the `echo.Context`, which makes it available throughout the rest of the request's lifetime.
You can access it by using the `sentryecho.GetHubFromContext()` method on the context itself in any of your proceeding middleware and routes.
And it should be used instead of the global `sentry.CaptureMessage`, `sentry.CaptureException`, or any other calls, as it keeps the separation of data between the requests.
**Keep in mind that `*sentry.Hub` won't be available in middleware attached before to `sentryecho`!**
```go
app := echo.New()
app.Use(middleware.Logger())
app.Use(middleware.Recover())
app.Use(sentryecho.New(sentryecho.Options{
Repanic: true,
}))
app.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
return func(ctx echo.Context) error {
if hub := sentryecho.GetHubFromContext(ctx); hub != nil {
hub.Scope().SetTag("someRandomTag", "maybeYouNeedIt")
}
return next(ctx)
}
})
app.GET("/", func(ctx echo.Context) error {
if hub := sentryecho.GetHubFromContext(ctx); hub != nil {
hub.WithScope(func(scope *sentry.Scope) {
scope.SetExtra("unwantedQuery", "someQueryDataMaybe")
hub.CaptureMessage("User provided unwanted query string, but we recovered just fine")
})
}
return ctx.String(http.StatusOK, "Hello, World!")
})
app.GET("/foo", func(ctx echo.Context) error {
// sentryecho handler will catch it just fine. Also, because we attached "someRandomTag"
// in the middleware before, it will be sent through as well
panic("y tho")
})
app.Logger.Fatal(app.Start(":3000"))
```
### Accessing Request in `BeforeSend` callback
```go
sentry.Init(sentry.ClientOptions{
Dsn: "your-public-dsn",
BeforeSend: func(event *sentry.Event, hint *sentry.EventHint) *sentry.Event {
if hint.Context != nil {
if req, ok := hint.Context.Value(sentry.RequestContextKey).(*http.Request); ok {
// You have access to the original Request here
}
}
return event
},
})
```

View File

@ -0,0 +1,87 @@
package sentryecho
import (
"context"
"net/http"
"time"
"github.com/getsentry/sentry-go"
"github.com/labstack/echo/v4"
)
const valuesKey = "sentry"
type handler struct {
repanic bool
waitForDelivery bool
timeout time.Duration
}
type Options struct {
// Repanic configures whether Sentry should repanic after recovery, in most cases it should be set to true,
// as echo includes it's own Recover middleware what handles http responses.
Repanic bool
// WaitForDelivery configures whether you want to block the request before moving forward with the response.
// Because Echo's `Recover` handler doesn't restart the application,
// it's safe to either skip this option or set it to `false`.
WaitForDelivery bool
// Timeout for the event delivery requests.
Timeout time.Duration
}
// New returns a function that satisfies echo.HandlerFunc interface
// It can be used with Use() methods.
func New(options Options) echo.MiddlewareFunc {
handler := handler{
repanic: false,
timeout: time.Second * 2,
waitForDelivery: false,
}
if options.Repanic {
handler.repanic = true
}
if options.Timeout != 0 {
handler.timeout = options.Timeout
}
if options.WaitForDelivery {
handler.waitForDelivery = true
}
return handler.handle
}
func (h *handler) handle(next echo.HandlerFunc) echo.HandlerFunc {
return func(ctx echo.Context) error {
hub := sentry.CurrentHub().Clone()
hub.Scope().SetRequest(ctx.Request())
ctx.Set(valuesKey, hub)
defer h.recoverWithSentry(hub, ctx.Request())
return next(ctx)
}
}
func (h *handler) recoverWithSentry(hub *sentry.Hub, r *http.Request) {
if err := recover(); err != nil {
eventID := hub.RecoverWithContext(
context.WithValue(r.Context(), sentry.RequestContextKey, r),
err,
)
if eventID != nil && h.waitForDelivery {
hub.Flush(h.timeout)
}
if h.repanic {
panic(err)
}
}
}
// GetHubFromContext retrieves attached *sentry.Hub instance from echo.Context.
func GetHubFromContext(ctx echo.Context) *sentry.Hub {
if hub, ok := ctx.Get(valuesKey).(*sentry.Hub); ok {
return hub
}
return nil
}

35
vendor/github.com/getsentry/sentry-go/go.mod generated vendored Normal file
View File

@ -0,0 +1,35 @@
module github.com/getsentry/sentry-go
go 1.12
require (
github.com/ajg/form v1.5.1 // indirect
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072 // indirect
github.com/gin-gonic/gin v1.4.0
github.com/go-errors/errors v1.0.1
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab
github.com/google/go-cmp v0.4.0
github.com/google/go-querystring v1.0.0 // indirect
github.com/imkira/go-interpol v1.1.0 // indirect
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect
github.com/kataras/iris/v12 v12.0.1
github.com/labstack/echo/v4 v4.1.11
github.com/moul/http2curl v1.0.0 // indirect
github.com/onsi/ginkgo v1.10.3 // indirect
github.com/onsi/gomega v1.7.1 // indirect
github.com/pingcap/errors v0.11.4
github.com/pkg/errors v0.8.1
github.com/sergi/go-diff v1.0.0 // indirect
github.com/smartystreets/goconvey v1.6.4 // indirect
github.com/ugorji/go v1.1.7 // indirect
github.com/urfave/negroni v1.0.0
github.com/valyala/fasthttp v1.6.0
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 // indirect
github.com/yudai/gojsondiff v1.0.0 // indirect
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect
github.com/yudai/pp v2.0.1+incompatible // indirect
)
replace github.com/ugorji/go v1.1.4 => github.com/ugorji/go/codec v0.0.0-20190204201341-e444a5086c43

250
vendor/github.com/getsentry/sentry-go/go.sum generated vendored Normal file
View File

@ -0,0 +1,250 @@
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a h1:3SgJcK9l5uPdBC/X17wanyJAMxM33+4ZhEIV96MIH8U=
github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw=
github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible h1:rZgFj+Gtf3NMi/U5FvCvhzaxzW/TaPYgUYx3bAPz9DE=
github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w=
github.com/Joker/hpp v1.0.0 h1:65+iuJYdRXv/XyN62C1uEmmOx3432rNG/rKlX6V7Kkc=
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7 h1:mreN1m/5VJ/Zc3b4pzj9qU6D9SRQ6Vm+3KfI328t3S8=
github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM=
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398 h1:WDC6ySpJzbxGWFh4aMxFFC28wwGp5pEuoTtvA4q/qQ4=
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible h1:Ppm0npCCsmuR9oQaBtRuZcmILVE74aXE+AmrJj8L2ns=
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q=
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o=
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072 h1:DddqAaWDpywytcG8w/qoQ5sAN8X12d3Z3koB0C3Rxsc=
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4 h1:GY1+t5Dr9OKADM64SYnQjw/w99HMYvQ0A8/JoUkxVmc=
github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gavv/httpexpect v2.0.0+incompatible h1:1X9kcRshkSKEjNJJxX9Y9mQ5BRfbxU5kORdjhlA1yX8=
github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 h1:t8FVkw33L+wilf2QiWkw0UV77qRpcH/JHPKGpKa2E8g=
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
github.com/gin-gonic/gin v1.4.0 h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ=
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJYCFOLkIBwI7xFExG03bbkOkCvUPI=
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab h1:xveKWz2iaueeTaUgdetzel+U7exyigDYBryyVfV/rZk=
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk=
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/iris-contrib/blackfriday v2.0.0+incompatible h1:o5sHQHHm0ToHUlAJSTjW9UWicjJSDDauOOQ2AHuIVp4=
github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI=
github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0=
github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI=
github.com/iris-contrib/schema v0.0.1 h1:10g/WnoRR+U+XXHWKBHeNy/+tZmM2kcAVGLOsz+yaDA=
github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5 h1:rhqTjzJlm7EbkELJDKMTU7udov+Se0xZkWmugr6zGok=
github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
github.com/juju/loggo v0.0.0-20180524022052-584905176618 h1:MK144iBQF9hTSwBW/9eJm034bVoG30IshVm688T2hi8=
github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073 h1:WQM1NildKThwdP7qWrNAFGzp4ijNLw8RlgENkaI4MJs=
github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA=
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM=
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
github.com/kataras/golog v0.0.9 h1:J7Dl82843nbKQDrQM/abbNJZvQjS6PfmkkffhOTXEpM=
github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk=
github.com/kataras/iris/v12 v12.0.1 h1:Wo5S7GMWv5OAzJmvFTvss/C4TS1W0uo6LkDlSymT4rM=
github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U=
github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw=
github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d h1:V5Rs9ztEWdp58oayPq/ulmlqJJZeJP6pP79uP3qjcao=
github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0=
github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.9.0 h1:GhthINjveNZAdFUD8QoQYfjxnOONZgztK/Yr6M23UTY=
github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/labstack/echo/v4 v4.1.11 h1:z0BZoArY4FqdpUEl+wlHp4hnr/oSR6MTmQmv8OHSoww=
github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g=
github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg=
github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ=
github.com/microcosm-cc/bluemonday v1.0.2 h1:5lPfLTTAvAbtS0VqT+94yOtFnGfUWYyx0+iToC3Os3s=
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs=
github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM=
github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY=
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/ryanuber/columnize v2.1.0+incompatible h1:j1Wcmh8OrK4Q7GXY+V7SVSY8nUWQxHW5TkBe7YUl+2s=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/ugorji/go v1.1.2/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8 h1:3SVOIvH7Ae1KRYyQWRjXWJEA9sS/c/pjvH++55Gr648=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/ugorji/go/codec v0.0.0-20190204201341-e444a5086c43 h1:BasDe+IErOQKrMVXab7UayvSlIpiyGwRvuX3EKYY7UA=
github.com/ugorji/go/codec v0.0.0-20190204201341-e444a5086c43/go.mod h1:iT03XoTwV7xq/+UGwKO3UbC1nNNlopQiY61beSdrtOA=
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc=
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.6.0 h1:uWF8lgKmeaIewWVPwi4GRq2P6+R46IgYZdxWtM+GtEY=
github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY=
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M=
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
github.com/yudai/pp v2.0.1+incompatible h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI=
github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce h1:xcEWjVhvbDy+nHP67nPDDpbYrY+ILlfndk4bRioVHaU=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

364
vendor/github.com/getsentry/sentry-go/hub.go generated vendored Normal file
View File

@ -0,0 +1,364 @@
package sentry
import (
"context"
"sync"
"time"
)
type contextKey int
// HubContextKey is a context key used to store Hub on any context.Context type
const HubContextKey = contextKey(1)
// RequestContextKey is a context key used to store http.Request on the context passed to RecoverWithContext
const RequestContextKey = contextKey(2)
// Default maximum number of breadcrumbs added to an event. Can be overwritten `maxBreadcrumbs` option.
const defaultMaxBreadcrumbs = 30
// Absolute maximum number of breadcrumbs added to an event.
// The `maxBreadcrumbs` option cannot be higher than this value.
const maxBreadcrumbs = 100
// Initial instance of the Hub that has no `Client` bound and an empty `Scope`
var currentHub = NewHub(nil, NewScope()) //nolint: gochecknoglobals
// Hub is the central object that manages scopes and clients.
//
// This can be used to capture events and manage the scope.
// The default hub that is available automatically.
//
// In most situations developers do not need to interface the hub. Instead
// toplevel convenience functions are exposed that will automatically dispatch
// to global (`CurrentHub`) hub. In some situations this might not be
// possible in which case it might become necessary to manually work with the
// hub. This is for instance the case when working with async code.
type Hub struct {
mu sync.RWMutex
stack *stack
lastEventID EventID
}
type layer struct {
// mu protects concurrent reads and writes to client.
mu sync.RWMutex
client *Client
// scope is read-only, not protected by mu.
scope *Scope
}
// Client returns the layer's client. Safe for concurrent use.
func (l *layer) Client() *Client {
l.mu.RLock()
defer l.mu.RUnlock()
return l.client
}
// SetClient sets the layer's client. Safe for concurrent use.
func (l *layer) SetClient(c *Client) {
l.mu.Lock()
defer l.mu.Unlock()
l.client = c
}
type stack []*layer
// NewHub returns an instance of a `Hub` with provided `Client` and `Scope` bound.
func NewHub(client *Client, scope *Scope) *Hub {
hub := Hub{
stack: &stack{{
client: client,
scope: scope,
}},
}
return &hub
}
// CurrentHub returns an instance of previously initialized `Hub` stored in the global namespace.
func CurrentHub() *Hub {
return currentHub
}
// LastEventID returns an ID of last captured event for the current `Hub`.
func (hub *Hub) LastEventID() EventID {
return hub.lastEventID
}
func (hub *Hub) stackTop() *layer {
hub.mu.RLock()
defer hub.mu.RUnlock()
stack := hub.stack
if stack == nil {
return nil
}
stackLen := len(*stack)
if stackLen == 0 {
return nil
}
top := (*stack)[stackLen-1]
return top
}
// Clone returns a copy of the current Hub with top-most scope and client copied over.
func (hub *Hub) Clone() *Hub {
top := hub.stackTop()
if top == nil {
return nil
}
scope := top.scope
if scope != nil {
scope = scope.Clone()
}
return NewHub(top.Client(), scope)
}
// Scope returns top-level `Scope` of the current `Hub` or `nil` if no `Scope` is bound.
func (hub *Hub) Scope() *Scope {
top := hub.stackTop()
if top == nil {
return nil
}
return top.scope
}
// Scope returns top-level `Client` of the current `Hub` or `nil` if no `Client` is bound.
func (hub *Hub) Client() *Client {
top := hub.stackTop()
if top == nil {
return nil
}
return top.Client()
}
// PushScope pushes a new scope for the current `Hub` and reuses previously bound `Client`.
func (hub *Hub) PushScope() *Scope {
top := hub.stackTop()
var client *Client
if top != nil {
client = top.Client()
}
var scope *Scope
if top != nil && top.scope != nil {
scope = top.scope.Clone()
} else {
scope = NewScope()
}
hub.mu.Lock()
defer hub.mu.Unlock()
*hub.stack = append(*hub.stack, &layer{
client: client,
scope: scope,
})
return scope
}
// PushScope pops the most recent scope for the current `Hub`.
func (hub *Hub) PopScope() {
hub.mu.Lock()
defer hub.mu.Unlock()
stack := *hub.stack
stackLen := len(stack)
if stackLen > 0 {
*hub.stack = stack[0 : stackLen-1]
}
}
// BindClient binds a new `Client` for the current `Hub`.
func (hub *Hub) BindClient(client *Client) {
top := hub.stackTop()
if top != nil {
top.SetClient(client)
}
}
// WithScope temporarily pushes a scope for a single call.
//
// A shorthand for:
// PushScope()
// f(scope)
// PopScope()
func (hub *Hub) WithScope(f func(scope *Scope)) {
scope := hub.PushScope()
defer hub.PopScope()
f(scope)
}
// ConfigureScope invokes a function that can modify the current scope.
//
// The function is passed a mutable reference to the `Scope` so that modifications
// can be performed.
func (hub *Hub) ConfigureScope(f func(scope *Scope)) {
scope := hub.Scope()
f(scope)
}
// CaptureEvent calls the method of a same name on currently bound `Client` instance
// passing it a top-level `Scope`.
// Returns `EventID` if successfully, or `nil` if there's no `Scope` or `Client` available.
func (hub *Hub) CaptureEvent(event *Event) *EventID {
client, scope := hub.Client(), hub.Scope()
if client == nil || scope == nil {
return nil
}
eventID := client.CaptureEvent(event, nil, scope)
if eventID != nil {
hub.lastEventID = *eventID
} else {
hub.lastEventID = ""
}
return eventID
}
// CaptureMessage calls the method of a same name on currently bound `Client` instance
// passing it a top-level `Scope`.
// Returns `EventID` if successfully, or `nil` if there's no `Scope` or `Client` available.
func (hub *Hub) CaptureMessage(message string) *EventID {
client, scope := hub.Client(), hub.Scope()
if client == nil || scope == nil {
return nil
}
eventID := client.CaptureMessage(message, nil, scope)
if eventID != nil {
hub.lastEventID = *eventID
} else {
hub.lastEventID = ""
}
return eventID
}
// CaptureException calls the method of a same name on currently bound `Client` instance
// passing it a top-level `Scope`.
// Returns `EventID` if successfully, or `nil` if there's no `Scope` or `Client` available.
func (hub *Hub) CaptureException(exception error) *EventID {
client, scope := hub.Client(), hub.Scope()
if client == nil || scope == nil {
return nil
}
eventID := client.CaptureException(exception, &EventHint{OriginalException: exception}, scope)
if eventID != nil {
hub.lastEventID = *eventID
} else {
hub.lastEventID = ""
}
return eventID
}
// AddBreadcrumb records a new breadcrumb.
//
// The total number of breadcrumbs that can be recorded are limited by the
// configuration on the client.
func (hub *Hub) AddBreadcrumb(breadcrumb *Breadcrumb, hint *BreadcrumbHint) {
client := hub.Client()
// If there's no client, just store it on the scope straight away
if client == nil {
hub.Scope().AddBreadcrumb(breadcrumb, maxBreadcrumbs)
return
}
options := client.Options()
max := defaultMaxBreadcrumbs
if options.MaxBreadcrumbs != 0 {
max = options.MaxBreadcrumbs
}
if max < 0 {
return
}
if options.BeforeBreadcrumb != nil {
h := &BreadcrumbHint{}
if hint != nil {
h = hint
}
if breadcrumb = options.BeforeBreadcrumb(breadcrumb, h); breadcrumb == nil {
Logger.Println("breadcrumb dropped due to BeforeBreadcrumb callback.")
return
}
}
if max > maxBreadcrumbs {
max = maxBreadcrumbs
}
hub.Scope().AddBreadcrumb(breadcrumb, max)
}
// Recover calls the method of a same name on currently bound `Client` instance
// passing it a top-level `Scope`.
// Returns `EventID` if successfully, or `nil` if there's no `Scope` or `Client` available.
func (hub *Hub) Recover(err interface{}) *EventID {
if err == nil {
err = recover()
}
client, scope := hub.Client(), hub.Scope()
if client == nil || scope == nil {
return nil
}
return client.Recover(err, &EventHint{RecoveredException: err}, scope)
}
// RecoverWithContext calls the method of a same name on currently bound `Client` instance
// passing it a top-level `Scope`.
// Returns `EventID` if successfully, or `nil` if there's no `Scope` or `Client` available.
func (hub *Hub) RecoverWithContext(ctx context.Context, err interface{}) *EventID {
if err == nil {
err = recover()
}
client, scope := hub.Client(), hub.Scope()
if client == nil || scope == nil {
return nil
}
return client.RecoverWithContext(ctx, err, &EventHint{RecoveredException: err}, scope)
}
// Flush waits until the underlying Transport sends any buffered events to the
// Sentry server, blocking for at most the given timeout. It returns false if
// the timeout was reached. In that case, some events may not have been sent.
//
// Flush should be called before terminating the program to avoid
// unintentionally dropping events.
//
// Do not call Flush indiscriminately after every call to CaptureEvent,
// CaptureException or CaptureMessage. Instead, to have the SDK send events over
// the network synchronously, configure it to use the HTTPSyncTransport in the
// call to Init.
func (hub *Hub) Flush(timeout time.Duration) bool {
client := hub.Client()
if client == nil {
return false
}
return client.Flush(timeout)
}
// HasHubOnContext checks whether `Hub` instance is bound to a given `Context` struct.
func HasHubOnContext(ctx context.Context) bool {
_, ok := ctx.Value(HubContextKey).(*Hub)
return ok
}
// GetHubFromContext tries to retrieve `Hub` instance from the given `Context` struct
// or return `nil` if one is not found.
func GetHubFromContext(ctx context.Context) *Hub {
if hub, ok := ctx.Value(HubContextKey).(*Hub); ok {
return hub
}
return nil
}
// SetHubOnContext stores given `Hub` instance on the `Context` struct and returns a new `Context`.
func SetHubOnContext(ctx context.Context, hub *Hub) context.Context {
return context.WithValue(ctx, HubContextKey, hub)
}

271
vendor/github.com/getsentry/sentry-go/integrations.go generated vendored Normal file
View File

@ -0,0 +1,271 @@
package sentry
import (
"fmt"
"regexp"
"runtime"
"runtime/debug"
"strings"
"sync"
)
// ================================
// Modules Integration
// ================================
type modulesIntegration struct {
once sync.Once
modules map[string]string
}
func (mi *modulesIntegration) Name() string {
return "Modules"
}
func (mi *modulesIntegration) SetupOnce(client *Client) {
client.AddEventProcessor(mi.processor)
}
func (mi *modulesIntegration) processor(event *Event, hint *EventHint) *Event {
if len(event.Modules) == 0 {
mi.once.Do(func() {
info, ok := debug.ReadBuildInfo()
if !ok {
Logger.Print("The Modules integration is not available in binaries built without module support.")
return
}
mi.modules = extractModules(info)
})
}
event.Modules = mi.modules
return event
}
func extractModules(info *debug.BuildInfo) map[string]string {
modules := map[string]string{
info.Main.Path: info.Main.Version,
}
for _, dep := range info.Deps {
ver := dep.Version
if dep.Replace != nil {
ver += fmt.Sprintf(" => %s %s", dep.Replace.Path, dep.Replace.Version)
}
modules[dep.Path] = strings.TrimSuffix(ver, " ")
}
return modules
}
// ================================
// Environment Integration
// ================================
type environmentIntegration struct{}
func (ei *environmentIntegration) Name() string {
return "Environment"
}
func (ei *environmentIntegration) SetupOnce(client *Client) {
client.AddEventProcessor(ei.processor)
}
func (ei *environmentIntegration) processor(event *Event, hint *EventHint) *Event {
if event.Contexts == nil {
event.Contexts = make(map[string]interface{})
}
event.Contexts["device"] = map[string]interface{}{
"arch": runtime.GOARCH,
"num_cpu": runtime.NumCPU(),
}
event.Contexts["os"] = map[string]interface{}{
"name": runtime.GOOS,
}
event.Contexts["runtime"] = map[string]interface{}{
"name": "go",
"version": runtime.Version(),
"go_numroutines": runtime.NumGoroutine(),
"go_maxprocs": runtime.GOMAXPROCS(0),
"go_numcgocalls": runtime.NumCgoCall(),
}
return event
}
// ================================
// Ignore Errors Integration
// ================================
type ignoreErrorsIntegration struct {
ignoreErrors []*regexp.Regexp
}
func (iei *ignoreErrorsIntegration) Name() string {
return "IgnoreErrors"
}
func (iei *ignoreErrorsIntegration) SetupOnce(client *Client) {
iei.ignoreErrors = transformStringsIntoRegexps(client.Options().IgnoreErrors)
client.AddEventProcessor(iei.processor)
}
func (iei *ignoreErrorsIntegration) processor(event *Event, hint *EventHint) *Event {
suspects := getIgnoreErrorsSuspects(event)
for _, suspect := range suspects {
for _, pattern := range iei.ignoreErrors {
if pattern.Match([]byte(suspect)) {
Logger.Printf("Event dropped due to being matched by `IgnoreErrors` option."+
"| Value matched: %s | Filter used: %s", suspect, pattern)
return nil
}
}
}
return event
}
func transformStringsIntoRegexps(strings []string) []*regexp.Regexp {
var exprs []*regexp.Regexp
for _, s := range strings {
r, err := regexp.Compile(s)
if err == nil {
exprs = append(exprs, r)
}
}
return exprs
}
func getIgnoreErrorsSuspects(event *Event) []string {
suspects := []string{}
if event.Message != "" {
suspects = append(suspects, event.Message)
}
for _, ex := range event.Exception {
suspects = append(suspects, ex.Type)
suspects = append(suspects, ex.Value)
}
return suspects
}
// ================================
// Contextify Frames Integration
// ================================
type contextifyFramesIntegration struct {
sr sourceReader
contextLines int
cachedLocations sync.Map
}
func (cfi *contextifyFramesIntegration) Name() string {
return "ContextifyFrames"
}
func (cfi *contextifyFramesIntegration) SetupOnce(client *Client) {
cfi.sr = newSourceReader()
cfi.contextLines = 5
client.AddEventProcessor(cfi.processor)
}
func (cfi *contextifyFramesIntegration) processor(event *Event, hint *EventHint) *Event {
// Range over all exceptions
for _, ex := range event.Exception {
// If it has no stacktrace, just bail out
if ex.Stacktrace == nil {
continue
}
// If it does, it should have frames, so try to contextify them
ex.Stacktrace.Frames = cfi.contextify(ex.Stacktrace.Frames)
}
// Range over all threads
for _, th := range event.Threads {
// If it has no stacktrace, just bail out
if th.Stacktrace == nil {
continue
}
// If it does, it should have frames, so try to contextify them
th.Stacktrace.Frames = cfi.contextify(th.Stacktrace.Frames)
}
return event
}
func (cfi *contextifyFramesIntegration) contextify(frames []Frame) []Frame {
contextifiedFrames := make([]Frame, 0, len(frames))
for _, frame := range frames {
if !frame.InApp {
contextifiedFrames = append(contextifiedFrames, frame)
continue
}
var path string
if cachedPath, ok := cfi.cachedLocations.Load(frame.AbsPath); ok {
if p, ok := cachedPath.(string); ok {
path = p
}
} else {
// Optimize for happy path here
if fileExists(frame.AbsPath) {
path = frame.AbsPath
} else {
path = cfi.findNearbySourceCodeLocation(frame.AbsPath)
}
}
if path == "" {
contextifiedFrames = append(contextifiedFrames, frame)
continue
}
lines, contextLine := cfi.sr.readContextLines(path, frame.Lineno, cfi.contextLines)
contextifiedFrames = append(contextifiedFrames, cfi.addContextLinesToFrame(frame, lines, contextLine))
}
return contextifiedFrames
}
func (cfi *contextifyFramesIntegration) findNearbySourceCodeLocation(originalPath string) string {
trimmedPath := strings.TrimPrefix(originalPath, "/")
components := strings.Split(trimmedPath, "/")
for len(components) > 0 {
components = components[1:]
possibleLocation := strings.Join(components, "/")
if fileExists(possibleLocation) {
cfi.cachedLocations.Store(originalPath, possibleLocation)
return possibleLocation
}
}
cfi.cachedLocations.Store(originalPath, "")
return ""
}
func (cfi *contextifyFramesIntegration) addContextLinesToFrame(frame Frame, lines [][]byte, contextLine int) Frame {
for i, line := range lines {
switch {
case i < contextLine:
frame.PreContext = append(frame.PreContext, string(line))
case i == contextLine:
frame.ContextLine = string(line)
default:
frame.PostContext = append(frame.PostContext, string(line))
}
}
return frame
}

221
vendor/github.com/getsentry/sentry-go/interfaces.go generated vendored Normal file
View File

@ -0,0 +1,221 @@
package sentry
import (
"context"
"encoding/json"
"fmt"
"net"
"net/http"
"strings"
"time"
)
// Protocol Docs (kinda)
// https://github.com/getsentry/rust-sentry-types/blob/master/src/protocol/v7.rs
// Level marks the severity of the event
type Level string
const (
LevelDebug Level = "debug"
LevelInfo Level = "info"
LevelWarning Level = "warning"
LevelError Level = "error"
LevelFatal Level = "fatal"
)
// https://docs.sentry.io/development/sdk-dev/event-payloads/sdk/
type SdkInfo struct {
Name string `json:"name,omitempty"`
Version string `json:"version,omitempty"`
Integrations []string `json:"integrations,omitempty"`
Packages []SdkPackage `json:"packages,omitempty"`
}
type SdkPackage struct {
Name string `json:"name,omitempty"`
Version string `json:"version,omitempty"`
}
// TODO: This type could be more useful, as map of interface{} is too generic
// and requires a lot of type assertions in beforeBreadcrumb calls
// plus it could just be `map[string]interface{}` then
type BreadcrumbHint map[string]interface{}
// https://docs.sentry.io/development/sdk-dev/event-payloads/breadcrumbs/
type Breadcrumb struct {
Category string `json:"category,omitempty"`
Data map[string]interface{} `json:"data,omitempty"`
Level Level `json:"level,omitempty"`
Message string `json:"message,omitempty"`
Timestamp time.Time `json:"timestamp"`
Type string `json:"type,omitempty"`
}
func (b *Breadcrumb) MarshalJSON() ([]byte, error) {
type alias Breadcrumb
// encoding/json doesn't support the "omitempty" option for struct types.
// See https://golang.org/issues/11939.
// This implementation of MarshalJSON shadows the original Timestamp field
// forcing it to be omitted when the Timestamp is the zero value of
// time.Time.
if b.Timestamp.IsZero() {
return json.Marshal(&struct {
*alias
Timestamp json.RawMessage `json:"timestamp,omitempty"`
}{
alias: (*alias)(b),
})
}
return json.Marshal(&struct {
*alias
}{
alias: (*alias)(b),
})
}
// https://docs.sentry.io/development/sdk-dev/event-payloads/user/
type User struct {
Email string `json:"email,omitempty"`
ID string `json:"id,omitempty"`
IPAddress string `json:"ip_address,omitempty"`
Username string `json:"username,omitempty"`
}
// https://docs.sentry.io/development/sdk-dev/event-payloads/request/
type Request struct {
URL string `json:"url,omitempty"`
Method string `json:"method,omitempty"`
Data string `json:"data,omitempty"`
QueryString string `json:"query_string,omitempty"`
Cookies string `json:"cookies,omitempty"`
Headers map[string]string `json:"headers,omitempty"`
Env map[string]string `json:"env,omitempty"`
}
// NewRequest returns a new Sentry Request from the given http.Request.
//
// NewRequest avoids operations that depend on network access. In particular, it
// does not read r.Body.
func NewRequest(r *http.Request) *Request {
protocol := schemeHTTP
if r.TLS != nil || r.Header.Get("X-Forwarded-Proto") == "https" {
protocol = schemeHTTPS
}
url := fmt.Sprintf("%s://%s%s", protocol, r.Host, r.URL.Path)
// We read only the first Cookie header because of the specification:
// https://tools.ietf.org/html/rfc6265#section-5.4
// When the user agent generates an HTTP request, the user agent MUST NOT
// attach more than one Cookie header field.
cookies := r.Header.Get("Cookie")
headers := make(map[string]string, len(r.Header))
for k, v := range r.Header {
headers[k] = strings.Join(v, ",")
}
headers["Host"] = r.Host
var env map[string]string
if addr, port, err := net.SplitHostPort(r.RemoteAddr); err == nil {
env = map[string]string{"REMOTE_ADDR": addr, "REMOTE_PORT": port}
}
return &Request{
URL: url,
Method: r.Method,
QueryString: r.URL.RawQuery,
Cookies: cookies,
Headers: headers,
Env: env,
}
}
// https://docs.sentry.io/development/sdk-dev/event-payloads/exception/
type Exception struct {
Type string `json:"type,omitempty"`
Value string `json:"value,omitempty"`
Module string `json:"module,omitempty"`
ThreadID string `json:"thread_id,omitempty"`
Stacktrace *Stacktrace `json:"stacktrace,omitempty"`
RawStacktrace *Stacktrace `json:"raw_stacktrace,omitempty"`
}
type EventID string
// https://docs.sentry.io/development/sdk-dev/event-payloads/
type Event struct {
Breadcrumbs []*Breadcrumb `json:"breadcrumbs,omitempty"`
Contexts map[string]interface{} `json:"contexts,omitempty"`
Dist string `json:"dist,omitempty"`
Environment string `json:"environment,omitempty"`
EventID EventID `json:"event_id,omitempty"`
Extra map[string]interface{} `json:"extra,omitempty"`
Fingerprint []string `json:"fingerprint,omitempty"`
Level Level `json:"level,omitempty"`
Message string `json:"message,omitempty"`
Platform string `json:"platform,omitempty"`
Release string `json:"release,omitempty"`
Sdk SdkInfo `json:"sdk,omitempty"`
ServerName string `json:"server_name,omitempty"`
Threads []Thread `json:"threads,omitempty"`
Tags map[string]string `json:"tags,omitempty"`
Timestamp time.Time `json:"timestamp"`
Transaction string `json:"transaction,omitempty"`
User User `json:"user,omitempty"`
Logger string `json:"logger,omitempty"`
Modules map[string]string `json:"modules,omitempty"`
Request *Request `json:"request,omitempty"`
Exception []Exception `json:"exception,omitempty"`
}
func (e *Event) MarshalJSON() ([]byte, error) {
type alias Event
// encoding/json doesn't support the "omitempty" option for struct types.
// See https://golang.org/issues/11939.
// This implementation of MarshalJSON shadows the original Timestamp field
// forcing it to be omitted when the Timestamp is the zero value of
// time.Time.
if e.Timestamp.IsZero() {
return json.Marshal(&struct {
*alias
Timestamp json.RawMessage `json:"timestamp,omitempty"`
}{
alias: (*alias)(e),
})
}
return json.Marshal(&struct {
*alias
}{
alias: (*alias)(e),
})
}
func NewEvent() *Event {
event := Event{
Contexts: make(map[string]interface{}),
Extra: make(map[string]interface{}),
Tags: make(map[string]string),
Modules: make(map[string]string),
}
return &event
}
type Thread struct {
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Stacktrace *Stacktrace `json:"stacktrace,omitempty"`
RawStacktrace *Stacktrace `json:"raw_stacktrace,omitempty"`
Crashed bool `json:"crashed,omitempty"`
Current bool `json:"current,omitempty"`
}
type EventHint struct {
Data interface{}
EventID string
OriginalException error
RecoveredException interface{}
Context context.Context
Request *http.Request
Response *http.Response
}

416
vendor/github.com/getsentry/sentry-go/scope.go generated vendored Normal file
View File

@ -0,0 +1,416 @@
package sentry
import (
"bytes"
"io"
"net/http"
"reflect"
"sync"
"time"
)
// Scope holds contextual data for the current scope.
//
// The scope is an object that can cloned efficiently and stores data that
// is locally relevant to an event. For instance the scope will hold recorded
// breadcrumbs and similar information.
//
// The scope can be interacted with in two ways:
//
// 1. the scope is routinely updated with information by functions such as
// `AddBreadcrumb` which will modify the currently top-most scope.
// 2. the topmost scope can also be configured through the `ConfigureScope`
// method.
//
// Note that the scope can only be modified but not inspected.
// Only the client can use the scope to extract information currently.
type Scope struct {
mu sync.RWMutex
breadcrumbs []*Breadcrumb
user User
tags map[string]string
contexts map[string]interface{}
extra map[string]interface{}
fingerprint []string
level Level
transaction string
request *http.Request
// requestBody holds a reference to the original request.Body.
requestBody interface {
// Bytes returns bytes from the original body, lazily buffered as the
// original body is read.
Bytes() []byte
// Overflow returns true if the body is larger than the maximum buffer
// size.
Overflow() bool
}
eventProcessors []EventProcessor
}
func NewScope() *Scope {
scope := Scope{
breadcrumbs: make([]*Breadcrumb, 0),
tags: make(map[string]string),
contexts: make(map[string]interface{}),
extra: make(map[string]interface{}),
fingerprint: make([]string, 0),
}
return &scope
}
// AddBreadcrumb adds new breadcrumb to the current scope
// and optionally throws the old one if limit is reached.
func (scope *Scope) AddBreadcrumb(breadcrumb *Breadcrumb, limit int) {
if breadcrumb.Timestamp.IsZero() {
breadcrumb.Timestamp = time.Now().UTC()
}
scope.mu.Lock()
defer scope.mu.Unlock()
breadcrumbs := append(scope.breadcrumbs, breadcrumb)
if len(breadcrumbs) > limit {
scope.breadcrumbs = breadcrumbs[1 : limit+1]
} else {
scope.breadcrumbs = breadcrumbs
}
}
// ClearBreadcrumbs clears all breadcrumbs from the current scope.
func (scope *Scope) ClearBreadcrumbs() {
scope.mu.Lock()
defer scope.mu.Unlock()
scope.breadcrumbs = []*Breadcrumb{}
}
// SetUser sets the user for the current scope.
func (scope *Scope) SetUser(user User) {
scope.mu.Lock()
defer scope.mu.Unlock()
scope.user = user
}
// SetRequest sets the request for the current scope.
func (scope *Scope) SetRequest(r *http.Request) {
scope.mu.Lock()
defer scope.mu.Unlock()
scope.request = r
if r == nil {
return
}
// Don't buffer request body if we know it is oversized.
if r.ContentLength > maxRequestBodyBytes {
return
}
// Don't buffer if there is no body.
if r.Body == nil || r.Body == http.NoBody {
return
}
buf := &limitedBuffer{Capacity: maxRequestBodyBytes}
r.Body = readCloser{
Reader: io.TeeReader(r.Body, buf),
Closer: r.Body,
}
scope.requestBody = buf
}
// SetRequestBody sets the request body for the current scope.
//
// This method should only be called when the body bytes are already available
// in memory. Typically, the request body is buffered lazily from the
// Request.Body from SetRequest.
func (scope *Scope) SetRequestBody(b []byte) {
scope.mu.Lock()
defer scope.mu.Unlock()
capacity := maxRequestBodyBytes
overflow := false
if len(b) > capacity {
overflow = true
b = b[:capacity]
}
scope.requestBody = &limitedBuffer{
Capacity: capacity,
Buffer: *bytes.NewBuffer(b),
overflow: overflow,
}
}
// maxRequestBodyBytes is the default maximum request body size to send to
// Sentry.
const maxRequestBodyBytes = 10 * 1024
// A limitedBuffer is like a bytes.Buffer, but limited to store at most Capacity
// bytes. Any writes past the capacity are silently discarded, similar to
// ioutil.Discard.
type limitedBuffer struct {
Capacity int
bytes.Buffer
overflow bool
}
// Write implements io.Writer.
func (b *limitedBuffer) Write(p []byte) (n int, err error) {
// Silently ignore writes after overflow.
if b.overflow {
return len(p), nil
}
left := b.Capacity - b.Len()
if left < 0 {
left = 0
}
if len(p) > left {
b.overflow = true
p = p[:left]
}
return b.Buffer.Write(p)
}
// Overflow returns true if the limitedBuffer discarded bytes written to it.
func (b *limitedBuffer) Overflow() bool {
return b.overflow
}
// readCloser combines an io.Reader and an io.Closer to implement io.ReadCloser.
type readCloser struct {
io.Reader
io.Closer
}
// SetTag adds a tag to the current scope.
func (scope *Scope) SetTag(key, value string) {
scope.mu.Lock()
defer scope.mu.Unlock()
scope.tags[key] = value
}
// SetTags assigns multiple tags to the current scope.
func (scope *Scope) SetTags(tags map[string]string) {
scope.mu.Lock()
defer scope.mu.Unlock()
for k, v := range tags {
scope.tags[k] = v
}
}
// RemoveTag removes a tag from the current scope.
func (scope *Scope) RemoveTag(key string) {
scope.mu.Lock()
defer scope.mu.Unlock()
delete(scope.tags, key)
}
// SetContext adds a context to the current scope.
func (scope *Scope) SetContext(key string, value interface{}) {
scope.mu.Lock()
defer scope.mu.Unlock()
scope.contexts[key] = value
}
// SetContexts assigns multiple contexts to the current scope.
func (scope *Scope) SetContexts(contexts map[string]interface{}) {
scope.mu.Lock()
defer scope.mu.Unlock()
for k, v := range contexts {
scope.contexts[k] = v
}
}
// RemoveContext removes a context from the current scope.
func (scope *Scope) RemoveContext(key string) {
scope.mu.Lock()
defer scope.mu.Unlock()
delete(scope.contexts, key)
}
// SetExtra adds an extra to the current scope.
func (scope *Scope) SetExtra(key string, value interface{}) {
scope.mu.Lock()
defer scope.mu.Unlock()
scope.extra[key] = value
}
// SetExtras assigns multiple extras to the current scope.
func (scope *Scope) SetExtras(extra map[string]interface{}) {
scope.mu.Lock()
defer scope.mu.Unlock()
for k, v := range extra {
scope.extra[k] = v
}
}
// RemoveExtra removes a extra from the current scope.
func (scope *Scope) RemoveExtra(key string) {
scope.mu.Lock()
defer scope.mu.Unlock()
delete(scope.extra, key)
}
// SetFingerprint sets new fingerprint for the current scope.
func (scope *Scope) SetFingerprint(fingerprint []string) {
scope.mu.Lock()
defer scope.mu.Unlock()
scope.fingerprint = fingerprint
}
// SetLevel sets new level for the current scope.
func (scope *Scope) SetLevel(level Level) {
scope.mu.Lock()
defer scope.mu.Unlock()
scope.level = level
}
// SetTransaction sets new transaction name for the current transaction.
func (scope *Scope) SetTransaction(transactionName string) {
scope.mu.Lock()
defer scope.mu.Unlock()
scope.transaction = transactionName
}
// Clone returns a copy of the current scope with all data copied over.
func (scope *Scope) Clone() *Scope {
scope.mu.RLock()
defer scope.mu.RUnlock()
clone := NewScope()
clone.user = scope.user
clone.breadcrumbs = make([]*Breadcrumb, len(scope.breadcrumbs))
copy(clone.breadcrumbs, scope.breadcrumbs)
for key, value := range scope.tags {
clone.tags[key] = value
}
for key, value := range scope.contexts {
clone.contexts[key] = value
}
for key, value := range scope.extra {
clone.extra[key] = value
}
clone.fingerprint = make([]string, len(scope.fingerprint))
copy(clone.fingerprint, scope.fingerprint)
clone.level = scope.level
clone.transaction = scope.transaction
clone.request = scope.request
return clone
}
// Clear removes the data from the current scope. Not safe for concurrent use.
func (scope *Scope) Clear() {
*scope = *NewScope()
}
// AddEventProcessor adds an event processor to the current scope.
func (scope *Scope) AddEventProcessor(processor EventProcessor) {
scope.mu.Lock()
defer scope.mu.Unlock()
scope.eventProcessors = append(scope.eventProcessors, processor)
}
// ApplyToEvent takes the data from the current scope and attaches it to the event.
func (scope *Scope) ApplyToEvent(event *Event, hint *EventHint) *Event {
scope.mu.RLock()
defer scope.mu.RUnlock()
if len(scope.breadcrumbs) > 0 {
if event.Breadcrumbs == nil {
event.Breadcrumbs = []*Breadcrumb{}
}
event.Breadcrumbs = append(event.Breadcrumbs, scope.breadcrumbs...)
}
if len(scope.tags) > 0 {
if event.Tags == nil {
event.Tags = make(map[string]string)
}
for key, value := range scope.tags {
event.Tags[key] = value
}
}
if len(scope.contexts) > 0 {
if event.Contexts == nil {
event.Contexts = make(map[string]interface{})
}
for key, value := range scope.contexts {
event.Contexts[key] = value
}
}
if len(scope.extra) > 0 {
if event.Extra == nil {
event.Extra = make(map[string]interface{})
}
for key, value := range scope.extra {
event.Extra[key] = value
}
}
if (reflect.DeepEqual(event.User, User{})) {
event.User = scope.user
}
if (event.Fingerprint == nil || len(event.Fingerprint) == 0) &&
len(scope.fingerprint) > 0 {
event.Fingerprint = make([]string, len(scope.fingerprint))
copy(event.Fingerprint, scope.fingerprint)
}
if scope.level != "" {
event.Level = scope.level
}
if scope.transaction != "" {
event.Transaction = scope.transaction
}
if event.Request == nil && scope.request != nil {
event.Request = NewRequest(scope.request)
// NOTE: The SDK does not attempt to send partial request body data.
//
// The reason being that Sentry's ingest pipeline and UI are optimized
// to show structured data. Additionally, tooling around PII scrubbing
// relies on structured data; truncated request bodies would create
// invalid payloads that are more prone to leaking PII data.
//
// Users can still send more data along their events if they want to,
// for example using Event.Extra.
if scope.requestBody != nil && !scope.requestBody.Overflow() {
event.Request.Data = string(scope.requestBody.Bytes())
}
}
for _, processor := range scope.eventProcessors {
id := event.EventID
event = processor(event, hint)
if event == nil {
Logger.Printf("Event dropped by one of the Scope EventProcessors: %s\n", id)
return nil
}
}
return event
}

135
vendor/github.com/getsentry/sentry-go/sentry.go generated vendored Normal file
View File

@ -0,0 +1,135 @@
package sentry
import (
"context"
"time"
)
// Version is the version of the sentry-go SDK.
const Version = "0.6.1"
// apiVersion is the minimum version of the Sentry API compatible with the
// sentry-go SDK.
const apiVersion = "7"
// Init initializes whole SDK by creating new `Client` and binding it to the current `Hub`
func Init(options ClientOptions) error {
hub := CurrentHub()
client, err := NewClient(options)
if err != nil {
return err
}
hub.BindClient(client)
return nil
}
// AddBreadcrumb records a new breadcrumb.
//
// The total number of breadcrumbs that can be recorded are limited by the
// configuration on the client.
func AddBreadcrumb(breadcrumb *Breadcrumb) {
hub := CurrentHub()
hub.AddBreadcrumb(breadcrumb, nil)
}
// CaptureMessage captures an arbitrary message.
func CaptureMessage(message string) *EventID {
hub := CurrentHub()
return hub.CaptureMessage(message)
}
// CaptureException captures an error.
func CaptureException(exception error) *EventID {
hub := CurrentHub()
return hub.CaptureException(exception)
}
// CaptureEvent captures an event on the currently active client if any.
//
// The event must already be assembled. Typically code would instead use
// the utility methods like `CaptureException`. The return value is the
// event ID. In case Sentry is disabled or event was dropped, the return value will be nil.
func CaptureEvent(event *Event) *EventID {
hub := CurrentHub()
return hub.CaptureEvent(event)
}
// Recover captures a panic.
func Recover() *EventID {
if err := recover(); err != nil {
hub := CurrentHub()
return hub.Recover(err)
}
return nil
}
// Recover captures a panic and passes relevant context object.
func RecoverWithContext(ctx context.Context) *EventID {
if err := recover(); err != nil {
var hub *Hub
if HasHubOnContext(ctx) {
hub = GetHubFromContext(ctx)
} else {
hub = CurrentHub()
}
return hub.RecoverWithContext(ctx, err)
}
return nil
}
// WithScope temporarily pushes a scope for a single call.
//
// This function takes one argument, a callback that executes
// in the context of that scope.
//
// This is useful when extra data should be send with a single capture call
// for instance a different level or tags
func WithScope(f func(scope *Scope)) {
hub := CurrentHub()
hub.WithScope(f)
}
// ConfigureScope invokes a function that can modify the current scope.
//
// The function is passed a mutable reference to the `Scope` so that modifications
// can be performed.
func ConfigureScope(f func(scope *Scope)) {
hub := CurrentHub()
hub.ConfigureScope(f)
}
// PushScope pushes a new scope.
func PushScope() {
hub := CurrentHub()
hub.PushScope()
}
// PopScope pushes a new scope.
func PopScope() {
hub := CurrentHub()
hub.PopScope()
}
// Flush waits until the underlying Transport sends any buffered events to the
// Sentry server, blocking for at most the given timeout. It returns false if
// the timeout was reached. In that case, some events may not have been sent.
//
// Flush should be called before terminating the program to avoid
// unintentionally dropping events.
//
// Do not call Flush indiscriminately after every call to CaptureEvent,
// CaptureException or CaptureMessage. Instead, to have the SDK send events over
// the network synchronously, configure it to use the HTTPSyncTransport in the
// call to Init.
func Flush(timeout time.Duration) bool {
hub := CurrentHub()
return hub.Flush(timeout)
}
// LastEventID returns an ID of last captured event.
func LastEventID() EventID {
hub := CurrentHub()
return hub.LastEventID()
}

69
vendor/github.com/getsentry/sentry-go/sourcereader.go generated vendored Normal file
View File

@ -0,0 +1,69 @@
package sentry
import (
"bytes"
"io/ioutil"
"sync"
)
type sourceReader struct {
mu sync.Mutex
cache map[string][][]byte
}
func newSourceReader() sourceReader {
return sourceReader{
cache: make(map[string][][]byte),
}
}
func (sr *sourceReader) readContextLines(filename string, line, context int) ([][]byte, int) {
sr.mu.Lock()
defer sr.mu.Unlock()
lines, ok := sr.cache[filename]
if !ok {
data, err := ioutil.ReadFile(filename)
if err != nil {
sr.cache[filename] = nil
return nil, 0
}
lines = bytes.Split(data, []byte{'\n'})
sr.cache[filename] = lines
}
return sr.calculateContextLines(lines, line, context)
}
// `contextLine` points to a line that caused an issue itself, in relation to returned slice
func (sr *sourceReader) calculateContextLines(lines [][]byte, line, context int) ([][]byte, int) {
// Stacktrace lines are 1-indexed, slices are 0-indexed
line--
contextLine := context
if lines == nil || line >= len(lines) || line < 0 {
return nil, 0
}
if context < 0 {
context = 0
contextLine = 0
}
start := line - context
if start < 0 {
contextLine += start
start = 0
}
end := line + context + 1
if end > len(lines) {
end = len(lines)
}
return lines[start:end], contextLine
}

283
vendor/github.com/getsentry/sentry-go/stacktrace.go generated vendored Normal file
View File

@ -0,0 +1,283 @@
package sentry
import (
"go/build"
"path/filepath"
"reflect"
"runtime"
"strings"
)
const unknown string = "unknown"
// The module download is split into two parts: downloading the go.mod and downloading the actual code.
// If you have dependencies only needed for tests, then they will show up in your go.mod,
// and go get will download their go.mods, but it will not download their code.
// The test-only dependencies get downloaded only when you need it, such as the first time you run go test.
//
// https://github.com/golang/go/issues/26913#issuecomment-411976222
// Stacktrace holds information about the frames of the stack.
type Stacktrace struct {
Frames []Frame `json:"frames,omitempty"`
FramesOmitted []uint `json:"frames_omitted,omitempty"`
}
// NewStacktrace creates a stacktrace using `runtime.Callers`.
func NewStacktrace() *Stacktrace {
pcs := make([]uintptr, 100)
n := runtime.Callers(1, pcs)
if n == 0 {
return nil
}
frames := extractFrames(pcs[:n])
frames = filterFrames(frames)
stacktrace := Stacktrace{
Frames: frames,
}
return &stacktrace
}
// ExtractStacktrace creates a new `Stacktrace` based on the given `error` object.
// TODO: Make it configurable so that anyone can provide their own implementation?
// Use of reflection allows us to not have a hard dependency on any given package, so we don't have to import it
func ExtractStacktrace(err error) *Stacktrace {
method := extractReflectedStacktraceMethod(err)
if !method.IsValid() {
return nil
}
pcs := extractPcs(method)
if len(pcs) == 0 {
return nil
}
frames := extractFrames(pcs)
frames = filterFrames(frames)
stacktrace := Stacktrace{
Frames: frames,
}
return &stacktrace
}
func extractReflectedStacktraceMethod(err error) reflect.Value {
var method reflect.Value
// https://github.com/pingcap/errors
methodGetStackTracer := reflect.ValueOf(err).MethodByName("GetStackTracer")
// https://github.com/pkg/errors
methodStackTrace := reflect.ValueOf(err).MethodByName("StackTrace")
// https://github.com/go-errors/errors
methodStackFrames := reflect.ValueOf(err).MethodByName("StackFrames")
if methodGetStackTracer.IsValid() {
stacktracer := methodGetStackTracer.Call(make([]reflect.Value, 0))[0]
stacktracerStackTrace := reflect.ValueOf(stacktracer).MethodByName("StackTrace")
if stacktracerStackTrace.IsValid() {
method = stacktracerStackTrace
}
}
if methodStackTrace.IsValid() {
method = methodStackTrace
}
if methodStackFrames.IsValid() {
method = methodStackFrames
}
return method
}
func extractPcs(method reflect.Value) []uintptr {
var pcs []uintptr
stacktrace := method.Call(make([]reflect.Value, 0))[0]
if stacktrace.Kind() != reflect.Slice {
return nil
}
for i := 0; i < stacktrace.Len(); i++ {
pc := stacktrace.Index(i)
if pc.Kind() == reflect.Uintptr {
pcs = append(pcs, uintptr(pc.Uint()))
continue
}
if pc.Kind() == reflect.Struct {
field := pc.FieldByName("ProgramCounter")
if field.IsValid() && field.Kind() == reflect.Uintptr {
pcs = append(pcs, uintptr(field.Uint()))
continue
}
}
}
return pcs
}
// https://docs.sentry.io/development/sdk-dev/event-payloads/stacktrace/
type Frame struct {
Function string `json:"function,omitempty"`
Symbol string `json:"symbol,omitempty"`
Module string `json:"module,omitempty"`
Package string `json:"package,omitempty"`
Filename string `json:"filename,omitempty"`
AbsPath string `json:"abs_path,omitempty"`
Lineno int `json:"lineno,omitempty"`
Colno int `json:"colno,omitempty"`
PreContext []string `json:"pre_context,omitempty"`
ContextLine string `json:"context_line,omitempty"`
PostContext []string `json:"post_context,omitempty"`
InApp bool `json:"in_app,omitempty"`
Vars map[string]interface{} `json:"vars,omitempty"`
}
// NewFrame assembles a stacktrace frame out of `runtime.Frame`.
func NewFrame(f runtime.Frame) Frame {
abspath := f.File
filename := f.File
function := f.Function
var pkg string
if filename != "" {
filename = filepath.Base(filename)
} else {
filename = unknown
}
if abspath == "" {
abspath = unknown
}
if function != "" {
pkg, function = splitQualifiedFunctionName(function)
}
frame := Frame{
AbsPath: abspath,
Filename: filename,
Lineno: f.Line,
Module: pkg,
Function: function,
}
frame.InApp = isInAppFrame(frame)
return frame
}
// splitQualifiedFunctionName splits a package path-qualified function name into
// package name and function name. Such qualified names are found in
// runtime.Frame.Function values.
func splitQualifiedFunctionName(name string) (pkg string, fun string) {
pkg = packageName(name)
fun = strings.TrimPrefix(name, pkg+".")
return
}
func extractFrames(pcs []uintptr) []Frame {
var frames []Frame
callersFrames := runtime.CallersFrames(pcs)
for {
callerFrame, more := callersFrames.Next()
frames = append([]Frame{
NewFrame(callerFrame),
}, frames...)
if !more {
break
}
}
return frames
}
// filterFrames filters out stack frames that are not meant to be reported to
// Sentry. Those are frames internal to the SDK or Go.
func filterFrames(frames []Frame) []Frame {
if len(frames) == 0 {
return nil
}
filteredFrames := make([]Frame, 0, len(frames))
for _, frame := range frames {
// Skip Go internal frames.
if frame.Module == "runtime" || frame.Module == "testing" {
continue
}
// Skip Sentry internal frames, except for frames in _test packages (for
// testing).
if strings.HasPrefix(frame.Module, "github.com/getsentry/sentry-go") &&
!strings.HasSuffix(frame.Module, "_test") {
continue
}
filteredFrames = append(filteredFrames, frame)
}
return filteredFrames
}
func isInAppFrame(frame Frame) bool {
if strings.HasPrefix(frame.AbsPath, build.Default.GOROOT) ||
strings.Contains(frame.Module, "vendor") ||
strings.Contains(frame.Module, "third_party") {
return false
}
return true
}
func callerFunctionName() string {
pcs := make([]uintptr, 1)
runtime.Callers(3, pcs)
callersFrames := runtime.CallersFrames(pcs)
callerFrame, _ := callersFrames.Next()
return baseName(callerFrame.Function)
}
// packageName returns the package part of the symbol name, or the empty string
// if there is none.
// It replicates https://golang.org/pkg/debug/gosym/#Sym.PackageName, avoiding a
// dependency on debug/gosym.
func packageName(name string) string {
// A prefix of "type." and "go." is a compiler-generated symbol that doesn't belong to any package.
// See variable reservedimports in cmd/compile/internal/gc/subr.go
if strings.HasPrefix(name, "go.") || strings.HasPrefix(name, "type.") {
return ""
}
pathend := strings.LastIndex(name, "/")
if pathend < 0 {
pathend = 0
}
if i := strings.Index(name[pathend:], "."); i != -1 {
return name[:pathend+i]
}
return ""
}
// baseName returns the symbol name without the package or receiver name.
// It replicates https://golang.org/pkg/debug/gosym/#Sym.BaseName, avoiding a
// dependency on debug/gosym.
func baseName(name string) string {
if i := strings.LastIndex(name, "."); i != -1 {
return name[i+1:]
}
return name
}

447
vendor/github.com/getsentry/sentry-go/transport.go generated vendored Normal file
View File

@ -0,0 +1,447 @@
package sentry
import (
"bytes"
"crypto/tls"
"encoding/json"
"net/http"
"net/url"
"strconv"
"sync"
"time"
)
const defaultBufferSize = 30
const defaultRetryAfter = time.Second * 60
const defaultTimeout = time.Second * 30
// Transport is used by the `Client` to deliver events to remote server.
type Transport interface {
Flush(timeout time.Duration) bool
Configure(options ClientOptions)
SendEvent(event *Event)
}
func getProxyConfig(options ClientOptions) func(*http.Request) (*url.URL, error) {
if options.HTTPSProxy != "" {
return func(_ *http.Request) (*url.URL, error) {
return url.Parse(options.HTTPSProxy)
}
} else if options.HTTPProxy != "" {
return func(_ *http.Request) (*url.URL, error) {
return url.Parse(options.HTTPProxy)
}
}
return http.ProxyFromEnvironment
}
func getTLSConfig(options ClientOptions) *tls.Config {
if options.CaCerts != nil {
return &tls.Config{
RootCAs: options.CaCerts,
}
}
return nil
}
func retryAfter(now time.Time, r *http.Response) time.Duration {
retryAfterHeader := r.Header["Retry-After"]
if retryAfterHeader == nil {
return defaultRetryAfter
}
if date, err := time.Parse(time.RFC1123, retryAfterHeader[0]); err == nil {
return date.Sub(now)
}
if seconds, err := strconv.Atoi(retryAfterHeader[0]); err == nil {
return time.Second * time.Duration(seconds)
}
return defaultRetryAfter
}
func getRequestBodyFromEvent(event *Event) []byte {
body, err := json.Marshal(event)
if err == nil {
return body
}
partialMarshallMessage := "Original event couldn't be marshalled. Succeeded by stripping the data " +
"that uses interface{} type. Please verify that the data you attach to the scope is serializable."
// Try to serialize the event, with all the contextual data that allows for interface{} stripped.
event.Breadcrumbs = nil
event.Contexts = nil
event.Extra = map[string]interface{}{
"info": partialMarshallMessage,
}
body, err = json.Marshal(event)
if err == nil {
Logger.Println(partialMarshallMessage)
return body
}
// This should _only_ happen when Event.Exception[0].Stacktrace.Frames[0].Vars is unserializable
// Which won't ever happen, as we don't use it now (although it's the part of public interface accepted by Sentry)
// Juuust in case something, somehow goes utterly wrong.
Logger.Println("Event couldn't be marshalled, even with stripped contextual data. Skipping delivery. " +
"Please notify the SDK owners with possibly broken payload.")
return nil
}
// ================================
// HTTPTransport
// ================================
// A batch groups items that are processed sequentially.
type batch struct {
items chan *http.Request
started chan struct{} // closed to signal items started to be worked on
done chan struct{} // closed to signal completion of all items
}
// HTTPTransport is a default implementation of `Transport` interface used by `Client`.
type HTTPTransport struct {
dsn *Dsn
client *http.Client
transport http.RoundTripper
// buffer is a channel of batches. Calling Flush terminates work on the
// current in-flight items and starts a new batch for subsequent events.
buffer chan batch
start sync.Once
// Size of the transport buffer. Defaults to 30.
BufferSize int
// HTTP Client request timeout. Defaults to 30 seconds.
Timeout time.Duration
mu sync.RWMutex
disabledUntil time.Time
}
// NewHTTPTransport returns a new pre-configured instance of HTTPTransport
func NewHTTPTransport() *HTTPTransport {
transport := HTTPTransport{
BufferSize: defaultBufferSize,
Timeout: defaultTimeout,
}
return &transport
}
// Configure is called by the `Client` itself, providing it it's own `ClientOptions`.
func (t *HTTPTransport) Configure(options ClientOptions) {
dsn, err := NewDsn(options.Dsn)
if err != nil {
Logger.Printf("%v\n", err)
return
}
t.dsn = dsn
// A buffered channel with capacity 1 works like a mutex, ensuring only one
// goroutine can access the current batch at a given time. Access is
// synchronized by reading from and writing to the channel.
t.buffer = make(chan batch, 1)
t.buffer <- batch{
items: make(chan *http.Request, t.BufferSize),
started: make(chan struct{}),
done: make(chan struct{}),
}
if options.HTTPTransport != nil {
t.transport = options.HTTPTransport
} else {
t.transport = &http.Transport{
Proxy: getProxyConfig(options),
TLSClientConfig: getTLSConfig(options),
}
}
if options.HTTPClient != nil {
t.client = options.HTTPClient
} else {
t.client = &http.Client{
Transport: t.transport,
Timeout: t.Timeout,
}
}
t.start.Do(func() {
go t.worker()
})
}
// SendEvent assembles a new packet out of `Event` and sends it to remote server.
func (t *HTTPTransport) SendEvent(event *Event) {
if t.dsn == nil {
return
}
t.mu.RLock()
disabled := time.Now().Before(t.disabledUntil)
t.mu.RUnlock()
if disabled {
return
}
body := getRequestBodyFromEvent(event)
if body == nil {
return
}
request, _ := http.NewRequest(
http.MethodPost,
t.dsn.StoreAPIURL().String(),
bytes.NewBuffer(body),
)
for headerKey, headerValue := range t.dsn.RequestHeaders() {
request.Header.Set(headerKey, headerValue)
}
// <-t.buffer is equivalent to acquiring a lock to access the current batch.
// A few lines below, t.buffer <- b releases the lock.
//
// The lock must be held during the select block below to guarantee that
// b.items is not closed while trying to send to it. Remember that sending
// on a closed channel panics.
//
// Note that the select block takes a bounded amount of CPU time because of
// the default case that is executed if sending on b.items would block. That
// is, the event is dropped if it cannot be sent immediately to the b.items
// channel (used as a queue).
b := <-t.buffer
select {
case b.items <- request:
Logger.Printf(
"Sending %s event [%s] to %s project: %d\n",
event.Level,
event.EventID,
t.dsn.host,
t.dsn.projectID,
)
default:
Logger.Println("Event dropped due to transport buffer being full.")
}
t.buffer <- b
}
// Flush waits until any buffered events are sent to the Sentry server, blocking
// for at most the given timeout. It returns false if the timeout was reached.
// In that case, some events may not have been sent.
//
// Flush should be called before terminating the program to avoid
// unintentionally dropping events.
//
// Do not call Flush indiscriminately after every call to SendEvent. Instead, to
// have the SDK send events over the network synchronously, configure it to use
// the HTTPSyncTransport in the call to Init.
func (t *HTTPTransport) Flush(timeout time.Duration) bool {
toolate := time.After(timeout)
// Wait until processing the current batch has started or the timeout.
//
// We must wait until the worker has seen the current batch, because it is
// the only way b.done will be closed. If we do not wait, there is a
// possible execution flow in which b.done is never closed, and the only way
// out of Flush would be waiting for the timeout, which is undesired.
var b batch
for {
select {
case b = <-t.buffer:
select {
case <-b.started:
goto started
default:
t.buffer <- b
}
case <-toolate:
goto fail
}
}
started:
// Signal that there won't be any more items in this batch, so that the
// worker inner loop can end.
close(b.items)
// Start a new batch for subsequent events.
t.buffer <- batch{
items: make(chan *http.Request, t.BufferSize),
started: make(chan struct{}),
done: make(chan struct{}),
}
// Wait until the current batch is done or the timeout.
select {
case <-b.done:
Logger.Println("Buffer flushed successfully.")
return true
case <-toolate:
goto fail
}
fail:
Logger.Println("Buffer flushing reached the timeout.")
return false
}
func (t *HTTPTransport) worker() {
for b := range t.buffer {
// Signal that processing of the current batch has started.
close(b.started)
// Return the batch to the buffer so that other goroutines can use it.
// Equivalent to releasing a lock.
t.buffer <- b
// Process all batch items.
for request := range b.items {
t.mu.RLock()
disabled := time.Now().Before(t.disabledUntil)
t.mu.RUnlock()
if disabled {
continue
}
response, err := t.client.Do(request)
if err != nil {
Logger.Printf("There was an issue with sending an event: %v", err)
}
if response != nil && response.StatusCode == http.StatusTooManyRequests {
deadline := time.Now().Add(retryAfter(time.Now(), response))
t.mu.Lock()
t.disabledUntil = deadline
t.mu.Unlock()
Logger.Printf("Too many requests, backing off till: %s\n", deadline)
}
}
// Signal that processing of the batch is done.
close(b.done)
}
}
// ================================
// HTTPSyncTransport
// ================================
// HTTPSyncTransport is an implementation of `Transport` interface which blocks after each captured event.
type HTTPSyncTransport struct {
dsn *Dsn
client *http.Client
transport http.RoundTripper
disabledUntil time.Time
// HTTP Client request timeout. Defaults to 30 seconds.
Timeout time.Duration
}
// NewHTTPSyncTransport returns a new pre-configured instance of HTTPSyncTransport
func NewHTTPSyncTransport() *HTTPSyncTransport {
transport := HTTPSyncTransport{
Timeout: defaultTimeout,
}
return &transport
}
// Configure is called by the `Client` itself, providing it it's own `ClientOptions`.
func (t *HTTPSyncTransport) Configure(options ClientOptions) {
dsn, err := NewDsn(options.Dsn)
if err != nil {
Logger.Printf("%v\n", err)
return
}
t.dsn = dsn
if options.HTTPTransport != nil {
t.transport = options.HTTPTransport
} else {
t.transport = &http.Transport{
Proxy: getProxyConfig(options),
TLSClientConfig: getTLSConfig(options),
}
}
if options.HTTPClient != nil {
t.client = options.HTTPClient
} else {
t.client = &http.Client{
Transport: t.transport,
Timeout: t.Timeout,
}
}
}
// SendEvent assembles a new packet out of `Event` and sends it to remote server.
func (t *HTTPSyncTransport) SendEvent(event *Event) {
if t.dsn == nil || time.Now().Before(t.disabledUntil) {
return
}
body := getRequestBodyFromEvent(event)
if body == nil {
return
}
request, _ := http.NewRequest(
http.MethodPost,
t.dsn.StoreAPIURL().String(),
bytes.NewBuffer(body),
)
for headerKey, headerValue := range t.dsn.RequestHeaders() {
request.Header.Set(headerKey, headerValue)
}
Logger.Printf(
"Sending %s event [%s] to %s project: %d\n",
event.Level,
event.EventID,
t.dsn.host,
t.dsn.projectID,
)
response, err := t.client.Do(request)
if err != nil {
Logger.Printf("There was an issue with sending an event: %v", err)
}
if response != nil && response.StatusCode == http.StatusTooManyRequests {
t.disabledUntil = time.Now().Add(retryAfter(time.Now(), response))
Logger.Printf("Too many requests, backing off till: %s\n", t.disabledUntil)
}
}
// Flush is a no-op for HTTPSyncTransport. It always returns true immediately.
func (t *HTTPSyncTransport) Flush(_ time.Duration) bool {
return true
}
// ================================
// noopTransport
// ================================
// noopTransport is an implementation of `Transport` interface which drops all the events.
// Only used internally when an empty DSN is provided, which effectively disables the SDK.
type noopTransport struct{}
func (t *noopTransport) Configure(options ClientOptions) {
Logger.Println("Sentry client initialized with an empty DSN. Using noopTransport. No events will be delivered.")
}
func (t *noopTransport) SendEvent(event *Event) {
Logger.Println("Event dropped due to noopTransport usage.")
}
func (t *noopTransport) Flush(_ time.Duration) bool {
return true
}

34
vendor/github.com/getsentry/sentry-go/util.go generated vendored Normal file
View File

@ -0,0 +1,34 @@
package sentry
import (
"crypto/rand"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"os"
)
func uuid() string {
id := make([]byte, 16)
_, _ = io.ReadFull(rand.Reader, id)
id[6] &= 0x0F // clear version
id[6] |= 0x40 // set version to 4 (random uuid)
id[8] &= 0x3F // clear variant
id[8] |= 0x80 // set to IETF variant
return hex.EncodeToString(id)
}
func fileExists(fileName string) bool {
if _, err := os.Stat(fileName); err != nil {
return false
}
return true
}
//nolint: deadcode, unused
func prettyPrint(data interface{}) {
dbg, _ := json.MarshalIndent(data, "", " ")
fmt.Println(string(dbg))
}

3
vendor/modules.txt vendored
View File

@ -56,6 +56,9 @@ github.com/fzipp/gocyclo
# github.com/garyburd/redigo v1.6.0
github.com/garyburd/redigo/internal
github.com/garyburd/redigo/redis
# github.com/getsentry/sentry-go v0.6.1
github.com/getsentry/sentry-go
github.com/getsentry/sentry-go/echo
# github.com/ghodss/yaml v1.0.0
github.com/ghodss/yaml
# github.com/go-openapi/jsonpointer v0.19.3