raygun4ruby 3.2.3 → 3.2.4
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/.gitignore +18 -18
- data/.rspec +1 -1
- data/.travis.yml +20 -20
- data/CHANGELOG.md +127 -124
- data/Gemfile +4 -4
- data/LICENSE.txt +22 -22
- data/README.md +420 -420
- data/Rakefile +27 -27
- data/examples/sinatras_raygun.rb +17 -17
- data/lib/generators/raygun/install_generator.rb +26 -26
- data/lib/raygun.rb +179 -179
- data/lib/raygun/affected_user.rb +59 -59
- data/lib/raygun/breadcrumbs.rb +34 -34
- data/lib/raygun/breadcrumbs/breadcrumb.rb +34 -34
- data/lib/raygun/breadcrumbs/store.rb +86 -86
- data/lib/raygun/client.rb +305 -305
- data/lib/raygun/configuration.rb +194 -194
- data/lib/raygun/error.rb +10 -10
- data/lib/raygun/javascript_tracker.rb +42 -42
- data/lib/raygun/middleware/breadcrumbs_store_initializer.rb +19 -19
- data/lib/raygun/middleware/javascript_exception_tracking.rb +32 -32
- data/lib/raygun/middleware/rack_exception_interceptor.rb +18 -18
- data/lib/raygun/middleware/rails_insert_affected_user.rb +26 -26
- data/lib/raygun/railtie.rb +39 -39
- data/lib/raygun/services/apply_whitelist_filter_to_payload.rb +27 -27
- data/lib/raygun/sidekiq.rb +71 -70
- data/lib/raygun/testable.rb +22 -22
- data/lib/raygun/version.rb +3 -3
- data/lib/raygun4ruby.rb +1 -1
- data/lib/resque/failure/raygun.rb +25 -25
- data/lib/tasks/raygun.tasks +7 -7
- data/raygun4ruby.gemspec +45 -45
- data/spec/dummy/.gitignore +17 -17
- data/spec/dummy/Gemfile +47 -47
- data/spec/dummy/README.rdoc +28 -28
- data/spec/dummy/Rakefile +6 -6
- data/spec/dummy/app/assets/config/manifest.js +2 -2
- data/spec/dummy/app/assets/javascripts/application.js +13 -13
- data/spec/dummy/app/assets/stylesheets/application.css +15 -15
- data/spec/dummy/app/controllers/application_controller.rb +5 -5
- data/spec/dummy/app/controllers/home_controller.rb +4 -4
- data/spec/dummy/app/helpers/application_helper.rb +2 -2
- data/spec/dummy/app/views/home/index.html.erb +3 -3
- data/spec/dummy/app/views/home/index.json.erb +1 -1
- data/spec/dummy/app/views/layouts/application.html.erb +14 -14
- data/spec/dummy/bin/bundle +3 -3
- data/spec/dummy/bin/rails +9 -9
- data/spec/dummy/bin/rake +9 -9
- data/spec/dummy/bin/setup +29 -29
- data/spec/dummy/bin/spring +17 -17
- data/spec/dummy/config.ru +4 -4
- data/spec/dummy/config/application.rb +26 -26
- data/spec/dummy/config/boot.rb +3 -3
- data/spec/dummy/config/database.yml +25 -25
- data/spec/dummy/config/environment.rb +5 -5
- data/spec/dummy/config/environments/development.rb +41 -41
- data/spec/dummy/config/environments/production.rb +79 -79
- data/spec/dummy/config/environments/test.rb +42 -42
- data/spec/dummy/config/initializers/assets.rb +11 -11
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -7
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -3
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -4
- data/spec/dummy/config/initializers/inflections.rb +16 -16
- data/spec/dummy/config/initializers/mime_types.rb +4 -4
- data/spec/dummy/config/initializers/session_store.rb +3 -3
- data/spec/dummy/config/initializers/to_time_preserves_timezone.rb +10 -10
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -14
- data/spec/dummy/config/locales/en.yml +23 -23
- data/spec/dummy/config/routes.rb +58 -58
- data/spec/dummy/config/secrets.yml +22 -22
- data/spec/dummy/db/seeds.rb +7 -7
- data/spec/dummy/public/404.html +67 -67
- data/spec/dummy/public/422.html +67 -67
- data/spec/dummy/public/500.html +66 -66
- data/spec/dummy/public/robots.txt +5 -5
- data/spec/dummy/test/test_helper.rb +10 -10
- data/spec/features/javascript_spec.rb +48 -48
- data/spec/rails_helper.rb +4 -4
- data/spec/raygun/breadcrumbs/breadcrumb_spec.rb +171 -171
- data/spec/raygun/breadcrumbs/store_spec.rb +170 -170
- data/spec/raygun/raygun_spec.rb +47 -47
- data/spec/services/apply_whitelist_filter_to_payload_spec.rb +251 -251
- data/spec/spec_helper.rb +24 -24
- data/spec/support/fake_logger.rb +17 -17
- data/test/integration/client_test.rb +19 -19
- data/test/test_helper.rb +72 -72
- data/test/unit/affected_user_test.rb +136 -136
- data/test/unit/client_test.rb +792 -792
- data/test/unit/configuration_test.rb +206 -206
- data/test/unit/raygun_test.rb +25 -25
- data/test/unit/resque_failure_test.rb +24 -24
- data/test/unit/sidekiq_failure_test.rb +32 -32
- metadata +7 -7
data/lib/raygun/affected_user.rb
CHANGED
@@ -1,59 +1,59 @@
|
|
1
|
-
module Raygun
|
2
|
-
class AffectedUser
|
3
|
-
|
4
|
-
DEFAULT_MAPPING = {
|
5
|
-
identifier: [ :id, :username ],
|
6
|
-
email: :email,
|
7
|
-
full_name: [ :full_name, :name ],
|
8
|
-
first_name: :first_name,
|
9
|
-
uuid: :uuid
|
10
|
-
}.freeze
|
11
|
-
SUPPORTED_ATTRIBUTES = DEFAULT_MAPPING.keys.freeze
|
12
|
-
NAME_TO_RAYGUN_NAME_MAPPING = {
|
13
|
-
identifier: :identifier,
|
14
|
-
email: :email,
|
15
|
-
full_name: :fullName,
|
16
|
-
first_name: :firstName,
|
17
|
-
uuid: :uuid
|
18
|
-
}.freeze
|
19
|
-
|
20
|
-
class << self
|
21
|
-
def information_hash(user_object)
|
22
|
-
if user_object.nil? || user_object.is_a?(String)
|
23
|
-
handle_anonymous_user(user_object)
|
24
|
-
else
|
25
|
-
handle_known_user(user_object)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
def handle_anonymous_user(user_object)
|
32
|
-
result = { isAnonymous: true }
|
33
|
-
result[:identifier] = user_object unless user_object.nil?
|
34
|
-
result
|
35
|
-
end
|
36
|
-
|
37
|
-
def handle_known_user(user_object)
|
38
|
-
SUPPORTED_ATTRIBUTES.reduce({ isAnonymous: false }) do |result, attribute|
|
39
|
-
mapping = Raygun.configuration.affected_user_mapping
|
40
|
-
method = mapping[attribute]
|
41
|
-
|
42
|
-
value = if method.is_a? Proc
|
43
|
-
method.call(user_object)
|
44
|
-
else
|
45
|
-
attributes = Array(method)
|
46
|
-
attribute_to_use = attributes.select do |attr|
|
47
|
-
user_object.respond_to?(attr, true)
|
48
|
-
end.first
|
49
|
-
|
50
|
-
user_object.send(attribute_to_use) unless attribute_to_use == nil
|
51
|
-
end
|
52
|
-
|
53
|
-
result[NAME_TO_RAYGUN_NAME_MAPPING[attribute]] = value unless value == nil
|
54
|
-
result
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
1
|
+
module Raygun
|
2
|
+
class AffectedUser
|
3
|
+
|
4
|
+
DEFAULT_MAPPING = {
|
5
|
+
identifier: [ :id, :username ],
|
6
|
+
email: :email,
|
7
|
+
full_name: [ :full_name, :name ],
|
8
|
+
first_name: :first_name,
|
9
|
+
uuid: :uuid
|
10
|
+
}.freeze
|
11
|
+
SUPPORTED_ATTRIBUTES = DEFAULT_MAPPING.keys.freeze
|
12
|
+
NAME_TO_RAYGUN_NAME_MAPPING = {
|
13
|
+
identifier: :identifier,
|
14
|
+
email: :email,
|
15
|
+
full_name: :fullName,
|
16
|
+
first_name: :firstName,
|
17
|
+
uuid: :uuid
|
18
|
+
}.freeze
|
19
|
+
|
20
|
+
class << self
|
21
|
+
def information_hash(user_object)
|
22
|
+
if user_object.nil? || user_object.is_a?(String)
|
23
|
+
handle_anonymous_user(user_object)
|
24
|
+
else
|
25
|
+
handle_known_user(user_object)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def handle_anonymous_user(user_object)
|
32
|
+
result = { isAnonymous: true }
|
33
|
+
result[:identifier] = user_object unless user_object.nil?
|
34
|
+
result
|
35
|
+
end
|
36
|
+
|
37
|
+
def handle_known_user(user_object)
|
38
|
+
SUPPORTED_ATTRIBUTES.reduce({ isAnonymous: false }) do |result, attribute|
|
39
|
+
mapping = Raygun.configuration.affected_user_mapping
|
40
|
+
method = mapping[attribute]
|
41
|
+
|
42
|
+
value = if method.is_a? Proc
|
43
|
+
method.call(user_object)
|
44
|
+
else
|
45
|
+
attributes = Array(method)
|
46
|
+
attribute_to_use = attributes.select do |attr|
|
47
|
+
user_object.respond_to?(attr, true)
|
48
|
+
end.first
|
49
|
+
|
50
|
+
user_object.send(attribute_to_use) unless attribute_to_use == nil
|
51
|
+
end
|
52
|
+
|
53
|
+
result[NAME_TO_RAYGUN_NAME_MAPPING[attribute]] = value unless value == nil
|
54
|
+
result
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/raygun/breadcrumbs.rb
CHANGED
@@ -1,34 +1,34 @@
|
|
1
|
-
module Raygun
|
2
|
-
module Breadcrumbs
|
3
|
-
BREADCRUMB_LEVELS = [
|
4
|
-
:debug,
|
5
|
-
:info,
|
6
|
-
:warning,
|
7
|
-
:error,
|
8
|
-
:fatal
|
9
|
-
]
|
10
|
-
|
11
|
-
def record_breadcrumb(
|
12
|
-
message: nil,
|
13
|
-
category: '',
|
14
|
-
level: :info,
|
15
|
-
timestamp: Time.now.utc.to_i,
|
16
|
-
metadata: {},
|
17
|
-
class_name: nil,
|
18
|
-
method_name: nil,
|
19
|
-
line_number: nil
|
20
|
-
)
|
21
|
-
class_name = class_name || self.class.name
|
22
|
-
Raygun::Breadcrumbs::Store.record(
|
23
|
-
message: message,
|
24
|
-
category: category,
|
25
|
-
level: level,
|
26
|
-
timestamp: timestamp,
|
27
|
-
metadata: metadata,
|
28
|
-
class_name: class_name,
|
29
|
-
method_name: method_name,
|
30
|
-
line_number: line_number,
|
31
|
-
)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
1
|
+
module Raygun
|
2
|
+
module Breadcrumbs
|
3
|
+
BREADCRUMB_LEVELS = [
|
4
|
+
:debug,
|
5
|
+
:info,
|
6
|
+
:warning,
|
7
|
+
:error,
|
8
|
+
:fatal
|
9
|
+
]
|
10
|
+
|
11
|
+
def record_breadcrumb(
|
12
|
+
message: nil,
|
13
|
+
category: '',
|
14
|
+
level: :info,
|
15
|
+
timestamp: Time.now.utc.to_i,
|
16
|
+
metadata: {},
|
17
|
+
class_name: nil,
|
18
|
+
method_name: nil,
|
19
|
+
line_number: nil
|
20
|
+
)
|
21
|
+
class_name = class_name || self.class.name
|
22
|
+
Raygun::Breadcrumbs::Store.record(
|
23
|
+
message: message,
|
24
|
+
category: category,
|
25
|
+
level: level,
|
26
|
+
timestamp: timestamp,
|
27
|
+
metadata: metadata,
|
28
|
+
class_name: class_name,
|
29
|
+
method_name: method_name,
|
30
|
+
line_number: line_number,
|
31
|
+
)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -1,34 +1,34 @@
|
|
1
|
-
module Raygun
|
2
|
-
module Breadcrumbs
|
3
|
-
class Breadcrumb
|
4
|
-
ATTRIBUTES = [
|
5
|
-
:message, :category, :metadata, :class_name,
|
6
|
-
:method_name, :line_number, :timestamp, :level,
|
7
|
-
:type
|
8
|
-
]
|
9
|
-
attr_accessor(*ATTRIBUTES)
|
10
|
-
|
11
|
-
def build_payload
|
12
|
-
payload = {
|
13
|
-
message: message,
|
14
|
-
category: category,
|
15
|
-
level: Breadcrumbs::BREADCRUMB_LEVELS.index(level),
|
16
|
-
CustomData: metadata,
|
17
|
-
timestamp: timestamp,
|
18
|
-
type: type
|
19
|
-
}
|
20
|
-
|
21
|
-
payload[:location] = "#{class_name}:#{method_name}" unless class_name == nil
|
22
|
-
payload[:location] += ":#{line_number}" if payload.has_key?(:location) && line_number != nil
|
23
|
-
|
24
|
-
Hash[payload.select do |k, v|
|
25
|
-
v != nil
|
26
|
-
end]
|
27
|
-
end
|
28
|
-
|
29
|
-
def size
|
30
|
-
return message.length + 100
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
1
|
+
module Raygun
|
2
|
+
module Breadcrumbs
|
3
|
+
class Breadcrumb
|
4
|
+
ATTRIBUTES = [
|
5
|
+
:message, :category, :metadata, :class_name,
|
6
|
+
:method_name, :line_number, :timestamp, :level,
|
7
|
+
:type
|
8
|
+
]
|
9
|
+
attr_accessor(*ATTRIBUTES)
|
10
|
+
|
11
|
+
def build_payload
|
12
|
+
payload = {
|
13
|
+
message: message,
|
14
|
+
category: category,
|
15
|
+
level: Breadcrumbs::BREADCRUMB_LEVELS.index(level),
|
16
|
+
CustomData: metadata,
|
17
|
+
timestamp: timestamp,
|
18
|
+
type: type
|
19
|
+
}
|
20
|
+
|
21
|
+
payload[:location] = "#{class_name}:#{method_name}" unless class_name == nil
|
22
|
+
payload[:location] += ":#{line_number}" if payload.has_key?(:location) && line_number != nil
|
23
|
+
|
24
|
+
Hash[payload.select do |k, v|
|
25
|
+
v != nil
|
26
|
+
end]
|
27
|
+
end
|
28
|
+
|
29
|
+
def size
|
30
|
+
return message.length + 100
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -1,86 +1,86 @@
|
|
1
|
-
require_relative 'breadcrumb'
|
2
|
-
|
3
|
-
module Raygun
|
4
|
-
module Breadcrumbs
|
5
|
-
class Store
|
6
|
-
def self.initialize
|
7
|
-
Thread.current[:breadcrumbs] ||= []
|
8
|
-
end
|
9
|
-
|
10
|
-
def self.clear
|
11
|
-
Thread.current[:breadcrumbs] = nil
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.stored
|
15
|
-
Thread.current[:breadcrumbs]
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.record(
|
19
|
-
message: nil,
|
20
|
-
category: '',
|
21
|
-
level: :info,
|
22
|
-
timestamp: Time.now.utc.to_i,
|
23
|
-
metadata: {},
|
24
|
-
class_name: nil,
|
25
|
-
method_name: nil,
|
26
|
-
line_number: nil
|
27
|
-
)
|
28
|
-
raise ArgumentError.new('missing keyword: message') if message == nil
|
29
|
-
crumb = Breadcrumb.new
|
30
|
-
|
31
|
-
crumb.message = message
|
32
|
-
crumb.category = category
|
33
|
-
crumb.level = level
|
34
|
-
crumb.metadata = metadata
|
35
|
-
crumb.timestamp = timestamp
|
36
|
-
crumb.type = 'manual'
|
37
|
-
|
38
|
-
caller = caller_locations[1]
|
39
|
-
crumb.class_name = class_name
|
40
|
-
crumb.method_name = method_name || caller.label
|
41
|
-
crumb.line_number = line_number || caller.lineno
|
42
|
-
|
43
|
-
Thread.current[:breadcrumbs] << crumb if should_record?(crumb)
|
44
|
-
end
|
45
|
-
|
46
|
-
def self.any?
|
47
|
-
stored != nil && stored.length > 0
|
48
|
-
end
|
49
|
-
|
50
|
-
def self.take_until_size(size)
|
51
|
-
breadcrumb_size = 0
|
52
|
-
|
53
|
-
stored.reverse.take_while do |crumb|
|
54
|
-
breadcrumb_size += crumb.size
|
55
|
-
|
56
|
-
breadcrumb_size < size
|
57
|
-
end.reverse
|
58
|
-
end
|
59
|
-
|
60
|
-
private
|
61
|
-
|
62
|
-
def self.should_record?(crumb)
|
63
|
-
if stored.nil?
|
64
|
-
if Raygun.configuration.debug
|
65
|
-
Raygun.log('[Raygun.breadcrumbs] store is uninitialized while breadcrumb is being recorded, discarding breadcrumb')
|
66
|
-
end
|
67
|
-
|
68
|
-
return false
|
69
|
-
end
|
70
|
-
|
71
|
-
levels = Raygun::Breadcrumbs::BREADCRUMB_LEVELS
|
72
|
-
|
73
|
-
active_level = levels.index(Raygun.configuration.breadcrumb_level)
|
74
|
-
crumb_level = levels.index(crumb.level) || -1
|
75
|
-
|
76
|
-
discard = crumb_level < active_level
|
77
|
-
|
78
|
-
if discard && Raygun.configuration.debug
|
79
|
-
Raygun.log("[Raygun.breadcrumbs] discarding breadcrumb because #{crumb.level} is below active breadcrumb level (#{Raygun.configuration.breadcrumb_level})")
|
80
|
-
end
|
81
|
-
|
82
|
-
!discard
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
1
|
+
require_relative 'breadcrumb'
|
2
|
+
|
3
|
+
module Raygun
|
4
|
+
module Breadcrumbs
|
5
|
+
class Store
|
6
|
+
def self.initialize
|
7
|
+
Thread.current[:breadcrumbs] ||= []
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.clear
|
11
|
+
Thread.current[:breadcrumbs] = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.stored
|
15
|
+
Thread.current[:breadcrumbs]
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.record(
|
19
|
+
message: nil,
|
20
|
+
category: '',
|
21
|
+
level: :info,
|
22
|
+
timestamp: Time.now.utc.to_i,
|
23
|
+
metadata: {},
|
24
|
+
class_name: nil,
|
25
|
+
method_name: nil,
|
26
|
+
line_number: nil
|
27
|
+
)
|
28
|
+
raise ArgumentError.new('missing keyword: message') if message == nil
|
29
|
+
crumb = Breadcrumb.new
|
30
|
+
|
31
|
+
crumb.message = message
|
32
|
+
crumb.category = category
|
33
|
+
crumb.level = level
|
34
|
+
crumb.metadata = metadata
|
35
|
+
crumb.timestamp = timestamp
|
36
|
+
crumb.type = 'manual'
|
37
|
+
|
38
|
+
caller = caller_locations[1]
|
39
|
+
crumb.class_name = class_name
|
40
|
+
crumb.method_name = method_name || caller.label
|
41
|
+
crumb.line_number = line_number || caller.lineno
|
42
|
+
|
43
|
+
Thread.current[:breadcrumbs] << crumb if should_record?(crumb)
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.any?
|
47
|
+
stored != nil && stored.length > 0
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.take_until_size(size)
|
51
|
+
breadcrumb_size = 0
|
52
|
+
|
53
|
+
stored.reverse.take_while do |crumb|
|
54
|
+
breadcrumb_size += crumb.size
|
55
|
+
|
56
|
+
breadcrumb_size < size
|
57
|
+
end.reverse
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def self.should_record?(crumb)
|
63
|
+
if stored.nil?
|
64
|
+
if Raygun.configuration.debug
|
65
|
+
Raygun.log('[Raygun.breadcrumbs] store is uninitialized while breadcrumb is being recorded, discarding breadcrumb')
|
66
|
+
end
|
67
|
+
|
68
|
+
return false
|
69
|
+
end
|
70
|
+
|
71
|
+
levels = Raygun::Breadcrumbs::BREADCRUMB_LEVELS
|
72
|
+
|
73
|
+
active_level = levels.index(Raygun.configuration.breadcrumb_level)
|
74
|
+
crumb_level = levels.index(crumb.level) || -1
|
75
|
+
|
76
|
+
discard = crumb_level < active_level
|
77
|
+
|
78
|
+
if discard && Raygun.configuration.debug
|
79
|
+
Raygun.log("[Raygun.breadcrumbs] discarding breadcrumb because #{crumb.level} is below active breadcrumb level (#{Raygun.configuration.breadcrumb_level})")
|
80
|
+
end
|
81
|
+
|
82
|
+
!discard
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
data/lib/raygun/client.rb
CHANGED
@@ -1,305 +1,305 @@
|
|
1
|
-
module Raygun
|
2
|
-
# client for the Raygun REST APIv1
|
3
|
-
# as per
|
4
|
-
class Client
|
5
|
-
|
6
|
-
ENV_IP_ADDRESS_KEYS = %w(action_dispatch.remote_ip raygun.remote_ip REMOTE_ADDR)
|
7
|
-
NO_API_KEY_MESSAGE = "[RAYGUN] Just a note, you've got no API Key configured, which means we can't report exceptions. Specify your Raygun API key using Raygun#setup (find yours at https://app.raygun.
|
8
|
-
MAX_BREADCRUMBS_SIZE = 100_000
|
9
|
-
|
10
|
-
include HTTParty
|
11
|
-
|
12
|
-
def initialize
|
13
|
-
@api_key = require_api_key
|
14
|
-
@headers = {
|
15
|
-
"X-ApiKey" => @api_key
|
16
|
-
}
|
17
|
-
|
18
|
-
enable_http_proxy if Raygun.configuration.proxy_settings[:address]
|
19
|
-
self.class.base_uri Raygun.configuration.api_url
|
20
|
-
self.class.default_timeout(Raygun.configuration.error_report_send_timeout)
|
21
|
-
end
|
22
|
-
|
23
|
-
def require_api_key
|
24
|
-
Raygun.configuration.api_key || print_api_key_warning
|
25
|
-
end
|
26
|
-
|
27
|
-
def track_exception(exception_instance, env = {}, user = nil)
|
28
|
-
create_entry(build_payload_hash(exception_instance, env, user))
|
29
|
-
end
|
30
|
-
|
31
|
-
private
|
32
|
-
|
33
|
-
def enable_http_proxy
|
34
|
-
self.class.http_proxy(Raygun.configuration.proxy_settings[:address],
|
35
|
-
Raygun.configuration.proxy_settings[:port] || "80",
|
36
|
-
Raygun.configuration.proxy_settings[:username],
|
37
|
-
Raygun.configuration.proxy_settings[:password])
|
38
|
-
end
|
39
|
-
|
40
|
-
def client_details
|
41
|
-
{
|
42
|
-
name: Raygun::CLIENT_NAME,
|
43
|
-
version: Raygun::VERSION,
|
44
|
-
clientUrl: Raygun::CLIENT_URL
|
45
|
-
}
|
46
|
-
end
|
47
|
-
|
48
|
-
def error_details(exception)
|
49
|
-
details = {
|
50
|
-
className: exception.class.to_s,
|
51
|
-
message: exception.message.to_s.encode('UTF-16', :undef => :replace, :invalid => :replace).encode('UTF-8'),
|
52
|
-
stackTrace: (exception.backtrace || []).map { |line| stack_trace_for(line) },
|
53
|
-
}
|
54
|
-
|
55
|
-
details.update(innerError: error_details(exception.cause)) if exception.respond_to?(:cause) && exception.cause
|
56
|
-
|
57
|
-
details
|
58
|
-
end
|
59
|
-
|
60
|
-
def stack_trace_for(line)
|
61
|
-
# see http://www.ruby-doc.org/core-2.0/Exception.html#method-i-backtrace
|
62
|
-
file_name, line_number, method = line.split(":")
|
63
|
-
{
|
64
|
-
lineNumber: line_number,
|
65
|
-
fileName: file_name,
|
66
|
-
methodName: method ? method.gsub(/^in `(.*?)'$/, "\\1") : "(none)"
|
67
|
-
}
|
68
|
-
end
|
69
|
-
|
70
|
-
def hostname
|
71
|
-
Socket.gethostname
|
72
|
-
end
|
73
|
-
|
74
|
-
def version
|
75
|
-
Raygun.configuration.version
|
76
|
-
end
|
77
|
-
|
78
|
-
def user_information(env)
|
79
|
-
env["raygun.affected_user"]
|
80
|
-
end
|
81
|
-
|
82
|
-
def affected_user_present?(env)
|
83
|
-
!!env["raygun.affected_user"]
|
84
|
-
end
|
85
|
-
|
86
|
-
def rack_env
|
87
|
-
ENV["RACK_ENV"]
|
88
|
-
end
|
89
|
-
|
90
|
-
def rails_env
|
91
|
-
ENV["RAILS_ENV"]
|
92
|
-
end
|
93
|
-
|
94
|
-
def request_information(env)
|
95
|
-
Raygun.log('retrieving request information')
|
96
|
-
|
97
|
-
return {} if env.nil? || env.empty?
|
98
|
-
{
|
99
|
-
hostName: env["SERVER_NAME"],
|
100
|
-
url: env["PATH_INFO"],
|
101
|
-
httpMethod: env["REQUEST_METHOD"],
|
102
|
-
iPAddress: "#{ip_address_from(env)}",
|
103
|
-
queryString: Rack::Utils.parse_nested_query(env["QUERY_STRING"]),
|
104
|
-
headers: headers(env),
|
105
|
-
form: form_params(env),
|
106
|
-
rawData: raw_data(env)
|
107
|
-
}
|
108
|
-
end
|
109
|
-
|
110
|
-
def headers(rack_env)
|
111
|
-
rack_env.select { |k, v| k.to_s.start_with?("HTTP_") }.inject({}) do |hsh, (k, v)|
|
112
|
-
hsh[normalize_raygun_header_key(k)] = v
|
113
|
-
hsh
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
def normalize_raygun_header_key(key)
|
118
|
-
key.sub(/^HTTP_/, '')
|
119
|
-
.sub(/_/, ' ')
|
120
|
-
.split.map(&:capitalize).join(' ')
|
121
|
-
.sub(/ /, '-')
|
122
|
-
end
|
123
|
-
|
124
|
-
def form_params(env)
|
125
|
-
Raygun.log('retrieving form params')
|
126
|
-
|
127
|
-
params = action_dispatch_params(env) || rack_params(env) || {}
|
128
|
-
filter_params_with_blacklist(params, env["action_dispatch.parameter_filter"])
|
129
|
-
end
|
130
|
-
|
131
|
-
def action_dispatch_params(env)
|
132
|
-
env["action_dispatch.request.parameters"]
|
133
|
-
end
|
134
|
-
|
135
|
-
def rack_params(env)
|
136
|
-
request = Rack::Request.new(env)
|
137
|
-
request.params if env["rack.input"]
|
138
|
-
end
|
139
|
-
|
140
|
-
def raw_data(rack_env)
|
141
|
-
Raygun.log('retrieving raw data')
|
142
|
-
request = Rack::Request.new(rack_env)
|
143
|
-
|
144
|
-
return unless Raygun.configuration.record_raw_data
|
145
|
-
return if request.get?
|
146
|
-
Raygun.log('passed raw_data checks')
|
147
|
-
|
148
|
-
input = rack_env['rack.input']
|
149
|
-
|
150
|
-
if input && !request.form_data?
|
151
|
-
input.rewind
|
152
|
-
|
153
|
-
body = input.read(4096) || ''
|
154
|
-
input.rewind
|
155
|
-
|
156
|
-
body
|
157
|
-
else
|
158
|
-
{}
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
def filter_custom_data(env)
|
163
|
-
params = env.delete(:custom_data) || {}
|
164
|
-
filter_params_with_blacklist(params, env["action_dispatch.parameter_filter"])
|
165
|
-
end
|
166
|
-
|
167
|
-
# see
|
168
|
-
def build_payload_hash(exception_instance, env = {}, user = nil)
|
169
|
-
Raygun.log('building payload hash')
|
170
|
-
custom_data = filter_custom_data(env) || {}
|
171
|
-
exception_custom_data = if exception_instance.respond_to?(:raygun_custom_data)
|
172
|
-
exception_instance.raygun_custom_data
|
173
|
-
else
|
174
|
-
{}
|
175
|
-
end
|
176
|
-
|
177
|
-
tags = env.delete(:tags) || []
|
178
|
-
|
179
|
-
if rails_env
|
180
|
-
tags << rails_env
|
181
|
-
else
|
182
|
-
tags << rack_env
|
183
|
-
end
|
184
|
-
|
185
|
-
configuration_tags = []
|
186
|
-
if Raygun.configuration.tags.is_a?(Proc)
|
187
|
-
configuration_tags = Raygun.configuration.tags.call(exception_instance, env)
|
188
|
-
else
|
189
|
-
configuration_tags = Raygun.configuration.tags
|
190
|
-
end
|
191
|
-
|
192
|
-
Raygun.log('set tags')
|
193
|
-
|
194
|
-
grouping_key = env.delete(:grouping_key)
|
195
|
-
correlation_id = env.delete(:correlation_id)
|
196
|
-
|
197
|
-
configuration_custom_data = Raygun.configuration.custom_data
|
198
|
-
configured_custom_data = if configuration_custom_data.is_a?(Proc)
|
199
|
-
configuration_custom_data.call(exception_instance, env)
|
200
|
-
else
|
201
|
-
configuration_custom_data
|
202
|
-
end
|
203
|
-
|
204
|
-
Raygun.log('set custom data')
|
205
|
-
|
206
|
-
error_details = {
|
207
|
-
machineName: hostname,
|
208
|
-
version: version,
|
209
|
-
client: client_details,
|
210
|
-
error: error_details(exception_instance),
|
211
|
-
userCustomData: exception_custom_data.merge(custom_data).merge(configured_custom_data),
|
212
|
-
tags: configuration_tags.concat(tags).compact.uniq,
|
213
|
-
request: request_information(env),
|
214
|
-
environment: {
|
215
|
-
utcOffset: Time.now.utc_offset / 3600
|
216
|
-
}
|
217
|
-
}
|
218
|
-
store = ::Raygun::Breadcrumbs::Store
|
219
|
-
error_details[:breadcrumbs] = store.take_until_size(MAX_BREADCRUMBS_SIZE).map(&:build_payload) if store.any?
|
220
|
-
|
221
|
-
Raygun.log('set details and breadcrumbs')
|
222
|
-
|
223
|
-
error_details.merge!(groupingKey: grouping_key) if grouping_key
|
224
|
-
error_details.merge!(correlationId: correlation_id) if correlation_id
|
225
|
-
|
226
|
-
user_details = if affected_user_present?(env)
|
227
|
-
user_information(env)
|
228
|
-
elsif user != nil
|
229
|
-
AffectedUser.information_hash(user)
|
230
|
-
end
|
231
|
-
error_details.merge!(user: user_details) unless user_details == nil
|
232
|
-
|
233
|
-
Raygun.log('set user details')
|
234
|
-
|
235
|
-
if Raygun.configuration.filter_payload_with_whitelist
|
236
|
-
Raygun.log('filtering payload with whitelist')
|
237
|
-
error_details = filter_payload_with_whitelist(error_details)
|
238
|
-
end
|
239
|
-
|
240
|
-
{
|
241
|
-
occurredOn: Time.now.utc.iso8601,
|
242
|
-
details: error_details
|
243
|
-
}
|
244
|
-
end
|
245
|
-
|
246
|
-
def create_entry(payload_hash)
|
247
|
-
Raygun.log('sending payload to api')
|
248
|
-
|
249
|
-
self.class.post(
|
250
|
-
"/entries",
|
251
|
-
verify_peer: true,
|
252
|
-
verify: true,
|
253
|
-
headers: @headers,
|
254
|
-
body: JSON.generate(payload_hash),
|
255
|
-
)
|
256
|
-
end
|
257
|
-
|
258
|
-
def filter_params_with_blacklist(params_hash = {}, extra_filter_keys = nil)
|
259
|
-
filter_parameters = Raygun.configuration.filter_parameters
|
260
|
-
|
261
|
-
if filter_parameters.is_a? Proc
|
262
|
-
filter_parameters.call(params_hash)
|
263
|
-
else
|
264
|
-
filter_keys = (Array(extra_filter_keys) + filter_parameters).map(&:to_s)
|
265
|
-
|
266
|
-
filter_params_with_array(params_hash, filter_keys)
|
267
|
-
end
|
268
|
-
end
|
269
|
-
|
270
|
-
def filter_payload_with_whitelist(payload_hash)
|
271
|
-
shape = Raygun.configuration.whitelist_payload_shape
|
272
|
-
|
273
|
-
if shape.is_a? Proc
|
274
|
-
shape.call(payload_hash)
|
275
|
-
else
|
276
|
-
# Always keep the client hash, so force it to true here
|
277
|
-
Services::ApplyWhitelistFilterToPayload.new.call(shape.merge(client: true), payload_hash)
|
278
|
-
end
|
279
|
-
end
|
280
|
-
|
281
|
-
def filter_params_with_array(params_hash, filter_keys)
|
282
|
-
# Recursive filtering of (nested) hashes
|
283
|
-
(params_hash || {}).inject({}) do |result, (k, v)|
|
284
|
-
result[k] = case v
|
285
|
-
when Hash
|
286
|
-
filter_params_with_array(v, filter_keys)
|
287
|
-
else
|
288
|
-
filter_keys.any? { |fk| /#{fk}/i === k.to_s } ? "[FILTERED]" : v
|
289
|
-
end
|
290
|
-
result
|
291
|
-
end
|
292
|
-
end
|
293
|
-
|
294
|
-
def ip_address_from(env_hash)
|
295
|
-
ENV_IP_ADDRESS_KEYS.each do |key_to_try|
|
296
|
-
return env_hash[key_to_try] unless env_hash[key_to_try].nil? || env_hash[key_to_try] == ""
|
297
|
-
end
|
298
|
-
"(Not Available)"
|
299
|
-
end
|
300
|
-
|
301
|
-
def print_api_key_warning
|
302
|
-
$stderr.puts(NO_API_KEY_MESSAGE)
|
303
|
-
end
|
304
|
-
end
|
305
|
-
end
|
1
|
+
module Raygun
|
2
|
+
# client for the Raygun REST APIv1
|
3
|
+
# as per https://raygun.com/documentation/product-guides/crash-reporting/api/
|
4
|
+
class Client
|
5
|
+
|
6
|
+
ENV_IP_ADDRESS_KEYS = %w(action_dispatch.remote_ip raygun.remote_ip REMOTE_ADDR)
|
7
|
+
NO_API_KEY_MESSAGE = "[RAYGUN] Just a note, you've got no API Key configured, which means we can't report exceptions. Specify your Raygun API key using Raygun#setup (find yours at https://app.raygun.com)"
|
8
|
+
MAX_BREADCRUMBS_SIZE = 100_000
|
9
|
+
|
10
|
+
include HTTParty
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@api_key = require_api_key
|
14
|
+
@headers = {
|
15
|
+
"X-ApiKey" => @api_key
|
16
|
+
}
|
17
|
+
|
18
|
+
enable_http_proxy if Raygun.configuration.proxy_settings[:address]
|
19
|
+
self.class.base_uri Raygun.configuration.api_url
|
20
|
+
self.class.default_timeout(Raygun.configuration.error_report_send_timeout)
|
21
|
+
end
|
22
|
+
|
23
|
+
def require_api_key
|
24
|
+
Raygun.configuration.api_key || print_api_key_warning
|
25
|
+
end
|
26
|
+
|
27
|
+
def track_exception(exception_instance, env = {}, user = nil)
|
28
|
+
create_entry(build_payload_hash(exception_instance, env, user))
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def enable_http_proxy
|
34
|
+
self.class.http_proxy(Raygun.configuration.proxy_settings[:address],
|
35
|
+
Raygun.configuration.proxy_settings[:port] || "80",
|
36
|
+
Raygun.configuration.proxy_settings[:username],
|
37
|
+
Raygun.configuration.proxy_settings[:password])
|
38
|
+
end
|
39
|
+
|
40
|
+
def client_details
|
41
|
+
{
|
42
|
+
name: Raygun::CLIENT_NAME,
|
43
|
+
version: Raygun::VERSION,
|
44
|
+
clientUrl: Raygun::CLIENT_URL
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
def error_details(exception)
|
49
|
+
details = {
|
50
|
+
className: exception.class.to_s,
|
51
|
+
message: exception.message.to_s.encode('UTF-16', :undef => :replace, :invalid => :replace).encode('UTF-8'),
|
52
|
+
stackTrace: (exception.backtrace || []).map { |line| stack_trace_for(line) },
|
53
|
+
}
|
54
|
+
|
55
|
+
details.update(innerError: error_details(exception.cause)) if exception.respond_to?(:cause) && exception.cause
|
56
|
+
|
57
|
+
details
|
58
|
+
end
|
59
|
+
|
60
|
+
def stack_trace_for(line)
|
61
|
+
# see http://www.ruby-doc.org/core-2.0/Exception.html#method-i-backtrace
|
62
|
+
file_name, line_number, method = line.split(":")
|
63
|
+
{
|
64
|
+
lineNumber: line_number,
|
65
|
+
fileName: file_name,
|
66
|
+
methodName: method ? method.gsub(/^in `(.*?)'$/, "\\1") : "(none)"
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
def hostname
|
71
|
+
Socket.gethostname
|
72
|
+
end
|
73
|
+
|
74
|
+
def version
|
75
|
+
Raygun.configuration.version
|
76
|
+
end
|
77
|
+
|
78
|
+
def user_information(env)
|
79
|
+
env["raygun.affected_user"]
|
80
|
+
end
|
81
|
+
|
82
|
+
def affected_user_present?(env)
|
83
|
+
!!env["raygun.affected_user"]
|
84
|
+
end
|
85
|
+
|
86
|
+
def rack_env
|
87
|
+
ENV["RACK_ENV"]
|
88
|
+
end
|
89
|
+
|
90
|
+
def rails_env
|
91
|
+
ENV["RAILS_ENV"]
|
92
|
+
end
|
93
|
+
|
94
|
+
def request_information(env)
|
95
|
+
Raygun.log('retrieving request information')
|
96
|
+
|
97
|
+
return {} if env.nil? || env.empty?
|
98
|
+
{
|
99
|
+
hostName: env["SERVER_NAME"],
|
100
|
+
url: env["PATH_INFO"],
|
101
|
+
httpMethod: env["REQUEST_METHOD"],
|
102
|
+
iPAddress: "#{ip_address_from(env)}",
|
103
|
+
queryString: Rack::Utils.parse_nested_query(env["QUERY_STRING"]),
|
104
|
+
headers: headers(env),
|
105
|
+
form: form_params(env),
|
106
|
+
rawData: raw_data(env)
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
def headers(rack_env)
|
111
|
+
rack_env.select { |k, v| k.to_s.start_with?("HTTP_") }.inject({}) do |hsh, (k, v)|
|
112
|
+
hsh[normalize_raygun_header_key(k)] = v
|
113
|
+
hsh
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def normalize_raygun_header_key(key)
|
118
|
+
key.sub(/^HTTP_/, '')
|
119
|
+
.sub(/_/, ' ')
|
120
|
+
.split.map(&:capitalize).join(' ')
|
121
|
+
.sub(/ /, '-')
|
122
|
+
end
|
123
|
+
|
124
|
+
def form_params(env)
|
125
|
+
Raygun.log('retrieving form params')
|
126
|
+
|
127
|
+
params = action_dispatch_params(env) || rack_params(env) || {}
|
128
|
+
filter_params_with_blacklist(params, env["action_dispatch.parameter_filter"])
|
129
|
+
end
|
130
|
+
|
131
|
+
def action_dispatch_params(env)
|
132
|
+
env["action_dispatch.request.parameters"]
|
133
|
+
end
|
134
|
+
|
135
|
+
def rack_params(env)
|
136
|
+
request = Rack::Request.new(env)
|
137
|
+
request.params if env["rack.input"]
|
138
|
+
end
|
139
|
+
|
140
|
+
def raw_data(rack_env)
|
141
|
+
Raygun.log('retrieving raw data')
|
142
|
+
request = Rack::Request.new(rack_env)
|
143
|
+
|
144
|
+
return unless Raygun.configuration.record_raw_data
|
145
|
+
return if request.get?
|
146
|
+
Raygun.log('passed raw_data checks')
|
147
|
+
|
148
|
+
input = rack_env['rack.input']
|
149
|
+
|
150
|
+
if input && !request.form_data?
|
151
|
+
input.rewind
|
152
|
+
|
153
|
+
body = input.read(4096) || ''
|
154
|
+
input.rewind
|
155
|
+
|
156
|
+
body
|
157
|
+
else
|
158
|
+
{}
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def filter_custom_data(env)
|
163
|
+
params = env.delete(:custom_data) || {}
|
164
|
+
filter_params_with_blacklist(params, env["action_dispatch.parameter_filter"])
|
165
|
+
end
|
166
|
+
|
167
|
+
# see https://raygun.com/documentation/product-guides/crash-reporting/api/
|
168
|
+
def build_payload_hash(exception_instance, env = {}, user = nil)
|
169
|
+
Raygun.log('building payload hash')
|
170
|
+
custom_data = filter_custom_data(env) || {}
|
171
|
+
exception_custom_data = if exception_instance.respond_to?(:raygun_custom_data)
|
172
|
+
exception_instance.raygun_custom_data
|
173
|
+
else
|
174
|
+
{}
|
175
|
+
end
|
176
|
+
|
177
|
+
tags = env.delete(:tags) || []
|
178
|
+
|
179
|
+
if rails_env
|
180
|
+
tags << rails_env
|
181
|
+
else
|
182
|
+
tags << rack_env
|
183
|
+
end
|
184
|
+
|
185
|
+
configuration_tags = []
|
186
|
+
if Raygun.configuration.tags.is_a?(Proc)
|
187
|
+
configuration_tags = Raygun.configuration.tags.call(exception_instance, env)
|
188
|
+
else
|
189
|
+
configuration_tags = Raygun.configuration.tags
|
190
|
+
end
|
191
|
+
|
192
|
+
Raygun.log('set tags')
|
193
|
+
|
194
|
+
grouping_key = env.delete(:grouping_key)
|
195
|
+
correlation_id = env.delete(:correlation_id)
|
196
|
+
|
197
|
+
configuration_custom_data = Raygun.configuration.custom_data
|
198
|
+
configured_custom_data = if configuration_custom_data.is_a?(Proc)
|
199
|
+
configuration_custom_data.call(exception_instance, env)
|
200
|
+
else
|
201
|
+
configuration_custom_data
|
202
|
+
end
|
203
|
+
|
204
|
+
Raygun.log('set custom data')
|
205
|
+
|
206
|
+
error_details = {
|
207
|
+
machineName: hostname,
|
208
|
+
version: version,
|
209
|
+
client: client_details,
|
210
|
+
error: error_details(exception_instance),
|
211
|
+
userCustomData: exception_custom_data.merge(custom_data).merge(configured_custom_data),
|
212
|
+
tags: configuration_tags.concat(tags).compact.uniq,
|
213
|
+
request: request_information(env),
|
214
|
+
environment: {
|
215
|
+
utcOffset: Time.now.utc_offset / 3600
|
216
|
+
}
|
217
|
+
}
|
218
|
+
store = ::Raygun::Breadcrumbs::Store
|
219
|
+
error_details[:breadcrumbs] = store.take_until_size(MAX_BREADCRUMBS_SIZE).map(&:build_payload) if store.any?
|
220
|
+
|
221
|
+
Raygun.log('set details and breadcrumbs')
|
222
|
+
|
223
|
+
error_details.merge!(groupingKey: grouping_key) if grouping_key
|
224
|
+
error_details.merge!(correlationId: correlation_id) if correlation_id
|
225
|
+
|
226
|
+
user_details = if affected_user_present?(env)
|
227
|
+
user_information(env)
|
228
|
+
elsif user != nil
|
229
|
+
AffectedUser.information_hash(user)
|
230
|
+
end
|
231
|
+
error_details.merge!(user: user_details) unless user_details == nil
|
232
|
+
|
233
|
+
Raygun.log('set user details')
|
234
|
+
|
235
|
+
if Raygun.configuration.filter_payload_with_whitelist
|
236
|
+
Raygun.log('filtering payload with whitelist')
|
237
|
+
error_details = filter_payload_with_whitelist(error_details)
|
238
|
+
end
|
239
|
+
|
240
|
+
{
|
241
|
+
occurredOn: Time.now.utc.iso8601,
|
242
|
+
details: error_details
|
243
|
+
}
|
244
|
+
end
|
245
|
+
|
246
|
+
def create_entry(payload_hash)
|
247
|
+
Raygun.log('sending payload to api')
|
248
|
+
|
249
|
+
self.class.post(
|
250
|
+
"/entries",
|
251
|
+
verify_peer: true,
|
252
|
+
verify: true,
|
253
|
+
headers: @headers,
|
254
|
+
body: JSON.generate(payload_hash),
|
255
|
+
)
|
256
|
+
end
|
257
|
+
|
258
|
+
def filter_params_with_blacklist(params_hash = {}, extra_filter_keys = nil)
|
259
|
+
filter_parameters = Raygun.configuration.filter_parameters
|
260
|
+
|
261
|
+
if filter_parameters.is_a? Proc
|
262
|
+
filter_parameters.call(params_hash)
|
263
|
+
else
|
264
|
+
filter_keys = (Array(extra_filter_keys) + filter_parameters).map(&:to_s)
|
265
|
+
|
266
|
+
filter_params_with_array(params_hash, filter_keys)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
def filter_payload_with_whitelist(payload_hash)
|
271
|
+
shape = Raygun.configuration.whitelist_payload_shape
|
272
|
+
|
273
|
+
if shape.is_a? Proc
|
274
|
+
shape.call(payload_hash)
|
275
|
+
else
|
276
|
+
# Always keep the client hash, so force it to true here
|
277
|
+
Services::ApplyWhitelistFilterToPayload.new.call(shape.merge(client: true), payload_hash)
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
def filter_params_with_array(params_hash, filter_keys)
|
282
|
+
# Recursive filtering of (nested) hashes
|
283
|
+
(params_hash || {}).inject({}) do |result, (k, v)|
|
284
|
+
result[k] = case v
|
285
|
+
when Hash
|
286
|
+
filter_params_with_array(v, filter_keys)
|
287
|
+
else
|
288
|
+
filter_keys.any? { |fk| /#{fk}/i === k.to_s } ? "[FILTERED]" : v
|
289
|
+
end
|
290
|
+
result
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
def ip_address_from(env_hash)
|
295
|
+
ENV_IP_ADDRESS_KEYS.each do |key_to_try|
|
296
|
+
return env_hash[key_to_try] unless env_hash[key_to_try].nil? || env_hash[key_to_try] == ""
|
297
|
+
end
|
298
|
+
"(Not Available)"
|
299
|
+
end
|
300
|
+
|
301
|
+
def print_api_key_warning
|
302
|
+
$stderr.puts(NO_API_KEY_MESSAGE)
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|