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
@@ -50,7 +50,7 @@ module ScoutApm
50
50
  @installed
51
51
  end
52
52
 
53
- def install
53
+ def install(prepend:)
54
54
  if install_via_after_initialize?
55
55
  Rails.configuration.after_initialize do
56
56
  add_instruments
@@ -82,10 +82,8 @@ module ScoutApm
82
82
 
83
83
  # Install #log tracing
84
84
  if Utils::KlassHelper.defined?("ActiveRecord::ConnectionAdapters::AbstractAdapter")
85
- ::ActiveRecord::ConnectionAdapters::AbstractAdapter.module_eval do
86
- include ::ScoutApm::Instruments::ActiveRecordInstruments
87
- include ::ScoutApm::Tracer
88
- end
85
+ ::ActiveRecord::ConnectionAdapters::AbstractAdapter.prepend(ActiveRecordInstruments)
86
+ ::ActiveRecord::ConnectionAdapters::AbstractAdapter.include(Tracer)
89
87
  end
90
88
 
91
89
  if Utils::KlassHelper.defined?("ActiveRecord::Base")
@@ -168,17 +166,64 @@ module ScoutApm
168
166
  #
169
167
  ################################################################################
170
168
  module ActiveRecordInstruments
171
- def self.included(instrumented_class)
169
+ def self.prepended(instrumented_class)
172
170
  ScoutApm::Agent.instance.context.logger.info "Instrumenting #{instrumented_class.inspect}"
173
- instrumented_class.class_eval do
174
- unless instrumented_class.method_defined?(:log_without_scout_instruments)
175
- alias_method :log_without_scout_instruments, :log
176
- alias_method :log, :log_with_scout_instruments
171
+ end
172
+
173
+ def log(*args, &block)
174
+ # Extract data from the arguments
175
+ sql, name = args
176
+ metric_name = Utils::ActiveRecordMetricName.new(sql, name)
177
+ desc = SqlList.new(sql)
178
+
179
+ # Get current ScoutApm context
180
+ req = ScoutApm::RequestManager.lookup
181
+ current_layer = req.current_layer
182
+
183
+ # If we call #log, we have a real query to run, and we've already
184
+ # gotten through the cache gatekeeper. Since we want to only trace real
185
+ # queries, and not repeated identical queries that just hit cache, we
186
+ # mark layer as ignorable initially in #find_by_sql, then only when we
187
+ # know it's a real database call do we mark it back as usable.
188
+ #
189
+ # This flag is later used in SlowRequestConverter to skip adding ignorable layers
190
+ current_layer.annotate_layer(:ignorable => false) if current_layer
191
+
192
+ # Either: update the current layer and yield, don't start a new one.
193
+ if current_layer && current_layer.type == "ActiveRecord"
194
+ # TODO: Get rid of call .to_s, need to find this without forcing a previous run of the name logic
195
+ if current_layer.name.to_s == Utils::ActiveRecordMetricName::DEFAULT_METRIC
196
+ current_layer.name = metric_name
197
+ end
198
+
199
+ if current_layer.desc.nil?
200
+ current_layer.desc = SqlList.new
201
+ end
202
+ current_layer.desc.merge(desc)
203
+
204
+ super(*args, &block)
205
+
206
+ # OR: Start a new layer, we didn't pick up instrumentation earlier in the stack.
207
+ else
208
+ layer = ScoutApm::Layer.new("ActiveRecord", metric_name)
209
+ layer.desc = desc
210
+ req.start_layer(layer)
211
+ begin
212
+ super(*args, &block)
213
+ ensure
214
+ req.stop_layer
177
215
  end
178
216
  end
179
217
  end
218
+ ruby2_keywords :log if respond_to?(:ruby2_keywords, true)
219
+ end
180
220
 
181
- def log_with_scout_instruments(*args, &block)
221
+ module ActiveRecordInstruments
222
+ def self.prepended(instrumented_class)
223
+ ScoutApm::Agent.instance.context.logger.info "Instrumenting #{instrumented_class.inspect}"
224
+ end
225
+
226
+ def log(*args, &block)
182
227
  # Extract data from the arguments
183
228
  sql, name = args
184
229
  metric_name = Utils::ActiveRecordMetricName.new(sql, name)
@@ -209,7 +254,7 @@ module ScoutApm
209
254
  end
210
255
  current_layer.desc.merge(desc)
211
256
 
212
- log_without_scout_instruments(*args, &block)
257
+ super(*args, &block)
213
258
 
