bugsnag 4.0.0 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -0
- data/VERSION +1 -1
- data/lib/bugsnag.rb +1 -1
- data/lib/bugsnag/helpers.rb +102 -15
- data/lib/bugsnag/middleware/rack_request.rb +7 -1
- data/lib/bugsnag/notification.rb +3 -10
- data/lib/bugsnag/railtie.rb +3 -1
- data/lib/bugsnag/sidekiq.rb +4 -0
- data/spec/helper_spec.rb +105 -16
- data/spec/notification_spec.rb +14 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3feeeeef834abcd2676f54ed08468f35d2e61cec
|
4
|
+
data.tar.gz: fa7ff7ef9f2e1619d3d00142f6e7eb1c241c514e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 08264576a36649e2850368e7f6d6c2190d9fe44d4489c963c464f7abcb4201a45a72b9d773a1d26eff2c98be41a0b18e953e295f06156ffe6e56de28a2601625
|
7
|
+
data.tar.gz: cd2424431cae73dea1e41f0b570e241834a063be6cf9c4a59964031467c77ed9089ab8ee312de9a11570a55de019e4bd109eae6e544f2355b1b09fa761948ea5
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,27 @@
|
|
1
1
|
Changelog
|
2
2
|
=========
|
3
3
|
|
4
|
+
## 4.0.1 (5 Apr 2016)
|
5
|
+
|
6
|
+
### Fixes
|
7
|
+
|
8
|
+
* Fix Sidekiq app type being overwritten by Rails
|
9
|
+
| [Luiz Felipe G. Pereira](https://github.com/Draiken)
|
10
|
+
| [#286](https://github.com/bugsnag/bugsnag-ruby/pull/286)
|
11
|
+
|
12
|
+
* Fix report uploads being rejected due to payload size
|
13
|
+
| [Ben Ibinson](https://github.com/CodeHex)
|
14
|
+
| [Duncan Hewett](https://github.com/duncanhewett)
|
15
|
+
| [#288](https://github.com/bugsnag/bugsnag-ruby/pull/288)
|
16
|
+
| [#290](https://github.com/bugsnag/bugsnag-ruby/pull/290)
|
17
|
+
|
18
|
+
* Fix a possible crash when parsing a URL for RackRequest
|
19
|
+
| [Max Schubert](https://github.com/perldork)
|
20
|
+
| [#289](https://github.com/bugsnag/bugsnag-ruby/pull/289)
|
21
|
+
|
22
|
+
* Hide partial API key logged when loading Bugsnag
|
23
|
+
| [#283](https://github.com/bugsnag/bugsnag-ruby/issues/283)
|
24
|
+
|
4
25
|
## 4.0.0 (9 Mar 2016)
|
5
26
|
|
6
27
|
This release includes general fixes as well as removing support
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
4.0.
|
1
|
+
4.0.1
|
data/lib/bugsnag.rb
CHANGED
@@ -47,7 +47,7 @@ module Bugsnag
|
|
47
47
|
@logged_ready = false unless defined?(@logged_ready)
|
48
48
|
|
49
49
|
if configuration.api_key && !@logged_ready
|
50
|
-
log "Bugsnag exception handler #{VERSION} ready
|
50
|
+
log "Bugsnag exception handler #{VERSION} ready"
|
51
51
|
@logged_ready = true
|
52
52
|
end
|
53
53
|
end
|
data/lib/bugsnag/helpers.rb
CHANGED
@@ -1,24 +1,21 @@
|
|
1
1
|
require 'uri'
|
2
|
+
require 'set' unless defined?(Set)
|
3
|
+
require 'json' unless defined?(JSON)
|
4
|
+
|
2
5
|
|
3
6
|
module Bugsnag
|
4
7
|
module Helpers
|
5
8
|
MAX_STRING_LENGTH = 4096
|
9
|
+
MAX_PAYLOAD_LENGTH = 128000
|
10
|
+
MAX_ARRAY_LENGTH = 400
|
6
11
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
else
|
15
|
-
val = v.to_s
|
16
|
-
val = val.slice(0, MAX_STRING_LENGTH) + "[TRUNCATED]" if val.length > MAX_STRING_LENGTH
|
17
|
-
h[k] = val
|
18
|
-
end
|
19
|
-
|
20
|
-
h
|
21
|
-
end
|
12
|
+
# Trim the size of value if the serialized JSON value is longer than is
|
13
|
+
# accepted by Bugsnag
|
14
|
+
def self.trim_if_needed(value)
|
15
|
+
return value unless payload_too_long?(value)
|
16
|
+
reduced_value = trim_strings_in_value(value)
|
17
|
+
return reduced_value unless payload_too_long?(reduced_value)
|
18
|
+
truncate_arrays_in_value(reduced_value)
|
22
19
|
end
|
23
20
|
|
24
21
|
def self.flatten_meta_data(overrides)
|
@@ -31,5 +28,95 @@ module Bugsnag
|
|
31
28
|
overrides
|
32
29
|
end
|
33
30
|
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
TRUNCATION_INFO = '[TRUNCATED]'
|
35
|
+
RAW_DATA_TYPES = [Numeric, TrueClass, FalseClass]
|
36
|
+
|
37
|
+
# Shorten array until it fits within the payload size limit when serialized
|
38
|
+
def self.truncate_arrays(array)
|
39
|
+
return [] unless array.respond_to?(:slice)
|
40
|
+
array = array.slice(0, MAX_ARRAY_LENGTH)
|
41
|
+
while array.length > 0 and payload_too_long?(array)
|
42
|
+
array = array.slice(0, array.length - 1)
|
43
|
+
end
|
44
|
+
array
|
45
|
+
end
|
46
|
+
|
47
|
+
# Trim all strings to be less than the maximum allowed string length
|
48
|
+
def self.trim_strings_in_value(value, seen=[])
|
49
|
+
return value if is_json_raw_type?(value)
|
50
|
+
case value
|
51
|
+
when Hash
|
52
|
+
trim_strings_in_hash(value, seen)
|
53
|
+
when Array, Set
|
54
|
+
trim_strings_in_array(value, seen)
|
55
|
+
else
|
56
|
+
trim_as_string(value)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Validate that the serialized JSON string value is below maximum payload
|
61
|
+
# length
|
62
|
+
def self.payload_too_long?(value)
|
63
|
+
::JSON.dump(value).length >= MAX_PAYLOAD_LENGTH
|
64
|
+
end
|
65
|
+
|
66
|
+
# Check if a value is a raw type which should not be trimmed, truncated
|
67
|
+
# or converted to a string
|
68
|
+
def self.is_json_raw_type?(value)
|
69
|
+
RAW_DATA_TYPES.detect {|klass| value.is_a?(klass)} != nil
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.trim_strings_in_hash(hash, seen=[])
|
73
|
+
return {} if seen.include?(hash) || !hash.is_a?(Hash)
|
74
|
+
result = hash.each_with_object({}) do |(key, value), reduced_hash|
|
75
|
+
if reduced_value = trim_strings_in_value(value, seen)
|
76
|
+
reduced_hash[key] = reduced_value
|
77
|
+
end
|
78
|
+
end
|
79
|
+
seen << hash
|
80
|
+
result
|
81
|
+
end
|
82
|
+
|
83
|
+
# If possible, convert the provided object to a string and trim to the
|
84
|
+
# maximum allowed string length
|
85
|
+
def self.trim_as_string(text)
|
86
|
+
return "" unless text.respond_to? :to_s
|
87
|
+
text = text.to_s
|
88
|
+
if text.length > MAX_STRING_LENGTH
|
89
|
+
length = MAX_STRING_LENGTH - TRUNCATION_INFO.length
|
90
|
+
text = text.slice(0, length) + TRUNCATION_INFO
|
91
|
+
end
|
92
|
+
text
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.trim_strings_in_array(collection, seen=[])
|
96
|
+
return [] if seen.include?(collection) || !collection.respond_to?(:map)
|
97
|
+
result = collection.map {|value| trim_strings_in_value(value, seen)}
|
98
|
+
seen << collection
|
99
|
+
result
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.truncate_arrays_in_value(value)
|
103
|
+
case value
|
104
|
+
when Hash
|
105
|
+
truncate_arrays_in_hash(value)
|
106
|
+
when Array, Set
|
107
|
+
truncate_arrays(value)
|
108
|
+
else
|
109
|
+
value
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.truncate_arrays_in_hash(hash)
|
114
|
+
return {} unless hash.is_a?(Hash)
|
115
|
+
hash.each_with_object({}) do |(key, value), reduced_hash|
|
116
|
+
if reduced_value = truncate_arrays_in_value(value)
|
117
|
+
reduced_hash[key] = reduced_value
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
34
121
|
end
|
35
122
|
end
|
@@ -23,7 +23,13 @@ module Bugsnag::Middleware
|
|
23
23
|
# Build the clean url (hide the port if it is obvious)
|
24
24
|
url = "#{request.scheme}://#{request.host}"
|
25
25
|
url << ":#{request.port}" unless [80, 443].include?(request.port)
|
26
|
-
|
26
|
+
|
27
|
+
# If app is passed a bad URL, this code will crash attempting to clean it
|
28
|
+
begin
|
29
|
+
url << Bugsnag::Cleaner.new(notification.configuration.params_filters).clean_url(request.fullpath)
|
30
|
+
rescue StandardError => stde
|
31
|
+
Bugsnag.log "RackRequest - Rescued error while cleaning request.fullpath: #{stde}"
|
32
|
+
end
|
27
33
|
|
28
34
|
headers = {}
|
29
35
|
|
data/lib/bugsnag/notification.rb
CHANGED
@@ -36,16 +36,9 @@ module Bugsnag
|
|
36
36
|
|
37
37
|
class << self
|
38
38
|
def deliver_exception_payload(url, payload, configuration=Bugsnag.configuration, delivery_method=nil)
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
payload_string = ::JSON.dump(payload)
|
43
|
-
if payload_string.length > 128000
|
44
|
-
payload[:events] = payload[:events].map {|e| Bugsnag::Helpers.reduce_hash_size(e)}
|
45
|
-
payload_string = ::JSON.dump(payload)
|
46
|
-
end
|
47
|
-
|
48
|
-
Bugsnag::Delivery[delivery_method || configuration.delivery_method].deliver(url, payload_string, configuration)
|
39
|
+
payload_string = ::JSON.dump(Bugsnag::Helpers.trim_if_needed(payload))
|
40
|
+
delivery_method = delivery_method || configuration.delivery_method
|
41
|
+
Bugsnag::Delivery[delivery_method].deliver(url, payload_string, configuration)
|
49
42
|
end
|
50
43
|
end
|
51
44
|
|
data/lib/bugsnag/railtie.rb
CHANGED
@@ -7,6 +7,8 @@ require "bugsnag/middleware/rack_request"
|
|
7
7
|
|
8
8
|
module Bugsnag
|
9
9
|
class Railtie < Rails::Railtie
|
10
|
+
cattr_accessor :running_as_dependency
|
11
|
+
|
10
12
|
rake_tasks do
|
11
13
|
require "bugsnag/rake"
|
12
14
|
load "bugsnag/tasks/bugsnag.rake"
|
@@ -49,7 +51,7 @@ module Bugsnag
|
|
49
51
|
ActiveRecord::Base.send(:include, Bugsnag::Rails::ActiveRecordRescue)
|
50
52
|
end
|
51
53
|
|
52
|
-
Bugsnag.configuration.app_type = "rails"
|
54
|
+
Bugsnag.configuration.app_type = "rails" unless Bugsnag::Railtie.running_as_dependency
|
53
55
|
end
|
54
56
|
|
55
57
|
# Configure params_filters after initialization, so that rails initializers
|
data/lib/bugsnag/sidekiq.rb
CHANGED
data/spec/helper_spec.rb
CHANGED
@@ -1,30 +1,119 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
|
+
require 'set'
|
4
5
|
|
5
6
|
describe Bugsnag::Helpers do
|
6
|
-
it "reduces hash size correctly" do
|
7
|
-
meta_data = {
|
8
|
-
:key_one => "this should not be truncated",
|
9
|
-
:key_two => ""
|
10
|
-
}
|
11
7
|
|
12
|
-
|
8
|
+
describe "trim_if_needed" do
|
13
9
|
|
14
|
-
|
10
|
+
context "payload length is less than allowed" do
|
15
11
|
|
16
|
-
|
12
|
+
it "does not change strings" do
|
13
|
+
value = SecureRandom.hex(4096)
|
14
|
+
expect(Bugsnag::Helpers.trim_if_needed(value)).to be value
|
15
|
+
end
|
17
16
|
|
18
|
-
|
19
|
-
|
17
|
+
it "does not change arrays" do
|
18
|
+
value = 1000.times.map {|i| "#{i} - #{i + 1}" }
|
19
|
+
expect(Bugsnag::Helpers.trim_if_needed(value)).to be value
|
20
|
+
end
|
20
21
|
|
21
|
-
|
22
|
-
|
22
|
+
it "does not change hashes" do
|
23
|
+
value = Hash[*1000.times.map{|i| ["#{i}", i]}.flatten]
|
24
|
+
expect(Bugsnag::Helpers.trim_if_needed(value)).to be value
|
25
|
+
end
|
26
|
+
end
|
23
27
|
|
24
|
-
|
25
|
-
expect(meta_data[:key_two].match(/\[TRUNCATED\]$/).nil?).to eq(true)
|
28
|
+
context "payload length is greater than allowed" do
|
26
29
|
|
27
|
-
|
28
|
-
|
30
|
+
context "value is a String" do
|
31
|
+
it "trims length" do
|
32
|
+
value = Bugsnag::Helpers.trim_if_needed(SecureRandom.hex(500_000/2))
|
33
|
+
expect(::JSON.dump(value.length).length).to be < Bugsnag::Helpers::MAX_STRING_LENGTH
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "value is an Array" do
|
38
|
+
it "trims nested string contents" do
|
39
|
+
value = [[30.times.map {|i| SecureRandom.hex(8192) }]]
|
40
|
+
json = ::JSON.dump(Bugsnag::Helpers.trim_if_needed(value))
|
41
|
+
expect(json.length).to be < Bugsnag::Helpers::MAX_PAYLOAD_LENGTH
|
42
|
+
end
|
43
|
+
|
44
|
+
it "trims string contents" do
|
45
|
+
value = 30.times.map {|i| SecureRandom.hex(8192) }
|
46
|
+
json = ::JSON.dump(Bugsnag::Helpers.trim_if_needed(value))
|
47
|
+
expect(json.length).to be < Bugsnag::Helpers::MAX_PAYLOAD_LENGTH
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "value is a Set" do
|
52
|
+
it "trims string contents" do
|
53
|
+
value = Set.new(30.times.map {|i| SecureRandom.hex(8192) })
|
54
|
+
json = ::JSON.dump(Bugsnag::Helpers.trim_if_needed(value))
|
55
|
+
expect(json.length).to be < Bugsnag::Helpers::MAX_PAYLOAD_LENGTH
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "value can be converted to a String" do
|
60
|
+
it "converts to a string and trims" do
|
61
|
+
value = Set.new(30_000.times.map {|i| Bugsnag::Helpers })
|
62
|
+
json = ::JSON.dump(Bugsnag::Helpers.trim_if_needed(value))
|
63
|
+
expect(json.length).to be < Bugsnag::Helpers::MAX_PAYLOAD_LENGTH
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "value is a Hash" do
|
68
|
+
|
69
|
+
before(:each) do
|
70
|
+
@metadata = {
|
71
|
+
:short_string => "this should not be truncated",
|
72
|
+
:long_string => 10000.times.map {|i| "should truncate" }.join(""),
|
73
|
+
:long_string_ary => 30.times.map {|i| SecureRandom.hex(8192) }
|
74
|
+
}
|
75
|
+
|
76
|
+
@trimmed_metadata = Bugsnag::Helpers.trim_if_needed @metadata
|
77
|
+
end
|
78
|
+
|
79
|
+
it "does not trim short values" do
|
80
|
+
expect(@trimmed_metadata[:short_string]).to eq @metadata[:short_string]
|
81
|
+
end
|
82
|
+
|
83
|
+
it "trims long string values" do
|
84
|
+
expect(@trimmed_metadata[:long_string].length).to eq(Bugsnag::Helpers::MAX_STRING_LENGTH)
|
85
|
+
expect(@trimmed_metadata[:long_string].match(/\[TRUNCATED\]$/)).to_not be_nil
|
86
|
+
end
|
87
|
+
|
88
|
+
it "trims nested long string values" do
|
89
|
+
@trimmed_metadata[:long_string_ary].each do |str|
|
90
|
+
expect(str.match(/\[TRUNCATED\]$/)).to_not be_nil
|
91
|
+
expect(str.length).to eq(Bugsnag::Helpers::MAX_STRING_LENGTH)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
it "does not change the argument value" do
|
96
|
+
expect(@metadata[:long_string].length).to be > Bugsnag::Helpers::MAX_STRING_LENGTH
|
97
|
+
expect(@metadata[:long_string].match(/\[TRUNCATED\]$/)).to be_nil
|
98
|
+
expect(@metadata[:short_string].length).to eq(28)
|
99
|
+
expect(@metadata[:short_string]).to eq("this should not be truncated")
|
100
|
+
expect(@trimmed_metadata[:long_string_ary].length).to eq(30)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context "and trimmed strings are not enough" do
|
105
|
+
it "truncates long arrays" do
|
106
|
+
value = 100.times.map {|i| SecureRandom.hex(8192) }
|
107
|
+
trimmed_value = Bugsnag::Helpers.trim_if_needed(value)
|
108
|
+
expect(trimmed_value.length).to be > 0
|
109
|
+
trimmed_value.each do |str|
|
110
|
+
expect(str.match(/\[TRUNCATED\]$/)).to_not be_nil
|
111
|
+
expect(str.length).to eq(Bugsnag::Helpers::MAX_STRING_LENGTH)
|
112
|
+
end
|
113
|
+
|
114
|
+
expect(::JSON.dump(trimmed_value).length).to be < Bugsnag::Helpers::MAX_PAYLOAD_LENGTH
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
29
118
|
end
|
30
119
|
end
|
data/spec/notification_spec.rb
CHANGED
@@ -289,6 +289,20 @@ describe Bugsnag::Notification do
|
|
289
289
|
}
|
290
290
|
end
|
291
291
|
|
292
|
+
it "truncate large stacktraces before sending" do
|
293
|
+
ex = BugsnagTestException.new("It crashed")
|
294
|
+
stacktrace = []
|
295
|
+
5000.times {|i| stacktrace.push("/Some/path/rspec/example.rb:113:in `instance_eval'")}
|
296
|
+
ex.set_backtrace(stacktrace)
|
297
|
+
Bugsnag.notify(ex)
|
298
|
+
|
299
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
300
|
+
# Truncated body should be no bigger than
|
301
|
+
# 400 stacktrace lines * approx 60 chars per line + rest of payload (20000)
|
302
|
+
expect(::JSON.dump(payload).length).to be < 400*60 + 20000
|
303
|
+
}
|
304
|
+
end
|
305
|
+
|
292
306
|
it "accepts a severity in overrides" do
|
293
307
|
Bugsnag.notify(BugsnagTestException.new("It crashed"), {
|
294
308
|
:severity => "info"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bugsnag
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0.
|
4
|
+
version: 4.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Smith
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-04-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|