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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +0 -4
  3. data/.travis.yml +0 -6
  4. data/CHANGELOG.markdown +30 -0
  5. data/Gemfile +1 -8
  6. data/lib/scout_apm.rb +21 -1
  7. data/lib/scout_apm/agent.rb +22 -0
  8. data/lib/scout_apm/agent_context.rb +14 -2
  9. data/lib/scout_apm/background_job_integrations/sidekiq.rb +2 -2
  10. data/lib/scout_apm/config.rb +17 -2
  11. data/lib/scout_apm/detailed_trace.rb +2 -1
  12. data/lib/scout_apm/error.rb +27 -0
  13. data/lib/scout_apm/error_service.rb +32 -0
  14. data/lib/scout_apm/error_service/error_buffer.rb +39 -0
  15. data/lib/scout_apm/error_service/error_record.rb +211 -0
  16. data/lib/scout_apm/error_service/ignored_exceptions.rb +66 -0
  17. data/lib/scout_apm/error_service/middleware.rb +32 -0
  18. data/lib/scout_apm/error_service/notifier.rb +33 -0
  19. data/lib/scout_apm/error_service/payload.rb +47 -0
  20. data/lib/scout_apm/error_service/periodic_work.rb +17 -0
  21. data/lib/scout_apm/error_service/railtie.rb +11 -0
  22. data/lib/scout_apm/error_service/sidekiq.rb +80 -0
  23. data/lib/scout_apm/extensions/transaction_callback_payload.rb +1 -1
  24. data/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb +47 -26
  25. data/lib/scout_apm/instruments/action_view.rb +7 -2
  26. data/lib/scout_apm/instruments/active_record.rb +13 -28
  27. data/lib/scout_apm/middleware.rb +1 -1
  28. data/lib/scout_apm/reporter.rb +8 -3
  29. data/lib/scout_apm/serializers/payload_serializer_to_json.rb +28 -10
  30. data/lib/scout_apm/slow_policy/age_policy.rb +33 -0
  31. data/lib/scout_apm/slow_policy/percent_policy.rb +22 -0
  32. data/lib/scout_apm/slow_policy/percentile_policy.rb +24 -0
  33. data/lib/scout_apm/slow_policy/policy.rb +21 -0
  34. data/lib/scout_apm/slow_policy/speed_policy.rb +16 -0
  35. data/lib/scout_apm/slow_request_policy.rb +18 -77
  36. data/lib/scout_apm/utils/sql_sanitizer.rb +1 -0
  37. data/lib/scout_apm/utils/sql_sanitizer_regex.rb +1 -1
  38. data/lib/scout_apm/utils/sql_sanitizer_regex_1_8_7.rb +1 -0
  39. data/lib/scout_apm/version.rb +1 -1
  40. data/scout_apm.gemspec +6 -6
  41. data/test/unit/agent_context_test.rb +29 -0
  42. data/test/unit/error_service/error_buffer_test.rb +25 -0
  43. data/test/unit/error_service/ignored_exceptions_test.rb +49 -0
  44. data/test/unit/serializers/payload_serializer_test.rb +36 -0
  45. data/test/unit/slow_request_policy_test.rb +41 -13
  46. data/test/unit/sql_sanitizer_test.rb +7 -0
  47. metadata +25 -62
  48. data/lib/scout_apm/slow_job_policy.rb +0 -111
  49. 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: 73af2b28e0b054233c1ccd48122741d7b8e27adf9c61ee93fea520f7e3a6b3c7
4
- data.tar.gz: 544c20bf5c56478269232f19a792dcbc00c125befb6e5e7b406be04dc954944e
3
+ metadata.gz: ffcf571075c7f443ebe029e8f07c726cc5cb6c12e156d47e2565c576ac671316
4
+ data.tar.gz: 684f8ed4ba52d2e5819ea319288333a83f8b5481491ae879be2e8031cdd5d6ee
5
5
  SHA512:
6
- metadata.gz: c8558cd998a6c54ca7cd3c3174ba96c28230b0041a49e2d494460116a6f9065ba28f998ce8a74b546f69a8f1d5ec5dd81b9be29e27f4a874f51e1352f02798f0
7
- data.tar.gz: 18f7152a257b7ff61cb0c4953542527a2af25220d726ac26ade9242421f817afc83ce18fa28ea018188215717cedb25336ba79a61572cb706f99f16278be3545
6
+ metadata.gz: a4d90917dc02469213092848211fe779f44ec09e7db4829aaaa737ca15cf1811137dc2a4ae00adaa76cc2be92916b0467f164f79a76fac501c7a4827ba5d6f7d
7
+ data.tar.gz: 776d064902d998cc69330e470fbc9bfb368ae401d8e8a341310e4dc2a9070a256a2e57370505ee3475761d26145e4efced633963243527e39b95ab584bf48b2a
data/.rubocop.yml CHANGED
@@ -10,7 +10,3 @@ AllCops:
10
10
  Metrics/LineLength:
11
11
  Enabled: false
12
12
  Max: 100
13
-
14
- Style/HashSyntax:
15
- Enabled: true
16
- EnforcedStyle: hash_rockets
data/.travis.yml CHANGED
@@ -4,12 +4,6 @@ cache: bundler
4
4
 
5
5
  matrix:
6
6
  include:
7
- - rvm: "1.8.7"
8
- gemfile: gems/rails3.gemfile
9
- - rvm: "1.9.3"
10
- gemfile: gems/rails3.gemfile
11
- - rvm: 2.0
12
- gemfile: gems/rails3.gemfile
13
7
  - rvm: 2.1
14
8
  gemfile: gems/rails3.gemfile
15
9
  - rvm: 2.2
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
- # Pin development dependencies more conservatively for Ruby 1.8.7
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/slow_job_policy'
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?
@@ -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::SlowJobPolicy.new(self)
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(boss)
43
+ def initialize_with_scout(*args)
44
44
  agent = ::ScoutApm::Agent.instance
45
45
  agent.start
46
- initialize_without_scout(boss)
46
+ initialize_without_scout(*args)
47
47
  end
48
48
 
49
49
  alias_method :initialize_without_scout, :initialize
@@ -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)
@@ -200,8 +200,9 @@ class DetailedTraceTags
200
200
  @tags = hash
201
201
  end
202
202
 
203
+ # @tags is already a hash, so no conversion needed
203
204
  def as_json(*)
204
- @tags.as_json
205
+ @tags
205
206
  end
206
207
  end
207
208
 
@@ -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