214
259
  # OR: Start a new layer, we didn't pick up instrumentation earlier in the stack.
215
260
  else
@@ -217,12 +262,13 @@ module ScoutApm
217
262
  layer.desc = desc
218
263
  req.start_layer(layer)
219
264
  begin
220
- log_without_scout_instruments(*args, &block)
265
+ super(*args, &block)
221
266
  ensure
222
267
  req.stop_layer
223
268
  end
224
269
  end
225
270
  end
271
+ ruby2_keywords :log if respond_to?(:ruby2_keywords, true)
226
272
  end
227
273
 
228
274
  ################################################################################
@@ -264,14 +310,18 @@ module ScoutApm
264
310
  end
265
311
  end
266
312
 
267
- def find_by_sql_with_scout_instruments(*args, &block)
313
+ def find_by_sql_with_scout_instruments(*args, **kwargs, &block)
268
314
  req = ScoutApm::RequestManager.lookup
269
315
  layer = ScoutApm::Layer.new("ActiveRecord", Utils::ActiveRecordMetricName::DEFAULT_METRIC)
270
316
  layer.annotate_layer(:ignorable => true)
271
317
  req.start_layer(layer)
272
318
  req.ignore_children!
273
319
  begin
274
- find_by_sql_without_scout_instruments(*args, &block)
320
+ if ScoutApm::Agent.instance.context.environment.supports_kwarg_delegation?
321
+ find_by_sql_without_scout_instruments(*args, **kwargs, &block)
322
+ else
323
+ find_by_sql_without_scout_instruments(*args, &block)
324
+ end
275
325
  ensure
276
326
  req.acknowledge_children!
277
327
  req.stop_layer
@@ -349,7 +399,7 @@ module ScoutApm
349
399
  end
350
400
 
351
401
  module ActiveRecordUpdateInstruments
352
- def save(*args, &block)
402
+ def save(*args, **options, &block)
353
403
  model = self.class.name
354
404
  operation = self.persisted? ? "Update" : "Create"
355
405
 
@@ -359,14 +409,14 @@ module ScoutApm
359
409
  req.start_layer(layer)
360
410
  req.ignore_children!
361
411
  begin
362
- super(*args, &block)
412
+ super(*args, **options, &block)
363
413
  ensure
364
414
  req.acknowledge_children!
365
415
  req.stop_layer
366
416
  end
367
417
  end
368
418
 
369
- def save!(*args, &block)
419
+ def save!(*args, **options, &block)
370
420
  model = self.class.name
371
421
  operation = self.persisted? ? "Update" : "Create"
372
422
 
@@ -375,7 +425,7 @@ module ScoutApm
375
425
  req.start_layer(layer)
376
426
  req.ignore_children!
377
427
  begin
378
- super(*args, &block)
428
+ super(*args, **options, &block)
379
429
  ensure
380
430
  req.acknowledge_children!
381
431
  req.stop_layer
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: false
2
+
1
3
  module ScoutApm
2
4
  module Instruments
3
5
  class Elasticsearch
@@ -16,66 +18,115 @@ module ScoutApm
16
18
  @installed
17
19
  end
18
20
 
19
- def install
21
+ def install(prepend:)
20
22
  if defined?(::Elasticsearch) &&
21
23
  defined?(::Elasticsearch::Transport) &&
22
24
  defined?(::Elasticsearch::Transport::Client)
23
25
 
24
26
  @installed = true
25
27
 
26
- logger.info "Instrumenting Elasticsearch"
28
+ logger.info "Instrumenting Elasticsearch. Prepend: #{prepend}"
27
29
 
28
- ::Elasticsearch::Transport::Client.class_eval do
29
- include ScoutApm::Tracer
30
+ if prepend
31
+ ::Elasticsearch::Transport::Client.send(:include, ScoutApm::Tracer)
32
+ ::Elasticsearch::Transport::Client.send(:prepend, ElasticsearchTransportClientInstrumentationPrepend)
33
+ else
34
+ ::Elasticsearch::Transport::Client.class_eval do
35
+ include ScoutApm::Tracer
30
36
 
31
- def perform_request_with_scout_instruments(*args, &block)
32
- name = _sanitize_name(args[1])
37
+ def perform_request_with_scout_instruments(*args, &block)
38
+ name = _sanitize_name(args[1])
33
39
 
