scout_apm 2.6.6 → 4.0.3

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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +49 -0
  3. data/.rubocop.yml +2 -5
  4. data/.travis.yml +3 -7
  5. data/CHANGELOG.markdown +45 -0
  6. data/Gemfile +1 -8
  7. data/gems/rails6.gemfile +1 -1
  8. data/lib/scout_apm.rb +22 -1
  9. data/lib/scout_apm/agent.rb +22 -0
  10. data/lib/scout_apm/agent_context.rb +14 -2
  11. data/lib/scout_apm/background_job_integrations/sidekiq.rb +2 -2
  12. data/lib/scout_apm/config.rb +17 -2
  13. data/lib/scout_apm/detailed_trace.rb +2 -1
  14. data/lib/scout_apm/environment.rb +16 -1
  15. data/lib/scout_apm/error.rb +27 -0
  16. data/lib/scout_apm/error_service.rb +32 -0
  17. data/lib/scout_apm/error_service/error_buffer.rb +39 -0
  18. data/lib/scout_apm/error_service/error_record.rb +211 -0
  19. data/lib/scout_apm/error_service/ignored_exceptions.rb +66 -0
  20. data/lib/scout_apm/error_service/middleware.rb +32 -0
  21. data/lib/scout_apm/error_service/notifier.rb +33 -0
  22. data/lib/scout_apm/error_service/payload.rb +47 -0
  23. data/lib/scout_apm/error_service/periodic_work.rb +17 -0
  24. data/lib/scout_apm/error_service/railtie.rb +11 -0
  25. data/lib/scout_apm/error_service/sidekiq.rb +80 -0
  26. data/lib/scout_apm/extensions/transaction_callback_payload.rb +1 -1
  27. data/lib/scout_apm/instrument_manager.rb +1 -0
  28. data/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb +47 -26
  29. data/lib/scout_apm/instruments/action_view.rb +21 -8
  30. data/lib/scout_apm/instruments/active_record.rb +17 -28
  31. data/lib/scout_apm/instruments/typhoeus.rb +88 -0
  32. data/lib/scout_apm/layer.rb +1 -1
  33. data/lib/scout_apm/middleware.rb +1 -1
  34. data/lib/scout_apm/remote/server.rb +13 -1
  35. data/lib/scout_apm/reporter.rb +8 -3
  36. data/lib/scout_apm/serializers/payload_serializer_to_json.rb +28 -10
  37. data/lib/scout_apm/slow_policy/age_policy.rb +33 -0
  38. data/lib/scout_apm/slow_policy/percent_policy.rb +22 -0
  39. data/lib/scout_apm/slow_policy/percentile_policy.rb +24 -0
  40. data/lib/scout_apm/slow_policy/policy.rb +21 -0
  41. data/lib/scout_apm/slow_policy/speed_policy.rb +16 -0
  42. data/lib/scout_apm/slow_request_policy.rb +18 -77
  43. data/lib/scout_apm/utils/sql_sanitizer.rb +1 -0
  44. data/lib/scout_apm/utils/sql_sanitizer_regex.rb +3 -3
  45. data/lib/scout_apm/utils/sql_sanitizer_regex_1_8_7.rb +1 -0
  46. data/lib/scout_apm/version.rb +1 -1
  47. data/scout_apm.gemspec +6 -6
  48. data/test/unit/agent_context_test.rb +29 -0
  49. data/test/unit/environment_test.rb +2 -2
  50. data/test/unit/error_service/error_buffer_test.rb +25 -0
  51. data/test/unit/error_service/ignored_exceptions_test.rb +49 -0
  52. data/test/unit/serializers/payload_serializer_test.rb +36 -0
  53. data/test/unit/slow_request_policy_test.rb +41 -13
  54. data/test/unit/sql_sanitizer_test.rb +38 -0
  55. metadata +26 -61
  56. data/lib/scout_apm/slow_job_policy.rb +0 -111
  57. data/test/unit/slow_job_policy_test.rb +0 -6
