Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support IgnoreTransactions client option #717

Merged
merged 3 commits into from Sep 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions client.go
Expand Up @@ -140,6 +140,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
// List of regexp strings that will be used to match against a transaction's
// name. If a match is found, then the transaction will be dropped.
IgnoreTransactions []string
// If this flag is enabled, certain personally identifiable information (PII) is added by active integrations.
// By default, no such data is sent.
SendDefaultPII bool
Expand Down Expand Up @@ -371,6 +374,7 @@ func (client *Client) setupIntegrations() {
new(environmentIntegration),
new(modulesIntegration),
new(ignoreErrorsIntegration),
new(ignoreTransactionsIntegration),
}

if client.options.Integrations != nil {
Expand Down
109 changes: 109 additions & 0 deletions client_test.go
Expand Up @@ -552,6 +552,115 @@ func TestBeforeSendTransactionIsCalled(t *testing.T) {
assertEqual(t, lastEvent.Contexts["trace"]["span_id"], transaction.SpanID)
}

func TestIgnoreErrors(t *testing.T) {
tests := []struct {
name string
ignoreErrors []string
message string
expectDrop bool
}{
{
name: "No Match",
message: "Foo",
ignoreErrors: []string{"Bar", "Baz"},
expectDrop: false,
},
{
name: "Partial Match",
message: "FooBar",
ignoreErrors: []string{"Foo", "Baz"},
expectDrop: true,
},
{
name: "Exact Match",
message: "Foo Bar",
ignoreErrors: []string{"\\bFoo\\b", "Baz"},
expectDrop: true,
},
{
name: "Wildcard Match",
message: "Foo",
ignoreErrors: []string{"F*", "Bar"},
expectDrop: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
scope := &ScopeMock{}
transport := &TransportMock{}
client, err := NewClient(ClientOptions{
Transport: transport,
IgnoreErrors: tt.ignoreErrors,
})
if err != nil {
t.Fatal(err)
}

client.CaptureMessage(tt.message, nil, scope)

dropped := transport.lastEvent == nil
if !(tt.expectDrop == dropped) {
t.Error("expected event to be dropped")
}
})
}
}

func TestIgnoreTransactions(t *testing.T) {
tests := []struct {
name string
ignoreTransactions []string
transaction string
expectDrop bool
}{
{
name: "No Match",
transaction: "Foo",
ignoreTransactions: []string{"Bar", "Baz"},
expectDrop: false,
},
{
name: "Partial Match",
transaction: "FooBar",
ignoreTransactions: []string{"Foo", "Baz"},
expectDrop: true,
},
{
name: "Exact Match",
transaction: "Foo Bar",
ignoreTransactions: []string{"\\bFoo\\b", "Baz"},
expectDrop: true,
},
{
name: "Wildcard Match",
transaction: "Foo",
ignoreTransactions: []string{"F*", "Bar"},
expectDrop: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
transport := &TransportMock{}
ctx := NewTestContext(ClientOptions{
EnableTracing: true,
TracesSampleRate: 1.0,
Transport: transport,
IgnoreTransactions: tt.ignoreTransactions,
})

transaction := StartTransaction(ctx,
tt.transaction,
)
transaction.Finish()

dropped := transport.lastEvent == nil
if !(tt.expectDrop == dropped) {
t.Error("expected event to be dropped")
}
})
}
}

func TestSampleRate(t *testing.T) {
tests := []struct {
SampleRate float64
Expand Down
34 changes: 34 additions & 0 deletions integrations.go
Expand Up @@ -177,6 +177,40 @@ func getIgnoreErrorsSuspects(event *Event) []string {
return suspects
}

// ================================
// Ignore Transactions Integration
// ================================

type ignoreTransactionsIntegration struct {
ignoreTransactions []*regexp.Regexp
}

func (iei *ignoreTransactionsIntegration) Name() string {
return "IgnoreTransactions"
}

func (iei *ignoreTransactionsIntegration) SetupOnce(client *Client) {
iei.ignoreTransactions = transformStringsIntoRegexps(client.options.IgnoreTransactions)
client.AddEventProcessor(iei.processor)
}

func (iei *ignoreTransactionsIntegration) processor(event *Event, hint *EventHint) *Event {
suspect := event.Transaction
if suspect == "" {
return event
}

for _, pattern := range iei.ignoreTransactions {
if pattern.Match([]byte(suspect)) {
Logger.Printf("Transaction dropped due to being matched by `IgnoreTransactions` option."+
"| Value matched: %s | Filter used: %s", suspect, pattern)
return nil
}
}

return event
}

// ================================
// Contextify Frames Integration
// ================================
Expand Down
33 changes: 33 additions & 0 deletions integrations_test.go
Expand Up @@ -173,6 +173,39 @@ func TestIgnoreErrorsIntegration(t *testing.T) {
}
}

func TestIgnoreTransactionsIntegration(t *testing.T) {
iei := ignoreTransactionsIntegration{
ignoreTransactions: []*regexp.Regexp{
regexp.MustCompile("foo"),
regexp.MustCompile("(?i)bar"),
},
}

dropped := &Event{
Transaction: "foo",
}

alsoDropped := &Event{
Transaction: "Bar",
}

notDropped := &Event{
Transaction: "dont",
}

if iei.processor(dropped, &EventHint{}) != nil {
t.Error("Transaction should be dropped")
}

if iei.processor(alsoDropped, &EventHint{}) != nil {
t.Error("Transaction should be dropped")
}

if iei.processor(notDropped, &EventHint{}) == nil {
t.Error("Transaction should not be dropped")
}
}

func TestContextifyFrames(t *testing.T) {
cfi := contextifyFramesIntegration{
sr: newSourceReader(),
Expand Down