scout_apm 2.5.1 → 5.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (156) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/test.yml +68 -0
  3. data/.gitignore +1 -0
  4. data/.rubocop.yml +5 -5
  5. data/CHANGELOG.markdown +176 -3
  6. data/Gemfile +1 -7
  7. data/LICENSE.md +21 -28
  8. data/gems/README.md +28 -0
  9. data/gems/instruments.gemfile +6 -0
  10. data/gems/octoshark.gemfile +4 -0
  11. data/gems/rails3.gemfile +5 -0
  12. data/gems/rails4.gemfile +4 -0
  13. data/gems/rails5.gemfile +4 -0
  14. data/gems/rails6.gemfile +4 -0
  15. data/gems/sidekiq.gemfile +4 -0
  16. data/gems/typhoeus.gemfile +3 -0
  17. data/lib/scout_apm/agent/preconditions.rb +3 -3
  18. data/lib/scout_apm/agent.rb +22 -0
  19. data/lib/scout_apm/agent_context.rb +21 -2
  20. data/lib/scout_apm/app_server_load.rb +7 -2
  21. data/lib/scout_apm/auto_instrument/instruction_sequence.rb +31 -0
  22. data/lib/scout_apm/auto_instrument/layer.rb +23 -0
  23. data/lib/scout_apm/auto_instrument/parser.rb +27 -0
  24. data/lib/scout_apm/auto_instrument/rails.rb +174 -0
  25. data/lib/scout_apm/auto_instrument.rb +5 -0
  26. data/lib/scout_apm/background_job_integrations/delayed_job.rb +1 -1
  27. data/lib/scout_apm/background_job_integrations/faktory.rb +103 -0
  28. data/lib/scout_apm/background_job_integrations/legacy_sneakers.rb +55 -0
  29. data/lib/scout_apm/background_job_integrations/que.rb +134 -0
  30. data/lib/scout_apm/background_job_integrations/shoryuken.rb +2 -0
  31. data/lib/scout_apm/background_job_integrations/sidekiq.rb +15 -10
  32. data/lib/scout_apm/background_job_integrations/sneakers.rb +11 -11
  33. data/lib/scout_apm/config.rb +54 -6
  34. data/lib/scout_apm/detailed_trace.rb +3 -2
  35. data/lib/scout_apm/environment.rb +18 -1
  36. data/lib/scout_apm/error.rb +27 -0
  37. data/lib/scout_apm/error_service/error_buffer.rb +39 -0
  38. data/lib/scout_apm/error_service/error_record.rb +211 -0
  39. data/lib/scout_apm/error_service/ignored_exceptions.rb +66 -0
  40. data/lib/scout_apm/error_service/middleware.rb +32 -0
  41. data/lib/scout_apm/error_service/notifier.rb +33 -0
  42. data/lib/scout_apm/error_service/payload.rb +47 -0
  43. data/lib/scout_apm/error_service/periodic_work.rb +17 -0
  44. data/lib/scout_apm/error_service/railtie.rb +11 -0
  45. data/lib/scout_apm/error_service/sidekiq.rb +80 -0
  46. data/lib/scout_apm/error_service.rb +34 -0
  47. data/lib/scout_apm/exceptions.rb +12 -0
  48. data/lib/scout_apm/extensions/transaction_callback_payload.rb +1 -1
  49. data/lib/scout_apm/external_service_metric_set.rb +97 -0
  50. data/lib/scout_apm/external_service_metric_stats.rb +85 -0
  51. data/lib/scout_apm/fake_store.rb +3 -0
  52. data/lib/scout_apm/framework_integrations/rails_3_or_4.rb +7 -2
  53. data/lib/scout_apm/git_revision.rb +9 -0
  54. data/lib/scout_apm/ignored_uris.rb +3 -1
  55. data/lib/scout_apm/instant/middleware.rb +4 -1
  56. data/lib/scout_apm/instrument_manager.rb +22 -1
  57. data/lib/scout_apm/instruments/action_controller_rails_2.rb +1 -1
  58. data/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb +53 -29
  59. data/lib/scout_apm/instruments/action_view.rb +30 -9
  60. data/lib/scout_apm/instruments/active_record.rb +69 -19
  61. data/lib/scout_apm/instruments/elasticsearch.rb +93 -42
  62. data/lib/scout_apm/instruments/grape.rb +1 -1
  63. data/lib/scout_apm/instruments/http.rb +68 -0
  64. data/lib/scout_apm/instruments/http_client.rb +33 -14
  65. data/lib/scout_apm/instruments/influxdb.rb +2 -2
  66. data/lib/scout_apm/instruments/memcached.rb +58 -0
  67. data/lib/scout_apm/instruments/middleware_detailed.rb +1 -1
  68. data/lib/scout_apm/instruments/middleware_summary.rb +1 -1
  69. data/lib/scout_apm/instruments/mongoid.rb +10 -5
  70. data/lib/scout_apm/instruments/moped.rb +44 -19
  71. data/lib/scout_apm/instruments/net_http.rb +51 -16
  72. data/lib/scout_apm/instruments/rails_router.rb +1 -1
  73. data/lib/scout_apm/instruments/redis.rb +27 -12
  74. data/lib/scout_apm/instruments/redis5.rb +59 -0
  75. data/lib/scout_apm/instruments/sinatra.rb +3 -1
  76. data/lib/scout_apm/instruments/typhoeus.rb +90 -0
  77. data/lib/scout_apm/job_record.rb +4 -2
  78. data/lib/scout_apm/layaway_file.rb +4 -0
  79. data/lib/scout_apm/layer.rb +5 -2
  80. data/lib/scout_apm/layer_children_set.rb +9 -8
  81. data/lib/scout_apm/layer_converters/external_service_converter.rb +65 -0
  82. data/lib/scout_apm/layer_converters/find_layer_by_type.rb +4 -0
  83. data/lib/scout_apm/layer_converters/request_queue_time_converter.rb +2 -0
  84. data/lib/scout_apm/layer_converters/trace_converter.rb +7 -4
  85. data/lib/scout_apm/logger.rb +5 -1
  86. data/lib/scout_apm/middleware.rb +1 -1
  87. data/lib/scout_apm/periodic_work.rb +19 -0
  88. data/lib/scout_apm/remote/message.rb +4 -0
  89. data/lib/scout_apm/remote/server.rb +13 -1
  90. data/lib/scout_apm/reporter.rb +8 -3
  91. data/lib/scout_apm/reporting.rb +2 -1
  92. data/lib/scout_apm/request_histograms.rb +8 -0
  93. data/lib/scout_apm/serializers/app_server_load_serializer.rb +4 -0
  94. data/lib/scout_apm/serializers/directive_serializer.rb +4 -0
  95. data/lib/scout_apm/serializers/external_service_serializer_to_json.rb +15 -0
  96. data/lib/scout_apm/serializers/payload_serializer.rb +4 -3
  97. data/lib/scout_apm/serializers/payload_serializer_to_json.rb +10 -3
  98. data/lib/scout_apm/slow_policy/age_policy.rb +33 -0
  99. data/lib/scout_apm/slow_policy/percent_policy.rb +22 -0
  100. data/lib/scout_apm/slow_policy/percentile_policy.rb +24 -0
  101. data/lib/scout_apm/slow_policy/policy.rb +21 -0
  102. data/lib/scout_apm/slow_policy/speed_policy.rb +16 -0
  103. data/lib/scout_apm/slow_request_policy.rb +18 -77
  104. data/lib/scout_apm/store.rb +31 -1
  105. data/lib/scout_apm/tracer.rb +2 -2
  106. data/lib/scout_apm/tracked_request.rb +35 -4
  107. data/lib/scout_apm/utils/backtrace_parser.rb +3 -0
  108. data/lib/scout_apm/utils/marshal_logging.rb +90 -0
  109. data/lib/scout_apm/utils/sql_sanitizer.rb +47 -7
  110. data/lib/scout_apm/version.rb +1 -1
  111. data/lib/scout_apm.rb +46 -1
  112. data/scout_apm.gemspec +14 -9
  113. data/test/test_helper.rb +2 -2
  114. data/test/tmp/README.md +17 -0
  115. data/test/unit/agent_context_test.rb +29 -0
  116. data/test/unit/auto_instrument/anonymous_block_value.rb +7 -0
  117. data/test/unit/auto_instrument/assignments-instrumented.rb +31 -0
  118. data/test/unit/auto_instrument/assignments.rb +31 -0
  119. data/test/unit/auto_instrument/controller-ast.txt +57 -0
  120. data/test/unit/auto_instrument/controller-instrumented.rb +49 -0
  121. data/test/unit/auto_instrument/controller.rb +49 -0
  122. data/test/unit/auto_instrument/hanging_method.rb +6 -0
  123. data/test/unit/auto_instrument/rescue_from-instrumented.rb +13 -0
  124. data/test/unit/auto_instrument/rescue_from.rb +13 -0
  125. data/test/unit/auto_instrument_test.rb +62 -0
  126. data/test/unit/background_job_integrations/sidekiq_test.rb +17 -0
  127. data/test/unit/environment_test.rb +2 -2
  128. data/test/unit/error_service/error_buffer_test.rb +25 -0
  129. data/test/unit/error_service/ignored_exceptions_test.rb +49 -0
  130. data/test/unit/external_service_metric_set_test.rb +67 -0
  131. data/test/unit/external_service_metric_stats_test.rb +106 -0
  132. data/test/unit/ignored_uris_test.rb +6 -0
  133. data/test/unit/instruments/active_record_test.rb +40 -0
  134. data/test/unit/instruments/http_client_test.rb +24 -0
  135. data/test/unit/instruments/http_test.rb +24 -0
  136. data/test/unit/instruments/moped_test.rb +24 -0
  137. data/test/unit/instruments/net_http_test.rb +11 -1
  138. data/test/unit/instruments/redis_test.rb +24 -0
  139. data/test/unit/instruments/typhoeus_test.rb +42 -0
  140. data/test/unit/layer_children_set_test.rb +9 -0
  141. data/test/unit/remote/{test_message.rb → message_test.rb} +0 -0
  142. data/test/unit/remote/{test_router.rb → route_test.rb} +0 -0
  143. data/test/unit/remote/{test_server.rb → server_test.rb} +4 -1
  144. data/test/unit/request_histograms_test.rb +17 -0
  145. data/test/unit/serializers/payload_serializer_test.rb +39 -3
  146. data/test/unit/slow_request_policy_test.rb +41 -13
  147. data/test/unit/sql_sanitizer_test.rb +106 -0
  148. data/test/unit/tracer_test.rb +25 -0
  149. metadata +118 -60
  150. data/.travis.yml +0 -25
  151. data/lib/scout_apm/instruments/.DS_Store +0 -0
  152. data/lib/scout_apm/slow_job_policy.rb +0 -111
  153. data/lib/scout_apm/utils/sql_sanitizer_regex.rb +0 -25
  154. data/lib/scout_apm/utils/sql_sanitizer_regex_1_8_7.rb +0 -26
  155. data/test/unit/instruments/active_record_instruments_test.rb +0 -5
  156. data/test/unit/slow_job_policy_test.rb +0 -6