@@ -0,0 +1,29 @@
1
+ require "test_helper"
2
+
3
+ require "scout_apm/agent_context"
4
+
5
+ class AgentContextTest < Minitest::Test
6
+ def test_has_error_service_ignored_exceptions
7
+ context = ScoutApm::AgentContext.new
8
+ assert ScoutApm::ErrorService::IgnoredExceptions, context.ignored_exceptions.class
9
+ end
10
+
11
+ def test_has_error_buffer
12
+ context = ScoutApm::AgentContext.new
13
+ assert ScoutApm::ErrorService::ErrorBuffer, context.error_buffer.class
14
+ end
15
+
16
+
17
+ class TestPolicy
18
+ def call(req); 1; end
19
+ def stored!(req); end
20
+ end
21
+
22
+ def test_customize_slow_request_policy
23
+ context = ScoutApm::AgentContext.new
24
+ assert 4, context.slow_request_policy.policies
25
+
26
+ context.slow_request_policy.add(TestPolicy.new)
27
+ assert 5, context.slow_request_policy.policies
28
+ end
29
+ end
@@ -44,8 +44,8 @@ class EnvironmentTest < Minitest::Test
44
44
  end
45
45
 
46
46
  def clean_fake_rails
47
- Kernel.const_unset("Rails") if defined?(Kernel::Rails)
48
- Kernel.const_unset("ActionController") if defined?(Kernel::ActionController)
47
+ Kernel.send(:remove_const, "Rails") if defined?(Kernel::Rails)
48
+ Kernel.send(:remove_const, "ActionController") if defined?(Kernel::ActionController)
49
49
  end
50
50
 
51
51
  def fake_sinatra
@@ -0,0 +1,25 @@
1
+ require "test_helper"
2
+
3
+ class ErrorBufferTest < Minitest::Test
4
+ class FakeError < StandardError
5
+ end
6
+
7
+ def test_captures_and_stores_exceptions_and_env
8
+ eb = ScoutApm::ErrorService::ErrorBuffer.new(context)
9
+ eb.capture(ex, env)
10
+ end
11
+
12
+ #### Helpers
13
+
14
+ def context
15
+ ScoutApm::AgentContext.new
16
+ end
17
+
18
+ def env
19
+ {}
20
+ end
21
+
22
+ def ex(msg="Whoops")
23
+ FakeError.new(msg)
24
+ end
25
+ end
@@ -0,0 +1,49 @@
1
+ require "test_helper"
2
+
3
+ class IgnoredExceptionsTest < Minitest::Test
4
+ class FakeError < StandardError
5
+ end
6
+
7
+ class SubclassFakeError < FakeError
8
+ end
9
+
10
+ def test_ignores_with_string_match
11
+ ig = ScoutApm::ErrorService::IgnoredExceptions.new(context, ["RuntimeError"])
12
+ assert ig.ignored?(RuntimeError.new("something went wrong"))
13
+ assert !ig.ignored?(FakeError.new("something went wrong"))
14
+ end
15
+
16
+ def test_ignores_with_block
17
+ ig = ScoutApm::ErrorService::IgnoredExceptions.new(context, [])
18
+ ig.add_callback { |e| e.message == "ignore me" }
19
+
20
+ should_ignore = RuntimeError.new("ignore me")
21
+ should_not_ignore = RuntimeError.new("super legit")
22
+
23
+ assert ig.ignored?(should_ignore)
24
+ assert !ig.ignored?(should_not_ignore)
25
+ end
26
+
27
+ def test_ignores_subclasses
28
+ ig = ScoutApm::ErrorService::IgnoredExceptions.new(context, ["IgnoredExceptionsTest::FakeError"])
29
+ assert ig.ignored?(SubclassFakeError.new("Subclass"))
30
+ end
31
+
32
+ # Check that a bad exception in the list doesn't stop the whole thing from working
33
+ def test_does_not_consider_unknown_errors
34
+ ig = ScoutApm::ErrorService::IgnoredExceptions.new(context, ["ThisDoesNotExist", "IgnoredExceptionsTest::FakeError"])
35
+ assert ig.ignored?(FakeError.new("ignore this one"))
36
+ end
37
+
38
+ def test_add_module
39
+ ig = ScoutApm::ErrorService::IgnoredExceptions.new(context, [])
40
+ ig.add(IgnoredExceptionsTest::FakeError)
41
+ assert ig.ignored?(FakeError.new("ignore this one"))
42
+ end
43
+
44
+ #### Helpers
45
+
46
+ def context
47
+ ScoutApm::AgentContext.new
48
+ end
49
+ end
@@ -108,4 +108,40 @@ class PayloadSerializerTest < Minitest::Test
108
108
  json = { "foo" => "\bbar\nbaz\r" }
