diff --git a/CHANGELOG.md b/CHANGELOG.md index f73be0415..083f2c569 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## Unreleased + +### Features + +- Add support for ActiveRecord binds in the log events ([#2761](https://github.com/getsentry/sentry-ruby/pull/2761)) + ## 6.0.0 ### Breaking Changes diff --git a/sentry-rails/lib/sentry/rails/log_subscribers/active_record_subscriber.rb b/sentry-rails/lib/sentry/rails/log_subscribers/active_record_subscriber.rb index c159e2423..72f563356 100644 --- a/sentry-rails/lib/sentry/rails/log_subscribers/active_record_subscriber.rb +++ b/sentry-rails/lib/sentry/rails/log_subscribers/active_record_subscriber.rb @@ -46,6 +46,17 @@ def sql(event) cached: cached } + binds = event.payload[:binds] + + if Sentry.configuration.send_default_pii && !binds&.empty? + type_casted_binds = type_casted_binds(event) + + binds.each_with_index do |bind, index| + name = bind.is_a?(Symbol) ? bind : bind.name + attributes["db.query.parameter.#{name}"] = type_casted_binds[index].to_s + end + end + attributes[:statement_name] = statement_name if statement_name && statement_name != "SQL" attributes[:connection_id] = connection_id if connection_id @@ -60,6 +71,16 @@ def sql(event) ) end + if RUBY_ENGINE == "jruby" + def type_casted_binds(event) + event.payload[:type_casted_binds].call + end + else + def type_casted_binds(event) + event.payload[:type_casted_binds] + end + end + private def build_log_message(statement_name) diff --git a/sentry-rails/spec/dummy/test_rails_app/apps/5-2.rb b/sentry-rails/spec/dummy/test_rails_app/apps/5-2.rb index 9dfcf0d62..273698df3 100644 --- a/sentry-rails/spec/dummy/test_rails_app/apps/5-2.rb +++ b/sentry-rails/spec/dummy/test_rails_app/apps/5-2.rb @@ -30,6 +30,8 @@ end create_table :posts, force: true do |t| + t.string :title + t.timestamps end create_table :comments, force: true do |t| diff --git a/sentry-rails/spec/dummy/test_rails_app/apps/6-0.rb b/sentry-rails/spec/dummy/test_rails_app/apps/6-0.rb index 9dfcf0d62..273698df3 100644 --- a/sentry-rails/spec/dummy/test_rails_app/apps/6-0.rb +++ b/sentry-rails/spec/dummy/test_rails_app/apps/6-0.rb @@ -30,6 +30,8 @@ end create_table :posts, force: true do |t| + t.string :title + t.timestamps end create_table :comments, force: true do |t| diff --git a/sentry-rails/spec/dummy/test_rails_app/apps/6-1.rb b/sentry-rails/spec/dummy/test_rails_app/apps/6-1.rb index a9148a3ee..494fe0eeb 100644 --- a/sentry-rails/spec/dummy/test_rails_app/apps/6-1.rb +++ b/sentry-rails/spec/dummy/test_rails_app/apps/6-1.rb @@ -30,6 +30,8 @@ end create_table :posts, force: true do |t| + t.string :title + t.timestamps end create_table :comments, force: true do |t| diff --git a/sentry-rails/spec/dummy/test_rails_app/apps/7-0.rb b/sentry-rails/spec/dummy/test_rails_app/apps/7-0.rb index a9148a3ee..494fe0eeb 100644 --- a/sentry-rails/spec/dummy/test_rails_app/apps/7-0.rb +++ b/sentry-rails/spec/dummy/test_rails_app/apps/7-0.rb @@ -30,6 +30,8 @@ end create_table :posts, force: true do |t| + t.string :title + t.timestamps end create_table :comments, force: true do |t| diff --git a/sentry-rails/spec/dummy/test_rails_app/apps/7-1.rb b/sentry-rails/spec/dummy/test_rails_app/apps/7-1.rb index a9148a3ee..494fe0eeb 100644 --- a/sentry-rails/spec/dummy/test_rails_app/apps/7-1.rb +++ b/sentry-rails/spec/dummy/test_rails_app/apps/7-1.rb @@ -30,6 +30,8 @@ end create_table :posts, force: true do |t| + t.string :title + t.timestamps end create_table :comments, force: true do |t| diff --git a/sentry-rails/spec/sentry/rails/log_subscribers/active_record_subscriber_spec.rb b/sentry-rails/spec/sentry/rails/log_subscribers/active_record_subscriber_spec.rb index 3f4c578a0..c97b44eec 100644 --- a/sentry-rails/spec/sentry/rails/log_subscribers/active_record_subscriber_spec.rb +++ b/sentry-rails/spec/sentry/rails/log_subscribers/active_record_subscriber_spec.rb @@ -12,6 +12,7 @@ config.rails.structured_logging.subscribers = { active_record: Sentry::Rails::LogSubscribers::ActiveRecordSubscriber } end end + describe "integration with ActiveSupport::Notifications" do it "logs SQL events when database queries are executed" do Post.create! @@ -45,6 +46,62 @@ expect(log_event[:attributes][:sql][:value]).to include("posts") end + context "when send_default_pii is enabled" do + before do + Sentry.configuration.send_default_pii = true + end + + after do + Sentry.configuration.send_default_pii = false + end + + it "logs SELECT queries with binds in attributes" do + post = Post.create!(title: "test") + + Sentry.get_current_client.flush + sentry_transport.events.clear + sentry_transport.envelopes.clear + + created_at = Time.new(2025, 10, 28, 13, 11, 44) + Post.where(id: post.id, title: post.title, created_at: created_at).to_a + + Sentry.get_current_client.flush + + log_event = sentry_logs.find { |log| log[:body]&.include?("Database query") } + expect(log_event).not_to be_nil + + # Follow Sentry convention: db.query.parameter. with string values + expect(log_event[:attributes]["db.query.parameter.id"][:value]).to eq(post.id.to_s) + expect(log_event[:attributes]["db.query.parameter.id"][:type]).to eql("string") + + expect(log_event[:attributes]["db.query.parameter.title"][:value]).to eql(post.title) + expect(log_event[:attributes]["db.query.parameter.title"][:type]).to eql("string") + + expect(log_event[:attributes]["db.query.parameter.created_at"][:value]).to include("2025-10-28 13:11:44") + expect(log_event[:attributes]["db.query.parameter.created_at"][:type]).to eql("string") + end + end + + context "when send_default_pii is disabled" do + it "logs SELECT queries without binds in attributes" do + post = Post.create!(title: "test") + + Sentry.get_current_client.flush + sentry_transport.events.clear + sentry_transport.envelopes.clear + + Post.where(id: post.id, title: post.title).to_a + + Sentry.get_current_client.flush + + log_event = sentry_logs.find { |log| log[:body]&.include?("Database query") } + expect(log_event).not_to be_nil + + expect(log_event[:attributes]["db.query.parameter.id"]).to be_nil + expect(log_event[:attributes]["db.query.parameter.title"]).to be_nil + end + end + if Rails.version.to_f > 5.1 it "excludes SCHEMA events" do ActiveSupport::Notifications.instrument("sql.active_record",