@@ -8,7 +8,7 @@ class PayloadSerializerTest < Minitest::Test
8
8
  :unique_id => "unique_idz",
9
9
  :agent_version => 123
10
10
  }
11
- payload = ScoutApm::Serializers::PayloadSerializerToJson.serialize(metadata, {}, {}, [], [], [], {}, [])
11
+ payload = ScoutApm::Serializers::PayloadSerializerToJson.serialize(metadata, {}, {}, [], [], [], {}, {}, [])
12
12
 
13
13
  # symbol keys turn to strings
14
14
  formatted_metadata = {
@@ -49,7 +49,7 @@ class PayloadSerializerTest < Minitest::Test
49
49
  stats.total_exclusive_time = 0.078132088
50
50
  }
51
51
  }
52
- payload = ScoutApm::Serializers::PayloadSerializerToJson.serialize({}, metrics, {}, [], [], [], {}, [])
52
+ payload = ScoutApm::Serializers::PayloadSerializerToJson.serialize({}, metrics, {}, [], [], [], {}, {}, [])
53
53
  formatted_metrics = [
54
54
  {
55
55
  "key" => {
@@ -94,7 +94,7 @@ class PayloadSerializerTest < Minitest::Test
94
94
  :quotie => "here are some \"quotes\"",
95
95
  :payload_version => 2,
96
96
  }
97
- payload = ScoutApm::Serializers::PayloadSerializerToJson.serialize(metadata, {}, {}, [], [], [], {}, [])
97
+ payload = ScoutApm::Serializers::PayloadSerializerToJson.serialize(metadata, {}, {}, [], [], [], {}, {}, [])
98
98
 
99
99
  # symbol keys turn to strings
100
100
  formatted_metadata = {
@@ -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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: false
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  module ScoutApm
@@ -28,7 +30,23 @@ module ScoutApm
28
30
  sql = %q|SELECT "users".* FROM "users" INNER JOIN "blogs" ON "blogs"."user_id" = "users"."id" WHERE (blogs.title = 'hello world')|
29
31
  ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :postgres }
30
32
  assert_equal %q|SELECT "users".* FROM "users" INNER JOIN "blogs" ON "blogs"."user_id" = "users"."id" WHERE (blogs.title = ?)|, ss.to_s
33
+ end
31
34
 
35
+ def test_postgres_strips_after_where
36
+ raw_sql = %q|SELECT DISTINCT ON (flagged_traces.metric_name) flagged_traces.metric_name, "flagged_traces"."trace_id", "flagged_traces"."trace_type", "flagged_traces"."trace_occurred_at", flagged_traces.details ->> 'uri' as uri, (flagged_traces.details ->> 'n_sum_millis')::float as potential_savings, (flagged_traces.details ->> 'n_count')::float as num_queries FROM "flagged_traces" WHERE "flagged_traces"."app_id" = 5 AND "flagged_traces"."trace_type" = 'Request' AND ("flagged_traces"."trace_occurred_at" BETWEEN '2019-04-17 12:28:00.000000' AND '2019-04-18 12:28:00.000000') AND "flagged_traces"."flag_type" = 'nplusone' ORDER BY "flagged_traces"."metric_name" ASC, potential_savings DESC|
37
+ sanitized_sql = SqlSanitizer.new(raw_sql).tap { |it| it.database_engine = :postgres}
38
+ expected_sql = %q|SELECT DISTINCT ON (flagged_traces.metric_name) flagged_traces.metric_name, "flagged_traces"."trace_id", "flagged_traces"."trace_type", "flagged_traces"."trace_occurred_at", flagged_traces.details ->> 'uri' as uri, (flagged_traces.details ->> 'n_sum_millis')::float as potential_savings, (flagged_traces.details ->> 'n_count')::float as num_queries FROM "flagged_traces" WHERE "flagged_traces"."app_id" = ? AND "flagged_traces"."trace_type" = ? AND ("flagged_traces"."trace_occurred_at" BETWEEN ? AND ?) AND "flagged_traces"."flag_type" = ? ORDER BY "flagged_traces"."metric_name" ASC, potential_savings DESC|
39
+ assert_equal expected_sql, sanitized_sql.to_s
40
+ end
41
+
42
+ def test_postgres_strips_subquery_strings
43
+ raw_sql = %q|"SELECT "orgs".* FROM "orgs" WHERE "orgs"."name" = 'Scout' AND "orgs"."created_by_user_id" IN (SELECT "users"."id" FROM "users" WHERE (id > AVG(id)) AND "type" = 'USER' AND "created_at" BETWEEN '2019-04-17 12:28:00.000000' AND '2019-04-18 12:28:00.000000')"|
44
+ sanitized_sql = SqlSanitizer.new(raw_sql).tap { |it| it.database_engine = :postgres}
45
+ expected_sql = %q|"SELECT "orgs".* FROM "orgs" WHERE "orgs"."name" = ? AND "orgs"."created_by_user_id" IN (SELECT "users"."id" FROM "users" WHERE (id > AVG(id)) AND "type" = ? AND "created_at" BETWEEN ? AND ?)"|
46
+ assert_equal expected_sql, sanitized_sql.to_s
47
+ end
48
+
49
+ def test_postgres_strips_integers
32
50
  # Strip integers
33
51
  sql = %q|SELECT "blogs".* FROM "blogs" WHERE (view_count > 10)|
34
52
  ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :postgres }
@@ -50,6 +68,21 @@ module ScoutApm
50
68
  end
51
69
  end
52
70
 
71
+ def test_postgres_inner_join_subquery
72
+ sql = %q{SELECT x AS y
73
+ FROM t1
74
+ INNER JOIN (
75
+ SELECT id,
76
+ (ts_rank((to_tsvector('simple', coalesce("pg_search_documents"."content"::text, ''))), (to_tsquery('simple', 'xyz' || 'omg' || 'secret')), ?)) AS rank
77
+ FROM t2
78
+ WHERE name = 'literal') sub ON sub.id = t1.id WHERE age > 10}
79
+
80
+ expected = %q{SELECT x AS y FROM t1 INNER JOIN ( SELECT id, (ts_rank((to_tsvector(?, coalesce("pg_search_documents"."content"::text, ?))), (to_tsquery(?, ? || ? || ?)), ?)) AS rank FROM t2 WHERE name = ?) sub ON sub.id = t1.id WHERE age > ?}
81
+ ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :postgres }
82
+
83
+ assert_equal expected, ss.to_s
84
+ end
85
+
53
86
  def test_mysql_where