109
109
  assert_equal json, JSON.parse(ScoutApm::Serializers::PayloadSerializerToJson.jsonify_hash(json))
110
110
  end
111
+
112
+ def test_escapes_escaped_quotes
113
+ # Some escapes haven't ever worked on 1.8.7, and is not the issue I'm
114
+ # fixing now. Remove this when we drop support for ancient ruby
115
+ skip if RUBY_VERSION == "1.8.7"
116
+
117
+ json = {"foo" => %q|`additional_details` = '{\"amount\":1}'|}
118
+ result = ScoutApm::Serializers::PayloadSerializerToJson.jsonify_hash(json)
119
+ assert_equal json, JSON.parse(result)
120
+ end
121
+
122
+ def test_escapes_various_special_characters
123
+ # Some escapes haven't ever worked on 1.8.7, and is not the issue I'm
124
+ # fixing now. Remove this when we drop support for ancient ruby
125
+ skip if RUBY_VERSION == "1.8.7"
126
+
127
+ json = {"foo" => [
128
+ %Q|\fbar|,
129
+ %Q|\rbar|,
130
+ %Q|\nbar|,
131
+ %Q|\tbar|,
132
+ %Q|"bar|,
133
+ %Q|'bar|,
134
+ %Q|{bar|,
135
+ %Q|}bar|,
136
+ %Q|\\bar|,
137
+ if RUBY_VERSION == '1.8.7'
138
+ ""
139
+ else
140
+ %Q|\\\nbar|
141
+ end,
142
+ ]}
143
+
144
+ result = ScoutApm::Serializers::PayloadSerializerToJson.jsonify_hash(json)
145
+ assert_equal json, JSON.parse(result)
146
+ end
111
147
  end
@@ -1,6 +1,7 @@
1
1
  require 'test_helper'
2
2
 
3
3
  require 'scout_apm/slow_request_policy'
4
+ require 'scout_apm/slow_policy/policy'
4
5
  require 'scout_apm/layer'
5
6
 
6
7
  class FakeRequest
@@ -16,35 +17,62 @@ class FakeRequest
16
17
  end
17
18
  end
18
19
 
20
+ class FixedPolicy < ScoutApm::SlowPolicy::Policy
21
+ attr_reader :stored
22
+
23
+ def initialize(x)
24
+ @x = x
25
+ end
26
+
27
+ def call(req)
28
+ @x
29
+ end
30
+
31
+ def stored!(req)
32
+ @stored = true
33
+ end
34
+ end
35
+
19
36
  class SlowRequestPolicyTest < Minitest::Test
20
37
  def setup
21
38
  @context = ScoutApm::AgentContext.new
22
39
  end
23
40
 
24
- def test_stored_records_current_time
41
+ def test_age_policy_stored_records_current_time
25
42
  test_start = Time.now
26
- policy = ScoutApm::SlowRequestPolicy.new(@context)
43
+ policy = ScoutApm::SlowPolicy::AgePolicy.new(@context)
27
44
  request = FakeRequest.new("users/index")
28
45
 
29
46
  policy.stored!(request)
30
47
  assert policy.last_seen[request.unique_name] > test_start
31
48
  end
32
49
 
33
- def test_score
50
+ def test_sums_up_score
34
51
  policy = ScoutApm::SlowRequestPolicy.new(@context)
35
52
  request = FakeRequest.new("users/index")
36
53
 
