oneapm_rpm 1.1.2 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|