From 785f15d42a95532e3aaba748eef506c89791237d Mon Sep 17 00:00:00 2001 From: Alexis Montagne Date: Wed, 8 Nov 2023 11:13:48 -0800 Subject: [PATCH] reporter/sentry: Add a WhitelistTag handler --- reporter/sentry/reporter.go | 22 ++++++++--- reporter/sentry/reporter_test.go | 67 +++++++++++++++++++++++++++----- 2 files changed, 74 insertions(+), 15 deletions(-) diff --git a/reporter/sentry/reporter.go b/reporter/sentry/reporter.go index 2ff64a1..93a0e07 100644 --- a/reporter/sentry/reporter.go +++ b/reporter/sentry/reporter.go @@ -21,7 +21,7 @@ import ( type Reporter struct { cl *sentry.Client - tagWhitelist map[string]struct{} + tagWhitelist []func(string) bool tagBlacklist []func(string) bool timeout time.Duration @@ -41,12 +41,20 @@ func NewReporter(os ...Option) (*Reporter, error) { } return &Reporter{ - cl: cl, - tagWhitelist: opts.TagWhitelist, + cl: cl, + tagWhitelist: []func(string) bool{ + func(k string) bool { + _, ok := opts.TagWhitelist[k] + return ok + }, + }, tagBlacklist: opts.TagBlacklist, timeout: opts.Timeout, }, nil } +func (r *Reporter) WhitelistTag(fns ...func(string) bool) { + r.tagWhitelist = append(r.tagWhitelist, fns...) +} func (r *Reporter) Report(err error, opts reporter.ReportOptions) { evt := r.buildEvent(err, opts) @@ -70,9 +78,11 @@ func (r *Reporter) appendTag(k string, v interface{}, evt *sentry.Event) { } } - if _, ok := r.tagWhitelist[k]; ok { - evt.Tags[k] = stringifyTag(v) - return + for _, fn := range r.tagWhitelist { + if fn(k) { + evt.Tags[k] = stringifyTag(v) + return + } } evt.Extra[k] = v diff --git a/reporter/sentry/reporter_test.go b/reporter/sentry/reporter_test.go index 62507b5..5675ee9 100644 --- a/reporter/sentry/reporter_test.go +++ b/reporter/sentry/reporter_test.go @@ -2,6 +2,7 @@ package sentry import ( "io" + "regexp" "testing" "github.com/getsentry/sentry-go" @@ -16,9 +17,10 @@ func TestBuildEvent(t *testing.T) { for _, tt := range []struct { name string - opts []Option - err error - ropts reporter.ReportOptions + opts []Option + modifiers []func(*Reporter) + err error + ropts reporter.ReportOptions evtfn func(*testing.T, *sentry.Event) }{ @@ -96,16 +98,58 @@ func TestBuildEvent(t *testing.T) { assertFuncNames( t, evt, - []string{"TestBuildEvent.func7", "tRunner", "goexit"}, + []string{`TestBuildEvent.func\d`, "tRunner", "goexit"}, ) }, }, + { + name: "simple error with http opts", + err: errors.WithTags( + errors.New("basic error"), + map[string]interface{}{"foo": "bar", "biz": "buz"}, + ), + evtfn: func(t *testing.T, evt *sentry.Event) { + assert.Equal(t, evt.Extra, map[string]interface{}{"foo": "bar", "biz": "buz"}) + assert.Equal(t, evt.Tags, map[string]string{"domain": "github.com/upfluence/errors/reporter/sentry"}) + }, + }, + { + name: "simple error with extra", + err: errors.WithTags( + errors.New("basic error"), + map[string]interface{}{"foo": "bar", "biz": "buz"}, + ), + evtfn: func(t *testing.T, evt *sentry.Event) { + assert.Equal(t, evt.Extra, map[string]interface{}{"foo": "bar", "biz": "buz"}) + assert.Equal(t, evt.Tags, map[string]string{"domain": "github.com/upfluence/errors/reporter/sentry"}) + }, + }, + { + name: "simple error with extra & whitelisted tag", + err: errors.WithTags( + errors.New("basic error"), + map[string]interface{}{"foo": "bar", "biz": "buz"}, + ), + modifiers: []func(*Reporter){ + func(r *Reporter) { + r.WhitelistTag(func(s string) bool { return s == "foo" }) + }, + }, + evtfn: func(t *testing.T, evt *sentry.Event) { + assert.Equal(t, evt.Extra, map[string]interface{}{"biz": "buz"}) + assert.Equal(t, evt.Tags, map[string]string{"foo": "bar", "domain": "github.com/upfluence/errors/reporter/sentry"}) + }, + }, } { t.Run(tt.name, func(t *testing.T) { r, err := NewReporter(tt.opts...) assert.NoError(t, err) + for _, fn := range tt.modifiers { + fn(r) + } + evt := r.buildEvent(tt.err, tt.ropts) tt.evtfn(t, evt) }) @@ -127,7 +171,7 @@ func TestSegfault(t *testing.T) { assertFuncNames( t, evt, - []string{"TestSegfault.func1", "gopanic", "panicmem", "sigpanic", "TestSegfault", "tRunner", "goexit"}, + []string{`TestSegfault.func\d`, "gopanic", "panicmem", "sigpanic", "TestSegfault", "tRunner", "goexit"}, ) } else { t.Error("no error recovered") @@ -144,11 +188,16 @@ func assertFuncNames(t testing.TB, evt *sentry.Event, want []string) { assert.Len(t, exc, 1) frames := exc[0].Stacktrace.Frames - fns := make([]string, len(frames)) + + assert.Len(t, frames, len(want)) for i, f := range frames { - fns[i] = f.Function + assert.True( + t, + regexp.MustCompile(want[i]).MatchString(f.Function), + "want regexp = %s, function = %s", + want[i], + f.Function, + ) } - - assert.Equal(t, want, fns) }