54
87
  sql = %q|SELECT `users`.* FROM `users` WHERE `users`.`name` = ? [["name", "chris"]]|
55
88
  ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :mysql }
@@ -89,6 +122,30 @@ module ScoutApm
89
122
  assert_equal %q|INSERT INTO `users` VALUES (?, ?)|, ss.to_s
90
123
  end
91
124
 
125
+ def test_sqlserver_integers
126
+ sql = "EXEC sp_executesql N'SELECT [users].* FROM [users] WHERE (age > 50) ORDER BY [users].[id] ASC OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY', N'@0 int', @0 = 10"
127
+ ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :sqlserver }
128
+ assert_equal "SELECT [users].* FROM [users] WHERE (age > ?) ORDER BY [users].[id] ASC OFFSET ? ROWS FETCH NEXT @0 ROWS ONLY?@0 int', @0 = ?", ss.to_s
129
+ end
130
+
131
+ def test_sqlserver_strings
132
+ sql = "EXEC sp_executesql N'SELECT [users].* FROM [users] WHERE first_name = N'john' AND last_name = N'doe' ORDER BY [users].[id] ASC OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY', N'@0 int', @0 = 10"
133
+ ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :sqlserver }
134
+ assert_equal "SELECT [users].* FROM [users] WHERE first_name = N? AND last_name = N? ORDER BY [users].[id] ASC OFFSET ? ROWS FETCH NEXT @0 ROWS ONLY?@0 int', @0 = ?", ss.to_s
135
+ end
136
+
137
+ def test_sqlserver_strings_no_executesql
138
+ sql = "EXEC Authenticate @username = N'abraham.lincoln', @password = N'somepassword!', @token = NULL, @app_name = N'Central Auth Service', @log_login = true, @ip_address = N'127.0.0.1', @external_type = NULL, @external_success = NULL"
139
+ ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :sqlserver }
140
+ assert_equal "EXEC Authenticate @username = N?, @password = N?, @token = NULL, @app_name = N?, @log_login = true, @ip_address = N?, @external_type = NULL, @external_success = NULL", ss.to_s
141
+ end
142
+
143
+ def test_sqlserver_in_clause
144
+ sql = "EXEC sp_executesql N'SELECT [users].* FROM [users] WHERE (id IN (1,2,3)) ORDER BY [users].[id] ASC OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY', N'@0 int', @0 = 10"
145
+ ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :sqlserver }
146
+ assert_equal "SELECT [users].* FROM [users] WHERE (id IN (?)) ORDER BY [users].[id] ASC OFFSET ? ROWS FETCH NEXT @0 ROWS ONLY?@0 int', @0 = ?", ss.to_s
147
+ end
148
+
92
149
  def test_scrubs_invalid_encoding