34
- self.class.instrument("Elasticsearch", name, :ignore_children => true) do
35
- perform_request_without_scout_instruments(*args, &block)
40
+ self.class.instrument("Elasticsearch", name, :ignore_children => true) do
41
+ perform_request_without_scout_instruments(*args, &block)
42
+ end
36
43
  end
37
- end
38
44
 
39
- alias_method :perform_request_without_scout_instruments, :perform_request
40
- alias_method :perform_request, :perform_request_with_scout_instruments
41
-
42
- def _sanitize_name(name)
43
- name = name.split("/").last.gsub(/^_/, '')
44
- allowed_names = ["bench",
45
- "bulk",
46
- "count",
47
- "exists",
48
- "explain",
49
- "field_stats",
50
- "health",
51
- "mget",
52
- "mlt",
53
- "mpercolate",
54
- "msearch",
55
- "mtermvectors",
56
- "percolate",
57
- "query",
58
- "scroll",
59
- "search_shards",
60
- "source",
61
- "suggest",
62
- "template",
63
- "termvectors",
64
- "update",
65
- "search", ]
66
-
67
- if allowed_names.include?(name)
68
- name
69
- else
45
+ alias_method :perform_request_without_scout_instruments, :perform_request
46
+ alias_method :perform_request, :perform_request_with_scout_instruments
47
+
48
+ def _sanitize_name(name)
49
+ name = name.split("/").last.gsub(/^_/, '')
50
+ allowed_names = ["bench",
51
+ "bulk",
52
+ "count",
53
+ "exists",
54
+ "explain",
55
+ "field_stats",
56
+ "health",
57
+ "mget",
58
+ "mlt",
59
+ "mpercolate",
60
+ "msearch",
61
+ "mtermvectors",
62
+ "percolate",
63
+ "query",
64
+ "scroll",
65
+ "search_shards",
66
+ "source",
67
+ "suggest",
68
+ "template",
69
+ "termvectors",
70
+ "update",
71
+ "search", ]
72
+
73
+ if allowed_names.include?(name)
74
+ name
75
+ else
76
+ "Unknown"
77
+ end
78
+ rescue
70
79
  "Unknown"
71
80
  end
72
- rescue
73
- "Unknown"
74
81
  end
75
82
  end
76
83
  end
77
84
  end
78
85
  end
86
+
87
+ module ElasticsearchTransportClientInstrumentationPrepend
88
+ def perform_request(*args, &block)
89
+ name = _sanitize_name(args[1])
90
+
91
+ self.class.instrument("Elasticsearch", name, :ignore_children => true) do
92
+ super(*args, &block)
93
+ end
94
+ end
95
+
96
+ def _sanitize_name(name)
97
+ name = name.split("/").last.gsub(/^_/, '')
98
+ allowed_names = ["bench",
99
+ "bulk",
100
+ "count",
101
+ "exists",
102
+ "explain",
103
+ "field_stats",
104
+ "health",
105
+ "mget",
106
+ "mlt",
107
+ "mpercolate",
108
+ "msearch",
109
+ "mtermvectors",
110
+ "percolate",
111
+ "query",
112
+ "scroll",
113
+ "search_shards",
114
+ "source",
115
+ "suggest",
116
+ "template",
117
+ "termvectors",
118
+ "update",
119
+ "search", ]
120
+
121
+ if allowed_names.include?(name)
122
+ name
123
+ else
124
+ "Unknown"
125
+ end
126
+ rescue
127
+ "Unknown"
128
+ end
129
+ end
79
130
  end
80
131
  end
81
132
 
@@ -16,7 +16,7 @@ module ScoutApm
16
16
  @installed
17
17
  end
18
18
 
19
- def install
19
+ def install(prepend:)
20
20
  if defined?(::Grape) && defined?(::Grape::Endpoint)
21
21
  @installed = true
22
22
 
