diff --git a/go.mod b/go.mod index 686d9927d..bfabe18c5 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/charmbracelet/glamour v0.2.0 github.com/fatih/color v1.10.0 // indirect github.com/fsnotify/fsnotify v1.4.7 - github.com/getsentry/sentry-go v0.10.0 + github.com/getsentry/sentry-go v0.11.0 github.com/golang/mock v1.5.0 github.com/golang/snappy v0.0.3 // indirect github.com/google/go-cmp v0.5.5 diff --git a/go.sum b/go.sum index 4b9a97927..b1693496c 100644 --- a/go.sum +++ b/go.sum @@ -133,8 +133,8 @@ github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga 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/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= -github.com/getsentry/sentry-go v0.10.0 h1:6gwY+66NHKqyZrdi6O2jGdo7wGdo9b3B69E01NFgT5g= -github.com/getsentry/sentry-go v0.10.0/go.mod h1:kELm/9iCblqUYh+ZRML7PNdCvEuw24wBvJPYyi86cws= +github.com/getsentry/sentry-go v0.11.0 h1:qro8uttJGvNAMr5CLcFI9CHR0aDzXl0Vs3Pmw/oTPg8= +github.com/getsentry/sentry-go v0.11.0/go.mod h1:KBQIxiZAetw62Cj8Ri964vAEWVdgfaUCn30Q3bCvANo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= diff --git a/vendor/github.com/getsentry/sentry-go/.gitattributes b/vendor/github.com/getsentry/sentry-go/.gitattributes new file mode 100644 index 000000000..bccfeeab0 --- /dev/null +++ b/vendor/github.com/getsentry/sentry-go/.gitattributes @@ -0,0 +1,5 @@ +# Tell Git to use LF for line endings on all platforms. +# Required to have correct test data on Windows. +# https://github.com/mvdan/github-actions-golang#caveats +# https://github.com/actions/checkout/issues/135#issuecomment-613361104 +* text eol=lf diff --git a/vendor/github.com/getsentry/sentry-go/.golangci.yml b/vendor/github.com/getsentry/sentry-go/.golangci.yml index 04c0bc198..65bb64e6f 100644 --- a/vendor/github.com/getsentry/sentry-go/.golangci.yml +++ b/vendor/github.com/getsentry/sentry-go/.golangci.yml @@ -20,7 +20,6 @@ linters: - govet - ineffassign - interfacer - - lll - maligned - misspell - nakedret diff --git a/vendor/github.com/getsentry/sentry-go/CHANGELOG.md b/vendor/github.com/getsentry/sentry-go/CHANGELOG.md index 6a205ca32..1d8497210 100644 --- a/vendor/github.com/getsentry/sentry-go/CHANGELOG.md +++ b/vendor/github.com/getsentry/sentry-go/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## v0.11.0 + +- feat(transports): Category-based Rate Limiting ([#354](https://github.com/getsentry/sentry-go/pull/354)) +- feat(transports): Report User-Agent identifying SDK ([#357](https://github.com/getsentry/sentry-go/pull/357)) +- fix(scope): Include event processors in clone ([#349](https://github.com/getsentry/sentry-go/pull/349)) +- Improvements to `go doc` documentation ([#344](https://github.com/getsentry/sentry-go/pull/344), [#350](https://github.com/getsentry/sentry-go/pull/350), [#351](https://github.com/getsentry/sentry-go/pull/351)) +- Miscellaneous changes to our testing infrastructure with GitHub Actions + ([57123a40](https://github.com/getsentry/sentry-go/commit/57123a409be55f61b1d5a6da93c176c55a399ad0), [#128](https://github.com/getsentry/sentry-go/pull/128), [#338](https://github.com/getsentry/sentry-go/pull/338), [#345](https://github.com/getsentry/sentry-go/pull/345), [#346](https://github.com/getsentry/sentry-go/pull/346), [#352](https://github.com/getsentry/sentry-go/pull/352), [#353](https://github.com/getsentry/sentry-go/pull/353), [#355](https://github.com/getsentry/sentry-go/pull/355)) + +_NOTE:_ +This version drops support for Go 1.13. The currently supported Go versions are the last 3 stable releases: 1.14, 1.15 and 1.16. +Users of the tracing functionality (`StartSpan`, etc) should upgrade to this version to benefit from separate rate limits for errors and transactions. +There are no breaking changes and upgrading should be a smooth experience for all users. + ## v0.10.0 - feat: Debug connection reuse (#323) diff --git a/vendor/github.com/getsentry/sentry-go/client.go b/vendor/github.com/getsentry/sentry-go/client.go index a4f4dc29f..7bab94b5e 100644 --- a/vendor/github.com/getsentry/sentry-go/client.go +++ b/vendor/github.com/getsentry/sentry-go/client.go @@ -129,7 +129,9 @@ type ClientOptions struct { // 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 is called before error events are sent to Sentry. + // Use it to mutate the event or return nil to discard the event. + // See EventProcessor if you need to mutate transactions. BeforeSend func(event *Event, hint *EventHint) *Event // Before breadcrumb add callback. BeforeBreadcrumb func(breadcrumb *Breadcrumb, hint *BreadcrumbHint) *Breadcrumb diff --git a/vendor/github.com/getsentry/sentry-go/dsn.go b/vendor/github.com/getsentry/sentry-go/dsn.go index 2bf9ae60e..ca9f118b6 100644 --- a/vendor/github.com/getsentry/sentry-go/dsn.go +++ b/vendor/github.com/getsentry/sentry-go/dsn.go @@ -100,7 +100,7 @@ func NewDsn(rawURL string) (*Dsn, error) { } // ProjectID - if len(parsedURL.Path) == 0 || parsedURL.Path == "/" { + if parsedURL.Path == "" || parsedURL.Path == "/" { return nil, &DsnParseError{"empty project id"} } pathSegments := strings.Split(parsedURL.Path[1:], "/") diff --git a/vendor/github.com/getsentry/sentry-go/go.mod b/vendor/github.com/getsentry/sentry-go/go.mod index 24962a979..300f22ff2 100644 --- a/vendor/github.com/getsentry/sentry-go/go.mod +++ b/vendor/github.com/getsentry/sentry-go/go.mod @@ -1,6 +1,6 @@ module github.com/getsentry/sentry-go -go 1.13 +go 1.14 require ( github.com/ajg/form v1.5.1 // indirect @@ -9,7 +9,7 @@ require ( 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-cmp v0.5.5 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 diff --git a/vendor/github.com/getsentry/sentry-go/go.sum b/vendor/github.com/getsentry/sentry-go/go.sum index 2f5857a9b..dcd1d2cf5 100644 --- a/vendor/github.com/getsentry/sentry-go/go.sum +++ b/vendor/github.com/getsentry/sentry-go/go.sum @@ -56,8 +56,8 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y 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-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/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/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -81,7 +81,6 @@ github.com/iris-contrib/pongo2 v0.0.1 h1:zGP7pW51oi5eQZMIlGA3I+FHY9/HOQWDB+572yi github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g= 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/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -175,7 +174,6 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= 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 v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= @@ -205,7 +203,6 @@ github.com/yudai/pp v2.0.1+incompatible h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcm 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/crypto v0.0.0-20191227163750-53104e6ec876 h1:sKJQZMuxjOAR/Uo2LBfU90onWEf1dF4C+0hPJCc9Mpc= golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -216,7 +213,6 @@ golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn 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/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -230,7 +226,6 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w 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/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -251,11 +246,9 @@ gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2G gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/ini.v1 v1.51.1 h1:GyboHr4UqMiLUybYjd22ZjQIKEJEpgtLXtuGbR21Oho= gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -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= diff --git a/vendor/github.com/getsentry/sentry-go/integrations.go b/vendor/github.com/getsentry/sentry-go/integrations.go index 1c2f5d6d5..c24704960 100644 --- a/vendor/github.com/getsentry/sentry-go/integrations.go +++ b/vendor/github.com/getsentry/sentry-go/integrations.go @@ -170,8 +170,7 @@ func getIgnoreErrorsSuspects(event *Event) []string { } for _, ex := range event.Exception { - suspects = append(suspects, ex.Type) - suspects = append(suspects, ex.Value) + suspects = append(suspects, ex.Type, ex.Value) } return suspects diff --git a/vendor/github.com/getsentry/sentry-go/internal/ratelimit/category.go b/vendor/github.com/getsentry/sentry-go/internal/ratelimit/category.go new file mode 100644 index 000000000..44d0a5688 --- /dev/null +++ b/vendor/github.com/getsentry/sentry-go/internal/ratelimit/category.go @@ -0,0 +1,41 @@ +package ratelimit + +import "strings" + +// Reference: +// https://github.com/getsentry/relay/blob/0424a2e017d193a93918053c90cdae9472d164bf/relay-common/src/constants.rs#L116-L127 + +// Category classifies supported payload types that can be ingested by Sentry +// and, therefore, rate limited. +type Category string + +// Known rate limit categories. As a special case, the CategoryAll applies to +// all known payload types. +const ( + CategoryAll Category = "" + CategoryError Category = "error" + CategoryTransaction Category = "transaction" +) + +// knownCategories is the set of currently known categories. Other categories +// are ignored for the purpose of rate-limiting. +var knownCategories = map[Category]struct{}{ + CategoryAll: {}, + CategoryError: {}, + CategoryTransaction: {}, +} + +// String returns the category formatted for debugging. +func (c Category) String() string { + switch c { + case "": + return "CategoryAll" + default: + var b strings.Builder + b.WriteString("Category") + for _, w := range strings.Fields(string(c)) { + b.WriteString(strings.Title(w)) + } + return b.String() + } +} diff --git a/vendor/github.com/getsentry/sentry-go/internal/ratelimit/deadline.go b/vendor/github.com/getsentry/sentry-go/internal/ratelimit/deadline.go new file mode 100644 index 000000000..c00258335 --- /dev/null +++ b/vendor/github.com/getsentry/sentry-go/internal/ratelimit/deadline.go @@ -0,0 +1,22 @@ +package ratelimit + +import "time" + +// A Deadline is a time instant when a rate limit expires. +type Deadline time.Time + +// After reports whether the deadline d is after other. +func (d Deadline) After(other Deadline) bool { + return time.Time(d).After(time.Time(other)) +} + +// Equal reports whether d and e represent the same deadline. +func (d Deadline) Equal(e Deadline) bool { + return time.Time(d).Equal(time.Time(e)) +} + +// String returns the deadline formatted for debugging. +func (d Deadline) String() string { + // Like time.Time.String, but without the monotonic clock reading. + return time.Time(d).Round(0).String() +} diff --git a/vendor/github.com/getsentry/sentry-go/internal/ratelimit/doc.go b/vendor/github.com/getsentry/sentry-go/internal/ratelimit/doc.go new file mode 100644 index 000000000..80b9fdda2 --- /dev/null +++ b/vendor/github.com/getsentry/sentry-go/internal/ratelimit/doc.go @@ -0,0 +1,3 @@ +// Package ratelimit provides tools to work with rate limits imposed by Sentry's +// data ingestion pipeline. +package ratelimit diff --git a/vendor/github.com/getsentry/sentry-go/internal/ratelimit/map.go b/vendor/github.com/getsentry/sentry-go/internal/ratelimit/map.go new file mode 100644 index 000000000..e590430ec --- /dev/null +++ b/vendor/github.com/getsentry/sentry-go/internal/ratelimit/map.go @@ -0,0 +1,64 @@ +package ratelimit + +import ( + "net/http" + "time" +) + +// Map maps categories to rate limit deadlines. +// +// A rate limit is in effect for a given category if either the category's +// deadline or the deadline for the special CategoryAll has not yet expired. +// +// Use IsRateLimited to check whether a category is rate-limited. +type Map map[Category]Deadline + +// IsRateLimited returns true if the category is currently rate limited. +func (m Map) IsRateLimited(c Category) bool { + return m.isRateLimited(c, time.Now()) +} + +func (m Map) isRateLimited(c Category, now time.Time) bool { + return m.Deadline(c).After(Deadline(now)) +} + +// Deadline returns the deadline when the rate limit for the given category or +// the special CategoryAll expire, whichever is furthest into the future. +func (m Map) Deadline(c Category) Deadline { + categoryDeadline := m[c] + allDeadline := m[CategoryAll] + if categoryDeadline.After(allDeadline) { + return categoryDeadline + } + return allDeadline +} + +// Merge merges the other map into m. +// +// If a category appears in both maps, the deadline that is furthest into the +// future is preserved. +func (m Map) Merge(other Map) { + for c, d := range other { + if d.After(m[c]) { + m[c] = d + } + } +} + +// FromResponse returns a rate limit map from an HTTP response. +func FromResponse(r *http.Response) Map { + return fromResponse(r, time.Now()) +} + +func fromResponse(r *http.Response, now time.Time) Map { + s := r.Header.Get("X-Sentry-Rate-Limits") + if s != "" { + return parseXSentryRateLimits(s, now) + } + if r.StatusCode == http.StatusTooManyRequests { + s := r.Header.Get("Retry-After") + deadline, _ := parseRetryAfter(s, now) + return Map{CategoryAll: deadline} + } + return Map{} +} diff --git a/vendor/github.com/getsentry/sentry-go/internal/ratelimit/rate_limits.go b/vendor/github.com/getsentry/sentry-go/internal/ratelimit/rate_limits.go new file mode 100644 index 000000000..2dcda27c2 --- /dev/null +++ b/vendor/github.com/getsentry/sentry-go/internal/ratelimit/rate_limits.go @@ -0,0 +1,76 @@ +package ratelimit + +import ( + "errors" + "math" + "strconv" + "strings" + "time" +) + +var errInvalidXSRLRetryAfter = errors.New("invalid retry-after value") + +// parseXSentryRateLimits returns a RateLimits map by parsing an input string in +// the format of the X-Sentry-Rate-Limits header. +// +// Example +// +// X-Sentry-Rate-Limits: 60:transaction, 2700:default;error;security +// +// This will rate limit transactions for the next 60 seconds and errors for the +// next 2700 seconds. +// +// Limits for unknown categories are ignored. +func parseXSentryRateLimits(s string, now time.Time) Map { + // https://github.com/getsentry/relay/blob/0424a2e017d193a93918053c90cdae9472d164bf/relay-server/src/utils/rate_limits.rs#L44-L82 + m := make(Map, len(knownCategories)) + for _, limit := range strings.Split(s, ",") { + limit = strings.TrimSpace(limit) + if limit == "" { + continue + } + components := strings.Split(limit, ":") + if len(components) == 0 { + continue + } + retryAfter, err := parseXSRLRetryAfter(strings.TrimSpace(components[0]), now) + if err != nil { + continue + } + categories := "" + if len(components) > 1 { + categories = components[1] + } + for _, category := range strings.Split(categories, ";") { + c := Category(strings.ToLower(strings.TrimSpace(category))) + if _, ok := knownCategories[c]; !ok { + // skip unknown categories, keep m small + continue + } + // always keep the deadline furthest into the future + if retryAfter.After(m[c]) { + m[c] = retryAfter + } + } + } + return m +} + +// parseXSRLRetryAfter parses a string into a retry-after rate limit deadline. +// +// Valid input is a number, possibly signed and possibly floating-point, +// indicating the number of seconds to wait before sending another request. +// Negative values are treated as zero. Fractional values are rounded to the +// next integer. +func parseXSRLRetryAfter(s string, now time.Time) (Deadline, error) { + // https://github.com/getsentry/relay/blob/0424a2e017d193a93918053c90cdae9472d164bf/relay-quotas/src/rate_limit.rs#L88-L96 + f, err := strconv.ParseFloat(s, 64) + if err != nil { + return Deadline{}, errInvalidXSRLRetryAfter + } + d := time.Duration(math.Ceil(math.Max(f, 0.0))) * time.Second + if d < 0 { + d = 0 + } + return Deadline(now.Add(d)), nil +} diff --git a/vendor/github.com/getsentry/sentry-go/internal/ratelimit/retry_after.go b/vendor/github.com/getsentry/sentry-go/internal/ratelimit/retry_after.go new file mode 100644 index 000000000..576e29dcd --- /dev/null +++ b/vendor/github.com/getsentry/sentry-go/internal/ratelimit/retry_after.go @@ -0,0 +1,40 @@ +package ratelimit + +import ( + "errors" + "strconv" + "time" +) + +const defaultRetryAfter = 1 * time.Minute + +var errInvalidRetryAfter = errors.New("invalid input") + +// parseRetryAfter parses a string s as in the standard Retry-After HTTP header +// and returns a deadline until when requests are rate limited and therefore new +// requests should not be sent. The input may be either a date or a non-negative +// integer number of seconds. +// +// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After +// +// parseRetryAfter always returns a usable deadline, even in case of an error. +// +// This is the original rate limiting mechanism used by Sentry, superseeded by +// the X-Sentry-Rate-Limits response header. +func parseRetryAfter(s string, now time.Time) (Deadline, error) { + if s == "" { + goto invalid + } + if n, err := strconv.Atoi(s); err == nil { + if n < 0 { + goto invalid + } + d := time.Duration(n) * time.Second + return Deadline(now.Add(d)), nil + } + if date, err := time.Parse(time.RFC1123, s); err == nil { + return Deadline(date), nil + } +invalid: + return Deadline(now.Add(defaultRetryAfter)), errInvalidRetryAfter +} diff --git a/vendor/github.com/getsentry/sentry-go/scope.go b/vendor/github.com/getsentry/sentry-go/scope.go index cdf0a0c1a..727921c3c 100644 --- a/vendor/github.com/getsentry/sentry-go/scope.go +++ b/vendor/github.com/getsentry/sentry-go/scope.go @@ -318,7 +318,7 @@ func (scope *Scope) Clone() *Scope { clone.transaction = scope.transaction clone.request = scope.request clone.requestBody = scope.requestBody - + clone.eventProcessors = scope.eventProcessors return clone } diff --git a/vendor/github.com/getsentry/sentry-go/sentry.go b/vendor/github.com/getsentry/sentry-go/sentry.go index 742ff12e2..530da0047 100644 --- a/vendor/github.com/getsentry/sentry-go/sentry.go +++ b/vendor/github.com/getsentry/sentry-go/sentry.go @@ -6,12 +6,15 @@ import ( ) // Version is the version of the SDK. -const Version = "0.10.0" +const Version = "0.11.0" // apiVersion is the minimum version of the Sentry API compatible with the // sentry-go SDK. const apiVersion = "7" +// userAgent is the User-Agent of outgoing HTTP requests. +const userAgent = "sentry-go/" + Version + // Init initializes the SDK with options. The returned error is non-nil if // options is invalid, for instance if a malformed DSN is provided. func Init(options ClientOptions) error { diff --git a/vendor/github.com/getsentry/sentry-go/transport.go b/vendor/github.com/getsentry/sentry-go/transport.go index bc290f021..6cdf0750e 100644 --- a/vendor/github.com/getsentry/sentry-go/transport.go +++ b/vendor/github.com/getsentry/sentry-go/transport.go @@ -10,13 +10,13 @@ import ( "io/ioutil" "net/http" "net/url" - "strconv" "sync" "time" + + "github.com/getsentry/sentry-go/internal/ratelimit" ) const defaultBufferSize = 30 -const defaultRetryAfter = time.Second * 60 const defaultTimeout = time.Second * 30 // maxDrainResponseBytes is the maximum number of bytes that transport @@ -61,26 +61,6 @@ func getTLSConfig(options ClientOptions) *tls.Config { return nil } -func retryAfter(now time.Time, r *http.Response) time.Duration { - // TODO(tracing): handle x-sentry-rate-limits, separate rate limiting - // per data type (error event, transaction, etc). - 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 { @@ -144,7 +124,12 @@ func transactionEnvelopeFromBody(eventID EventID, sentAt time.Time, body json.Ra return &b, nil } -func getRequestFromEvent(event *Event, dsn *Dsn) (*http.Request, error) { +func getRequestFromEvent(event *Event, dsn *Dsn) (r *http.Request, err error) { + defer func() { + if r != nil { + r.Header.Set("User-Agent", userAgent) + } + }() body := getRequestBodyFromEvent(event) if body == nil { return nil, errors.New("event could not be marshaled") @@ -167,18 +152,38 @@ func getRequestFromEvent(event *Event, dsn *Dsn) (*http.Request, error) { ) } +func categoryFor(eventType string) ratelimit.Category { + switch eventType { + case "": + return ratelimit.CategoryError + case transactionType: + return ratelimit.CategoryTransaction + default: + return ratelimit.Category(eventType) + } +} + // ================================ // HTTPTransport // ================================ // A batch groups items that are processed sequentially. type batch struct { - items chan *http.Request + items chan batchItem 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 batchItem struct { + request *http.Request + category ratelimit.Category +} + +// HTTPTransport is the default, non-blocking, implementation of Transport. +// +// Clients using this transport will enqueue requests in a buffer and return to +// the caller before any network communication has happened. Requests are sent +// to Sentry sequentially from a background goroutine. type HTTPTransport struct { dsn *Dsn client *http.Client @@ -195,8 +200,8 @@ type HTTPTransport struct { // HTTP Client request timeout. Defaults to 30 seconds. Timeout time.Duration - mu sync.RWMutex - disabledUntil time.Time + mu sync.RWMutex + limits ratelimit.Map } // NewHTTPTransport returns a new pre-configured instance of HTTPTransport. @@ -204,6 +209,7 @@ func NewHTTPTransport() *HTTPTransport { transport := HTTPTransport{ BufferSize: defaultBufferSize, Timeout: defaultTimeout, + limits: make(ratelimit.Map), } return &transport } @@ -222,7 +228,7 @@ func (t *HTTPTransport) Configure(options ClientOptions) { // 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), + items: make(chan batchItem, t.BufferSize), started: make(chan struct{}), done: make(chan struct{}), } @@ -255,10 +261,10 @@ 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 { + + category := categoryFor(event.Type) + + if t.disabled(category) { return } @@ -285,7 +291,10 @@ func (t *HTTPTransport) SendEvent(event *Event) { b := <-t.buffer select { - case b.items <- request: + case b.items <- batchItem{ + request: request, + category: category, + }: var eventType string if event.Type == transactionType { eventType = "transaction" @@ -346,7 +355,7 @@ started: close(b.items) // Start a new batch for subsequent events. t.buffer <- batch{ - items: make(chan *http.Request, t.BufferSize), + items: make(chan batchItem, t.BufferSize), started: make(chan struct{}), done: make(chan struct{}), } @@ -375,26 +384,19 @@ func (t *HTTPTransport) worker() { 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 { + for item := range b.items { + if t.disabled(item.category) { continue } - response, err := t.client.Do(request) + response, err := t.client.Do(item.request) if err != nil { Logger.Printf("There was an issue with sending an event: %v", err) continue } - if 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) - } + t.mu.Lock() + t.limits.Merge(ratelimit.FromResponse(response)) + t.mu.Unlock() // Drain body up to a limit and close it, allowing the // transport to reuse TCP connections. _, _ = io.CopyN(ioutil.Discard, response.Body, maxDrainResponseBytes) @@ -406,16 +408,38 @@ func (t *HTTPTransport) worker() { } } +func (t *HTTPTransport) disabled(c ratelimit.Category) bool { + t.mu.RLock() + defer t.mu.RUnlock() + disabled := t.limits.IsRateLimited(c) + if disabled { + Logger.Printf("Too many requests for %q, backing off till: %v", c, t.limits.Deadline(c)) + } + return disabled +} + // ================================ // HTTPSyncTransport // ================================ -// HTTPSyncTransport is an implementation of Transport interface which blocks after each captured event. +// HTTPSyncTransport is a blocking implementation of Transport. +// +// Clients using this transport will send requests to Sentry sequentially and +// block until a response is returned. +// +// The blocking behavior is useful in a limited set of use cases. For example, +// use it when deploying code to a Function as a Service ("Serverless") +// platform, where any work happening in a background goroutine is not +// guaranteed to execute. +// +// For most cases, prefer HTTPTransport. type HTTPSyncTransport struct { - dsn *Dsn - client *http.Client - transport http.RoundTripper - disabledUntil time.Time + dsn *Dsn + client *http.Client + transport http.RoundTripper + + mu sync.Mutex + limits ratelimit.Map // HTTP Client request timeout. Defaults to 30 seconds. Timeout time.Duration @@ -425,6 +449,7 @@ type HTTPSyncTransport struct { func NewHTTPSyncTransport() *HTTPSyncTransport { transport := HTTPSyncTransport{ Timeout: defaultTimeout, + limits: make(ratelimit.Map), } return &transport @@ -460,7 +485,11 @@ func (t *HTTPSyncTransport) Configure(options ClientOptions) { // 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) { + if t.dsn == nil { + return + } + + if t.disabled(categoryFor(event.Type)) { return } @@ -492,10 +521,10 @@ func (t *HTTPSyncTransport) SendEvent(event *Event) { Logger.Printf("There was an issue with sending an event: %v", err) return } - if 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) - } + t.mu.Lock() + t.limits.Merge(ratelimit.FromResponse(response)) + t.mu.Unlock() + // Drain body up to a limit and close it, allowing the // transport to reuse TCP connections. _, _ = io.CopyN(ioutil.Discard, response.Body, maxDrainResponseBytes) @@ -507,6 +536,16 @@ func (t *HTTPSyncTransport) Flush(_ time.Duration) bool { return true } +func (t *HTTPSyncTransport) disabled(c ratelimit.Category) bool { + t.mu.Lock() + defer t.mu.Unlock() + disabled := t.limits.IsRateLimited(c) + if disabled { + Logger.Printf("Too many requests for %q, backing off till: %v", c, t.limits.Deadline(c)) + } + return disabled +} + // ================================ // noopTransport // ================================ diff --git a/vendor/modules.txt b/vendor/modules.txt index 8fcaf727e..9326c4255 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -75,11 +75,12 @@ github.com/fatih/color # github.com/fsnotify/fsnotify v1.4.7 ## explicit github.com/fsnotify/fsnotify -# github.com/getsentry/sentry-go v0.10.0 +# github.com/getsentry/sentry-go v0.11.0 ## explicit github.com/getsentry/sentry-go github.com/getsentry/sentry-go/internal/crypto/randutil github.com/getsentry/sentry-go/internal/debug +github.com/getsentry/sentry-go/internal/ratelimit # github.com/goccy/go-json v0.4.7 github.com/goccy/go-json # github.com/godbus/dbus/v5 v5.0.3