scout_apm 3.0.0.pre28 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (127) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -1
  3. data/.rubocop.yml +3 -4
  4. data/.travis.yml +17 -14
  5. data/CHANGELOG.markdown +124 -4
  6. data/Gemfile +1 -7
  7. data/README.markdown +13 -4
  8. data/Rakefile +1 -1
  9. data/ext/allocations/allocations.c +2 -0
  10. data/gems/README.md +28 -0
  11. data/gems/octoshark.gemfile +4 -0
  12. data/gems/rails3.gemfile +5 -0
  13. data/gems/rails4.gemfile +4 -0
  14. data/gems/rails5.gemfile +4 -0
  15. data/gems/rails6.gemfile +4 -0
  16. data/lib/scout_apm.rb +37 -9
  17. data/lib/scout_apm/agent.rb +29 -10
  18. data/lib/scout_apm/agent/exit_handler.rb +0 -1
  19. data/lib/scout_apm/agent_context.rb +22 -3
  20. data/lib/scout_apm/app_server_load.rb +7 -2
  21. data/lib/scout_apm/attribute_arranger.rb +0 -2
  22. data/lib/scout_apm/auto_instrument.rb +5 -0
  23. data/lib/scout_apm/auto_instrument/instruction_sequence.rb +31 -0
  24. data/lib/scout_apm/auto_instrument/layer.rb +23 -0
  25. data/lib/scout_apm/auto_instrument/parser.rb +27 -0
  26. data/lib/scout_apm/auto_instrument/rails.rb +175 -0
  27. data/lib/scout_apm/background_job_integrations/legacy_sneakers.rb +55 -0
  28. data/lib/scout_apm/background_job_integrations/que.rb +134 -0
  29. data/lib/scout_apm/background_job_integrations/resque.rb +6 -2
  30. data/lib/scout_apm/background_job_integrations/shoryuken.rb +124 -0
  31. data/lib/scout_apm/background_job_integrations/sidekiq.rb +5 -19
  32. data/lib/scout_apm/background_job_integrations/sneakers.rb +87 -0
  33. data/lib/scout_apm/config.rb +45 -8
  34. data/lib/scout_apm/detailed_trace.rb +217 -0
  35. data/lib/scout_apm/environment.rb +3 -0
  36. data/lib/scout_apm/error.rb +27 -0
  37. data/lib/scout_apm/error_service.rb +32 -0
  38. data/lib/scout_apm/error_service/error_buffer.rb +39 -0
  39. data/lib/scout_apm/error_service/error_record.rb +211 -0
  40. data/lib/scout_apm/error_service/ignored_exceptions.rb +66 -0
  41. data/lib/scout_apm/error_service/middleware.rb +32 -0
  42. data/lib/scout_apm/error_service/notifier.rb +33 -0
  43. data/lib/scout_apm/error_service/payload.rb +47 -0
  44. data/lib/scout_apm/error_service/periodic_work.rb +17 -0
  45. data/lib/scout_apm/error_service/railtie.rb +11 -0
  46. data/lib/scout_apm/error_service/sidekiq.rb +80 -0
  47. data/lib/scout_apm/extensions/transaction_callback_payload.rb +1 -1
  48. data/lib/scout_apm/fake_store.rb +3 -0
  49. data/lib/scout_apm/framework_integrations/rails_2.rb +2 -1
  50. data/lib/scout_apm/framework_integrations/rails_3_or_4.rb +3 -1
  51. data/lib/scout_apm/git_revision.rb +6 -3
  52. data/lib/scout_apm/instant/middleware.rb +2 -1
  53. data/lib/scout_apm/instrument_manager.rb +8 -7
  54. data/lib/scout_apm/instruments/action_controller_rails_2.rb +3 -1
  55. data/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb +56 -55
  56. data/lib/scout_apm/instruments/action_view.rb +114 -26
  57. data/lib/scout_apm/instruments/active_record.rb +62 -18
  58. data/lib/scout_apm/instruments/http.rb +48 -0
  59. data/lib/scout_apm/instruments/memcached.rb +43 -0
  60. data/lib/scout_apm/instruments/mongoid.rb +9 -4
  61. data/lib/scout_apm/instruments/net_http.rb +8 -1
  62. data/lib/scout_apm/job_record.rb +4 -2
  63. data/lib/scout_apm/layaway_file.rb +4 -0
  64. data/lib/scout_apm/layer.rb +5 -56
  65. data/lib/scout_apm/layer_children_set.rb +9 -8
  66. data/lib/scout_apm/layer_converters/converter_base.rb +15 -30
  67. data/lib/scout_apm/layer_converters/slow_job_converter.rb +12 -2
  68. data/lib/scout_apm/layer_converters/slow_request_converter.rb +14 -4
  69. data/lib/scout_apm/layer_converters/trace_converter.rb +184 -0
  70. data/lib/scout_apm/limited_layer.rb +0 -7
  71. data/lib/scout_apm/metric_stats.rb +0 -8
  72. data/lib/scout_apm/middleware.rb +1 -1
  73. data/lib/scout_apm/periodic_work.rb +19 -0
  74. data/lib/scout_apm/remote/message.rb +4 -0
  75. data/lib/scout_apm/reporter.rb +8 -3
  76. data/lib/scout_apm/reporting.rb +2 -1
  77. data/lib/scout_apm/request_histograms.rb +8 -0
  78. data/lib/scout_apm/serializers/app_server_load_serializer.rb +4 -0
  79. data/lib/scout_apm/serializers/directive_serializer.rb +4 -0
  80. data/lib/scout_apm/serializers/payload_serializer.rb +2 -2
  81. data/lib/scout_apm/serializers/payload_serializer_to_json.rb +30 -15
  82. data/lib/scout_apm/slow_job_record.rb +5 -1
  83. data/lib/scout_apm/slow_policy/age_policy.rb +33 -0
  84. data/lib/scout_apm/slow_policy/percent_policy.rb +22 -0
  85. data/lib/scout_apm/slow_policy/percentile_policy.rb +24 -0
  86. data/lib/scout_apm/slow_policy/policy.rb +21 -0
  87. data/lib/scout_apm/slow_policy/speed_policy.rb +16 -0
  88. data/lib/scout_apm/slow_request_policy.rb +18 -77
  89. data/lib/scout_apm/slow_transaction.rb +3 -1
  90. data/lib/scout_apm/store.rb +0 -1
  91. data/lib/scout_apm/tracked_request.rb +39 -30
  92. data/lib/scout_apm/utils/backtrace_parser.rb +3 -0
  93. data/lib/scout_apm/utils/marshal_logging.rb +90 -0
  94. data/lib/scout_apm/utils/sql_sanitizer.rb +10 -1
  95. data/lib/scout_apm/utils/sql_sanitizer_regex.rb +7 -0
  96. data/lib/scout_apm/utils/sql_sanitizer_regex_1_8_7.rb +6 -0
  97. data/lib/scout_apm/utils/unique_id.rb +27 -0
  98. data/lib/scout_apm/version.rb +1 -1
  99. data/scout_apm.gemspec +13 -7
  100. data/test/test_helper.rb +2 -2
  101. data/test/unit/agent_context_test.rb +29 -0
  102. data/test/unit/auto_instrument/assignments-instrumented.rb +31 -0
  103. data/test/unit/auto_instrument/assignments.rb +31 -0
  104. data/test/unit/auto_instrument/controller-ast.txt +57 -0
  105. data/test/unit/auto_instrument/controller-instrumented.rb +49 -0
  106. data/test/unit/auto_instrument/controller.rb +49 -0
  107. data/test/unit/auto_instrument/rescue_from-instrumented.rb +13 -0
  108. data/test/unit/auto_instrument/rescue_from.rb +13 -0
  109. data/test/unit/auto_instrument_test.rb +54 -0
  110. data/test/unit/error_service/error_buffer_test.rb +25 -0
  111. data/test/unit/error_service/ignored_exceptions_test.rb +49 -0
  112. data/test/unit/instruments/active_record_test.rb +40 -0
  113. data/test/unit/layer_children_set_test.rb +9 -0
  114. data/test/unit/request_histograms_test.rb +17 -0
  115. data/test/unit/serializers/payload_serializer_test.rb +39 -5
  116. data/test/unit/slow_request_policy_test.rb +41 -13
  117. data/test/unit/sql_sanitizer_test.rb +47 -0
  118. metadata +99 -19
  119. data/ext/stacks/extconf.rb +0 -38
  120. data/ext/stacks/scout_atomics.h +0 -86
  121. data/ext/stacks/stacks.c +0 -814
  122. data/lib/scout_apm/slow_job_policy.rb +0 -111
  123. data/lib/scout_apm/trace_compactor.rb +0 -312
  124. data/lib/scout_apm/utils/fake_stacks.rb +0 -88
  125. data/test/unit/instruments/active_record_instruments_test.rb +0 -5
  126. data/test/unit/slow_job_policy_test.rb +0 -6
  127. data/tester.rb +0 -53