@@ -0,0 +1,68 @@
1
+ module ScoutApm
2
+ module Instruments
3
+ class HTTP
4
+ attr_reader :context
5
+
6
+ def initialize(context)
7
+ @context = context
8
+ @installed = false
9
+ end
10
+
11
+ def logger
12
+ context.logger
13
+ end
14
+
15
+ def installed?
16
+ @installed
17
+ end
18
+
19
+ def install(prepend:)
20
+ if defined?(::HTTP) && defined?(::HTTP::Client)
21
+ @installed = true
22
+
23
+ logger.info "Instrumenting HTTP::Client. Prepend: #{prepend}"
24
+
25
+ if prepend
26
+ ::HTTP::Client.send(:include, ScoutApm::Tracer)
27
+ ::HTTP::Client.send(:prepend, HTTPInstrumentationPrepend)
28
+ else
29
+ ::HTTP::Client.class_eval do
30
+ include ScoutApm::Tracer
31
+
32
+ def request_with_scout_instruments(verb, uri, opts = {})
33
+ self.class.instrument("HTTP", verb, :ignore_children => true, :desc => request_scout_description(verb, uri)) do
34
+ request_without_scout_instruments(verb, uri, opts)
35
+ end
36
+ end
37
+
38
+ def request_scout_description(verb, uri)
39
+ max_length = ScoutApm::Agent.instance.context.config.value('instrument_http_url_length')
40
+ (String(uri).split('?').first)[0..(max_length - 1)]
41
+ rescue
42
+ ""
43
+ end
44
+
45
+ alias request_without_scout_instruments request
46
+ alias request request_with_scout_instruments
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ module HTTPInstrumentationPrepend
54
+ def request(verb, uri, opts = {})
55
+ self.class.instrument("HTTP", verb, :ignore_children => true, :desc => request_scout_description(verb, uri)) do
56
+ super(verb, uri, opts)
57
+ end
58
+ end
59
+
60
+ def request_scout_description(verb, uri)
61
+ max_length = ScoutApm::Agent.instance.context.config.value('instrument_http_url_length')
62
+ (String(uri).split('?').first)[0..(max_length - 1)]
63
+ rescue
64
+ ""
65
+ end
66
+ end
67
+ end
68
+ end
@@ -16,33 +16,52 @@ module ScoutApm
16
16
  @installed
17
17
  end
18
18
 
19
- def install
19
+ def install(prepend:)
20
20
  if defined?(::HTTPClient)
21
21
  @installed = true
22
22
 
23
- logger.info "Instrumenting HTTPClient"
23
+ logger.info "Instrumenting HTTPClient. Prepend: #{prepend}"
24
24
 
25
- ::HTTPClient.class_eval do
26
- include ScoutApm::Tracer
25
+ if prepend
26
+ ::HTTPClient.send(:include, ScoutApm::Tracer)
27
+ ::HTTPClient.send(:prepend, HttpClientInstrumentationPrepend)
28
+ else
29
+ ::HTTPClient.class_eval do
30
+ include ScoutApm::Tracer
27
31
 
28
- def request_with_scout_instruments(*args, &block)
32
+ def request_with_scout_instruments(*args, &block)
29
33
 
30
- method = args[0].to_s
31
- url = args[1]
34
+ method = args[0].to_s
35
+ url = args[1]
32
36
 
33
- max_length = ScoutApm::Agent.instance.context.config.value('instrument_http_url_length')
34
- url = url && url.to_s[0..(max_length - 1)]
37
+ max_length = ScoutApm::Agent.instance.context.config.value('instrument_http_url_length')
38
+ url = url && url.to_s[0..(max_length - 1)]
35
39
 
36
- self.class.instrument("HTTP", method, :desc => url) do
37
- request_without_scout_instruments(*args, &block)
40
+ self.class.instrument("HTTP", method, :desc => url) do
41
+ request_without_scout_instruments(*args, &block)
42
+ end
38
43
  end
39
- end
40
44
 
41
- alias request_without_scout_instruments request
42
- alias request request_with_scout_instruments
45
+ alias request_without_scout_instruments request
46
+ alias request request_with_scout_instruments
47
+ end
43
48
  end
44
49
  end
45
50
  end
46
51
  end
52
+
53
+ module HttpClientInstrumentationPrepend
54
+ def request(*args, &block)
55
+ method = args[0].to_s
56
+ url = args[1]
57
+
58
+ max_length = ScoutApm::Agent.instance.context.config.value('instrument_http_url_length')
59
+ url = url && url.to_s[0..(max_length - 1)]
60
+
61
+ self.class.instrument("HTTP", method, :desc => url) do
62
+ super(*args, &block)
63
+ end
64
+ end
65
+ end
47
66
  end
48
67
  end
@@ -16,11 +16,11 @@ module ScoutApm
16
16
  @installed
17
17
  end
18
18
 
19
- def install
19
+ def install(prepend:)
20
20
  if defined?(::InfluxDB)
21
21
  @installed = true
22
22
 
23
- logger.debug "Instrumenting InfluxDB"
23
+ logger.debug "Instrumenting InfluxDB."
24
24
 
