scout_apm 2.6.6 → 4.0.0
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/.rubocop.yml +0 -4
- data/.travis.yml +0 -6
- data/CHANGELOG.markdown +30 -0
- data/Gemfile +1 -8
- data/lib/scout_apm.rb +21 -1
- data/lib/scout_apm/agent.rb +22 -0
- data/lib/scout_apm/agent_context.rb +14 -2
- data/lib/scout_apm/background_job_integrations/sidekiq.rb +2 -2
- data/lib/scout_apm/config.rb +17 -2
- data/lib/scout_apm/detailed_trace.rb +2 -1
- data/lib/scout_apm/error.rb +27 -0
- data/lib/scout_apm/error_service.rb +32 -0
- data/lib/scout_apm/error_service/error_buffer.rb +39 -0
- data/lib/scout_apm/error_service/error_record.rb +211 -0
- data/lib/scout_apm/error_service/ignored_exceptions.rb +66 -0
- data/lib/scout_apm/error_service/middleware.rb +32 -0
- data/lib/scout_apm/error_service/notifier.rb +33 -0
- data/lib/scout_apm/error_service/payload.rb +47 -0
- data/lib/scout_apm/error_service/periodic_work.rb +17 -0
- data/lib/scout_apm/error_service/railtie.rb +11 -0
- data/lib/scout_apm/error_service/sidekiq.rb +80 -0
- data/lib/scout_apm/extensions/transaction_callback_payload.rb +1 -1
- data/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb +47 -26
- data/lib/scout_apm/instruments/action_view.rb +7 -2
- data/lib/scout_apm/instruments/active_record.rb +13 -28
- data/lib/scout_apm/middleware.rb +1 -1
- data/lib/scout_apm/reporter.rb +8 -3
- data/lib/scout_apm/serializers/payload_serializer_to_json.rb +28 -10
- data/lib/scout_apm/slow_policy/age_policy.rb +33 -0
- data/lib/scout_apm/slow_policy/percent_policy.rb +22 -0
- data/lib/scout_apm/slow_policy/percentile_policy.rb +24 -0
- data/lib/scout_apm/slow_policy/policy.rb +21 -0
- data/lib/scout_apm/slow_policy/speed_policy.rb +16 -0
- data/lib/scout_apm/slow_request_policy.rb +18 -77
- data/lib/scout_apm/utils/sql_sanitizer.rb +1 -0
- data/lib/scout_apm/utils/sql_sanitizer_regex.rb +1 -1
- data/lib/scout_apm/utils/sql_sanitizer_regex_1_8_7.rb +1 -0
- data/lib/scout_apm/version.rb +1 -1
- data/scout_apm.gemspec +6 -6
- data/test/unit/agent_context_test.rb +29 -0
- data/test/unit/error_service/error_buffer_test.rb +25 -0
- data/test/unit/error_service/ignored_exceptions_test.rb +49 -0
- data/test/unit/serializers/payload_serializer_test.rb +36 -0
- data/test/unit/slow_request_policy_test.rb +41 -13
- data/test/unit/sql_sanitizer_test.rb +7 -0
- metadata +25 -62
- data/lib/scout_apm/slow_job_policy.rb +0 -111
- data/test/unit/slow_job_policy_test.rb +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ffcf571075c7f443ebe029e8f07c726cc5cb6c12e156d47e2565c576ac671316
|
4
|
+
data.tar.gz: 684f8ed4ba52d2e5819ea319288333a83f8b5481491ae879be2e8031cdd5d6ee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a4d90917dc02469213092848211fe779f44ec09e7db4829aaaa737ca15cf1811137dc2a4ae00adaa76cc2be92916b0467f164f79a76fac501c7a4827ba5d6f7d
|
7
|
+
data.tar.gz: 776d064902d998cc69330e470fbc9bfb368ae401d8e8a341310e4dc2a9070a256a2e57370505ee3475761d26145e4efced633963243527e39b95ab584bf48b2a
|
data/.rubocop.yml
CHANGED
data/.travis.yml
CHANGED
data/CHANGELOG.markdown
CHANGED
@@ -1,3 +1,33 @@
|
|
1
|
+
# 4.0.0
|
2
|
+
|
3
|
+
* Require Ruby >= 2.1 (#270)
|
4
|
+
* ErrorService reporting. Enable with `errors_enabled` config setting. (#347)
|
5
|
+
* Modular SlowRequestPolicy (#364)
|
6
|
+
* Fix deprecation warnings (#354)
|
7
|
+
|
8
|
+
# 2.6.10
|
9
|
+
|
10
|
+
* Fix an edge case in JSON serialization (#360)
|
11
|
+
|
12
|
+
# 2.6.9
|
13
|
+
|
14
|
+
* Add `ssl_cert_file` config option (#352)
|
15
|
+
* Improve sanitization of Postgres UPDATE SQL (#351)
|
16
|
+
* Allow custom URL sanitization (#341)
|
17
|
+
|
18
|
+
# 2.6.8
|
19
|
+
|
20
|
+
* Lock rake version for 1.8.7 to older version (#329)
|
21
|
+
* Delete unneeded .DS_Store file that snuck in (#334)
|
22
|
+
* Fix typo in "queue_time_ms"
|
23
|
+
* Fix Rails 6 deprecation warning at boot time (#337)
|
24
|
+
* Fix partial naming on Rails 6.0 (#339)
|
25
|
+
* Support Sidekiq 6.1 instrumentation (#340)
|
26
|
+
|
27
|
+
# 2.6.7
|
28
|
+
|
29
|
+
* Remove accidental call to `as_json`
|
30
|
+
|
1
31
|
# 2.6.6
|
2
32
|
|
3
33
|
* Add basic support for parsing Microsoft SQLServer queries (#317)
|
data/Gemfile
CHANGED
@@ -3,11 +3,4 @@ source "https://rubygems.org"
|
|
3
3
|
# Specify your gem's dependencies in scout_apm.gemspec
|
4
4
|
gemspec
|
5
5
|
|
6
|
-
|
7
|
-
if RUBY_VERSION <= "1.8.7"
|
8
|
-
gem "activesupport", "~> 3.2"
|
9
|
-
gem "i18n", "~> 0.6.11"
|
10
|
-
gem "pry", "~> 0.9.12"
|
11
|
-
gem "rake", "~> 10.5"
|
12
|
-
gem "minitest", "~> 5.11.3"
|
13
|
-
end
|
6
|
+
gem "rake", ">= 12.3.3"
|
data/lib/scout_apm.rb
CHANGED
@@ -144,8 +144,13 @@ require 'scout_apm/slow_transaction'
|
|
144
144
|
require 'scout_apm/slow_job_record'
|
145
145
|
require 'scout_apm/detailed_trace'
|
146
146
|
require 'scout_apm/scored_item_set'
|
147
|
+
|
147
148
|
require 'scout_apm/slow_request_policy'
|
148
|
-
require 'scout_apm/
|
149
|
+
require 'scout_apm/slow_policy/age_policy'
|
150
|
+
require 'scout_apm/slow_policy/speed_policy'
|
151
|
+
require 'scout_apm/slow_policy/percent_policy'
|
152
|
+
require 'scout_apm/slow_policy/percentile_policy'
|
153
|
+
|
149
154
|
require 'scout_apm/job_record'
|
150
155
|
require 'scout_apm/request_histograms'
|
151
156
|
require 'scout_apm/transaction_time_consumed'
|
@@ -186,6 +191,16 @@ require 'scout_apm/tasks/support'
|
|
186
191
|
require 'scout_apm/extensions/config'
|
187
192
|
require 'scout_apm/extensions/transaction_callback_payload'
|
188
193
|
|
194
|
+
require 'scout_apm/error_service'
|
195
|
+
require 'scout_apm/error_service/middleware'
|
196
|
+
require 'scout_apm/error_service/notifier'
|
197
|
+
require 'scout_apm/error_service/sidekiq'
|
198
|
+
require 'scout_apm/error_service/ignored_exceptions'
|
199
|
+
require 'scout_apm/error_service/error_buffer'
|
200
|
+
require 'scout_apm/error_service/error_record'
|
201
|
+
require 'scout_apm/error_service/periodic_work'
|
202
|
+
require 'scout_apm/error_service/payload'
|
203
|
+
|
189
204
|
if defined?(Rails) && defined?(Rails::VERSION) && defined?(Rails::VERSION::MAJOR) && Rails::VERSION::MAJOR >= 3 && defined?(Rails::Railtie)
|
190
205
|
module ScoutApm
|
191
206
|
class Railtie < Rails::Railtie
|
@@ -205,6 +220,11 @@ if defined?(Rails) && defined?(Rails::VERSION) && defined?(Rails::VERSION::MAJOR
|
|
205
220
|
ScoutApm::Agent.instance.context.logger.debug("AutoInstruments is disabled.")
|
206
221
|
end
|
207
222
|
|
223
|
+
if ScoutApm::Agent.instance.context.config.value("errors_enabled")
|
224
|
+
app.config.middleware.insert_after ActionDispatch::DebugExceptions, ScoutApm::ErrorService::Middleware
|
225
|
+
ScoutApm::ErrorService::Sidekiq.new.install
|
226
|
+
end
|
227
|
+
|
208
228
|
# Install the middleware every time in development mode.
|
209
229
|
# The middleware is a noop if dev_trace is not enabled in config
|
210
230
|
if Rails.env.development?
|
data/lib/scout_apm/agent.rb
CHANGED
@@ -66,6 +66,7 @@ module ScoutApm
|
|
66
66
|
|
67
67
|
if context.started?
|
68
68
|
start_background_worker unless background_worker_running?
|
69
|
+
start_error_service_background_worker unless error_service_background_worker_running?
|
69
70
|
return
|
70
71
|
end
|
71
72
|
|
@@ -81,6 +82,7 @@ module ScoutApm
|
|
81
82
|
@app_server_load ||= AppServerLoad.new(context).run
|
82
83
|
|
83
84
|
start_background_worker
|
85
|
+
start_error_service_background_worker
|
84
86
|
end
|
85
87
|
|
86
88
|
def instrument_manager
|
@@ -198,5 +200,25 @@ module ScoutApm
|
|
198
200
|
@background_worker &&
|
199
201
|
@background_worker.running?
|
200
202
|
end
|
203
|
+
|
204
|
+
# seconds to batch error reports
|
205
|
+
ERROR_SEND_FREQUENCY = 5
|
206
|
+
def start_error_service_background_worker
|
207
|
+
periodic_work = ScoutApm::ErrorService::PeriodicWork.new(context)
|
208
|
+
|
209
|
+
@error_service_background_worker = ScoutApm::BackgroundWorker.new(context, ERROR_SEND_FREQUENCY)
|
210
|
+
@error_service_background_worker_thread = Thread.new do
|
211
|
+
@error_service_background_worker.start {
|
212
|
+
periodic_work.run
|
213
|
+
}
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def error_service_background_worker_running?
|
218
|
+
@error_service_background_worker_thread &&
|
219
|
+
@error_service_background_worker_thread.alive? &&
|
220
|
+
@error_service_background_worker &&
|
221
|
+
@error_service_background_worker.running?
|
222
|
+
end
|
201
223
|
end
|
202
224
|
end
|
@@ -96,11 +96,11 @@ module ScoutApm
|
|
96
96
|
end
|
97
97
|
|
98
98
|
def slow_request_policy
|
99
|
-
@slow_request_policy ||= ScoutApm::SlowRequestPolicy.new(self)
|
99
|
+
@slow_request_policy ||= ScoutApm::SlowRequestPolicy.new(self).tap{|p| p.add_default_policies }
|
100
100
|
end
|
101
101
|
|
102
102
|
def slow_job_policy
|
103
|
-
@slow_job_policy ||= ScoutApm::
|
103
|
+
@slow_job_policy ||= ScoutApm::SlowRequestPolicy.new(self).tap{|p| p.add_default_policies }
|
104
104
|
end
|
105
105
|
|
106
106
|
# Maintains a Histogram of insignificant/significant autoinstrument layers.
|
@@ -142,6 +142,18 @@ module ScoutApm
|
|
142
142
|
config.value('dev_trace') && environment.env == "development"
|
143
143
|
end
|
144
144
|
|
145
|
+
###################
|
146
|
+
# Error Service #
|
147
|
+
###################
|
148
|
+
|
149
|
+
def error_buffer
|
150
|
+
@error_buffer ||= ScoutApm::ErrorService::ErrorBuffer.new(self)
|
151
|
+
end
|
152
|
+
|
153
|
+
def ignored_exceptions
|
154
|
+
@ignored_exceptions ||= ScoutApm::ErrorService::IgnoredExceptions.new(self, config.value('errors_ignored_exceptions'))
|
155
|
+
end
|
156
|
+
|
145
157
|
#############
|
146
158
|
# Setters #
|
147
159
|
#############
|
@@ -40,10 +40,10 @@ module ScoutApm
|
|
40
40
|
require 'sidekiq/processor' # sidekiq v4 has not loaded this file by this point
|
41
41
|
|
42
42
|
::Sidekiq::Processor.class_eval do
|
43
|
-
def initialize_with_scout(
|
43
|
+
def initialize_with_scout(*args)
|
44
44
|
agent = ::ScoutApm::Agent.instance
|
45
45
|
agent.start
|
46
|
-
initialize_without_scout(
|
46
|
+
initialize_without_scout(*args)
|
47
47
|
end
|
48
48
|
|
49
49
|
alias_method :initialize_without_scout, :initialize
|
data/lib/scout_apm/config.rb
CHANGED
@@ -75,11 +75,18 @@ module ScoutApm
|
|
75
75
|
'revision_sha',
|
76
76
|
'scm_subdirectory',
|
77
77
|
'start_resque_server_instrument',
|
78
|
+
'ssl_cert_file',
|
78
79
|
'uri_reporting',
|
79
80
|
'instrument_http_url_length',
|
80
81
|
'timeline_traces',
|
81
82
|
'auto_instruments',
|
82
|
-
'auto_instruments_ignore'
|
83
|
+
'auto_instruments_ignore',
|
84
|
+
|
85
|
+
# Error Service Related Configuration
|
86
|
+
'errors_enabled',
|
87
|
+
'errors_ignored_exceptions',
|
88
|
+
'errors_filtered_params',
|
89
|
+
'errors_host',
|
83
90
|
]
|
84
91
|
|
85
92
|
################################################################################
|
@@ -175,6 +182,9 @@ module ScoutApm
|
|
175
182
|
'timeline_traces' => BooleanCoercion.new,
|
176
183
|
'auto_instruments' => BooleanCoercion.new,
|
177
184
|
'auto_instruments_ignore' => JsonCoercion.new,
|
185
|
+
'errors_enabled' => BooleanCoercion.new,
|
186
|
+
'errors_ignored_exceptions' => JsonCoercion.new,
|
187
|
+
'errors_filtered_params' => JsonCoercion.new,
|
178
188
|
}
|
179
189
|
|
180
190
|
|
@@ -284,7 +294,12 @@ module ScoutApm
|
|
284
294
|
'collect_remote_ip' => true,
|
285
295
|
'timeline_traces' => true,
|
286
296
|
'auto_instruments' => false,
|
287
|
-
'auto_instruments_ignore' => []
|
297
|
+
'auto_instruments_ignore' => [],
|
298
|
+
'ssl_cert_file' => File.join( File.dirname(__FILE__), *%w[.. .. data cacert.pem] ),
|
299
|
+
'errors_enabled' => false,
|
300
|
+
'errors_ignored_exceptions' => %w(ActiveRecord::RecordNotFound ActionController::RoutingError),
|
301
|
+
'errors_filtered_params' => %w(password s3-key),
|
302
|
+
'errors_host' => 'https://errors.scoutapm.com',
|
288
303
|
}.freeze
|
289
304
|
|
290
305
|
def value(key)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# Public API for the Scout Error Monitoring service
|
2
|
+
#
|
3
|
+
# See-Also ScoutApm::Transaction and ScoutApm::Tracing for APM related APIs
|
4
|
+
module ScoutApm
|
5
|
+
module Error
|
6
|
+
# Capture an exception, optionally with an environment hash. This may be a
|
7
|
+
# Rack environment, but is not required.
|
8
|
+
def self.capture(exception, env={})
|
9
|
+
context = ScoutApm::Agent.instance.context
|
10
|
+
|
11
|
+
# Skip if error monitoring isn't enabled at all
|
12
|
+
if ! context.config.value("errors_enabled")
|
13
|
+
return false
|
14
|
+
end
|
15
|
+
|
16
|
+
# Skip if this one error is ignored
|
17
|
+
if context.ignored_exceptions.ignored?(exception)
|
18
|
+
return false
|
19
|
+
end
|
20
|
+
|
21
|
+
# Capture the error for further processing and shipping
|
22
|
+
context.error_buffer.capture(exception, env)
|
23
|
+
|
24
|
+
return true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "net/http"
|
2
|
+
require "net/https"
|
3
|
+
require "uri"
|
4
|
+
|
5
|
+
module ScoutApm
|
6
|
+
module ErrorService
|
7
|
+
API_VERSION = "1"
|
8
|
+
|
9
|
+
HEADERS = {
|
10
|
+
"Content-type" => "application/json",
|
11
|
+
"Accept" => "application/json"
|
12
|
+
}
|
13
|
+
|
14
|
+
# Public API to force a given exception to be captured.
|
15
|
+
# Still obeys the ignore list
|
16
|
+
# Used internally by SidekiqException
|
17
|
+
def self.capture(exception, params = {})
|
18
|
+
return if disabled?
|
19
|
+
return if ScoutApm::Agent.instance.context.ignored_exceptions.ignore?(exception)
|
20
|
+
|
21
|
+
context.errors_buffer.capture(exception, env)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.enabled?
|
25
|
+
ScoutApm::Agent.instance.context.config.value("errors_enabled")
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.disabled?
|
29
|
+
!enabled?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# Holds onto exceptions, and moves them forward to shipping when appropriate
|
2
|
+
module ScoutApm
|
3
|
+
module ErrorService
|
4
|
+
class ErrorBuffer
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
attr_reader :agent_context
|
8
|
+
|
9
|
+
def initialize(agent_context)
|
10
|
+
@agent_context = agent_context
|
11
|
+
@error_records = []
|
12
|
+
@mutex = Monitor.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def capture(exception, env)
|
16
|
+
context = ScoutApm::Context.current
|
17
|
+
|
18
|
+
@mutex.synchronize {
|
19
|
+
@error_records << ErrorRecord.new(agent_context, exception, env, context)
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_and_reset_error_records
|
24
|
+
@mutex.synchronize {
|
25
|
+
ret = @error_records
|
26
|
+
@error_records = []
|
27
|
+
ret
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
# Enables enumerable - for count and each and similar methods
|
32
|
+
def each
|
33
|
+
@error_records.each do |error_record|
|
34
|
+
yield error_record
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,211 @@
|
|
1
|
+
module ScoutApm
|
2
|
+
module ErrorService
|
3
|
+
# Converts the raw error data captured into the captured data, and holds it
|
4
|
+
# until it's ready to be reported.
|
5
|
+
class ErrorRecord
|
6
|
+
attr_reader :exception_class
|
7
|
+
attr_reader :message
|
8
|
+
attr_reader :request_uri
|
9
|
+
attr_reader :request_params
|
10
|
+
attr_reader :request_session
|
11
|
+
attr_reader :environment
|
12
|
+
attr_reader :trace
|
13
|
+
attr_reader :request_components
|
14
|
+
attr_reader :context
|
15
|
+
|
16
|
+
def initialize(agent_context, exception, env, context=nil)
|
17
|
+
@agent_context = agent_context
|
18
|
+
|
19
|
+
@context = if context
|
20
|
+
context.to_hash
|
21
|
+
else
|
22
|
+
{}
|
23
|
+
end
|
24
|
+
|
25
|
+
@exception_class = LengthLimit.new(exception.class.name).to_s
|
26
|
+
@message = LengthLimit.new(exception.message, 100).to_s
|
27
|
+
@request_uri = LengthLimit.new(rack_request_url(env), 200).to_s
|
28
|
+
@request_params = clean_params(env["action_dispatch.request.parameters"])
|
29
|
+
@request_session = clean_params(session_data(env))
|
30
|
+
@environment = clean_params(strip_env(env))
|
31
|
+
@trace = clean_backtrace(exception.backtrace)
|
32
|
+
@request_components = components(env)
|
33
|
+
end
|
34
|
+
|
35
|
+
# TODO: This is rails specific
|
36
|
+
def components(env)
|
37
|
+
components = {}
|
38
|
+
unless env["action_dispatch.request.parameters"].nil?
|
39
|
+
components[:controller] = env["action_dispatch.request.parameters"][:controller] || nil
|
40
|
+
components[:action] = env["action_dispatch.request.parameters"][:action] || nil
|
41
|
+
components[:module] = env["action_dispatch.request.parameters"][:module] || nil
|
42
|
+
end
|
43
|
+
|
44
|
+
# For background workers like sidekiq
|
45
|
+
# TODO: extract data creation for background jobs
|
46
|
+
components[:controller] ||= env[:custom_controller]
|
47
|
+
|
48
|
+
components
|
49
|
+
end
|
50
|
+
|
51
|
+
# TODO: Can I use the same thing we use in traces?
|
52
|
+
def rack_request_url(env)
|
53
|
+
protocol = rack_scheme(env)
|
54
|
+
protocol = protocol.nil? ? "" : "#{protocol}://"
|
55
|
+
|
56
|
+
host = env["SERVER_NAME"] || ""
|
57
|
+
path = env["REQUEST_URI"] || ""
|
58
|
+
port = env["SERVER_PORT"] || "80"
|
59
|
+
port = ["80", "443"].include?(port.to_s) ? "" : ":#{port}"
|
60
|
+
|
61
|
+
protocol.to_s + host.to_s + port.to_s + path.to_s
|
62
|
+
end
|
63
|
+
|
64
|
+
def rack_scheme(env)
|
65
|
+
if env["HTTPS"] == "on"
|
66
|
+
"https"
|
67
|
+
elsif env["HTTP_X_FORWARDED_PROTO"]
|
68
|
+
env["HTTP_X_FORWARDED_PROTO"].split(",")[0]
|
69
|
+
else
|
70
|
+
env["rack.url_scheme"]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# TODO: This name is too vague
|
75
|
+
def clean_params(params)
|
76
|
+
return if params.nil?
|
77
|
+
|
78
|
+
normalized = normalize_data(params)
|
79
|
+
filter_params(normalized)
|
80
|
+
end
|
81
|
+
|
82
|
+
# TODO: When was backtrace_cleaner introduced?
|
83
|
+
def clean_backtrace(backtrace)
|
84
|
+
if defined?(Rails) && Rails.respond_to?(:backtrace_cleaner)
|
85
|
+
Rails.backtrace_cleaner.send(:filter, backtrace)
|
86
|
+
else
|
87
|
+
backtrace
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Deletes params from env
|
92
|
+
#
|
93
|
+
# These are not configurable, and will leak PII info up to Scout if
|
94
|
+
# allowed through. Things like specific parameters can be exposed with
|
95
|
+
# the ScoutApm::Context interface.
|
96
|
+
KEYS_TO_REMOVE = [
|
97
|
+
"rack.request.form_hash",
|
98
|
+
"rack.request.form_vars",
|
99
|
+
"async.callback",
|
100
|
+
|
101
|
+
# Security related items
|
102
|
+
"action_dispatch.secret_key_base",
|
103
|
+
"action_dispatch.http_auth_salt",
|
104
|
+
"action_dispatch.signed_cookie_salt",
|
105
|
+
"action_dispatch.encrypted_cookie_salt",
|
106
|
+
"action_dispatch.encrypted_signed_cookie_salt",
|
107
|
+
"action_dispatch.authenticated_encrypted_cookie_salt",
|
108
|
+
|
109
|
+
# Raw data from the URL & parameters. Would bypass our normal params filtering
|
110
|
+
"QUERY_STRING",
|
111
|
+
"REQUEST_URI",
|
112
|
+
"REQUEST_PATH",
|
113
|
+
"ORIGINAL_FULLPATH",
|
114
|
+
"action_dispatch.request.query_parameters",
|
115
|
+
"action_dispatch.request.parameters",
|
116
|
+
"rack.request.query_string",
|
117
|
+
"rack.request.query_hash",
|
118
|
+
]
|
119
|
+
def strip_env(env)
|
120
|
+
env.reject { |k, v| KEYS_TO_REMOVE.include?(k) }
|
121
|
+
end
|
122
|
+
|
123
|
+
def session_data(env)
|
124
|
+
session = env["action_dispatch.request.session"]
|
125
|
+
return if session.nil?
|
126
|
+
|
127
|
+
if session.respond_to?(:to_hash)
|
128
|
+
session.to_hash
|
129
|
+
else
|
130
|
+
session.data
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# TODO: Rename and make this clearer. I think it maps over the whole tree of a hash, and to_s each leaf node?
|
135
|
+
def normalize_data(hash)
|
136
|
+
new_hash = {}
|
137
|
+
|
138
|
+
hash.each do |key, value|
|
139
|
+
if value.respond_to?(:to_hash)
|
140
|
+
begin
|
141
|
+
new_hash[key] = normalize_data(value.to_hash)
|
142
|
+
rescue
|
143
|
+
new_hash[key] = LengthLimit.new(value.to_s).to_s
|
144
|
+
end
|
145
|
+
else
|
146
|
+
new_hash[key] = LengthLimit.new(value.to_s).to_s
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
new_hash
|
151
|
+
end
|
152
|
+
|
153
|
+
###################
|
154
|
+
# Filtering Params
|
155
|
+
###################
|
156
|
+
|
157
|
+
# Replaces parameter values with a string / set in config file
|
158
|
+
def filter_params(params)
|
159
|
+
return params unless filtered_params_config
|
160
|
+
|
161
|
+
params.each do |k, v|
|
162
|
+
if filter_key?(k)
|
163
|
+
params[k] = "[FILTERED]"
|
164
|
+
elsif v.respond_to?(:to_hash)
|
165
|
+
filter_params(params[k])
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
params
|
170
|
+
end
|
171
|
+
|
172
|
+
# Check, if a key should be filtered
|
173
|
+
def filter_key?(key)
|
174
|
+
params_to_filter.any? do |filter|
|
175
|
+
key.to_s == filter.to_s # key.to_s.include?(filter.to_s)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def params_to_filter
|
180
|
+
@params_to_filter ||= filtered_params_config + rails_filtered_params
|
181
|
+
end
|
182
|
+
|
183
|
+
# Accessor for the filtered params config value. Will be removed as we refactor and clean up this code.
|
184
|
+
# TODO: Flip this over to use a new class like filtered exceptions?
|
185
|
+
def filtered_params_config
|
186
|
+
@agent_context.config.value("errors_filtered_params")
|
187
|
+
end
|
188
|
+
|
189
|
+
def rails_filtered_params
|
190
|
+
return [] unless defined?(Rails)
|
191
|
+
Rails.configuration.filter_parameters
|
192
|
+
rescue
|
193
|
+
[]
|
194
|
+
end
|
195
|
+
|
196
|
+
class LengthLimit
|
197
|
+
attr_reader :text
|
198
|
+
attr_reader :char_limit
|
199
|
+
|
200
|
+
def initialize(text, char_limit=100)
|
201
|
+
@text = text
|
202
|
+
@char_limit = char_limit
|
203
|
+
end
|
204
|
+
|
205
|
+
def to_s
|
206
|
+
text[0..char_limit]
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|