@@ -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
@@ -0,0 +1,40 @@
1
+ require 'test_helper'
2
+ require 'sqlite3'
3
+ require 'active_record'
4
+
5
+ begin
6
+ require 'octoshark'
7
+ rescue LoadError
8
+ # Ignore
9
+ end
10
+
11
+ class ActiveRecordTest < Minitest::Test
12
+ def database_path
13
+ File.expand_path('test.sqlite3', DATA_FILE_DIR)
14
+ end
15
+
16
+ def setup
17
+ database = SQLite3::Database.new(database_path)
18
+ database.execute("DROP TABLE IF EXISTS users;")
19
+ database.execute("CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(100));")
20
+
21
+ ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => database_path)
22
+ end
23
+
24
+ class User < ActiveRecord::Base
25
+ end
26
+
27
+ def test_instrumentation
28
+ recorder = FakeRecorder.new
29
+ agent_context.recorder = recorder
30
+
31
+ instrument = ScoutApm::Instruments::ActiveRecord.new(agent_context)
32
+ instrument.install
33
+
34
+ ScoutApm::Tracer.instrument("Controller", "foo/bar") do
35
+ user = User.create
36
+ end
37
+
38
+ assert 1, recorder.requests.size
39
+ end
40
+ end
@@ -71,6 +71,15 @@ class LayerChildrenSetTest < Minitest::Test
71
71
  limited_layers.each { |ml| assert_equal 5, ml.count }
