scout_apm 3.0.0.pre13 → 3.0.0.pre14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/scout_apm.rb +20 -10
- data/lib/scout_apm/agent.rb +114 -319
- data/lib/scout_apm/agent/exit_handler.rb +66 -0
- data/lib/scout_apm/agent/preconditions.rb +69 -0
- data/lib/scout_apm/agent_context.rb +234 -0
- data/lib/scout_apm/app_server_load.rb +24 -14
- data/lib/scout_apm/background_job_integrations/resque.rb +7 -8
- data/lib/scout_apm/background_job_integrations/sidekiq.rb +2 -2
- data/lib/scout_apm/background_recorder.rb +8 -3
- data/lib/scout_apm/background_worker.rb +14 -7
- data/lib/scout_apm/config.rb +35 -26
- data/lib/scout_apm/context.rb +11 -4
- data/lib/scout_apm/db_query_metric_set.rb +17 -5
- data/lib/scout_apm/debug.rb +1 -1
- data/lib/scout_apm/environment.rb +10 -14
- data/lib/scout_apm/framework_integrations/sinatra.rb +1 -1
- data/lib/scout_apm/git_revision.rb +13 -8
- data/lib/scout_apm/histogram.rb +1 -1
- data/lib/scout_apm/instant/middleware.rb +7 -7
- data/lib/scout_apm/instant_reporting.rb +7 -7
- data/lib/scout_apm/instrument_manager.rb +87 -0
- data/lib/scout_apm/instruments/action_controller_rails_2.rb +12 -7
- data/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb +17 -12
- data/lib/scout_apm/instruments/action_view.rb +11 -7
- data/lib/scout_apm/instruments/active_record.rb +25 -11
- data/lib/scout_apm/instruments/elasticsearch.rb +10 -6
- data/lib/scout_apm/instruments/grape.rb +12 -8
- data/lib/scout_apm/instruments/http_client.rb +10 -6
- data/lib/scout_apm/instruments/influxdb.rb +10 -6
- data/lib/scout_apm/instruments/middleware_detailed.rb +11 -5
- data/lib/scout_apm/instruments/middleware_summary.rb +11 -5
- data/lib/scout_apm/instruments/mongoid.rb +10 -5
- data/lib/scout_apm/instruments/moped.rb +11 -6
- data/lib/scout_apm/instruments/net_http.rb +10 -6
- data/lib/scout_apm/instruments/percentile_sampler.rb +8 -6
- data/lib/scout_apm/instruments/process/process_cpu.rb +8 -4
- data/lib/scout_apm/instruments/process/process_memory.rb +15 -10
- data/lib/scout_apm/instruments/rails_router.rb +12 -6
- data/lib/scout_apm/instruments/redis.rb +10 -6
- data/lib/scout_apm/instruments/samplers.rb +11 -0
- data/lib/scout_apm/instruments/sinatra.rb +5 -4
- data/lib/scout_apm/layaway.rb +21 -20
- data/lib/scout_apm/layaway_file.rb +8 -3
- data/lib/scout_apm/layer.rb +3 -3
- data/lib/scout_apm/layer_converters/converter_base.rb +6 -7
- data/lib/scout_apm/layer_converters/database_converter.rb +1 -1
- data/lib/scout_apm/layer_converters/histograms.rb +2 -2
- data/lib/scout_apm/layer_converters/slow_job_converter.rb +4 -3
- data/lib/scout_apm/layer_converters/slow_request_converter.rb +5 -4
- data/lib/scout_apm/logger.rb +143 -0
- data/lib/scout_apm/middleware.rb +7 -9
- data/lib/scout_apm/periodic_work.rb +28 -0
- data/lib/scout_apm/reporter.rb +14 -8
- data/lib/scout_apm/reporting.rb +135 -0
- data/lib/scout_apm/request_manager.rb +4 -6
- data/lib/scout_apm/serializers/payload_serializer.rb +1 -1
- data/lib/scout_apm/slow_job_policy.rb +6 -2
- data/lib/scout_apm/slow_job_record.rb +5 -5
- data/lib/scout_apm/slow_request_policy.rb +6 -2
- data/lib/scout_apm/slow_transaction.rb +5 -5
- data/lib/scout_apm/store.rb +22 -16
- data/lib/scout_apm/synchronous_recorder.rb +7 -3
- data/lib/scout_apm/tasks/doctor.rb +75 -0
- data/lib/scout_apm/tasks/support.rb +22 -0
- data/lib/scout_apm/tracer.rb +5 -5
- data/lib/scout_apm/tracked_request.rb +43 -19
- data/lib/scout_apm/utils/active_record_metric_name.rb +66 -8
- data/lib/scout_apm/utils/backtrace_parser.rb +1 -1
- data/lib/scout_apm/utils/installed_gems.rb +7 -3
- data/lib/scout_apm/utils/klass_helper.rb +8 -2
- data/lib/scout_apm/utils/scm.rb +1 -1
- data/lib/scout_apm/utils/sql_sanitizer.rb +3 -3
- data/lib/scout_apm/version.rb +1 -1
- data/lib/tasks/doctor.rake +11 -0
- data/scout_apm.gemspec +1 -0
- data/test/test_helper.rb +17 -2
- data/test/unit/agent_test.rb +1 -54
- data/test/unit/config_test.rb +9 -5
- data/test/unit/context_test.rb +4 -4
- data/test/unit/db_query_metric_set_test.rb +11 -4
- data/test/unit/fake_store_test.rb +1 -1
- data/test/unit/git_revision_test.rb +3 -3
- data/test/unit/instruments/net_http_test.rb +2 -1
- data/test/unit/instruments/percentile_sampler_test.rb +5 -9
- data/test/unit/layaway_test.rb +10 -5
- data/test/unit/layer_converters/metric_converter_test.rb +2 -2
- data/test/unit/slow_request_policy_test.rb +7 -3
- data/test/unit/sql_sanitizer_test.rb +0 -6
- data/test/unit/store_test.rb +11 -8
- data/test/unit/utils/active_record_metric_name_test.rb +45 -7
- metadata +27 -5
- data/lib/scout_apm/agent/logging.rb +0 -74
- data/lib/scout_apm/agent/reporting.rb +0 -129
- data/lib/scout_apm/utils/null_logger.rb +0 -13
@@ -4,10 +4,14 @@
|
|
4
4
|
|
5
5
|
module ScoutApm
|
6
6
|
class SynchronousRecorder
|
7
|
-
attr_reader :
|
7
|
+
attr_reader :context
|
8
8
|
|
9
|
-
def initialize(
|
10
|
-
@
|
9
|
+
def initialize(context)
|
10
|
+
@context = context
|
11
|
+
end
|
12
|
+
|
13
|
+
def logger
|
14
|
+
context.logger
|
11
15
|
end
|
12
16
|
|
13
17
|
def start
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module ScoutApm
|
2
|
+
module Tasks
|
3
|
+
class Doctor
|
4
|
+
def self.run!
|
5
|
+
new.run!
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize()
|
9
|
+
end
|
10
|
+
|
11
|
+
def run!
|
12
|
+
puts "Scout Doctor"
|
13
|
+
puts "============"
|
14
|
+
puts
|
15
|
+
puts "Detected App Server: #{agent_context.environment.app_server_integration.name}"
|
16
|
+
# puts "Detected Background Job: #{agent_context.environment.background_job_integration.name}"
|
17
|
+
puts
|
18
|
+
puts "Instruments:"
|
19
|
+
puts "----------------------------------------"
|
20
|
+
puts installed_instruments
|
21
|
+
puts
|
22
|
+
puts
|
23
|
+
puts "Configuration Settings:"
|
24
|
+
puts "-------------|------------------------------|-------"
|
25
|
+
puts " From | Key | Value "
|
26
|
+
puts "-------------|------------------------------|-------"
|
27
|
+
puts configuration_settings
|
28
|
+
puts
|
29
|
+
puts
|
30
|
+
puts "Misc:"
|
31
|
+
puts "---------------"
|
32
|
+
puts "Layaway Files stored at: #{agent_context.layaway.directory}"
|
33
|
+
puts "Logs stored at: #{log_details}"
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
def agent_context
|
38
|
+
ScoutApm::Agent.instance.context
|
39
|
+
end
|
40
|
+
|
41
|
+
def installed_instruments
|
42
|
+
ScoutApm::Agent.
|
43
|
+
instance.
|
44
|
+
instrument_manager.
|
45
|
+
installed_instruments.
|
46
|
+
map{|instance| "#{instance.installed? ? "Installed " : "Not Installed"} - #{instance.class.to_s}"}.
|
47
|
+
join("\n")
|
48
|
+
end
|
49
|
+
|
50
|
+
def configuration_settings
|
51
|
+
all_settings = agent_context.config.all_settings
|
52
|
+
|
53
|
+
longest_key = all_settings.
|
54
|
+
map{|setting| setting[:key] }.
|
55
|
+
inject(0) { |len, key| key.length > len ? key.length : len }
|
56
|
+
|
57
|
+
format_string = "%12s | %-#{longest_key}s | %s"
|
58
|
+
|
59
|
+
all_settings.
|
60
|
+
map{|setting| sprintf format_string, setting[:source], setting[:key], setting[:value]}.
|
61
|
+
join("\n")
|
62
|
+
end
|
63
|
+
|
64
|
+
def log_details
|
65
|
+
if agent_context.logger.log_destination == STDOUT
|
66
|
+
"STDOUT"
|
67
|
+
elsif agent_context.logger.log_destination == STDERR
|
68
|
+
"STDERR"
|
69
|
+
else
|
70
|
+
"#{agent_context.logger.log_file_path}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module ScoutApm
|
2
|
+
module Tasks
|
3
|
+
class Support
|
4
|
+
def self.run!
|
5
|
+
puts "Support Task"
|
6
|
+
new.run!
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@doctor = ScoutApm::Tasks::Doctor.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def run!
|
14
|
+
instruments = @doctor.installed_instruments
|
15
|
+
config = @doctor.configuration_settings
|
16
|
+
collect_logs
|
17
|
+
|
18
|
+
post_data
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/scout_apm/tracer.rb
CHANGED
@@ -45,13 +45,13 @@ module ScoutApm
|
|
45
45
|
# type - "View" or "ActiveRecord" and similar
|
46
46
|
# name - "users/show", "App#find"
|
47
47
|
def instrument_method(method_name, options = {})
|
48
|
-
ScoutApm::Agent.instance.logger.info "Instrumenting #{method_name}"
|
48
|
+
ScoutApm::Agent.instance.context.logger.info "Instrumenting #{method_name}"
|
49
49
|
type = options[:type] || "Custom"
|
50
50
|
name = options[:name] || "#{self.name}/#{method_name.to_s}"
|
51
51
|
|
52
52
|
instrumented_name, uninstrumented_name = _determine_instrumented_name(method_name, type)
|
53
53
|
|
54
|
-
ScoutApm::Agent.instance.logger.info "Instrumenting #{instrumented_name}, #{uninstrumented_name}"
|
54
|
+
ScoutApm::Agent.instance.context.logger.info "Instrumenting #{instrumented_name}, #{uninstrumented_name}"
|
55
55
|
|
56
56
|
return if !_instrumentable?(method_name) or _instrumented?(instrumented_name, method_name)
|
57
57
|
|
@@ -91,7 +91,7 @@ module ScoutApm
|
|
91
91
|
name = begin
|
92
92
|
"#{name}"
|
93
93
|
rescue => e
|
94
|
-
ScoutApm::Agent.instance.logger.error("Error raised while interpreting instrumented name: %s, %s" % ['#{name}', e.message])
|
94
|
+
ScoutApm::Agent.instance.context.logger.error("Error raised while interpreting instrumented name: %s, %s" % ['#{name}', e.message])
|
95
95
|
"Unknown"
|
96
96
|
end
|
97
97
|
|
@@ -110,14 +110,14 @@ module ScoutApm
|
|
110
110
|
# The method must exist to be instrumented.
|
111
111
|
def _instrumentable?(method_name)
|
112
112
|
exists = method_defined?(method_name) || private_method_defined?(method_name)
|
113
|
-
ScoutApm::Agent.instance.logger.warn "The method [#{self.name}##{method_name}] does not exist and will not be instrumented" unless exists
|
113
|
+
ScoutApm::Agent.instance.context.logger.warn "The method [#{self.name}##{method_name}] does not exist and will not be instrumented" unless exists
|
114
114
|
exists
|
115
115
|
end
|
116
116
|
|
117
117
|
# +True+ if the method is already instrumented.
|
118
118
|
def _instrumented?(instrumented_name, method_name)
|
119
119
|
instrumented = method_defined?(instrumented_name)
|
120
|
-
ScoutApm::Agent.instance.logger.warn("The method [#{self.name}##{method_name}] has already been instrumented") if instrumented
|
120
|
+
ScoutApm::Agent.instance.context.logger.warn("The method [#{self.name}##{method_name}] has already been instrumented") if instrumented
|
121
121
|
instrumented
|
122
122
|
end
|
123
123
|
|
@@ -39,26 +39,23 @@ module ScoutApm
|
|
39
39
|
# this is set in the controller instumentation (ActionControllerRails3Rails4 according)
|
40
40
|
attr_accessor :instant_key
|
41
41
|
|
42
|
-
# Whereas the instant_key gets set per-request in reponse to a URL param, dev_trace is set in the config file
|
43
|
-
attr_accessor :dev_trace
|
44
|
-
|
45
42
|
# An object that responds to `record!(TrackedRequest)` to store this tracked request
|
46
43
|
attr_reader :recorder
|
47
44
|
|
48
|
-
def initialize(store)
|
45
|
+
def initialize(agent_context, store)
|
46
|
+
@agent_context = agent_context
|
49
47
|
@store = store #this is passed in so we can use a real store (normal operation) or fake store (instant mode only)
|
50
48
|
@layers = []
|
51
49
|
@call_set = Hash.new { |h, k| h[k] = CallSet.new }
|
52
50
|
@annotations = {}
|
53
51
|
@ignoring_children = 0
|
54
|
-
@context = Context.new
|
52
|
+
@context = Context.new(agent_context)
|
55
53
|
@root_layer = nil
|
56
54
|
@error = false
|
57
55
|
@stopping = false
|
58
56
|
@instant_key = nil
|
59
57
|
@mem_start = mem_usage
|
60
|
-
@
|
61
|
-
@recorder = ScoutApm::Agent.instance.recorder
|
58
|
+
@recorder = agent_context.recorder
|
62
59
|
|
63
60
|
ignore_request! if @recorder.nil?
|
64
61
|
end
|
@@ -113,7 +110,7 @@ module ScoutApm
|
|
113
110
|
if finalized?
|
114
111
|
stop_request
|
115
112
|
else
|
116
|
-
continue_sampling_for_layers if
|
113
|
+
continue_sampling_for_layers if @agent_context.config.value('profile')
|
117
114
|
end
|
118
115
|
end
|
119
116
|
|
@@ -157,9 +154,15 @@ module ScoutApm
|
|
157
154
|
@call_set[layer.name].update!(layer.desc)
|
158
155
|
end
|
159
156
|
|
157
|
+
# Grab backtraces more aggressively when running in dev trace mode
|
158
|
+
def backtrace_threshold
|
159
|
+
@agent_context.dev_trace_enabled? ? 0.05 : 0.5 # the minimum threshold in seconds to record the backtrace for a metric.
|
160
|
+
end
|
161
|
+
|
160
162
|
# This may be in bytes or KB based on the OSX. We store this as-is here and only do conversion to MB in Layer Converters.
|
163
|
+
# XXX: Move this to environment?
|
161
164
|
def mem_usage
|
162
|
-
ScoutApm::Instruments::Process::ProcessMemory.rss
|
165
|
+
ScoutApm::Instruments::Process::ProcessMemory.new(@agent_context).rss
|
163
166
|
end
|
164
167
|
|
165
168
|
def capture_mem_delta!
|
@@ -196,7 +199,7 @@ module ScoutApm
|
|
196
199
|
def stop_request
|
197
200
|
@stopping = true
|
198
201
|
|
199
|
-
if
|
202
|
+
if @agent_context.config.value('profile')
|
200
203
|
ScoutApm::Instruments::Stacks.stop_sampling(true)
|
201
204
|
ScoutApm::Instruments::Stacks.update_indexes(0, 0)
|
202
205
|
end
|
@@ -288,7 +291,7 @@ module ScoutApm
|
|
288
291
|
restore_store if @store.nil?
|
289
292
|
|
290
293
|
# Bail out early if the user asked us to ignore this uri
|
291
|
-
return if
|
294
|
+
return if @agent_context.ignored_uris.ignore?(annotations[:uri])
|
292
295
|
|
293
296
|
converters = [
|
294
297
|
LayerConverters::Histograms,
|
@@ -306,7 +309,7 @@ module ScoutApm
|
|
306
309
|
layer_finder = LayerConverters::FindLayerByType.new(self)
|
307
310
|
walker = LayerConverters::DepthFirstWalker.new(self.root_layer)
|
308
311
|
converters = converters.map do |klass|
|
309
|
-
instance = klass.new(self, layer_finder, @store)
|
312
|
+
instance = klass.new(@agent_context, self, layer_finder, @store)
|
310
313
|
instance.register_hooks(walker)
|
311
314
|
instance
|
312
315
|
end
|
@@ -319,8 +322,26 @@ module ScoutApm
|
|
319
322
|
trace = converter.call
|
320
323
|
ScoutApm::InstantReporting.new(trace, instant_key).call
|
321
324
|
end
|
325
|
+
|
326
|
+
if web? || job?
|
327
|
+
ensure_background_worker
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
# Ensure the background worker thread is up & running - a fallback if other
|
332
|
+
# detection doesn't achieve this at boot.
|
333
|
+
def ensure_background_worker
|
334
|
+
agent = ScoutApm::Agent.instance
|
335
|
+
agent.start
|
336
|
+
|
337
|
+
if agent.start_background_worker(:quiet)
|
338
|
+
agent.logger.info("Force Started BG Worker")
|
339
|
+
end
|
340
|
+
rescue => e
|
341
|
+
true
|
322
342
|
end
|
323
343
|
|
344
|
+
|
324
345
|
# Only call this after the request is complete
|
325
346
|
def unique_name
|
326
347
|
return nil if ignoring_request?
|
@@ -385,11 +406,6 @@ module ScoutApm
|
|
385
406
|
@ignoring_children > 0
|
386
407
|
end
|
387
408
|
|
388
|
-
# Grab backtraces more aggressively when running in dev trace mode
|
389
|
-
def backtrace_threshold
|
390
|
-
dev_trace ? 0.05 : 0.5 # the minimum threshold in seconds to record the backtrace for a metric.
|
391
|
-
end
|
392
|
-
|
393
409
|
################################################################################
|
394
410
|
# Ignoring the rest of a request
|
395
411
|
################################################################################
|
@@ -399,6 +415,10 @@ module ScoutApm
|
|
399
415
|
# layers, and delete any existing layer info. This class will still exist,
|
400
416
|
# and respond to methods as normal, but `record!` won't be called, and no
|
401
417
|
# data will be recorded.
|
418
|
+
#
|
419
|
+
# We still need to keep track of the current layer depth (via
|
420
|
+
# @ignoring_depth counter) so we know when to report that the class was
|
421
|
+
# "reported", and ready to be recreated for the next request.
|
402
422
|
|
403
423
|
def ignore_request!
|
404
424
|
return if @ignoring_request
|
@@ -434,9 +454,13 @@ module ScoutApm
|
|
434
454
|
end
|
435
455
|
|
436
456
|
def logger
|
437
|
-
|
457
|
+
@agent_context.logger
|
438
458
|
end
|
439
459
|
|
460
|
+
###########################
|
461
|
+
# Serialization Helpers
|
462
|
+
###########################
|
463
|
+
|
440
464
|
# Actually go fetch & make-real any lazily created data.
|
441
465
|
# Clean up any cleverness in objects.
|
442
466
|
# Makes this object ready to be Marshal Dumped (or otherwise serialized)
|
@@ -449,7 +473,7 @@ module ScoutApm
|
|
449
473
|
# Go re-fetch the store based on what the Agent's official one is. Used
|
450
474
|
# after hydrating a dumped TrackedRequest
|
451
475
|
def restore_store
|
452
|
-
@store =
|
476
|
+
@store = @agent_context.store
|
453
477
|
end
|
454
478
|
end
|
455
479
|
end
|
@@ -1,12 +1,11 @@
|
|
1
1
|
module ScoutApm
|
2
2
|
module Utils
|
3
3
|
class ActiveRecordMetricName
|
4
|
-
DEFAULT_METRIC = "SQL/Unknown"
|
5
|
-
|
6
4
|
attr_reader :sql, :name
|
5
|
+
DEFAULT_METRIC = 'SQL/other'.freeze
|
7
6
|
|
8
7
|
def initialize(sql, name)
|
9
|
-
@sql = sql
|
8
|
+
@sql = sql || ""
|
10
9
|
@name = name.to_s
|
11
10
|
end
|
12
11
|
|
@@ -17,13 +16,11 @@ module ScoutApm
|
|
17
16
|
# name: Place Load
|
18
17
|
# metric_name: Place/find
|
19
18
|
def to_s
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
if parsed = parse_operation
|
19
|
+
parsed = parse_operation
|
20
|
+
if parsed
|
24
21
|
"#{model}/#{parsed}"
|
25
22
|
else
|
26
|
-
|
23
|
+
regex_name(sql)
|
27
24
|
end
|
28
25
|
end
|
29
26
|
|
@@ -76,6 +73,67 @@ module ScoutApm
|
|
76
73
|
end
|
77
74
|
end
|
78
75
|
end
|
76
|
+
|
77
|
+
|
78
|
+
########################
|
79
|
+
# Regex based naming #
|
80
|
+
########################
|
81
|
+
#
|
82
|
+
WHITE_SPACE = '\s*'
|
83
|
+
REGEX_OPERATION = '(SELECT|UPDATE|INSERT|DELETE)'
|
84
|
+
FROM = 'FROM'
|
85
|
+
INTO = 'INTO'
|
86
|
+
NON_GREEDY_CONSUME = '.*?'
|
87
|
+
TABLE = '(?:"|`)?(.*?)(?:"|`)?\s'
|
88
|
+
COUNT = 'COUNT\(.*?\)'
|
89
|
+
|
90
|
+
SELECT_REGEX = /\A#{WHITE_SPACE}(SELECT)#{WHITE_SPACE}(#{COUNT})?#{NON_GREEDY_CONSUME}#{FROM}#{WHITE_SPACE}#{TABLE}/i.freeze
|
91
|
+
UPDATE_REGEX = /\A#{WHITE_SPACE}(UPDATE)#{WHITE_SPACE}#{TABLE}/i.freeze
|
92
|
+
INSERT_REGEX = /\A#{WHITE_SPACE}(INSERT)#{WHITE_SPACE}#{INTO}#{WHITE_SPACE}#{TABLE}/i.freeze
|
93
|
+
DELETE_REGEX = /\A#{WHITE_SPACE}(DELETE)#{WHITE_SPACE}#{FROM}#{TABLE}/i.freeze
|
94
|
+
|
95
|
+
COUNT_LABEL = 'count'.freeze
|
96
|
+
SELECT_LABEL = 'find'.freeze
|
97
|
+
UPDATE_LABEL = 'save'.freeze
|
98
|
+
INSERT_LABEL = 'create'.freeze
|
99
|
+
DELETE_LABEL = 'destroy'.freeze
|
100
|
+
UNKNOWN_LABEL = 'SQL/other'.freeze
|
101
|
+
|
102
|
+
# Attempt to do some basic parsing of SQL via regexes to extract the SQL
|
103
|
+
# verb (select, update, etc) and the table being operated on.
|
104
|
+
#
|
105
|
+
# This is a fallback from what ActiveRecord gives us, we prefer its
|
106
|
+
# names. But sometimes it is giving us a no-name query, and we have to
|
107
|
+
# attempt to figure it out ourselves.
|
108
|
+
#
|
109
|
+
# This relies on ActiveSupport's classify method. If it's not present,
|
110
|
+
# just skip the attempt to rename here. This could happen in a Grape or
|
111
|
+
# Sinatra application that doesn't import ActiveSupport. At this point,
|
112
|
+
# you're already using ActiveRecord, so it's likely loaded anyway.
|
113
|
+
def regex_name(sql)
|
114
|
+
# We rely on the ActiveSupport inflections code here. Bail early if we can't use it.
|
115
|
+
return UNKNOWN_LABEL unless UNKNOWN_LABEL.respond_to?(:classify)
|
116
|
+
|
117
|
+
if match = SELECT_REGEX.match(sql)
|
118
|
+
operation =
|
119
|
+
if match[2]
|
120
|
+
COUNT_LABEL
|
121
|
+
else
|
122
|
+
SELECT_LABEL
|
123
|
+
end
|
124
|
+
"#{match[3].classify}/#{operation}"
|
125
|
+
elsif match = UPDATE_REGEX.match(sql)
|
126
|
+
"#{match[2].classify}/#{UPDATE_LABEL}"
|
127
|
+
elsif match = INSERT_REGEX.match(sql)
|
128
|
+
"#{match[2].classify}/#{INSERT_LABEL}"
|
129
|
+
elsif match = DELETE_REGEX.match(sql)
|
130
|
+
"#{match[2].classify}/#{DELETE_LABEL}"
|
131
|
+
else
|
132
|
+
UNKNOWN_LABEL
|
133
|
+
end
|
134
|
+
rescue
|
135
|
+
UNKNOWN_LABEL
|
136
|
+
end
|
79
137
|
end
|
80
138
|
end
|
81
139
|
end
|
@@ -11,7 +11,7 @@ module ScoutApm
|
|
11
11
|
|
12
12
|
attr_reader :call_stack
|
13
13
|
|
14
|
-
def initialize(call_stack, root=ScoutApm::
|
14
|
+
def initialize(call_stack, root=ScoutApm::Agent.instance.context.environment.root)
|
15
15
|
@call_stack = call_stack
|
16
16
|
# We can't use a constant as it'd be too early to fetch environment info
|
17
17
|
#
|
@@ -1,10 +1,14 @@
|
|
1
1
|
module ScoutApm
|
2
2
|
module Utils
|
3
3
|
class InstalledGems
|
4
|
-
attr_reader :
|
4
|
+
attr_reader :context
|
5
5
|
|
6
|
-
def initialize(
|
7
|
-
@
|
6
|
+
def initialize(context)
|
7
|
+
@context = context
|
8
|
+
end
|
9
|
+
|
10
|
+
def logger
|
11
|
+
context.logger
|
8
12
|
end
|
9
13
|
|
10
14
|
def run
|
@@ -5,6 +5,12 @@ module ScoutApm
|
|
5
5
|
# KlassHelper.defined?("ActiveRecord::Base") #=> true / false
|
6
6
|
|
7
7
|
def self.defined?(*names)
|
8
|
+
lookup(*names) != :missing_class
|
9
|
+
end
|
10
|
+
|
11
|
+
# KlassHelper.lookup("ActiveRecord::Base") => ActiveRecord::Base
|
12
|
+
# KlassHelper.lookup("ActiveRecord::SomethingThatDoesNotExist") => :missing_class
|
13
|
+
def self.lookup(*names)
|
8
14
|
if names.length == 1
|
9
15
|
names = names[0].split("::")
|
10
16
|
end
|
@@ -15,11 +21,11 @@ module ScoutApm
|
|
15
21
|
begin
|
16
22
|
obj = obj.const_get(name)
|
17
23
|
rescue NameError
|
18
|
-
return
|
24
|
+
return :missing_class
|
19
25
|
end
|
20
26
|
end
|
21
27
|
|
22
|
-
|
28
|
+
obj
|
23
29
|
end
|
24
30
|
end
|
25
31
|
end
|