Skip to content

Commit

Permalink
Merge pull request #286 from airbrake/285-truncation-fix
Browse files Browse the repository at this point in the history
 truncator: fix circular references
  • Loading branch information
kyrylo authored Dec 1, 2017
2 parents 532bb70 + 92b4feb commit 50c97db
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 2 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ Airbrake Ruby Changelog

### master

* Fixed circular references in the new truncator
([#286](https://github.com/airbrake/airbrake-ruby/pull/286)). All v2.6.0 users
are *highly recommended* to upgrade.

### [v2.6.0][v2.6.0] (November 9, 2017)

* Reworked truncation to not mutate given payload (params) and made it freeze it
Expand Down
16 changes: 14 additions & 2 deletions lib/airbrake-ruby/truncator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,15 @@ class Truncator
# strings with +ENCODING_OPTIONS+
TEMP_ENCODING = 'utf-16'.freeze

# @return [String] what to append when something is a circular reference
CIRCULAR = '[Circular]'.freeze

# @return [String] what to append when something is truncated
TRUNCATED = '[Truncated]'.freeze

# @return [Array<Class>] The types that can contain references to itself
CIRCULAR_TYPES = [Array, Hash, Set].freeze

# @param [Integer] max_size maximum size of hashes, arrays and strings
def initialize(max_size)
@max_size = max_size
Expand All @@ -24,7 +33,10 @@ def initialize(max_size)
# @param [Set] seen The cache that helps to detect recursion
# @return [Object] truncated object
def truncate(object, seen = Set.new)
return '[Circular]'.freeze if seen.include?(object)
if seen.include?(object)
return CIRCULAR if CIRCULAR_TYPES.any? { |t| object.is_a?(t) }
return object
end
truncate_object(object, seen << object)
end

Expand All @@ -51,7 +63,7 @@ def truncate_object(object, seen)
def truncate_string(str)
fixed_str = replace_invalid_characters(str)
return fixed_str if fixed_str.length <= @max_size
(fixed_str.slice(0, @max_size) + '[Truncated]').freeze
(fixed_str.slice(0, @max_size) + TRUNCATED).freeze
end

def stringify_object(object)
Expand Down
23 changes: 23 additions & 0 deletions spec/truncator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -211,5 +211,28 @@ def obj.to_json
expect(subject).to be_frozen
end
end

context "given an array with hashes and hash-like objects with identical keys" do
let(:hashie) { Class.new(Hash) }

let(:object) do
{
errors: [
{ file: 'a' },
hashie.new.merge(file: 'bcde')
]
}
end

it "truncates values" do
expect(subject).to eq(
errors: [
{ file: 'a' },
hashie.new.merge(file: 'bcd[Truncated]')
]
)
expect(subject).to be_frozen
end
end
end
end

0 comments on commit 50c97db

Please sign in to comment.