72
72
  end
73
73
 
74
+ def test_works_with_marshal
75
+ s = SET.new(5)
76
+ 10.times do
77
+ s << make_layer("LayerType", "LayerName")
78
+ end
79
+
80
+ Marshal.dump(s)
81
+ end
82
+
74
83
  #############
75
84
  # Helpers #
76
85
  #############
@@ -0,0 +1,17 @@
1
+ require 'test_helper'
2
+
3
+ require 'scout_apm/request_histograms'
4
+
5
+ class RequestHistogramsTest < Minitest::Test
6
+ def test_as_json_without_activesupport
7
+ rh = ScoutApm::RequestHistograms.new
8
+
9
+ rh.add("foo", 1)
10
+ rh.add("foo", 2)
11
+ rh.add("bar", 3)
12
+
13
+ j = rh.as_json
14
+ assert_equal 2, j.size
15
+ assert_equal ["bar", "foo"], j.keys.sort
16
+ end
17
+ end
@@ -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" => {
@@ -69,7 +69,6 @@ class PayloadSerializerTest < Minitest::Test
69
69
  "min_call_time" => 0.000613518,
70
70
  "total_call_time" => 0.033245704,
71
71
  "total_exclusive_time" => 0.033245704,
72
- "traces" => []
73
72
  },
74
73
  {
75
74
  "key" => {
@@ -84,7 +83,6 @@ class PayloadSerializerTest < Minitest::Test
84
83
  "min_call_time" => 0.034881757,
85
84
  "total_call_time" => 0.113403176,
86
85
  "total_exclusive_time" => 0.078132088,
87
- "traces" => []
88
86
  }
89
87
  ]
