oneapm_rpm 1.1.2 → 1.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/one_apm/agent.rb +185 -192
- data/lib/one_apm/agent/agent/connect.rb +17 -17
- data/lib/one_apm/agent/agent/container_data_manager.rb +14 -14
- data/lib/one_apm/agent/agent/forkable_dispatcher_functions.rb +6 -35
- data/lib/one_apm/agent/agent/helpers.rb +6 -17
- data/lib/one_apm/agent/agent/start.rb +27 -27
- data/lib/one_apm/agent/agent/start_worker_thread.rb +19 -51
- data/lib/one_apm/agent/busy_calculator.rb +8 -34
- data/lib/one_apm/agent/cross_app/cross_app_monitor.rb +10 -10
- data/lib/one_apm/agent/cross_app/cross_app_tracing.rb +14 -14
- data/lib/one_apm/agent/database.rb +8 -35
- data/lib/one_apm/agent/database/active_record_helper.rb +1 -1
- data/lib/one_apm/agent/datastores.rb +2 -109
- data/lib/one_apm/agent/datastores/metric_helper.rb +1 -1
- data/lib/one_apm/agent/datastores/mongo/metric_translator.rb +3 -3
- data/lib/one_apm/agent/datastores/mongo/statement_formatter.rb +2 -2
- data/lib/one_apm/agent/harvester.rb +3 -6
- data/lib/one_apm/agent/inbound_request_monitor.rb +2 -2
- data/lib/one_apm/agent/javascript_instrumentor.rb +28 -28
- data/lib/one_apm/agent/sampler.rb +1 -1
- data/lib/one_apm/agent/sampler_collection.rb +6 -9
- data/lib/one_apm/agent/samplers/cpu_sampler.rb +4 -4
- data/lib/one_apm/agent/samplers/delayed_job_sampler.rb +5 -5
- data/lib/one_apm/agent/samplers/memory_sampler.rb +5 -5
- data/lib/one_apm/agent/samplers/object_sampler.rb +1 -1
- data/lib/one_apm/agent/samplers/vm_sampler.rb +6 -6
- data/lib/one_apm/agent/synthetics_monitor.rb +2 -2
- data/lib/one_apm/agent/threading/agent_thread.rb +6 -6
- data/lib/one_apm/agent/threading/backtrace_service.rb +9 -9
- data/lib/one_apm/agent/threading/thread_profile.rb +3 -3
- data/lib/one_apm/collector/collector/helper.rb +10 -10
- data/lib/one_apm/collector/collector/http_connection.rb +14 -14
- data/lib/one_apm/collector/collector/server_methods.rb +12 -12
- data/lib/one_apm/collector/collector_service.rb +8 -8
- data/lib/one_apm/collector/commands/thread_profiler_session.rb +4 -4
- data/lib/one_apm/collector/commands/xray_session.rb +1 -1
- data/lib/one_apm/collector/commands/xray_session_collection.rb +10 -10
- data/lib/one_apm/collector/containers/agent_command_router.rb +7 -7
- data/lib/one_apm/collector/containers/custom_event_aggregator.rb +6 -6
- data/lib/one_apm/collector/containers/error_collector.rb +16 -16
- data/lib/one_apm/collector/containers/sql_sampler.rb +8 -11
- data/lib/one_apm/collector/containers/transaction_event_aggregator.rb +15 -15
- data/lib/one_apm/collector/containers/transaction_sampler.rb +14 -16
- data/lib/one_apm/{agent/pipe/pipe_service.rb → collector/forked_process_service.rb} +3 -3
- data/lib/one_apm/collector/stats_engine/gc_profiler.rb +3 -3
- data/lib/one_apm/collector/stats_engine/metric_stats.rb +4 -4
- data/lib/one_apm/collector/stats_engine/stats_hash.rb +2 -2
- data/lib/one_apm/configuration.rb +16 -16
- data/lib/one_apm/configuration/autostart.rb +4 -4
- data/lib/one_apm/configuration/default_source.rb +9 -9
- data/lib/one_apm/configuration/environment_source.rb +1 -1
- data/lib/one_apm/configuration/high_security_source.rb +1 -1
- data/lib/one_apm/configuration/yaml_source.rb +7 -7
- data/lib/one_apm/errors/noticed_error.rb +2 -2
- data/lib/one_apm/frameworks/external.rb +2 -0
- data/lib/one_apm/frameworks/rails.rb +8 -18
- data/lib/one_apm/frameworks/rails3.rb +1 -0
- data/lib/one_apm/frameworks/rails4.rb +2 -6
- data/lib/one_apm/frameworks/ruby.rb +7 -2
- data/lib/one_apm/frameworks/sinatra.rb +1 -2
- data/lib/one_apm/inst/3rd/active_merchant.rb +1 -1
- data/lib/one_apm/inst/3rd/acts_as_solr.rb +2 -2
- data/lib/one_apm/inst/3rd/authlogic.rb +1 -1
- data/lib/one_apm/inst/3rd/sunspot.rb +1 -1
- data/lib/one_apm/inst/background_job/active_job.rb +1 -1
- data/lib/one_apm/inst/background_job/delayed_job.rb +4 -4
- data/lib/one_apm/inst/background_job/event_machine_standalone.rb +2 -2
- data/lib/one_apm/inst/background_job/resque.rb +11 -11
- data/lib/one_apm/inst/background_job/sidekiq.rb +5 -5
- data/lib/one_apm/inst/dispatcher/passenger.rb +4 -4
- data/lib/one_apm/inst/dispatcher/puma.rb +23 -0
- data/lib/one_apm/inst/dispatcher/rainbows.rb +2 -2
- data/lib/one_apm/inst/framework/grape.rb +4 -4
- data/lib/one_apm/inst/framework/padrino.rb +2 -2
- data/lib/one_apm/inst/framework/sinatra.rb +9 -9
- data/lib/one_apm/inst/framework/sinatra/transaction_namer.rb +1 -1
- data/lib/one_apm/inst/http_clients/curb.rb +6 -6
- data/lib/one_apm/inst/http_clients/excon.rb +4 -4
- data/lib/one_apm/inst/http_clients/excon/middleware.rb +3 -3
- data/lib/one_apm/inst/http_clients/httpclient.rb +1 -1
- data/lib/one_apm/inst/http_clients/net.rb +2 -2
- data/lib/one_apm/inst/http_clients/typhoeus.rb +2 -2
- data/lib/one_apm/inst/nosql/memcache.rb +7 -7
- data/lib/one_apm/inst/nosql/mongo.rb +6 -6
- data/lib/one_apm/inst/nosql/mongo_moped.rb +2 -2
- data/lib/one_apm/inst/nosql/redis.rb +3 -3
- data/lib/one_apm/inst/orm/active_record.rb +4 -4
- data/lib/one_apm/inst/orm/active_record_4.rb +2 -2
- data/lib/one_apm/inst/orm/sequel.rb +4 -4
- data/lib/one_apm/inst/rack.rb +3 -3
- data/lib/one_apm/inst/rack/rack_builder.rb +4 -4
- data/lib/one_apm/inst/rails/action_controller.rb +7 -7
- data/lib/one_apm/inst/rails/action_web_service.rb +1 -1
- data/lib/one_apm/inst/rails/errors.rb +1 -1
- data/lib/one_apm/inst/rails3/action_controller.rb +6 -6
- data/lib/one_apm/inst/rails3/errors.rb +1 -1
- data/lib/one_apm/inst/rails4/action_controller.rb +1 -1
- data/lib/one_apm/inst/rails4/action_controller_subscriber.rb +4 -4
- data/lib/one_apm/inst/rails4/action_view.rb +2 -2
- data/lib/one_apm/inst/rails4/action_view_subscriber.rb +4 -4
- data/lib/one_apm/inst/rails4/active_record_subscriber.rb +7 -7
- data/lib/one_apm/inst/rails4/errors.rb +1 -1
- data/lib/one_apm/inst/rails_middleware.rb +2 -2
- data/lib/one_apm/inst/support/evented_subscriber.rb +2 -2
- data/lib/one_apm/inst/support/queue_time.rb +1 -1
- data/lib/one_apm/inst/transaction_base.rb +6 -6
- data/lib/one_apm/logger/agent_logger.rb +8 -8
- data/lib/one_apm/logger/audit_logger.rb +8 -8
- data/lib/one_apm/logger/memory_logger.rb +1 -1
- data/lib/one_apm/logger/null_logger.rb +1 -3
- data/lib/one_apm/manager.rb +249 -0
- data/lib/one_apm/metrics/metric_spec.rb +1 -1
- data/lib/one_apm/metrics/stats.rb +1 -1
- data/lib/one_apm/probe.rb +1 -1
- data/lib/one_apm/probe/framework_loader.rb +2 -2
- data/lib/one_apm/probe/instance_methods.rb +19 -19
- data/lib/one_apm/probe/instrumentation.rb +5 -5
- data/lib/one_apm/rack/browser_monitoring.rb +6 -6
- data/lib/one_apm/rack/middleware_hooks.rb +1 -1
- data/lib/one_apm/rack/middleware_tracing.rb +2 -2
- data/lib/one_apm/support/chained_call.rb +1 -1
- data/lib/one_apm/support/coerce.rb +1 -1
- data/lib/one_apm/support/collection_helper.rb +1 -1
- data/lib/one_apm/support/encoders.rb +1 -1
- data/lib/one_apm/support/environment_report.rb +10 -10
- data/lib/one_apm/{agent → support}/event/event_listener.rb +3 -3
- data/lib/one_apm/{agent → support}/event/event_loop.rb +8 -8
- data/lib/one_apm/{agent → support}/event/timer.rb +1 -1
- data/lib/one_apm/{agent → support}/event/worker_loop.rb +5 -19
- data/lib/one_apm/{agent/pipe/pipe_channel_manager.rb → support/forked_process_channel.rb} +13 -51
- data/lib/one_apm/support/json_marshaller.rb +6 -6
- data/lib/one_apm/support/json_wrapper.rb +2 -2
- data/lib/one_apm/support/language_support.rb +1 -1
- data/lib/one_apm/support/library_detection.rb +5 -5
- data/lib/one_apm/support/marshaller.rb +1 -1
- data/lib/one_apm/support/method_tracer.rb +12 -12
- data/lib/one_apm/support/method_tracer/helpers.rb +6 -6
- data/lib/one_apm/support/system_info.rb +2 -2
- data/lib/one_apm/support/traced_method_stack.rb +4 -4
- data/lib/one_apm/support/vm/monotonic_gc_profiler.rb +1 -1
- data/lib/one_apm/support/vm/mri_vm.rb +1 -1
- data/lib/one_apm/transaction.rb +3 -3
- data/lib/one_apm/transaction/class_methods.rb +3 -3
- data/lib/one_apm/transaction/instance_helpers.rb +3 -3
- data/lib/one_apm/transaction/sample_buffer/synthetics_sample_buffer.rb +1 -1
- data/lib/one_apm/transaction/sample_buffer/xray_sample_buffer.rb +5 -5
- data/lib/one_apm/transaction/thread_local_access.rb +2 -2
- data/lib/one_apm/transaction/transaction_apdex.rb +2 -2
- data/lib/one_apm/transaction/transaction_finish_append.rb +1 -1
- data/lib/one_apm/transaction/transaction_jruby_functions.rb +2 -2
- data/lib/one_apm/transaction/transaction_name.rb +2 -2
- data/lib/one_apm/transaction/transaction_sample.rb +1 -1
- data/lib/one_apm/transaction/transaction_sample_builder.rb +7 -7
- data/lib/one_apm/transaction/transaction_state.rb +1 -1
- data/lib/one_apm/version.rb +1 -1
- data/lib/sequel/extensions/oneapm_instrumentation.rb +7 -7
- data/oneapm.yml +6 -7
- metadata +10 -9
- data/lib/one_apm/agent/agent.rb +0 -283
@@ -4,25 +4,13 @@ require 'one_apm/transaction/transaction_state'
|
|
4
4
|
|
5
5
|
module OneApm
|
6
6
|
module Agent
|
7
|
-
# This module supports calculation of actual time spent processing requests over the course of
|
8
|
-
# one harvest period. It's similar to what you would get if you just added up all the
|
9
|
-
# execution times of controller calls, however that will be inaccurate when requests
|
10
|
-
# span the minute boundaries. This module manages accounting of requests not yet
|
11
|
-
# completed.
|
12
|
-
#
|
13
|
-
# Calls are re-entrant. All start calls must be paired with finish
|
14
|
-
# calls, or a reset call.
|
15
7
|
module BusyCalculator
|
16
8
|
|
17
9
|
extend self
|
18
10
|
|
19
|
-
# For testability, add accessors:
|
20
11
|
attr_reader :harvest_start, :accumulator
|
21
12
|
|
22
|
-
|
23
|
-
# transactions - used for a rough estimate of what percentage of
|
24
|
-
# wall clock time is spent processing requests
|
25
|
-
def dispatcher_start(time) #THREAD_LOCAL_ACCESS
|
13
|
+
def dispatcher_start(time)
|
26
14
|
state = TransactionState.tl_get
|
27
15
|
state.busy_entries ||= 0
|
28
16
|
callers = state.busy_entries += 1
|
@@ -32,38 +20,29 @@ module OneApm
|
|
32
20
|
end
|
33
21
|
end
|
34
22
|
|
35
|
-
|
36
|
-
# instance variable accumulator. this is harvested when we send
|
37
|
-
# data to the server
|
38
|
-
def dispatcher_finish(end_time = nil) #THREAD_LOCAL_ACCESS
|
23
|
+
def dispatcher_finish(end_time = nil)
|
39
24
|
state = TransactionState.tl_get
|
40
|
-
# If #dispatcher_start hasn't been called at least once, abort early
|
41
25
|
return unless state.busy_entries
|
42
26
|
|
43
27
|
end_time ||= time_now
|
44
28
|
callers = state.busy_entries -= 1
|
45
29
|
|
46
|
-
# Ignore nested calls
|
47
30
|
return if callers > 0
|
48
31
|
|
49
32
|
@lock.synchronize do
|
50
33
|
if @entrypoint_stack.empty?
|
51
|
-
|
34
|
+
OneApm::Manager.logger.warn("Stack underflow tracking dispatcher entry and exit!\n #{caller.join(" \n")}")
|
52
35
|
else
|
53
36
|
@accumulator += (end_time - @entrypoint_stack.pop).to_f
|
54
37
|
end
|
55
38
|
end
|
56
39
|
end
|
57
40
|
|
58
|
-
# this returns the size of the entry point stack, which
|
59
|
-
# determines how many transactions are running
|
60
41
|
def busy_count
|
61
42
|
@entrypoint_stack.size
|
62
43
|
end
|
63
44
|
|
64
|
-
|
65
|
-
# but only reset the recursion counter for this thread.
|
66
|
-
def reset #THREAD_LOCAL_ACCESS
|
45
|
+
def reset
|
67
46
|
@entrypoint_stack = []
|
68
47
|
TransactionState.tl_get.busy_entries = 0
|
69
48
|
@lock ||= Mutex.new
|
@@ -71,8 +50,6 @@ module OneApm
|
|
71
50
|
@harvest_start = time_now
|
72
51
|
end
|
73
52
|
|
74
|
-
|
75
|
-
# Called before uploading to to the server to collect current busy stats.
|
76
53
|
def harvest_busy
|
77
54
|
busy = 0
|
78
55
|
t0 = time_now
|
@@ -80,8 +57,6 @@ module OneApm
|
|
80
57
|
busy = accumulator
|
81
58
|
@accumulator = 0
|
82
59
|
|
83
|
-
# Walk through the stack and capture all times up to
|
84
|
-
# now for entrypoints
|
85
60
|
@entrypoint_stack.size.times do |frame|
|
86
61
|
busy += (t0 - @entrypoint_stack[frame]).to_f
|
87
62
|
@entrypoint_stack[frame] = t0
|
@@ -89,22 +64,21 @@ module OneApm
|
|
89
64
|
|
90
65
|
end
|
91
66
|
|
92
|
-
busy = 0.0 if busy < 0.0
|
67
|
+
busy = 0.0 if busy < 0.0
|
93
68
|
|
94
69
|
time_window = (t0 - harvest_start).to_f
|
95
|
-
time_window = 1.0 if time_window == 0.0
|
70
|
+
time_window = 1.0 if time_window == 0.0
|
96
71
|
|
97
72
|
busy = busy / time_window
|
98
73
|
|
99
|
-
if
|
100
|
-
OneApm::
|
74
|
+
if OneApm::Manager.config[:report_instance_busy]
|
75
|
+
OneApm::Manager.record_metric('Instance/Busy', busy)
|
101
76
|
end
|
102
77
|
@harvest_start = t0
|
103
78
|
end
|
104
79
|
|
105
80
|
private
|
106
81
|
|
107
|
-
# so we can stub Time.now only for the BusyCalculator in tests
|
108
82
|
def time_now
|
109
83
|
Time.now
|
110
84
|
end
|
@@ -26,10 +26,10 @@ module OneApm
|
|
26
26
|
# :before_call will save our cross application request id to the thread
|
27
27
|
# :after_call will write our response headers/metrics and clean up the thread
|
28
28
|
def register_event_listeners(events)
|
29
|
-
OneApm::
|
29
|
+
OneApm::Manager.logger.
|
30
30
|
debug("Wiring up Cross Application Tracing to events after finished configuring")
|
31
31
|
|
32
|
-
events.subscribe(:before_call) do |env|
|
32
|
+
events.subscribe(:before_call) do |env|
|
33
33
|
if should_process_request(env)
|
34
34
|
state = OneApm::TransactionState.tl_get
|
35
35
|
|
@@ -39,13 +39,13 @@ module OneApm
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
-
events.subscribe(:after_call) do |env, (_status_code, headers, _body)|
|
42
|
+
events.subscribe(:after_call) do |env, (_status_code, headers, _body)|
|
43
43
|
state = OneApm::TransactionState.tl_get
|
44
44
|
|
45
45
|
insert_response_header(state, env, headers)
|
46
46
|
end
|
47
47
|
|
48
|
-
events.subscribe(:notice_error) do |_, options|
|
48
|
+
events.subscribe(:notice_error) do |_, options|
|
49
49
|
state = OneApm::TransactionState.tl_get
|
50
50
|
|
51
51
|
set_error_custom_parameters(state, options)
|
@@ -116,7 +116,7 @@ module OneApm
|
|
116
116
|
split_id = id.match(/(\d+)#\d+/)
|
117
117
|
return false if split_id.nil?
|
118
118
|
|
119
|
-
OneApm::
|
119
|
+
OneApm::Manager.config[:trusted_account_ids].include?(split_id.captures.first.to_i)
|
120
120
|
end
|
121
121
|
|
122
122
|
def set_response_headers(state, response_headers, timings, content_length)
|
@@ -125,7 +125,7 @@ module OneApm
|
|
125
125
|
|
126
126
|
def build_payload(state, timings, content_length)
|
127
127
|
payload = [
|
128
|
-
OneApm::
|
128
|
+
OneApm::Manager.config[:cross_process_id],
|
129
129
|
timings.transaction_name,
|
130
130
|
timings.queue_time_in_seconds.to_f,
|
131
131
|
timings.app_time_in_seconds.to_f,
|
@@ -138,11 +138,11 @@ module OneApm
|
|
138
138
|
def set_transaction_custom_parameters(state)
|
139
139
|
# We expect to get the before call to set the id (if we have it) before
|
140
140
|
# this, and then write our custom parameter when the transaction starts
|
141
|
-
OneApm::
|
141
|
+
OneApm::Manager.add_custom_parameters(:client_cross_process_id => state.client_cross_app_id) if state.client_cross_app_id
|
142
142
|
|
143
143
|
referring_guid = client_referring_transaction_guid(state)
|
144
144
|
if referring_guid
|
145
|
-
OneApm::
|
145
|
+
OneApm::Manager.add_custom_parameters(:referring_transaction_guid => referring_guid)
|
146
146
|
end
|
147
147
|
end
|
148
148
|
|
@@ -152,7 +152,7 @@ module OneApm
|
|
152
152
|
|
153
153
|
def set_metrics(id, timings)
|
154
154
|
metric_name = "ClientApplication/#{id}/all"
|
155
|
-
OneApm::
|
155
|
+
OneApm::Manager.record_metric(metric_name, timings.app_time_in_seconds)
|
156
156
|
end
|
157
157
|
|
158
158
|
def decoded_id(request)
|
@@ -172,7 +172,7 @@ module OneApm
|
|
172
172
|
|
173
173
|
def path_hash(txn_name, seed)
|
174
174
|
rotated = ((seed << 1) | (seed >> 31)) & 0xffffffff
|
175
|
-
app_name = OneApm::
|
175
|
+
app_name = OneApm::Manager.config.app_names.first
|
176
176
|
identifier = "#{app_name};#{txn_name}"
|
177
177
|
sprintf("%08x", rotated ^ hash_transaction_name(identifier))
|
178
178
|
end
|
@@ -72,10 +72,10 @@ module OneApm
|
|
72
72
|
|
73
73
|
return segment
|
74
74
|
rescue => err
|
75
|
-
OneApm::
|
75
|
+
OneApm::Manager.logger.error "Uncaught exception while tracing HTTP request", err
|
76
76
|
return nil
|
77
77
|
rescue Exception => e
|
78
|
-
OneApm::
|
78
|
+
OneApm::Manager.logger.debug "Unexpected exception raised while tracing HTTP request", e
|
79
79
|
|
80
80
|
raise e
|
81
81
|
end
|
@@ -94,7 +94,7 @@ module OneApm
|
|
94
94
|
#
|
95
95
|
def finish_trace(state, t0, segment, request, response)
|
96
96
|
unless t0
|
97
|
-
OneApm::
|
97
|
+
OneApm::Manager.logger.error("HTTP request trace finished without start time. This is probably an agent bug.")
|
98
98
|
return
|
99
99
|
end
|
100
100
|
|
@@ -127,9 +127,9 @@ module OneApm
|
|
127
127
|
end
|
128
128
|
end
|
129
129
|
rescue OneApm::Agent::CrossAppTracing::Error => err
|
130
|
-
OneApm::
|
130
|
+
OneApm::Manager.logger.debug "while cross app tracing", err
|
131
131
|
rescue => err
|
132
|
-
OneApm::
|
132
|
+
OneApm::Manager.logger.error "Uncaught exception while finishing an HTTP request trace", err
|
133
133
|
end
|
134
134
|
|
135
135
|
# Return +true+ if cross app tracing is enabled in the config.
|
@@ -140,21 +140,21 @@ module OneApm
|
|
140
140
|
end
|
141
141
|
|
142
142
|
def valid_cross_process_id?
|
143
|
-
OneApm::
|
143
|
+
OneApm::Manager.config[:cross_process_id] && OneApm::Manager.config[:cross_process_id].length > 0
|
144
144
|
end
|
145
145
|
|
146
146
|
def valid_encoding_key?
|
147
|
-
OneApm::
|
147
|
+
OneApm::Manager.config[:encoding_key] && OneApm::Manager.config[:encoding_key].length > 0
|
148
148
|
end
|
149
149
|
|
150
150
|
def cross_application_tracer_enabled?
|
151
|
-
OneApm::
|
151
|
+
OneApm::Manager.config[:"cross_application_tracer.enabled"]
|
152
152
|
end
|
153
153
|
|
154
154
|
# Fetcher for the cross app encoding key. Raises a
|
155
155
|
# OneApm::Agent::CrossAppTracing::Error if the key isn't configured.
|
156
156
|
def cross_app_encoding_key
|
157
|
-
OneApm::
|
157
|
+
OneApm::Manager.config[:encoding_key] or
|
158
158
|
raise OneApm::Agent::CrossAppTracing::Error, "No encoding_key set."
|
159
159
|
end
|
160
160
|
|
@@ -164,7 +164,7 @@ module OneApm
|
|
164
164
|
|
165
165
|
# Inject the X-Process header into the outgoing +request+.
|
166
166
|
def inject_request_headers(state, request)
|
167
|
-
cross_app_id = OneApm::
|
167
|
+
cross_app_id = OneApm::Manager.config[:cross_process_id] or
|
168
168
|
raise OneApm::Agent::CrossAppTracing::Error, "no cross app ID configured"
|
169
169
|
|
170
170
|
state.is_cross_app_caller = true
|
@@ -184,7 +184,7 @@ module OneApm
|
|
184
184
|
request[OA_TXN_HEADER] = obfuscator.obfuscate(txn_data)
|
185
185
|
|
186
186
|
rescue OneApm::Agent::CrossAppTracing::Error => err
|
187
|
-
OneApm::
|
187
|
+
OneApm::Manager.logger.debug "Not injecting x-process header", err
|
188
188
|
end
|
189
189
|
|
190
190
|
def add_transaction_trace_parameters(request, response)
|
@@ -217,7 +217,7 @@ module OneApm
|
|
217
217
|
metrics.concat metrics_for_crossapp_response( request, response )
|
218
218
|
rescue => err
|
219
219
|
# Fall back to regular metrics if there's a problem with x-process metrics
|
220
|
-
OneApm::
|
220
|
+
OneApm::Manager.logger.debug "%p while fetching x-process metrics: %s" %
|
221
221
|
[ err.class, err.message ]
|
222
222
|
metrics.concat metrics_for_regular_request( request )
|
223
223
|
end
|
@@ -308,11 +308,11 @@ module OneApm
|
|
308
308
|
|
309
309
|
# Fetch a reference to the stats engine.
|
310
310
|
def stats_engine
|
311
|
-
OneApm::
|
311
|
+
OneApm::Manager.agent.stats_engine
|
312
312
|
end
|
313
313
|
|
314
314
|
def transaction_sampler
|
315
|
-
OneApm::
|
315
|
+
OneApm::Manager.agent.transaction_sampler
|
316
316
|
end
|
317
317
|
|
318
318
|
# Check the given +id+ to ensure it conforms to the format of a cross-application
|
@@ -6,7 +6,6 @@ require 'one_apm/agent/database/obfuscator'
|
|
6
6
|
require 'one_apm/agent/database/postgres_explain_obfuscator'
|
7
7
|
|
8
8
|
module OneApm
|
9
|
-
# columns for a mysql explain plan
|
10
9
|
MYSQL_EXPLAIN_COLUMNS = [
|
11
10
|
"Id",
|
12
11
|
"Select Type",
|
@@ -47,7 +46,7 @@ module OneApm
|
|
47
46
|
end
|
48
47
|
|
49
48
|
def record_sql_method(config_section=:transaction_tracer)
|
50
|
-
case
|
49
|
+
case OneApm::Manager.config["#{config_section}.record_sql".to_sym].to_s
|
51
50
|
when 'off'
|
52
51
|
:off
|
53
52
|
when 'none'
|
@@ -69,7 +68,7 @@ module OneApm
|
|
69
68
|
|
70
69
|
def should_collect_explain_plans?(config_section=:transaction_tracer)
|
71
70
|
should_record_sql?(config_section) &&
|
72
|
-
|
71
|
+
OneApm::Manager.config["#{config_section}.explain_enabled".to_sym]
|
73
72
|
end
|
74
73
|
|
75
74
|
def get_connection(config, &connector)
|
@@ -80,26 +79,14 @@ module OneApm
|
|
80
79
|
ConnectionManager.instance.close_connections
|
81
80
|
end
|
82
81
|
|
83
|
-
# This takes a connection config hash from ActiveRecord or Sequel and
|
84
|
-
# returns a string describing the associated database adapter
|
85
82
|
def adapter_from_config(config)
|
86
83
|
if config[:adapter]
|
87
84
|
return config[:adapter].to_s
|
88
85
|
elsif config[:uri] && config[:uri].to_s =~ /^jdbc:([^:]+):/
|
89
|
-
# This case is for Sequel with the jdbc-mysql, jdbc-postgres, or
|
90
|
-
# jdbc-sqlite3 gems.
|
91
86
|
return $1
|
92
87
|
end
|
93
88
|
end
|
94
89
|
|
95
|
-
# Perform this in the runtime environment of a managed
|
96
|
-
# application, to explain the sql statement executed within a
|
97
|
-
# segment of a transaction sample. Returns an array of
|
98
|
-
# explanations (which is an array rows consisting of an array of
|
99
|
-
# strings for each column returned by the the explain query)
|
100
|
-
# Note this happens only for statements whose execution time
|
101
|
-
# exceeds a threshold (e.g. 500ms) and only within the slowest
|
102
|
-
# transaction in a report period, selected for shipment to OneApm
|
103
90
|
def explain_sql(sql, connection_config, &explainer)
|
104
91
|
return nil unless sql && connection_config
|
105
92
|
statement = sql.split(";\n")[0] # only explain the first
|
@@ -113,25 +100,25 @@ module OneApm
|
|
113
100
|
return unless is_select?(statement)
|
114
101
|
|
115
102
|
if statement[-3,3] == '...'
|
116
|
-
OneApm::
|
103
|
+
OneApm::Manager.logger.debug('Unable to collect explain plan for truncated query.')
|
117
104
|
return
|
118
105
|
end
|
119
106
|
|
120
107
|
if parameterized?(statement)
|
121
|
-
OneApm::
|
108
|
+
OneApm::Manager.logger.debug('Unable to collect explain plan for parameterized query.')
|
122
109
|
return
|
123
110
|
end
|
124
111
|
|
125
112
|
adapter = adapter_from_config(config)
|
126
113
|
if !SUPPORTED_ADAPTERS_FOR_EXPLAIN.include?(adapter)
|
127
|
-
OneApm::
|
114
|
+
OneApm::Manager.logger.debug("Not collecting explain plan because an unknown connection adapter ('#{adapter}') was used.")
|
128
115
|
return
|
129
116
|
end
|
130
117
|
|
131
118
|
handle_exception_in_explain do
|
132
119
|
start = Time.now
|
133
120
|
plan = explainer.call(config, statement)
|
134
|
-
|
121
|
+
OneApm::Manager.record_metric("Supportability/Database/execute_explain_plan", Time.now - start)
|
135
122
|
return process_resultset(plan, adapter) if plan
|
136
123
|
end
|
137
124
|
end
|
@@ -168,11 +155,6 @@ module OneApm
|
|
168
155
|
[[QUERY_PLAN], values]
|
169
156
|
end
|
170
157
|
|
171
|
-
# Sequel returns explain plans as just one big pre-formatted String
|
172
|
-
# In that case, we send a nil headers array, and the single string
|
173
|
-
# wrapped in an array for the values.
|
174
|
-
# Note that we don't use this method for Postgres explain plans, since
|
175
|
-
# they need to be passed through the explain plan obfuscator first.
|
176
158
|
def string_explain_plan_results(results)
|
177
159
|
[nil, [results]]
|
178
160
|
end
|
@@ -182,15 +164,11 @@ module OneApm
|
|
182
164
|
headers = []
|
183
165
|
values = []
|
184
166
|
if results.is_a?(Array)
|
185
|
-
# We're probably using the jdbc-mysql gem for JRuby, which will give
|
186
|
-
# us an array of hashes.
|
187
167
|
headers = results.first.keys
|
188
168
|
results.each do |row|
|
189
169
|
values << headers.map { |h| row[h] }
|
190
170
|
end
|
191
171
|
else
|
192
|
-
# We're probably using the native mysql driver gem, which will give us
|
193
|
-
# a Mysql::Result object that responds to each_hash
|
194
172
|
results.each_hash do |row|
|
195
173
|
headers = row.keys
|
196
174
|
values << headers.map { |h| row[h] }
|
@@ -224,7 +202,7 @@ module OneApm
|
|
224
202
|
rescue => e
|
225
203
|
begin
|
226
204
|
# guarantees no throw from explain_sql
|
227
|
-
|
205
|
+
OneApm::Manager.logger.error("Error getting query plan:", e)
|
228
206
|
nil
|
229
207
|
rescue
|
230
208
|
# double exception. throw up your hands
|
@@ -267,10 +245,6 @@ module OneApm
|
|
267
245
|
class ConnectionManager
|
268
246
|
include Singleton
|
269
247
|
|
270
|
-
# Returns a cached connection for a given ActiveRecord
|
271
|
-
# configuration - these are stored or reopened as needed, and if
|
272
|
-
# we cannot get one, we ignore it and move on without explaining
|
273
|
-
# the sql
|
274
248
|
def get_connection(config, &connector)
|
275
249
|
@connections ||= {}
|
276
250
|
|
@@ -281,12 +255,11 @@ module OneApm
|
|
281
255
|
begin
|
282
256
|
@connections[config] = connector.call(config)
|
283
257
|
rescue => e
|
284
|
-
|
258
|
+
OneApm::Manager.logger.error("Caught exception trying to get connection to DB for explain.", e)
|
285
259
|
nil
|
286
260
|
end
|
287
261
|
end
|
288
262
|
|
289
|
-
# Closes all the connections in the internal connection cache
|
290
263
|
def close_connections
|
291
264
|
@connections ||= {}
|
292
265
|
@connections.values.each do |connection|
|
@@ -6,23 +6,6 @@ module OneApm
|
|
6
6
|
module Agent
|
7
7
|
module Datastores
|
8
8
|
|
9
|
-
# Add Datastore tracing to a method. This properly generates the metrics
|
10
|
-
# for OneApm's Datastore features. It does not capture the actual
|
11
|
-
# query content into Transaction Traces. Use wrap if you want to provide
|
12
|
-
# that functionality.
|
13
|
-
#
|
14
|
-
# @param [Class] clazz the class to instrument
|
15
|
-
#
|
16
|
-
# @param [String, Symbol] method_name the name of instance method to
|
17
|
-
# instrument
|
18
|
-
#
|
19
|
-
# @param [String] product name of your datastore for use in metric naming, e.g. "Redis"
|
20
|
-
#
|
21
|
-
# @param [optional,String] operation the name of operation if different
|
22
|
-
# than the instrumented method name
|
23
|
-
#
|
24
|
-
# @api public
|
25
|
-
#
|
26
9
|
def self.trace(clazz, method_name, product, operation = method_name)
|
27
10
|
clazz.class_eval do
|
28
11
|
method_name_without_oneapm = "#{method_name}_without_oneapm"
|
@@ -47,49 +30,6 @@ module OneApm
|
|
47
30
|
end
|
48
31
|
end
|
49
32
|
|
50
|
-
# Wrap a call to a datastore and record OneApm Datastore metrics. This
|
51
|
-
# method can be used when a collection (i.e. table or model name) is
|
52
|
-
# known at runtime to be included in the metric naming. It is intended
|
53
|
-
# for situations that the simpler OneApm::Agent::Datastores.trace can't
|
54
|
-
# properly handle.
|
55
|
-
#
|
56
|
-
# To use this, wrap the datastore operation in the block passed to wrap.
|
57
|
-
#
|
58
|
-
# OneApm::Agent::Datastores.wrap("FauxDB", "find", "items") do
|
59
|
-
# FauxDB.find(query)
|
60
|
-
# end
|
61
|
-
#
|
62
|
-
# @param [String] product the datastore name for use in metric naming,
|
63
|
-
# e.g. "FauxDB"
|
64
|
-
#
|
65
|
-
# @param [String,Symbol] operation the name of operation (e.g. "select"),
|
66
|
-
# often named after the method that's being instrumented.
|
67
|
-
#
|
68
|
-
# @param [optional, String] collection the collection name for use in
|
69
|
-
# statement-level metrics (i.e. table or model name)
|
70
|
-
#
|
71
|
-
# @param [Proc,#call] callback proc or other callable to invoke after
|
72
|
-
# running the datastore block. Receives three arguments: result of the
|
73
|
-
# yield, the most specific (scoped) metric name, and elapsed time of the
|
74
|
-
# call. An example use is attaching SQL to Transaction Traces at the end
|
75
|
-
# of a wrapped datastore call.
|
76
|
-
#
|
77
|
-
# callback = Proc.new do |result, metrics, elapsed|
|
78
|
-
# OneApm::Agent::Datastores.notice_sql(query, metrics, elapsed)
|
79
|
-
# end
|
80
|
-
#
|
81
|
-
# OneApm::Agent::Datastores.wrap("FauxDB", "find", "items", callback) do
|
82
|
-
# FauxDB.find(query)
|
83
|
-
# end
|
84
|
-
#
|
85
|
-
# **NOTE: THERE ARE SECURITY CONCERNS WHEN CAPTURING SQL!**
|
86
|
-
# OneApm's Transaction Tracing and Slow SQL features will
|
87
|
-
# attempt to apply obfuscation to the passed queries, but it is possible
|
88
|
-
# for a query format to be unsupported and result in exposing user
|
89
|
-
# information embedded within captured queries.
|
90
|
-
#
|
91
|
-
# @api public
|
92
|
-
#
|
93
33
|
def self.wrap(product, operation, collection = nil, callback = nil)
|
94
34
|
return yield unless operation
|
95
35
|
|
@@ -108,64 +48,17 @@ module OneApm
|
|
108
48
|
end
|
109
49
|
end
|
110
50
|
|
111
|
-
# Wrapper for simplifying attaching SQL queries during a transaction.
|
112
|
-
#
|
113
|
-
# If you are recording non-SQL data, please use the notice_statement
|
114
|
-
# method instead.
|
115
|
-
#
|
116
|
-
# OneApm::Agent::Datastores.notice_sql(query, metrics, elapsed)
|
117
|
-
#
|
118
|
-
# @param [String] query the SQL text to be captured. Note that depending
|
119
|
-
# on user settings, this string will be run through obfuscation, but
|
120
|
-
# some dialects of SQL (or non-SQL queries) are not guaranteed to be
|
121
|
-
# properly obfuscated by these routines!
|
122
|
-
#
|
123
|
-
# @param [String] scoped_metric The most specific metric relating to this
|
124
|
-
# query. Typically the result of
|
125
|
-
# OneApm::Agent::Datastores::MetricHelper#metrics_for
|
126
|
-
#
|
127
|
-
# @param [Float] elapsed the elapsed time during query execution
|
128
|
-
#
|
129
|
-
# **NOTE: THERE ARE SECURITY CONCERNS WHEN CAPTURING SQL!**
|
130
|
-
# OneApm's Transaction Tracing and Slow SQL features will
|
131
|
-
# attempt to apply obfuscation to the passed queries, but it is possible
|
132
|
-
# for a query format to be unsupported and result in exposing user
|
133
|
-
# information embedded within captured queries.
|
134
|
-
#
|
135
51
|
def self.notice_sql(query, scoped_metric, elapsed)
|
136
|
-
agent = OneApm::
|
52
|
+
agent = OneApm::Manager.agent
|
137
53
|
agent.transaction_sampler.notice_sql(query, nil, elapsed)
|
138
54
|
agent.sql_sampler.notice_sql(query, scoped_metric, nil, elapsed)
|
139
55
|
nil
|
140
56
|
end
|
141
57
|
|
142
|
-
# Wrapper for simplifying attaching non-SQL data statements to a
|
143
|
-
# transaction. For instance, Mongo or CQL queries, Memcached or Redis
|
144
|
-
# keys would all be appropriate data to attach as statements.
|
145
|
-
#
|
146
|
-
# Data passed to this method is NOT obfuscated by OneApm, so please
|
147
|
-
# ensure that user information is obfuscated if the agent setting
|
148
|
-
# `transaction_tracer.record_sql` is set to `obfuscated`
|
149
|
-
#
|
150
|
-
# OneApm::Agent::Datastores.notice_statement("key", elapsed)
|
151
|
-
#
|
152
|
-
# @param [String] statement text of the statement to capture.
|
153
|
-
#
|
154
|
-
# @param [Float] elapsed the elapsed time during query execution
|
155
|
-
#
|
156
|
-
# **NOTE: THERE ARE SECURITY CONCERNS WHEN CAPTURING STATEMENTS!**
|
157
|
-
# This method will properly ignore statements when the user has turned
|
158
|
-
# off capturing queries, but it is not able to obfuscate arbitrary data!
|
159
|
-
# To prevent exposing user information embedded in captured queries,
|
160
|
-
# please ensure all data passed to this method is safe to transmit to
|
161
|
-
# OneApm.
|
162
|
-
#
|
163
58
|
def self.notice_statement(statement, elapsed)
|
164
|
-
# Settings may change eventually, but for now we follow the same
|
165
|
-
# capture rules as SQL for non-SQL statements.
|
166
59
|
return unless OneApm::Agent::Database.should_record_sql?
|
167
60
|
|
168
|
-
agent = OneApm::
|
61
|
+
agent = OneApm::Manager.agent
|
169
62
|
agent.transaction_sampler.notice_nosql_statement(statement, elapsed)
|
170
63
|
nil
|
171
64
|
end
|