37
- request.set_duration(10) # 10 seconds
38
- policy.last_seen[request.unique_name] = Time.now - 120 # 2 minutes since last seen
39
- @context.request_histograms.add(request.unique_name, 1)
40
- @context.transaction_time_consumed.add(request.unique_name, 1)
54
+ policy.add(FixedPolicy.new(1))
55
+ policy.add(FixedPolicy.new(2))
41
56
 
42
- # Actual value I have in console is 4.01
43
- # Score uses Time.now to compare w/ last_seen, and will tick up slowly as
44
- # time passes, hence the range below.
45
- score = policy.score(request)
57
+ assert_equal 3, policy.score(request)
58
+ end
59
+
60
+ def test_calls_store_on_policies
61
+ policy = ScoutApm::SlowRequestPolicy.new(@context)
62
+ request = FakeRequest.new("users/index")
63
+
64
+ policy.add(fp1 = FixedPolicy.new(1))
65
+ policy.add(fp2 = FixedPolicy.new(2))
66
+ policy.stored!(request)
67
+
68
+ assert_equal true, fp1.stored
69
+ assert_equal true, fp2.stored
70
+ end
71
+
72
+ def test_checks_new_policy_api
73
+ policy = ScoutApm::SlowRequestPolicy.new(@context)
46
74
 
47
- assert score > 3.95
48
- assert score < 4.05
75
+ assert_raises { policy.add(Object.new) }
76
+ assert_raises { policy.add(->(req){1}) } # only implements call
49
77
  end
50
78
  end
@@ -139,6 +139,44 @@ module ScoutApm
139
139
  assert_equal %q|SELECT `blogs`.* FROM `blogs` WHERE (title = ?)|, ss.to_s
140
140
  end
141
141
 
142
+ def test_set_columns
143
+ sql = %q|UPDATE "mytable" SET "myfield" = 'fieldcontent', "countofthings" = 10 WHERE "user_id" = 10|
144
+
145
+ ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :postgres }
146
+ assert_equal %q|UPDATE "mytable" SET "myfield" = ?, "countofthings" = ? WHERE "user_id" = ?|, ss.to_s
147
+ end
148
+
149
+ def test_postgres_multiline_sql
150
+ sql = %q|
151
+ SELECT "html_form_payloads".*
152
+ FROM "html_form_payloads"
153
+ INNER JOIN "leads" ON "leads"."payload_id" = "html_form_payloads"."id"
154
+ AND "leads"."payload_type" = ?
155
+ WHERE html_form_payloads.id < 10
156
+ AND "form_type" = 'xyz'
157
+ AND (params::varchar = '{"name":"Chris","resident":"Yes","e-content":"Secret content"}')
158
+ AND (leads.url = 'http://example.com')
159
+ ORDER BY "html_form_payloads"."id" ASC
160
+ LIMIT ?
161
+ |
162
+
163
+ ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :postgres }
164
+ assert_equal %q|SELECT "html_form_payloads".* FROM "html_form_payloads" INNER JOIN "leads" ON "leads"."payload_id" = "html_form_payloads"."id" AND "leads"."payload_type" = ? WHERE html_form_payloads.id < ? AND "form_type" = ? AND (params::varchar = ?) AND (leads.url = ?) ORDER BY "html_form_payloads"."id" ASC LIMIT ?|, ss.to_s
165
+ end
166
+
167
+ def test_mysql_multiline
168
+ sql = %q|
169
+ SELECT `blogs`.*
170
+ FROM `blogs`
171
+ WHERE (title = 'abc')
172
+ |
173
+
174
+ ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :mysql }
175
+ assert_equal %q|SELECT `blogs`.*
176
+ FROM `blogs`
177
+ WHERE (title = ?)|, ss.to_s
178
+ end
179
+
142
180
  def assert_faster_than(target_seconds)
143
181
  t1 = ::Time.now
144
182
  yield
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scout_apm
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.6.6
4
+ version: 4.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Derek Haynes
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-12-19 00:00:00.000000000 Z
12
+ date: 2021-01-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest
@@ -216,6 +216,7 @@ extensions:
216
216
  - ext/rusage/extconf.rb
217
217
  extra_rdoc_files: []
218
218
  files:
219
+ - ".github/workflows/test.yml"
219
220
  - ".gitignore"
220
221
  - ".rubocop.yml"
221
222
  - ".travis.yml"
@@ -267,6 +268,17 @@ files:
267
268
  - lib/scout_apm/debug.rb
268
269
  - lib/scout_apm/detailed_trace.rb
269
270
  - lib/scout_apm/environment.rb
271
+ - lib/scout_apm/error.rb
272
+ - lib/scout_apm/error_service.rb
273
+ - lib/scout_apm/error_service/error_buffer.rb
274
+ - lib/scout_apm/error_service/error_record.rb
275
+ - lib/scout_apm/error_service/ignored_exceptions.rb
276
+ - lib/scout_apm/error_service/middleware.rb
277
+ - lib/scout_apm/error_service/notifier.rb
278
+ - lib/scout_apm/error_service/payload.rb
279
+ - lib/scout_apm/error_service/periodic_work.rb
280
+ - lib/scout_apm/error_service/railtie.rb
281
+ - lib/scout_apm/error_service/sidekiq.rb
270
282
  - lib/scout_apm/extensions/config.rb
271
283
  - lib/scout_apm/extensions/transaction_callback_payload.rb
272
284
  - lib/scout_apm/fake_store.rb
@@ -281,7 +293,6 @@ files:
281
293
  - lib/scout_apm/instant/middleware.rb
282
294
  - lib/scout_apm/instant_reporting.rb
283
295
  - lib/scout_apm/instrument_manager.rb
284
- - lib/scout_apm/instruments/.DS_Store
285
296
  - lib/scout_apm/instruments/action_controller_rails_2.rb
286
297
  - lib/scout_apm/instruments/action_controller_rails_3_rails4.rb
287
298
  - lib/scout_apm/instruments/action_view.rb
@@ -305,6 +316,7 @@ files:
305
316
  - lib/scout_apm/instruments/resque.rb
306
317
  - lib/scout_apm/instruments/samplers.rb
307
318
  - lib/scout_apm/instruments/sinatra.rb
319
+ - lib/scout_apm/instruments/typhoeus.rb
308
320
  - lib/scout_apm/job_record.rb
309
321
  - lib/scout_apm/layaway.rb
310
322
  - lib/scout_apm/layaway_file.rb
@@ -359,8 +371,12 @@ files:
359
371
  - lib/scout_apm/server_integrations/thin.rb
360
372
  - lib/scout_apm/server_integrations/unicorn.rb
361
373
  - lib/scout_apm/server_integrations/webrick.rb
362
- - lib/scout_apm/slow_job_policy.rb
363
374
  - lib/scout_apm/slow_job_record.rb
375
+ - lib/scout_apm/slow_policy/age_policy.rb
376
+ - lib/scout_apm/slow_policy/percent_policy.rb
377
+ - lib/scout_apm/slow_policy/percentile_policy.rb
378
+ - lib/scout_apm/slow_policy/policy.rb
379
+ - lib/scout_apm/slow_policy/speed_policy.rb
364
380
  - lib/scout_apm/slow_request_policy.rb
365
381
  - lib/scout_apm/slow_transaction.rb
366
382
  - lib/scout_apm/stack_item.rb
@@ -391,6 +407,7 @@ files:
391
407
  - test/data/config_test_1.yml
392
408
  - test/test_helper.rb
393
409
  - test/tmp/README.md
410
+ - test/unit/agent_context_test.rb
394
411
  - test/unit/agent_test.rb
395
412
  - test/unit/auto_instrument/assignments-instrumented.rb
396
413
  - test/unit/auto_instrument/assignments.rb
@@ -406,6 +423,8 @@ files:
406
423
  - test/unit/db_query_metric_set_test.rb
407
424
  - test/unit/db_query_metric_stats_test.rb
408
425
  - test/unit/environment_test.rb
426
+ - test/unit/error_service/error_buffer_test.rb
427
+ - test/unit/error_service/ignored_exceptions_test.rb
409
428
  - test/unit/extensions/periodic_callbacks_test.rb