90
88
  assert_equal formatted_metrics,
@@ -96,7 +94,7 @@ class PayloadSerializerTest < Minitest::Test
96
94
  :quotie => "here are some \"quotes\"",
97
95
  :payload_version => 2,
98
96
  }
99
- payload = ScoutApm::Serializers::PayloadSerializerToJson.serialize(metadata, {}, {}, [], [], [], {})
97
+ payload = ScoutApm::Serializers::PayloadSerializerToJson.serialize(metadata, {}, {}, [], [], [], {}, [])
100
98
 
101
99
  # symbol keys turn to strings
102
100
  formatted_metadata = {
@@ -110,4 +108,40 @@ class PayloadSerializerTest < Minitest::Test
110
108
  json = { "foo" => "\bbar\nbaz\r" }
111
109
  assert_equal json, JSON.parse(ScoutApm::Serializers::PayloadSerializerToJson.jsonify_hash(json))
112
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
113
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
@@ -28,7 +28,23 @@ module ScoutApm
28
28
  sql = %q|SELECT "users".* FROM "users" INNER JOIN "blogs" ON "blogs"."user_id" = "users"."id" WHERE (blogs.title = 'hello world')|
29
29
  ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :postgres }
30
30
  assert_equal %q|SELECT "users".* FROM "users" INNER JOIN "blogs" ON "blogs"."user_id" = "users"."id" WHERE (blogs.title = ?)|, ss.to_s
31
+ end
32
+
33
+ def test_postgres_strips_after_where
34
+ 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|
35
+ sanitized_sql = SqlSanitizer.new(raw_sql).tap { |it| it.database_engine = :postgres}
36
+ 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|
37
+ assert_equal expected_sql, sanitized_sql.to_s
38
+ end
39
+
40
+ def test_postgres_strips_subquery_strings
41
+ 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')"|
42
+ sanitized_sql = SqlSanitizer.new(raw_sql).tap { |it| it.database_engine = :postgres}
43
+ 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 ?)"|
44
+ assert_equal expected_sql, sanitized_sql.to_s
45
+ end
31
46
 
47
+ def test_postgres_strips_integers
32
48
  # Strip integers
33
49
  sql = %q|SELECT "blogs".* FROM "blogs" WHERE (view_count > 10)|
34
50
  ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :postgres }
@@ -89,6 +105,30 @@ module ScoutApm
89
105
  assert_equal %q|INSERT INTO `users` VALUES (?, ?)|, ss.to_s
90
106
  end
91
107
 
108
+ def test_sqlserver_integers
109
+ skip "SQLServer Support requires Ruby 1.9+ For Regexes"
110
+
111
+ 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"
112
+ ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :sqlserver }
113
+ assert_equal %q|SELECT [users].* FROM [users] WHERE (age > ?) ORDER BY [users].[id] ASC OFFSET ? ROWS FETCH NEXT @0 ROWS ONLY|, ss.to_s
114
+ end
115
+
116
+ def test_sqlserver_strings
117
+ skip "SQLServer Support requires Ruby 1.9+ For Regexes"
118
+
119
+ sql = "EXEC sp_executesql N'SELECT [users].* FROM [users] WHERE [users].[email] = @0 ORDER BY [users].[id] ASC OFFSET 0 ROWS FETCH NEXT @1 ROWS ONLY', N'@0 nvarchar(4000), @1 int', @0 = N'foo', @1 = 10"
120
+ ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :sqlserver }
121
+ assert_equal %q|SELECT [users].* FROM [users] WHERE [users].[email] = @0 ORDER BY [users].[id] ASC OFFSET ? ROWS FETCH NEXT @1 ROWS ONLY|, ss.to_s
122
+ end
123
+
124
+ def test_sqlserver_in_clause
125
+ skip "SQLServer Support requires Ruby 1.9+ For Regexes"
126
+
127
+ 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"
128
+ ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :sqlserver }
129
+ assert_equal %q|SELECT [users].* FROM [users] WHERE (id IN (?)) ORDER BY [users].[id] ASC OFFSET ? ROWS FETCH NEXT @0 ROWS ONLY|, ss.to_s
130
+ end
131
+
92
132
  def test_scrubs_invalid_encoding
