From 64bf1f7a2dd6766c5638581a078ffcaf8fe4b3d3 Mon Sep 17 00:00:00 2001 From: Neel Shah Date: Mon, 23 Jan 2023 14:47:48 +0100 Subject: [PATCH] Add before_send_transaction hook --- CHANGELOG.md | 13 ++++++ sentry-ruby/lib/sentry/client.rb | 10 +++++ sentry-ruby/lib/sentry/configuration.rb | 20 +++++++++ .../spec/sentry/client/event_sending_spec.rb | 43 +++++++++++++++++++ sentry-ruby/spec/sentry/configuration_spec.rb | 6 +++ 5 files changed, 92 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6060d7fa..38f5c9b23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,20 @@ - Add global event processor in OpenTelemetry `SpanProcessor` to link errors with transactions [#1983](https://github.com/getsentry/sentry-ruby/pull/1983) - Fix some inconsistencies in setting name/op/status in OpenTelemetry `SpanProcessor` [#1987](https://github.com/getsentry/sentry-ruby/pull/1987) +- Add `config.before_send_transaction` hook [#1989](https://github.com/getsentry/sentry-ruby/pull/1989) + Users can now configure a `before_send_transaction` callback that runs similar to `before_send` but for transaction events. + + ```rb + config.before_send_transaction = lambda do |event, hint| + # skip unimportant transactions or strip sensitive data + if event.transaction == "/healthcheck/route" + nil + else + event + end + end + ``` ### Bug Fixes diff --git a/sentry-ruby/lib/sentry/client.rb b/sentry-ruby/lib/sentry/client.rb index a43da611b..d983ad91f 100644 --- a/sentry-ruby/lib/sentry/client.rb +++ b/sentry-ruby/lib/sentry/client.rb @@ -122,6 +122,16 @@ def send_event(event, hint = nil) end end + if event_type == TransactionEvent::TYPE && configuration.before_send_transaction + event = configuration.before_send_transaction.call(event, hint) + + if event.nil? + log_info("Discarded event because before_send_transaction returned nil") + transport.record_lost_event(:before_send, 'transaction') + return + end + end + transport.send_event(event) event diff --git a/sentry-ruby/lib/sentry/configuration.rb b/sentry-ruby/lib/sentry/configuration.rb index b7ca6d42f..36b440adf 100644 --- a/sentry-ruby/lib/sentry/configuration.rb +++ b/sentry-ruby/lib/sentry/configuration.rb @@ -72,6 +72,19 @@ class Configuration # @return [Proc] attr_reader :before_send + # Optional Proc, called before sending an event to the server + # @example + # config.before_send_transaction = lambda do |event, hint| + # # skip unimportant transactions or strip sensitive data + # if event.transaction == "/healthcheck/route" + # nil + # else + # event + # end + # end + # @return [Proc] + attr_reader :before_send_transaction + # An array of breadcrumbs loggers to be used. Available options are: # - :sentry_logger # - :http_logger @@ -287,6 +300,7 @@ def initialize self.instrumenter = :sentry self.before_send = nil + self.before_send_transaction = nil self.rack_env_whitelist = RACK_ENV_WHITELIST_DEFAULT self.traces_sample_rate = nil self.traces_sampler = nil @@ -338,6 +352,12 @@ def before_send=(value) @before_send = value end + def before_send_transaction=(value) + check_callable!("before_send_transaction", value) + + @before_send_transaction = value + end + def before_breadcrumb=(value) check_callable!("before_breadcrumb", value) diff --git a/sentry-ruby/spec/sentry/client/event_sending_spec.rb b/sentry-ruby/spec/sentry/client/event_sending_spec.rb index 5fb55dfd9..fe7aad6bd 100644 --- a/sentry-ruby/spec/sentry/client/event_sending_spec.rb +++ b/sentry-ruby/spec/sentry/client/event_sending_spec.rb @@ -224,6 +224,15 @@ expect(event["tags"]["called"]).to eq(true) end end + + it "doesn't apply before_send_transaction to Event" do + dbl = double("before_send_transaction") + allow(dbl).to receive(:call) + configuration.before_send_transaction = dbl + + expect(dbl).not_to receive(:call) + subject.send_event(event) + end end it_behaves_like "Event in send_event" do @@ -246,6 +255,26 @@ subject.send_event(event) end + + it "applies before_send_transaction callback before sending the event" do + configuration.before_send_transaction = lambda do |event, _hint| + if event.is_a?(Sentry::TransactionEvent) + event.tags[:called] = true + else + event["tags"]["called"] = true + end + + event + end + + subject.send_event(event) + + if event.is_a?(Sentry::Event) + expect(event.tags[:called]).to eq(true) + else + expect(event["tags"]["called"]).to eq(true) + end + end end it_behaves_like "TransactionEvent in send_event" do @@ -451,6 +480,20 @@ expect(subject.transport).to have_recorded_lost_event(:before_send, 'event') end end + + context "before_send_transaction returns nil" do + before do + configuration.before_send_transaction = lambda do |_event, _hint| + nil + end + end + + it "records lost event" do + transaction_event = subject.event_from_transaction(Sentry::Transaction.new(hub: hub)) + subject.send_event(transaction_event) + expect(subject.transport).to have_recorded_lost_event(:before_send, 'transaction') + end + end end end end diff --git a/sentry-ruby/spec/sentry/configuration_spec.rb b/sentry-ruby/spec/sentry/configuration_spec.rb index e164f9313..2c2909316 100644 --- a/sentry-ruby/spec/sentry/configuration_spec.rb +++ b/sentry-ruby/spec/sentry/configuration_spec.rb @@ -127,6 +127,12 @@ expect { subject.before_send = true }.to raise_error(ArgumentError, "before_send must be callable (or nil to disable)") end + it 'raises error when setting before_send_transaction to anything other than callable or nil' do + subject.before_send_transaction = -> {} + subject.before_send_transaction = nil + expect { subject.before_send_transaction = true }.to raise_error(ArgumentError, "before_send_transaction must be callable (or nil to disable)") + end + it 'raises error when setting before_breadcrumb to anything other than callable or nil' do subject.before_breadcrumb = -> {} subject.before_breadcrumb = nil