93
150
  skip "Ruby 1.8.7 has no concept of encoding" if RUBY_VERSION.start_with?("1.8.")
94
151
 
@@ -99,6 +156,55 @@ module ScoutApm
99
156
  assert_equal %q|SELECT `blogs`.* FROM `blogs` WHERE (title = ?)|, ss.to_s
100
157
  end
101
158
 
159
+ def test_set_columns
160
+ sql = %q|UPDATE "mytable" SET "myfield" = 'fieldcontent', "countofthings" = 10 WHERE "user_id" = 10|
161
+
162
+ ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :postgres }
163
+ assert_equal %q|UPDATE "mytable" SET "myfield" = ?, "countofthings" = ? WHERE "user_id" = ?|, ss.to_s
164
+ end
165
+
166
+ def test_postgres_multiline_sql
167
+ sql = %q|
168
+ SELECT "html_form_payloads".*
169
+ FROM "html_form_payloads"
170
+ INNER JOIN "leads" ON "leads"."payload_id" = "html_form_payloads"."id"
171
+ AND "leads"."payload_type" = ?
172
+ WHERE html_form_payloads.id < 10
173
+ AND "form_type" = 'xyz'
174
+ AND (params::varchar = '{"name":"Chris","resident":"Yes","e-content":"Secret content"}')
175
+ AND (leads.url = 'http://example.com')
176
+ ORDER BY "html_form_payloads"."id" ASC
177
+ LIMIT ?
178
+ |
179
+
180
+ ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :postgres }
181
+ 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
182
+ end
183
+
184
+ def test_mysql_multiline
185
+ sql = %q|
186
+ SELECT `blogs`.*
187
+ FROM `blogs`
188
+ WHERE (title = 'abc')
189
+ |
190
+
191
+ ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :mysql }
192
+ assert_equal %q|SELECT `blogs`.*
193
+ FROM `blogs`
194
+ WHERE (title = ?)|, ss.to_s
195
+ end
196
+
197
+ def test_postgres_insert_select_from_jsonb_to_recordset_with_as
198
+ sql = %q|
199
+ INSERT INTO foos(foo_id, bar_id, external_id, email_address, created_at, updated_at)
200
+ SELECT 123, 456, external_id, email_address, NOW(), NOW()
201
+ FROM jsonb_to_recordset($${"items":[{"external_id":1234,"email_address":"test@domain.com"}]}$$::jsonb->'items')
202
+ AS t(external_id integer, email_address varchar)
203
+ |
204
+ ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :postgres }
205
+ assert_equal %q|INSERT INTO foos(foo_id, bar_id, external_id, email_address, created_at, updated_at) SELECT ?, ?, external_id, email_address, NOW(), NOW() FROM jsonb_to_recordset($${"items":[{"external_id":?,"email_address":"?"}]}$$::jsonb->'items') AS t(external_id integer, email_address varchar)|, ss.to_s
206
+ end
207
+
102
208
  def assert_faster_than(target_seconds)
