From d9ce354e4362259a25d36ea5c3ad2b71a4376f25 Mon Sep 17 00:00:00 2001 From: Joshua Pinter Date: Wed, 7 Oct 2020 22:10:48 -0600 Subject: [PATCH] Truncate Exception Messages if needed. If an exception occurs, such as a `Mysql2::Error::ConnectionError`, where the query is extremely long, this can cause the payload to exceed what Bugsnag will accept and throw a `Errno::EPIPE: Broken pipe` error when trying to send the request to Bugsnag. A number of elements are already trimmed when the payload is too large, including meta data, stacktrace code, etc. However, the exception messages were not being trimmed. This commit adds exception message trimming to `Bugsnag::Helpers.trim_if_needed`, which should help reduce errors when the queries causing the errors are exceptionally long. It also adds a spec to `helper_spec.rb` that tests this functionality. --- lib/bugsnag/helpers.rb | 17 +++++++++++++++-- spec/helper_spec.rb | 16 ++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/lib/bugsnag/helpers.rb b/lib/bugsnag/helpers.rb index 21223f74a..41fc19618 100644 --- a/lib/bugsnag/helpers.rb +++ b/lib/bugsnag/helpers.rb @@ -19,8 +19,12 @@ def self.trim_if_needed(value) return value unless payload_too_long?(value) + # Truncate exception messages + reduced_value = truncate_exception_messages(value) + return reduced_value unless payload_too_long?(reduced_value) + # Trim metadata - reduced_value = trim_metadata(value) + reduced_value = trim_metadata(reduced_value) return reduced_value unless payload_too_long?(reduced_value) # Trim code from stacktrace @@ -71,6 +75,15 @@ def self.deep_merge!(l_hash, r_hash) TRUNCATION_INFO = '[TRUNCATED]' + ## + # Truncate exception messages + def self.truncate_exception_messages(payload) + extract_exception(payload) do |exception| + exception[:message] = trim_as_string(exception[:message]) + end + payload + end + ## # Remove all code from stacktraces def self.trim_stacktrace_code(payload) @@ -98,7 +111,7 @@ def self.extract_exception(payload) valid_payload = payload.is_a?(Hash) && payload[:events].respond_to?(:map) return unless valid_payload && block_given? payload[:events].each do |event| - event[:exceptions].each { |exception| yield exception } + event.fetch(:exceptions, []).each { |exception| yield exception } end end diff --git a/spec/helper_spec.rb b/spec/helper_spec.rb index 11323c932..2d0c7b94e 100644 --- a/spec/helper_spec.rb +++ b/spec/helper_spec.rb @@ -41,6 +41,22 @@ end context "payload length is greater than allowed" do + it "trims exception messages" do + payload = { + :events => [{ + :exceptions => [{ + :message => 50000.times.map {|i| "should truncate" }.join(""), + :preserved => "Foo" + }] + }] + } + expect(::JSON.dump(payload).length).to be > Bugsnag::Helpers::MAX_PAYLOAD_LENGTH + trimmed = Bugsnag::Helpers.trim_if_needed(payload) + expect(::JSON.dump(trimmed).length).to be <= Bugsnag::Helpers::MAX_PAYLOAD_LENGTH + expect(trimmed[:events][0][:exceptions][0][:message].length).to be <= Bugsnag::Helpers::MAX_STRING_LENGTH + expect(trimmed[:events][0][:exceptions][0][:preserved]).to eq("Foo") + end + it "trims metadata strings" do payload = { :events => [{