93
133
  skip "Ruby 1.8.7 has no concept of encoding" if RUBY_VERSION.start_with?("1.8.")
94
134
 
@@ -99,6 +139,13 @@ module ScoutApm
99
139
  assert_equal %q|SELECT `blogs`.* FROM `blogs` WHERE (title = ?)|, ss.to_s
100
140
  end
101
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
+
102
149
  def assert_faster_than(target_seconds)
103
150
  t1 = ::Time.now
104
151
  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: 3.0.0.pre28
4
+ version: 4.0.0
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: 2018-08-29 00:00:00.000000000 Z
12
+ date: 2020-11-25 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
@@ -171,7 +213,6 @@ email:
171
213
  executables: []
172
214
  extensions:
173
215
  - ext/allocations/extconf.rb
174
- - ext/stacks/extconf.rb
175
216
  - ext/rusage/extconf.rb
176
217
  extra_rdoc_files: []
177
218
  files:
@@ -190,9 +231,12 @@ files:
190
231
  - ext/rusage/README.md
191
232
  - ext/rusage/extconf.rb
192
233
  - ext/rusage/rusage.c
193
- - ext/stacks/extconf.rb
194
- - ext/stacks/scout_atomics.h
195
- - ext/stacks/stacks.c
234
+ - gems/README.md
235
+ - gems/octoshark.gemfile
236
+ - gems/rails3.gemfile
237
+ - gems/rails4.gemfile
238
+ - gems/rails5.gemfile
239
+ - gems/rails6.gemfile
196
240
  - lib/scout_apm.rb
197
241
  - lib/scout_apm/agent.rb
198
242
  - lib/scout_apm/agent/exit_handler.rb
@@ -200,9 +244,18 @@ files:
200
244
  - lib/scout_apm/agent_context.rb
201
245
  - lib/scout_apm/app_server_load.rb
202
246
  - lib/scout_apm/attribute_arranger.rb
247
+ - lib/scout_apm/auto_instrument.rb
248
+ - lib/scout_apm/auto_instrument/instruction_sequence.rb
249
+ - lib/scout_apm/auto_instrument/layer.rb
250
+ - lib/scout_apm/auto_instrument/parser.rb
251
+ - lib/scout_apm/auto_instrument/rails.rb
203
252
  - lib/scout_apm/background_job_integrations/delayed_job.rb
253
+ - lib/scout_apm/background_job_integrations/legacy_sneakers.rb
254
+ - lib/scout_apm/background_job_integrations/que.rb
204
255
  - lib/scout_apm/background_job_integrations/resque.rb
256
+ - lib/scout_apm/background_job_integrations/shoryuken.rb
205
257
  - lib/scout_apm/background_job_integrations/sidekiq.rb
258
+ - lib/scout_apm/background_job_integrations/sneakers.rb
206
259
  - lib/scout_apm/background_recorder.rb
207
260
  - lib/scout_apm/background_worker.rb
208
261
  - lib/scout_apm/bucket_name_splitter.rb
@@ -212,7 +265,19 @@ files:
212
265
  - lib/scout_apm/db_query_metric_set.rb
213
266
  - lib/scout_apm/db_query_metric_stats.rb
214
267
  - lib/scout_apm/debug.rb
268
+ - lib/scout_apm/detailed_trace.rb
215
269
  - lib/scout_apm/environment.rb
270
+ - lib/scout_apm/error.rb
271
+ - lib/scout_apm/error_service.rb
272
+ - lib/scout_apm/error_service/error_buffer.rb
273
+ - lib/scout_apm/error_service/error_record.rb
274
+ - lib/scout_apm/error_service/ignored_exceptions.rb
275
+ - lib/scout_apm/error_service/middleware.rb
276
+ - lib/scout_apm/error_service/notifier.rb
277
+ - lib/scout_apm/error_service/payload.rb
278
+ - lib/scout_apm/error_service/periodic_work.rb
279
+ - lib/scout_apm/error_service/railtie.rb
280
+ - lib/scout_apm/error_service/sidekiq.rb
216
281
  - lib/scout_apm/extensions/config.rb