103
209
  t1 = ::Time.now
104
210
  yield
@@ -65,6 +65,31 @@ class TracerTest < Minitest::Test
65
65
  assert_recorded(recorder, "Test", "name")
66
66
  end
67
67
 
68
+ if ScoutApm::Agent.instance.context.environment.supports_kwarg_delegation?
69
+ def test_instrument_method_with_keyword_args
70
+ initial_value = Warning[:deprecated]
71
+ Warning[:deprecated] = true
72
+ recorder = FakeRecorder.new
73
+ ScoutApm::Agent.instance.context.recorder = recorder
74
+
75
+ klass = Class.new { include ScoutApm::Tracer }
76
+
77
+ invoked = false
78
+ klass.send(:define_method, :work) { |run:| invoked = true }
79
+ klass.instrument_method(:work, :type => "Test", :name => "name")
80
+
81
+ args = { run: false }
82
+ assert_output(nil, '') do
83
+ klass.new.work(**args)
84
+ end
85
+
86
+ assert invoked, "instrumented code was not invoked"
87
+ assert_recorded(recorder, "Test", "name")
88
+ ensure
89
+ Warning[:deprecated] = initial_value
90
+ end
91
+ end
92
+
68
93
  private
69
94
 
70
95
  def assert_recorded(recorder, type, name)
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.5.1
4
+ version: 5.3.2
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-06-24 00:00:00.000000000 Z
12
+ date: 2022-10-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest
@@ -109,6 +109,48 @@ dependencies:
109
109
  - - ">="
110
110
  - !ruby/object:Gem::Version
111
111
  version: '0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: parser
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ type: :runtime
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: activerecord
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ - !ruby/object:Gem::Dependency
141
+ name: sqlite3
142
+ requirement: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ type: :development
148
+ prerelease: false
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
112
154
  - !ruby/object:Gem::Dependency
113
155
  name: rubocop
114
156
  requirement: !ruby/object:Gem::Requirement
@@ -174,9 +216,9 @@ extensions:
174
216
  - ext/rusage/extconf.rb
175
217
  extra_rdoc_files: []
176
218
  files:
219
+ - ".github/workflows/test.yml"
177
220
  - ".gitignore"
178
221
  - ".rubocop.yml"
179
- - ".travis.yml"
180
222
  - CHANGELOG.markdown
181
223
  - Gemfile
182
224
  - Guardfile
@@ -189,6 +231,15 @@ files:
189
231
  - ext/rusage/README.md
190
232
  - ext/rusage/extconf.rb
191
233
  - ext/rusage/rusage.c
234
+ - gems/README.md
235
+ - gems/instruments.gemfile
236
+ - gems/octoshark.gemfile
237
+ - gems/rails3.gemfile
238
+ - gems/rails4.gemfile
239
+ - gems/rails5.gemfile
240
+ - gems/rails6.gemfile
241
+ - gems/sidekiq.gemfile
242
+ - gems/typhoeus.gemfile
192
243
  - lib/scout_apm.rb
193
244
  - lib/scout_apm/agent.rb
194
245
  - lib/scout_apm/agent/exit_handler.rb
@@ -196,7 +247,15 @@ files:
196
247
  - lib/scout_apm/agent_context.rb
197
248
  - lib/scout_apm/app_server_load.rb
198
249
  - lib/scout_apm/attribute_arranger.rb
250
+ - lib/scout_apm/auto_instrument.rb
251
+ - lib/scout_apm/auto_instrument/instruction_sequence.rb
252
+ - lib/scout_apm/auto_instrument/layer.rb
253
+ - lib/scout_apm/auto_instrument/parser.rb
254
+ - lib/scout_apm/auto_instrument/rails.rb
199
255
  - lib/scout_apm/background_job_integrations/delayed_job.rb
256
+ - lib/scout_apm/background_job_integrations/faktory.rb
257
+ - lib/scout_apm/background_job_integrations/legacy_sneakers.rb
258
+ - lib/scout_apm/background_job_integrations/que.rb
200
259
  - lib/scout_apm/background_job_integrations/resque.rb
201
260
  - lib/scout_apm/background_job_integrations/shoryuken.rb
202
261
  - lib/scout_apm/background_job_integrations/sidekiq.rb
@@ -212,8 +271,22 @@ files:
212
271
  - lib/scout_apm/debug.rb
213
272
  - lib/scout_apm/detailed_trace.rb
214
273
  - lib/scout_apm/environment.rb
274
+ - lib/scout_apm/error.rb
275
+ - lib/scout_apm/error_service.rb
276
+ - lib/scout_apm/error_service/error_buffer.rb
277
+ - lib/scout_apm/error_service/error_record.rb
278
+ - lib/scout_apm/error_service/ignored_exceptions.rb
279
+ - lib/scout_apm/error_service/middleware.rb
280
+ - lib/scout_apm/error_service/notifier.rb
281
+ - lib/scout_apm/error_service/payload.rb
282
+ - lib/scout_apm/error_service/periodic_work.rb
283
+ - lib/scout_apm/error_service/railtie.rb
284
+ - lib/scout_apm/error_service/sidekiq.rb
285
+ - lib/scout_apm/exceptions.rb
215
286
  - lib/scout_apm/extensions/config.rb
216
287
  - lib/scout_apm/extensions/transaction_callback_payload.rb
288
+ - lib/scout_apm/external_service_metric_set.rb
289
+ - lib/scout_apm/external_service_metric_stats.rb
217
290
  - lib/scout_apm/fake_store.rb
218
291
  - lib/scout_apm/framework_integrations/rails_2.rb
219
292
  - lib/scout_apm/framework_integrations/rails_3_or_4.rb
@@ -226,15 +299,16 @@ files:
226
299
  - lib/scout_apm/instant/middleware.rb
227
300
  - lib/scout_apm/instant_reporting.rb
228
301
  - lib/scout_apm/instrument_manager.rb
229
- - lib/scout_apm/instruments/.DS_Store
230
302
  - lib/scout_apm/instruments/action_controller_rails_2.rb
231
303
  - lib/scout_apm/instruments/action_controller_rails_3_rails4.rb
232
304
  - lib/scout_apm/instruments/action_view.rb
233
305
  - lib/scout_apm/instruments/active_record.rb
234
306
  - lib/scout_apm/instruments/elasticsearch.rb
235
307
  - lib/scout_apm/instruments/grape.rb
308
+ - lib/scout_apm/instruments/http.rb
236
309
  - lib/scout_apm/instruments/http_client.rb
237
310
  - lib/scout_apm/instruments/influxdb.rb
311
+ - lib/scout_apm/instruments/memcached.rb
238
312
  - lib/scout_apm/instruments/middleware_detailed.rb
239
313
  - lib/scout_apm/instruments/middleware_summary.rb
240
314
  - lib/scout_apm/instruments/mongoid.rb
@@ -245,9 +319,11 @@ files:
245
319
  - lib/scout_apm/instruments/process/process_memory.rb
246
320
  - lib/scout_apm/instruments/rails_router.rb
247
321
  - lib/scout_apm/instruments/redis.rb
322
+ - lib/scout_apm/instruments/redis5.rb
248
323
  - lib/scout_apm/instruments/resque.rb
