From aad89b30b54975b2510721d671630ed919890037 Mon Sep 17 00:00:00 2001 From: Peter Solnica Date: Tue, 18 Nov 2025 11:08:18 +0000 Subject: [PATCH 1/3] fix(logs): don't choke on malformed attributes --- sentry-ruby/lib/sentry/client.rb | 12 +++++++++++- sentry-ruby/spec/sentry/structured_logger_spec.rb | 7 +++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/sentry-ruby/lib/sentry/client.rb b/sentry-ruby/lib/sentry/client.rb index 56ec28f04..9d439ddc9 100644 --- a/sentry-ruby/lib/sentry/client.rb +++ b/sentry-ruby/lib/sentry/client.rb @@ -199,7 +199,17 @@ def event_from_log(message, level:, **options) return unless body - LogEvent.new(level: level, body: body, attributes: attributes, origin: origin) + sanitized_attributes = attributes.transform_values do |value| + if value.is_a?(String) + return unless (sanitized_string = Utils::EncodingHelper.safe_utf_8_string(value)) + + sanitized_string + else + value + end + end + + LogEvent.new(level: level, body: body, attributes: sanitized_attributes, origin: origin) end # Initializes an Event object with the given Transaction object. diff --git a/sentry-ruby/spec/sentry/structured_logger_spec.rb b/sentry-ruby/spec/sentry/structured_logger_spec.rb index 5ca5e1ed8..dd253b255 100644 --- a/sentry-ruby/spec/sentry/structured_logger_spec.rb +++ b/sentry-ruby/spec/sentry/structured_logger_spec.rb @@ -102,6 +102,13 @@ expect(sentry_logs).to be_empty end + + it "doesn't choke on malformed UTF-8 in attributes" do + malformed_user_agent = "Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp\xA1\xB1)".dup.force_encoding("UTF-8") + Sentry.logger.public_send(level, "Valid message", user_agent: malformed_user_agent) + + expect(sentry_logs).to be_empty + end end end From 94cc9e323948770ae74876d3a5587db7d951ed46 Mon Sep 17 00:00:00 2001 From: Peter Solnica Date: Wed, 19 Nov 2025 13:06:08 +0000 Subject: [PATCH 2/3] Replace malformed strings instead of dropping logs --- .devcontainer/run | 4 +-- sentry-ruby/lib/sentry/client.rb | 6 +--- .../lib/sentry/utils/encoding_helper.rb | 3 +- .../spec/sentry/structured_logger_spec.rb | 36 ++++++++++++++----- 4 files changed, 32 insertions(+), 17 deletions(-) diff --git a/.devcontainer/run b/.devcontainer/run index 1044180b7..59661dace 100755 --- a/.devcontainer/run +++ b/.devcontainer/run @@ -7,8 +7,8 @@ cd /workspace/sentry sudo mkdir -p vendor/gems sudo chown -R sentry:sentry vendor/gems -git config --global --replace-all safe.directory /workspace/sentry -git config --global --replace-all safe.directory /workspace/sentry/vendor/gems/* +# git config --global --replace-all safe.directory /workspace/sentry +# git config --global --replace-all safe.directory /workspace/sentry/vendor/gems/* sudo chown -R sentry:sentry . diff --git a/sentry-ruby/lib/sentry/client.rb b/sentry-ruby/lib/sentry/client.rb index 9d439ddc9..6da454721 100644 --- a/sentry-ruby/lib/sentry/client.rb +++ b/sentry-ruby/lib/sentry/client.rb @@ -197,13 +197,9 @@ def event_from_log(message, level:, **options) origin = options[:origin] body = Utils::EncodingHelper.safe_utf_8_string(message) - return unless body - sanitized_attributes = attributes.transform_values do |value| if value.is_a?(String) - return unless (sanitized_string = Utils::EncodingHelper.safe_utf_8_string(value)) - - sanitized_string + Utils::EncodingHelper.safe_utf_8_string(value) else value end diff --git a/sentry-ruby/lib/sentry/utils/encoding_helper.rb b/sentry-ruby/lib/sentry/utils/encoding_helper.rb index 1587e6efa..10442c168 100644 --- a/sentry-ruby/lib/sentry/utils/encoding_helper.rb +++ b/sentry-ruby/lib/sentry/utils/encoding_helper.rb @@ -4,6 +4,7 @@ module Sentry module Utils module EncodingHelper EMPTY_STRING = "" + MALFORMED_STRING = "" def self.encode_to_utf_8(value) if value.encoding != Encoding::UTF_8 && value.respond_to?(:force_encoding) @@ -21,7 +22,7 @@ def self.valid_utf_8?(value) end def self.safe_utf_8_string(value) - valid_utf_8?(value) && value + valid_utf_8?(value) ? value : MALFORMED_STRING end end end diff --git a/sentry-ruby/spec/sentry/structured_logger_spec.rb b/sentry-ruby/spec/sentry/structured_logger_spec.rb index dd253b255..d9160ed74 100644 --- a/sentry-ruby/spec/sentry/structured_logger_spec.rb +++ b/sentry-ruby/spec/sentry/structured_logger_spec.rb @@ -96,18 +96,36 @@ expect(log_event[:attributes]["sentry.message.parameter.day"]).to eql({ value: "Monday", type: "string" }) end - it "doesn't choke on malformed UTF-8 strings" do - malformed_string = "Hello World\x92".dup.force_encoding("UTF-8") - Sentry.logger.public_send(level, malformed_string, user_id: 123) + context "handling of malformed strings" do + let(:malformed_string_default) do + Sentry::Utils::EncodingHelper::MALFORMED_STRING + end - expect(sentry_logs).to be_empty - end + it "doesn't choke on malformed UTF-8 strings" do + malformed_string = "Hello World\x92".dup.force_encoding("UTF-8") + Sentry.logger.public_send(level, malformed_string, user_id: 123) + + expect(sentry_logs).to_not be_empty - it "doesn't choke on malformed UTF-8 in attributes" do - malformed_user_agent = "Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp\xA1\xB1)".dup.force_encoding("UTF-8") - Sentry.logger.public_send(level, "Valid message", user_agent: malformed_user_agent) + log_event = sentry_logs.last + + expect(log_event[:level]).to eql(level) + expect(log_event[:body]).to eql(malformed_string_default) + end - expect(sentry_logs).to be_empty + it "doesn't choke on malformed UTF-8 in attributes" do + malformed_user_agent = "Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp\xA1\xB1)".dup.force_encoding("UTF-8") + Sentry.logger.public_send(level, "Valid message %{user_agent}", user_agent: malformed_user_agent) + + expect(sentry_logs).to_not be_empty + + log_event = sentry_logs.last + + expect(log_event[:level]).to eql(level) + expect(log_event[:body]).to include("Valid message") + expect(log_event[:attributes]["sentry.message.parameter.user_agent"]) + .to eql({ value: malformed_string_default, type: "string" }) + end end end end From 3a9b5ebbd0f3549f41b9e77464166225a7bcf6b9 Mon Sep 17 00:00:00 2001 From: Peter Solnica Date: Wed, 19 Nov 2025 13:14:52 +0000 Subject: [PATCH 3/3] Add another test scenario --- .../spec/sentry/structured_logger_spec.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sentry-ruby/spec/sentry/structured_logger_spec.rb b/sentry-ruby/spec/sentry/structured_logger_spec.rb index d9160ed74..7dd772ad3 100644 --- a/sentry-ruby/spec/sentry/structured_logger_spec.rb +++ b/sentry-ruby/spec/sentry/structured_logger_spec.rb @@ -113,6 +113,22 @@ expect(log_event[:body]).to eql(malformed_string_default) end + it "doesn't choke on malformed UTF-8 in body and attributes" do + malformed_string = "Hello World %{user_agent} \x92".dup.force_encoding("UTF-8") + malformed_user_agent = "Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp\xA1\xB1)".dup.force_encoding("UTF-8") + Sentry.logger.public_send(level, malformed_string, user_agent: malformed_user_agent, user_id: 312) + + expect(sentry_logs).to_not be_empty + + log_event = sentry_logs.last + + expect(log_event[:level]).to eql(level) + expect(log_event[:body]).to eql(malformed_string_default) + + expect(log_event[:attributes]["sentry.message.parameter.user_id"]).to be_nil + expect(log_event[:attributes]["sentry.message.parameter.user_agent"]).to be_nil + end + it "doesn't choke on malformed UTF-8 in attributes" do malformed_user_agent = "Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp\xA1\xB1)".dup.force_encoding("UTF-8") Sentry.logger.public_send(level, "Valid message %{user_agent}", user_agent: malformed_user_agent)