217
282
  - lib/scout_apm/extensions/transaction_callback_payload.rb
218
283
  - lib/scout_apm/fake_store.rb
@@ -227,15 +292,16 @@ files:
227
292
  - lib/scout_apm/instant/middleware.rb
228
293
  - lib/scout_apm/instant_reporting.rb
229
294
  - lib/scout_apm/instrument_manager.rb
230
- - lib/scout_apm/instruments/.DS_Store
231
295
  - lib/scout_apm/instruments/action_controller_rails_2.rb
232
296
  - lib/scout_apm/instruments/action_controller_rails_3_rails4.rb
233
297
  - lib/scout_apm/instruments/action_view.rb
234
298
  - lib/scout_apm/instruments/active_record.rb
235
299
  - lib/scout_apm/instruments/elasticsearch.rb
236
300
  - lib/scout_apm/instruments/grape.rb
301
+ - lib/scout_apm/instruments/http.rb
237
302
  - lib/scout_apm/instruments/http_client.rb
238
303
  - lib/scout_apm/instruments/influxdb.rb
304
+ - lib/scout_apm/instruments/memcached.rb
239
305
  - lib/scout_apm/instruments/middleware_detailed.rb
240
306
  - lib/scout_apm/instruments/middleware_summary.rb
241
307
  - lib/scout_apm/instruments/mongoid.rb
@@ -266,6 +332,7 @@ files:
266
332
  - lib/scout_apm/layer_converters/request_queue_time_converter.rb
267
333
  - lib/scout_apm/layer_converters/slow_job_converter.rb
268
334
  - lib/scout_apm/layer_converters/slow_request_converter.rb
335
+ - lib/scout_apm/layer_converters/trace_converter.rb
269
336
  - lib/scout_apm/limited_layer.rb
270
337
  - lib/scout_apm/logger.rb
271
338
  - lib/scout_apm/metric_meta.rb
@@ -302,8 +369,12 @@ files:
302
369
  - lib/scout_apm/server_integrations/thin.rb
303
370
  - lib/scout_apm/server_integrations/unicorn.rb
304
371
  - lib/scout_apm/server_integrations/webrick.rb
305
- - lib/scout_apm/slow_job_policy.rb
306
372
  - lib/scout_apm/slow_job_record.rb
373
+ - lib/scout_apm/slow_policy/age_policy.rb
374
+ - lib/scout_apm/slow_policy/percent_policy.rb
375
+ - lib/scout_apm/slow_policy/percentile_policy.rb
376
+ - lib/scout_apm/slow_policy/policy.rb
377
+ - lib/scout_apm/slow_policy/speed_policy.rb
307
378
  - lib/scout_apm/slow_request_policy.rb
308
379
  - lib/scout_apm/slow_transaction.rb
309
380
  - lib/scout_apm/stack_item.rb
@@ -311,17 +382,16 @@ files:
311
382
  - lib/scout_apm/synchronous_recorder.rb
312
383
  - lib/scout_apm/tasks/doctor.rb
313
384
  - lib/scout_apm/tasks/support.rb
314
- - lib/scout_apm/trace_compactor.rb
315
385
  - lib/scout_apm/tracer.rb
316
386
  - lib/scout_apm/tracked_request.rb
317
387
  - lib/scout_apm/transaction.rb
318
388
  - lib/scout_apm/transaction_time_consumed.rb
319
389
  - lib/scout_apm/utils/active_record_metric_name.rb
320
390
  - lib/scout_apm/utils/backtrace_parser.rb
321
- - lib/scout_apm/utils/fake_stacks.rb
322
391
  - lib/scout_apm/utils/gzip_helper.rb
323
392
  - lib/scout_apm/utils/installed_gems.rb
324
393
  - lib/scout_apm/utils/klass_helper.rb