249
324
  - lib/scout_apm/instruments/samplers.rb
250
325
  - lib/scout_apm/instruments/sinatra.rb
326
+ - lib/scout_apm/instruments/typhoeus.rb
251
327
  - lib/scout_apm/job_record.rb
252
328
  - lib/scout_apm/layaway.rb
253
329
  - lib/scout_apm/layaway_file.rb
@@ -258,6 +334,7 @@ files:
258
334
  - lib/scout_apm/layer_converters/database_converter.rb
259
335
  - lib/scout_apm/layer_converters/depth_first_walker.rb
260
336
  - lib/scout_apm/layer_converters/error_converter.rb
337
+ - lib/scout_apm/layer_converters/external_service_converter.rb
261
338
  - lib/scout_apm/layer_converters/find_layer_by_type.rb
262
339
  - lib/scout_apm/layer_converters/histograms.rb
263
340
  - lib/scout_apm/layer_converters/job_converter.rb
@@ -289,6 +366,7 @@ files:
289
366
  - lib/scout_apm/serializers/app_server_load_serializer.rb
290
367
  - lib/scout_apm/serializers/db_query_serializer_to_json.rb
291
368
  - lib/scout_apm/serializers/directive_serializer.rb
369
+ - lib/scout_apm/serializers/external_service_serializer_to_json.rb
292
370
  - lib/scout_apm/serializers/histograms_serializer_to_json.rb
293
371
  - lib/scout_apm/serializers/jobs_serializer_to_json.rb
294
372
  - lib/scout_apm/serializers/metrics_to_json_serializer.rb
@@ -302,8 +380,12 @@ files:
302
380
  - lib/scout_apm/server_integrations/thin.rb
303
381
  - lib/scout_apm/server_integrations/unicorn.rb
304
382
  - lib/scout_apm/server_integrations/webrick.rb
305
- - lib/scout_apm/slow_job_policy.rb
306
383
  - lib/scout_apm/slow_job_record.rb
384
+ - lib/scout_apm/slow_policy/age_policy.rb
385
+ - lib/scout_apm/slow_policy/percent_policy.rb
386
+ - lib/scout_apm/slow_policy/percentile_policy.rb
387
+ - lib/scout_apm/slow_policy/policy.rb
388
+ - lib/scout_apm/slow_policy/speed_policy.rb
307
389
  - lib/scout_apm/slow_request_policy.rb
308
390
  - lib/scout_apm/slow_transaction.rb
309
391
  - lib/scout_apm/stack_item.rb
@@ -320,11 +402,10 @@ files:
320
402
  - lib/scout_apm/utils/gzip_helper.rb
321
403
  - lib/scout_apm/utils/installed_gems.rb
322
404
  - lib/scout_apm/utils/klass_helper.rb
405
+ - lib/scout_apm/utils/marshal_logging.rb
323
406
  - lib/scout_apm/utils/numbers.rb
324
407
  - lib/scout_apm/utils/scm.rb
325
408
  - lib/scout_apm/utils/sql_sanitizer.rb
326
- - lib/scout_apm/utils/sql_sanitizer_regex.rb
327
- - lib/scout_apm/utils/sql_sanitizer_regex_1_8_7.rb
328
409
  - lib/scout_apm/utils/time.rb
329
410
  - lib/scout_apm/utils/unique_id.rb
330
411
  - lib/scout_apm/version.rb
@@ -332,22 +413,43 @@ files:
332
413
  - scout_apm.gemspec
333
414
  - test/data/config_test_1.yml
334
415
  - test/test_helper.rb
416
+ - test/tmp/README.md
417
+ - test/unit/agent_context_test.rb
335
418
  - test/unit/agent_test.rb
419
+ - test/unit/auto_instrument/anonymous_block_value.rb
420
+ - test/unit/auto_instrument/assignments-instrumented.rb
421
+ - test/unit/auto_instrument/assignments.rb
422
+ - test/unit/auto_instrument/controller-ast.txt
423
+ - test/unit/auto_instrument/controller-instrumented.rb
424
+ - test/unit/auto_instrument/controller.rb
425
+ - test/unit/auto_instrument/hanging_method.rb
426
+ - test/unit/auto_instrument/rescue_from-instrumented.rb
427
+ - test/unit/auto_instrument/rescue_from.rb
428
+ - test/unit/auto_instrument_test.rb
336
429
  - test/unit/background_job_integrations/sidekiq_test.rb
337
430
  - test/unit/config_test.rb
338
431
  - test/unit/context_test.rb
339
432
  - test/unit/db_query_metric_set_test.rb
340
433
  - test/unit/db_query_metric_stats_test.rb
341
434
  - test/unit/environment_test.rb
435
+ - test/unit/error_service/error_buffer_test.rb
436
+ - test/unit/error_service/ignored_exceptions_test.rb
342
437
  - test/unit/extensions/periodic_callbacks_test.rb
343
438
  - test/unit/extensions/transaction_callbacks_test.rb
439
+ - test/unit/external_service_metric_set_test.rb
440
+ - test/unit/external_service_metric_stats_test.rb
344
441
  - test/unit/fake_store_test.rb