410
429
  - test/unit/extensions/transaction_callbacks_test.rb
411
430
  - test/unit/fake_store_test.rb
@@ -429,7 +448,6 @@ files:
429
448
  - test/unit/request_histograms_test.rb
430
449
  - test/unit/scored_item_set_test.rb
431
450
  - test/unit/serializers/payload_serializer_test.rb
432
- - test/unit/slow_job_policy_test.rb
433
451
  - test/unit/slow_request_policy_test.rb
434
452
  - test/unit/sql_sanitizer_test.rb
435
453
  - test/unit/store_test.rb
@@ -454,68 +472,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
454
472
  requirements:
455
473
  - - ">="
456
474
  - !ruby/object:Gem::Version
457
- version: '0'
475
+ version: '2.1'
458
476
  required_rubygems_version: !ruby/object:Gem::Requirement
459
477
  requirements:
460
478
  - - ">="
461
479
  - !ruby/object:Gem::Version
462
480
  version: '0'
463
481
  requirements: []
464
- rubygems_version: 3.0.4
482
+ rubygems_version: 3.0.8
465
483
  signing_key:
466
484
  specification_version: 4
467
485
  summary: Ruby application performance monitoring
468
- test_files:
469
- - test/data/config_test_1.yml
470
- - test/test_helper.rb
471
- - test/tmp/README.md
472
- - test/unit/agent_test.rb
473
- - test/unit/auto_instrument/assignments-instrumented.rb
474
- - test/unit/auto_instrument/assignments.rb
475
- - test/unit/auto_instrument/controller-ast.txt
476
- - test/unit/auto_instrument/controller-instrumented.rb
477
- - test/unit/auto_instrument/controller.rb
478
- - test/unit/auto_instrument/rescue_from-instrumented.rb
479
- - test/unit/auto_instrument/rescue_from.rb
480
- - test/unit/auto_instrument_test.rb
481
- - test/unit/background_job_integrations/sidekiq_test.rb
482
- - test/unit/config_test.rb
483
- - test/unit/context_test.rb
484
- - test/unit/db_query_metric_set_test.rb
485
- - test/unit/db_query_metric_stats_test.rb
486
- - test/unit/environment_test.rb
487
- - test/unit/extensions/periodic_callbacks_test.rb
488
- - test/unit/extensions/transaction_callbacks_test.rb
489
- - test/unit/fake_store_test.rb
490
- - test/unit/git_revision_test.rb
491
- - test/unit/histogram_test.rb
492
- - test/unit/ignored_uris_test.rb
493
- - test/unit/instruments/active_record_test.rb
494
- - test/unit/instruments/net_http_test.rb
495
- - test/unit/instruments/percentile_sampler_test.rb
496
- - test/unit/layaway_test.rb
497
- - test/unit/layer_children_set_test.rb
498
- - test/unit/layer_converters/depth_first_walker_test.rb
499
- - test/unit/layer_converters/metric_converter_test.rb
500
- - test/unit/layer_converters/stubs.rb
501
- - test/unit/limited_layer_test.rb
502
- - test/unit/logger_test.rb
503
- - test/unit/metric_set_test.rb
504
- - test/unit/remote/test_message.rb
505
- - test/unit/remote/test_router.rb
506
- - test/unit/remote/test_server.rb
507
- - test/unit/request_histograms_test.rb
508
- - test/unit/scored_item_set_test.rb
509
- - test/unit/serializers/payload_serializer_test.rb
510
- - test/unit/slow_job_policy_test.rb
511
- - test/unit/slow_request_policy_test.rb
512
- - test/unit/sql_sanitizer_test.rb
513
- - test/unit/store_test.rb
514
- - test/unit/tracer_test.rb
515
- - test/unit/tracked_request_test.rb
516
- - test/unit/transaction_test.rb
517
- - test/unit/transaction_time_consumed_test.rb
518
- - test/unit/utils/active_record_metric_name_test.rb
519
- - test/unit/utils/backtrace_parser_test.rb
520
- - test/unit/utils/numbers_test.rb
521
- - test/unit/utils/scm.rb
486
+ test_files: []