394
+ - lib/scout_apm/utils/marshal_logging.rb
325
395
  - lib/scout_apm/utils/numbers.rb
326
396
  - lib/scout_apm/utils/scm.rb
327
397
  - lib/scout_apm/utils/sql_sanitizer.rb
@@ -334,20 +404,32 @@ files:
334
404
  - scout_apm.gemspec
335
405
  - test/data/config_test_1.yml
336
406
  - test/test_helper.rb
407
+ - test/tmp/README.md
408
+ - test/unit/agent_context_test.rb
337
409
  - test/unit/agent_test.rb
410
+ - test/unit/auto_instrument/assignments-instrumented.rb
411
+ - test/unit/auto_instrument/assignments.rb
412
+ - test/unit/auto_instrument/controller-ast.txt
413
+ - test/unit/auto_instrument/controller-instrumented.rb
414
+ - test/unit/auto_instrument/controller.rb
415
+ - test/unit/auto_instrument/rescue_from-instrumented.rb
416
+ - test/unit/auto_instrument/rescue_from.rb
417
+ - test/unit/auto_instrument_test.rb
338
418
  - test/unit/background_job_integrations/sidekiq_test.rb
339
419
  - test/unit/config_test.rb
340
420
  - test/unit/context_test.rb
341
421
  - test/unit/db_query_metric_set_test.rb
342
422
  - test/unit/db_query_metric_stats_test.rb
343
423
  - test/unit/environment_test.rb
424
+ - test/unit/error_service/error_buffer_test.rb
425
+ - test/unit/error_service/ignored_exceptions_test.rb
344
426
  - test/unit/extensions/periodic_callbacks_test.rb
345
427
  - test/unit/extensions/transaction_callbacks_test.rb
346
428
  - test/unit/fake_store_test.rb
347
429
  - test/unit/git_revision_test.rb
348
430
  - test/unit/histogram_test.rb
349
431
  - test/unit/ignored_uris_test.rb
350
- - test/unit/instruments/active_record_instruments_test.rb
432
+ - test/unit/instruments/active_record_test.rb
351
433
  - test/unit/instruments/net_http_test.rb
352
434
  - test/unit/instruments/percentile_sampler_test.rb
353
435
  - test/unit/layaway_test.rb
@@ -361,9 +443,9 @@ files:
361
443
  - test/unit/remote/test_message.rb
362
444
  - test/unit/remote/test_router.rb
363
445
  - test/unit/remote/test_server.rb
446
+ - test/unit/request_histograms_test.rb
364
447
  - test/unit/scored_item_set_test.rb
365
448
  - test/unit/serializers/payload_serializer_test.rb
366
- - test/unit/slow_job_policy_test.rb
367
449
  - test/unit/slow_request_policy_test.rb
368
450
  - test/unit/sql_sanitizer_test.rb
369
451
  - test/unit/store_test.rb
@@ -375,7 +457,6 @@ files:
375
457
  - test/unit/utils/backtrace_parser_test.rb
376
458
  - test/unit/utils/numbers_test.rb
377
459
  - test/unit/utils/scm.rb
378
- - tester.rb
379
460
  homepage: https://github.com/scoutapp/scout_apm_ruby
380
461
  licenses:
381
462
  - Proprietary (See LICENSE.md)
@@ -387,17 +468,16 @@ require_paths:
387
468
  - data
388
469
  required_ruby_version: !ruby/object:Gem::Requirement
389
470
  requirements:
390
- - - ">="
471
+ - - "~>"
391
472
  - !ruby/object:Gem::Version
392
- version: '0'
473
+ version: '2.1'
393
474
  required_rubygems_version: !ruby/object:Gem::Requirement
394
475
  requirements:
395
- - - ">"
476
+ - - ">="
396
477
  - !ruby/object:Gem::Version
397
- version: 1.3.1
478
+ version: '0'
398
479
  requirements: []
399
- rubyforge_project: scout_apm
400
- rubygems_version: 2.4.5.5
480
+ rubygems_version: 3.0.3
401
481
  signing_key:
402
482
  specification_version: 4
403
483
  summary: Ruby application performance monitoring