345
442
  - test/unit/git_revision_test.rb
346
443
  - test/unit/histogram_test.rb
347
444
  - test/unit/ignored_uris_test.rb
348
- - test/unit/instruments/active_record_instruments_test.rb
445
+ - test/unit/instruments/active_record_test.rb
446
+ - test/unit/instruments/http_client_test.rb
447
+ - test/unit/instruments/http_test.rb
448
+ - test/unit/instruments/moped_test.rb
349
449
  - test/unit/instruments/net_http_test.rb
350
450
  - test/unit/instruments/percentile_sampler_test.rb
451
+ - test/unit/instruments/redis_test.rb
452
+ - test/unit/instruments/typhoeus_test.rb
351
453
  - test/unit/layaway_test.rb
352
454
  - test/unit/layer_children_set_test.rb
353
455
  - test/unit/layer_converters/depth_first_walker_test.rb
@@ -356,12 +458,12 @@ files:
356
458
  - test/unit/limited_layer_test.rb
357
459
  - test/unit/logger_test.rb
358
460
  - test/unit/metric_set_test.rb
359
- - test/unit/remote/test_message.rb
360
- - test/unit/remote/test_router.rb
361
- - test/unit/remote/test_server.rb
461
+ - test/unit/remote/message_test.rb
462
+ - test/unit/remote/route_test.rb
463
+ - test/unit/remote/server_test.rb
464
+ - test/unit/request_histograms_test.rb
362
465
  - test/unit/scored_item_set_test.rb
363
466
  - test/unit/serializers/payload_serializer_test.rb
364
- - test/unit/slow_job_policy_test.rb
365
467
  - test/unit/slow_request_policy_test.rb
366
468
  - test/unit/sql_sanitizer_test.rb
367
469
  - test/unit/store_test.rb
@@ -375,7 +477,7 @@ files:
375
477
  - test/unit/utils/scm.rb
376
478
  homepage: https://github.com/scoutapp/scout_apm_ruby
377
479
  licenses:
378
- - Proprietary (See LICENSE.md)
480
+ - MIT
379
481
  metadata: {}
380
482
  post_install_message:
381
483
  rdoc_options: []
@@ -386,59 +488,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
386
488
  requirements:
387
489
  - - ">="
388
490
  - !ruby/object:Gem::Version
389
- version: '0'
491
+ version: '2.1'
390
492
  required_rubygems_version: !ruby/object:Gem::Requirement
391
493
  requirements:
392
494
  - - ">="
393
495
  - !ruby/object:Gem::Version
394
496
  version: '0'
395
497
  requirements: []
396
- rubyforge_project: scout_apm
397
- rubygems_version: 2.4.6
498
+ rubygems_version: 3.0.3
398
499
  signing_key:
399
500
  specification_version: 4
400
501
  summary: Ruby application performance monitoring
401
- test_files:
402
- - test/data/config_test_1.yml
403
- - test/test_helper.rb
404
- - test/unit/agent_test.rb
405
- - test/unit/background_job_integrations/sidekiq_test.rb
406
- - test/unit/config_test.rb
407
- - test/unit/context_test.rb
408
- - test/unit/db_query_metric_set_test.rb
409
- - test/unit/db_query_metric_stats_test.rb
410
- - test/unit/environment_test.rb
411
- - test/unit/extensions/periodic_callbacks_test.rb
412
- - test/unit/extensions/transaction_callbacks_test.rb
413
- - test/unit/fake_store_test.rb
414
- - test/unit/git_revision_test.rb
415
- - test/unit/histogram_test.rb
416
- - test/unit/ignored_uris_test.rb
417
- - test/unit/instruments/active_record_instruments_test.rb
418
- - test/unit/instruments/net_http_test.rb
419
- - test/unit/instruments/percentile_sampler_test.rb
420
- - test/unit/layaway_test.rb
421
- - test/unit/layer_children_set_test.rb
422
- - test/unit/layer_converters/depth_first_walker_test.rb
423
- - test/unit/layer_converters/metric_converter_test.rb
424
- - test/unit/layer_converters/stubs.rb
425
- - test/unit/limited_layer_test.rb
426
- - test/unit/logger_test.rb
427
- - test/unit/metric_set_test.rb
428
- - test/unit/remote/test_message.rb
429
- - test/unit/remote/test_router.rb
430
- - test/unit/remote/test_server.rb
431
- - test/unit/scored_item_set_test.rb
432
- - test/unit/serializers/payload_serializer_test.rb
433
- - test/unit/slow_job_policy_test.rb
434
- - test/unit/slow_request_policy_test.rb
435
- - test/unit/sql_sanitizer_test.rb
436
- - test/unit/store_test.rb
437
- - test/unit/tracer_test.rb
438
- - test/unit/tracked_request_test.rb
439
- - test/unit/transaction_test.rb
440
- - test/unit/transaction_time_consumed_test.rb
441
- - test/unit/utils/active_record_metric_name_test.rb
442
- - test/unit/utils/backtrace_parser_test.rb
443
- - test/unit/utils/numbers_test.rb
444
- - test/unit/utils/scm.rb
502
+ test_files: []