25
25
  ::InfluxDB::Client.class_eval do
26
26
  include ScoutApm::Tracer
@@ -0,0 +1,58 @@
1
+ module ScoutApm
2
+ module Instruments
3
+ class Memcached
4
+ attr_reader :context
5
+
6
+ def initialize(context)
7
+ @context = context
8
+ @installed = false
9
+ end
10
+
11
+ def logger
12
+ context.logger
13
+ end
14
+
15
+ def installed?
16
+ @installed
17
+ end
18
+
19
+ def install(prepend:)
20
+ if defined?(::Dalli) && defined?(::Dalli::Client)
21
+ @installed = true
22
+
23
+ logger.info "Instrumenting Memcached. Prepend: #{prepend}"
24
+
25
+ if prepend
26
+ ::Dalli::Client.send(:include, ScoutApm::Tracer)
27
+ ::Dalli::Client.send(:prepend, MemcachedInstrumentationPrepend)
28
+ else
29
+ ::Dalli::Client.class_eval do
30
+ include ScoutApm::Tracer
31
+
32
+ def perform_with_scout_instruments(*args, &block)
33
+ command = args.first rescue "Unknown"
34
+
35
+ self.class.instrument("Memcached", command) do
36
+ perform_without_scout_instruments(*args, &block)
37
+ end
38
+ end
39
+
40
+ alias_method :perform_without_scout_instruments, :perform
41
+ alias_method :perform, :perform_with_scout_instruments
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ module MemcachedInstrumentationPrepend
49
+ def perform(*args, &block)
50
+ command = args.first rescue "Unknown"
51
+
52
+ self.class.instrument("Memcached", command) do
53
+ super(*args, &block)
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -24,7 +24,7 @@ module ScoutApm
24
24
  @installed
25
25
  end
26
26
 
27
- def install
27
+ def install(prepend:)
28
28
  if defined?(ActionDispatch) && defined?(ActionDispatch::MiddlewareStack) && defined?(ActionDispatch::MiddlewareStack::Middleware)
29
29
  @installed = true
30
30
 
@@ -21,7 +21,7 @@ module ScoutApm
21
21
  @installed
22
22
  end
23
23
 
24
- def install
24
+ def install(prepend:)
25
25
  if defined?(ActionDispatch) && defined?(ActionDispatch::MiddlewareStack)
26
26
  @installed = true
27
27
 
@@ -16,7 +16,7 @@ module ScoutApm
16
16
  @installed
17
17
  end
18
18
 
19
- def install
19
+ def install(prepend:)
20
20
  @installed = true
21
21
 
22
22
  # Mongoid versions that use Moped should instrument Moped.
@@ -37,8 +37,8 @@ module ScoutApm
37
37
  ### See moped instrument for Moped driven deploys
38
38
 
39
39
  ### 5.x Mongoid
40
- if (mongoid_v5? || mongoid_v6?) && defined?(::Mongoid::Contextual::Mongo)
41
- logger.info "Instrumenting Mongoid 5.x/6.x"
40
+ if (mongoid_v5? || mongoid_v6? || mongoid_v7?) && defined?(::Mongoid::Contextual::Mongo)
41
+ logger.info "Instrumenting Mongoid 5.x/6.x/7.x"
42
42
  # All the public methods from Mongoid::Contextual::Mongo.
43
43
  # TODO: Geo and MapReduce support (?). They are in other Contextual::* classes
44
44
  methods = [
@@ -54,8 +54,6 @@ module ScoutApm
54
54
  if ::Mongoid::Contextual::Mongo.method_defined?(method)
55
55
  with_scout_instruments = %Q[
56
56
  def #{method}_with_scout_instruments(*args, &block)
57
-
58
-
59
57
  req = ScoutApm::RequestManager.lookup
60
58
  *db, collection = view.collection.namespace.split(".")
61
59
 
@@ -112,6 +110,13 @@ module ScoutApm
112
110
  end
113
111
  end
114
112
 
113
+ def mongoid_v7?
114
+ if defined?(::Mongoid::VERSION)
115
+ ::Mongoid::VERSION =~ /\A7/
116
+ else
117
+ false
118
+ end
119
+ end
115
120
 
116
121
  # Example of what a filter looks like: => {"founded"=>{"$gte"=>"1980-1-1"}, "name"=>{"$in"=>["Tool", "Deftones", "Melvins"]}}
117
122
  # Approach: find every leaf-node, clear it. inspect the whole thing when done.