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

Trim nested arrays and drop metadata to save on payload size #295

Merged
merged 3 commits into from
May 11, 2016
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 18 additions & 9 deletions lib/bugsnag/helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

module Bugsnag
module Helpers
MAX_STRING_LENGTH = 4096
MAX_STRING_LENGTH = 3072
MAX_PAYLOAD_LENGTH = 128000
MAX_ARRAY_LENGTH = 400
MAX_ARRAY_LENGTH = 40
RAW_DATA_TYPES = [Numeric, TrueClass, FalseClass]

# Trim the size of value if the serialized JSON value is longer than is
Expand All @@ -17,7 +17,9 @@ def self.trim_if_needed(value)
return sanitized_value unless payload_too_long?(sanitized_value)
reduced_value = trim_strings_in_value(sanitized_value)
return reduced_value unless payload_too_long?(reduced_value)
truncate_arrays_in_value(reduced_value)
reduced_value = truncate_arrays_in_value(reduced_value)
return reduced_value unless payload_too_long?(reduced_value)
remove_metadata_from_events(reduced_value)
end

def self.flatten_meta_data(overrides)
Expand All @@ -42,13 +44,11 @@ def self.is_json_raw_type?(value)
TRUNCATION_INFO = '[TRUNCATED]'

# Shorten array until it fits within the payload size limit when serialized
def self.truncate_arrays(array)
def self.truncate_array(array)
return [] unless array.respond_to?(:slice)
array = array.slice(0, MAX_ARRAY_LENGTH)
while array.length > 0 and payload_too_long?(array)
array = array.slice(0, array.length - 1)
array.slice(0, MAX_ARRAY_LENGTH).map do |item|
truncate_arrays_in_value(item)
end
array
end

# Trim all strings to be less than the maximum allowed string length
Expand Down Expand Up @@ -101,12 +101,21 @@ def self.truncate_arrays_in_value(value)
when Hash
truncate_arrays_in_hash(value)
when Array, Set
truncate_arrays(value)
truncate_array(value)
else
value
end
end

# Remove `metaData` from array of `events` within object
def self.remove_metadata_from_events(object)
return {} unless object.is_a?(Hash) and object[:events].respond_to?(:map)
object[:events].map do |event|
event.delete(:metaData) if object.is_a?(Hash)
end
object
end

def self.truncate_arrays_in_hash(hash)
return {} unless hash.is_a?(Hash)
hash.each_with_object({}) do |(key, value), reduced_hash|
Expand Down
18 changes: 15 additions & 3 deletions spec/helper_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -135,16 +135,28 @@

context "and trimmed strings are not enough" do
it "truncates long arrays" do
value = 100.times.map {|i| SecureRandom.hex(8192) }
value = [100.times.map {|i| SecureRandom.hex(8192) }, "a"]
trimmed_value = Bugsnag::Helpers.trim_if_needed(value)
expect(trimmed_value.length).to be > 0
trimmed_value.each do |str|
expect(trimmed_value.length).to eq 2
expect(trimmed_value.first.length).to eq Bugsnag::Helpers::MAX_ARRAY_LENGTH
trimmed_value.first.each do |str|
expect(str.match(/\[TRUNCATED\]$/)).to_not be_nil
expect(str.length).to eq(Bugsnag::Helpers::MAX_STRING_LENGTH)
end

expect(::JSON.dump(trimmed_value).length).to be < Bugsnag::Helpers::MAX_PAYLOAD_LENGTH
end

it "removes metadata from events" do
metadata = Hash[*20000.times.map {|i| [i,i+1]}.flatten]
frames = 100.times.map {|i| SecureRandom.hex(4096) }
value = {key:"abc", events:[{metaData: metadata, frames: frames, cake: "carrot"}]}
trimmed_value = Bugsnag::Helpers.trim_if_needed(value)
expect(::JSON.dump(trimmed_value).length).to be < Bugsnag::Helpers::MAX_PAYLOAD_LENGTH
expect(trimmed_value[:key]).to eq value[:key]
expect(trimmed_value[:events].first.keys.to_set).to eq [:frames, :cake].to_set
expect(trimmed_value[:events].first[:metaData]).to be_nil
end
end
end
end
Expand Down