newrelic_rpm 3.8.0.218 → 3.8.1.221
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/CHANGELOG +32 -0
- data/README.md +4 -7
- data/Rakefile +3 -0
- data/lib/new_relic/agent.rb +3 -7
- data/lib/new_relic/agent/agent.rb +4 -14
- data/lib/new_relic/agent/agent_logger.rb +19 -11
- data/lib/new_relic/agent/autostart.rb +1 -1
- data/lib/new_relic/agent/configuration/default_source.rb +25 -12
- data/lib/new_relic/agent/configuration/manager.rb +14 -7
- data/lib/new_relic/agent/configuration/yaml_source.rb +39 -8
- data/lib/new_relic/agent/cross_app_monitor.rb +9 -7
- data/lib/new_relic/agent/cross_app_tracing.rb +6 -6
- data/lib/new_relic/agent/datastores/mongo.rb +6 -7
- data/lib/new_relic/agent/datastores/mongo/metric_translator.rb +32 -13
- data/lib/new_relic/agent/datastores/mongo/statement_formatter.rb +4 -3
- data/lib/new_relic/agent/error_collector.rb +2 -2
- data/lib/new_relic/agent/instrumentation/action_controller_subscriber.rb +10 -69
- data/lib/new_relic/agent/instrumentation/action_view_subscriber.rb +5 -7
- data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +2 -2
- data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +77 -93
- data/lib/new_relic/agent/instrumentation/evented_subscriber.rb +1 -1
- data/lib/new_relic/agent/instrumentation/mongo.rb +26 -42
- data/lib/new_relic/agent/instrumentation/rubyprof.rb +1 -1
- data/lib/new_relic/agent/instrumentation/sinatra.rb +4 -1
- data/lib/new_relic/agent/javascript_instrumentor.rb +15 -6
- data/lib/new_relic/agent/method_tracer.rb +41 -92
- data/lib/new_relic/agent/request_sampler.rb +0 -1
- data/lib/new_relic/agent/rules_engine.rb +36 -12
- data/lib/new_relic/agent/shim_agent.rb +0 -1
- data/lib/new_relic/agent/sql_sampler.rb +8 -15
- data/lib/new_relic/agent/stats_engine.rb +2 -6
- data/lib/new_relic/agent/stats_engine/metric_stats.rb +8 -2
- data/lib/new_relic/agent/stats_engine/stats_hash.rb +1 -1
- data/lib/new_relic/agent/supported_versions.rb +1 -1
- data/lib/new_relic/agent/traced_method_stack.rb +87 -0
- data/lib/new_relic/agent/transaction.rb +277 -107
- data/lib/new_relic/agent/transaction_sample_builder.rb +2 -2
- data/lib/new_relic/agent/transaction_sampler.rb +18 -27
- data/lib/new_relic/agent/transaction_state.rb +15 -40
- data/lib/new_relic/control/instance_methods.rb +8 -4
- data/lib/new_relic/recipes.rb +3 -3
- data/lib/new_relic/transaction_sample.rb +3 -7
- data/lib/new_relic/version.rb +1 -1
- data/lib/sequel/extensions/newrelic_instrumentation.rb +3 -3
- data/newrelic_rpm.gemspec +15 -9
- data/test/agent_helper.rb +71 -36
- data/test/environments/norails/Gemfile +2 -0
- data/test/environments/rails21/Gemfile +2 -0
- data/test/environments/rails22/Gemfile +2 -0
- data/test/environments/rails23/Gemfile +2 -0
- data/test/environments/rails30/Gemfile +2 -0
- data/test/environments/rails31/Gemfile +2 -0
- data/test/environments/rails32/Gemfile +2 -0
- data/test/environments/rails40/Gemfile +2 -0
- data/test/environments/rails41/Gemfile +1 -0
- data/test/helpers/mongo_metric_builder.rb +1 -1
- data/test/multiverse/suites/agent_only/audit_log_test.rb +2 -2
- data/test/multiverse/suites/agent_only/cross_application_tracing_test.rb +9 -1
- data/test/multiverse/suites/agent_only/encoding_handling_test.rb +1 -1
- data/test/multiverse/suites/agent_only/logging_test.rb +2 -2
- data/test/multiverse/suites/agent_only/marshaling_test.rb +8 -9
- data/test/multiverse/suites/agent_only/rum_instrumentation_test.rb +14 -1
- data/test/multiverse/suites/agent_only/set_transaction_name_test.rb +30 -13
- data/test/multiverse/suites/agent_only/thread_profiling_test.rb +9 -8
- data/test/multiverse/suites/agent_only/transaction_ignoring_test.rb +43 -0
- data/test/multiverse/suites/config_file_loading/config_file_loading_test.rb +77 -5
- data/test/multiverse/suites/excon/excon_test.rb +1 -1
- data/test/multiverse/suites/mongo/Envfile +4 -7
- data/test/multiverse/suites/mongo/helpers/mongo_operation_tests.rb +55 -16
- data/test/multiverse/suites/mongo/helpers/mongo_server.rb +6 -4
- data/test/multiverse/suites/rails/bad_instrumentation_test.rb +2 -2
- data/test/multiverse/suites/rails/error_tracing_test.rb +3 -1
- data/test/multiverse/suites/rails/request_statistics_test.rb +14 -14
- data/test/multiverse/suites/rails/transaction_ignoring_test.rb +45 -0
- data/test/multiverse/suites/sequel/sequel_instrumentation_test.rb +1 -1
- data/test/new_relic/agent/agent/connect_test.rb +4 -4
- data/test/new_relic/agent/agent_logger_test.rb +32 -0
- data/test/new_relic/agent/configuration/manager_test.rb +12 -4
- data/test/new_relic/agent/configuration/yaml_source_test.rb +2 -2
- data/test/new_relic/agent/cross_app_monitor_test.rb +6 -2
- data/test/new_relic/agent/cross_app_tracing_test.rb +5 -5
- data/test/new_relic/agent/datastores/mongo/statement_formatter_test.rb +7 -6
- data/test/new_relic/agent/error_collector_test.rb +1 -2
- data/test/new_relic/agent/instrumentation/action_controller_subscriber_test.rb +24 -11
- data/test/new_relic/agent/instrumentation/action_view_subscriber_test.rb +2 -2
- data/test/new_relic/agent/instrumentation/active_record_subscriber_test.rb +12 -17
- data/test/new_relic/agent/instrumentation/controller_instrumentation_test.rb +43 -32
- data/test/new_relic/agent/instrumentation/net_instrumentation_test.rb +3 -4
- data/test/new_relic/agent/instrumentation/task_instrumentation_test.rb +36 -20
- data/test/new_relic/agent/javascript_instrumentor_test.rb +1 -2
- data/test/new_relic/agent/method_tracer/class_methods/add_method_tracer_test.rb +15 -26
- data/test/new_relic/agent/method_tracer/instance_methods/trace_execution_scoped_test.rb +66 -103
- data/test/new_relic/agent/method_tracer_test.rb +2 -2
- data/test/new_relic/agent/mock_scope_listener.rb +3 -6
- data/test/new_relic/agent/pipe_channel_manager_test.rb +4 -4
- data/test/new_relic/agent/rules_engine_test.rb +13 -0
- data/test/new_relic/agent/sql_sampler_test.rb +8 -10
- data/test/new_relic/agent/stats_engine/metric_stats_test.rb +18 -0
- data/test/new_relic/agent/stats_engine_test.rb +0 -173
- data/test/new_relic/agent/threading/agent_thread_test.rb +27 -26
- data/test/new_relic/agent/traced_method_stack_test.rb +139 -0
- data/test/new_relic/agent/transaction_sample_builder_test.rb +2 -12
- data/test/new_relic/agent/transaction_sampler_test.rb +98 -107
- data/test/new_relic/agent/transaction_state_test.rb +52 -61
- data/test/new_relic/agent/transaction_test.rb +209 -140
- data/test/new_relic/agent_test.rb +3 -2
- data/test/new_relic/control_test.rb +10 -9
- data/test/new_relic/fake_collector.rb +34 -2
- data/test/new_relic/http_client_test_cases.rb +0 -5
- data/test/new_relic/license_test.rb +4 -2
- data/test/new_relic/local_environment_test.rb +14 -28
- data/test/new_relic/multiverse_helpers.rb +2 -2
- data/test/new_relic/rack/developer_mode_test.rb +4 -5
- data/test/new_relic/transaction_ignoring_test_cases.rb +104 -0
- data/test/new_relic/transaction_sample_test.rb +14 -7
- data/test/performance/lib/performance/instrumentation/gc_stats.rb +6 -3
- data/test/performance/suites/transaction_tracing.rb +4 -1
- data/test/test_helper.rb +31 -60
- data/ui/views/newrelic/show_sample.rhtml +1 -1
- metadata +46 -101
- metadata.gz.sig +0 -0
- data/lib/new_relic/agent/stats_engine/transactions.rb +0 -114
- data/lib/new_relic/agent/transaction/pop.rb +0 -52
- data/test/new_relic/agent/transaction/pop_test.rb +0 -79
@@ -10,13 +10,7 @@ module NewRelic
|
|
10
10
|
# No version constant in < 2.0 versions of Mongo :(
|
11
11
|
defined?(::Mongo) &&
|
12
12
|
defined?(::Mongo::MongoClient) &&
|
13
|
-
!is_version2?
|
14
|
-
!is_version_1_10_or_later?
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.is_version_1_10_or_later?
|
18
|
-
# Again, no VERSION constant in 1.x, so we have to rely on constant checks
|
19
|
-
defined?(::Mongo::CollectionOperationWriter)
|
13
|
+
!is_version2?
|
20
14
|
end
|
21
15
|
|
22
16
|
# At present we explicitly don't support version 2.x of the driver yet
|
@@ -24,6 +18,11 @@ module NewRelic
|
|
24
18
|
defined?(::Mongo::VERSION) &&
|
25
19
|
NewRelic::VersionNumber.new(::Mongo::VERSION) > NewRelic::VersionNumber.new("2.0.0")
|
26
20
|
end
|
21
|
+
|
22
|
+
def self.is_version_1_10_or_later?
|
23
|
+
# Again, no VERSION constant in 1.x, so we have to rely on constant checks
|
24
|
+
defined?(::Mongo::CollectionOperationWriter)
|
25
|
+
end
|
27
26
|
end
|
28
27
|
end
|
29
28
|
end
|
@@ -12,21 +12,27 @@ module NewRelic
|
|
12
12
|
def self.metrics_for(name, payload, request_type = :web)
|
13
13
|
payload ||= {}
|
14
14
|
|
15
|
-
|
16
|
-
collection = payload[:collection]
|
17
|
-
|
18
|
-
if collection_in_selector?(collection, payload)
|
15
|
+
if collection_in_selector?(payload)
|
19
16
|
command_key = command_key_from_selector(payload)
|
20
17
|
name = get_name_from_selector(command_key, payload)
|
21
18
|
collection = get_collection_from_selector(command_key, payload)
|
19
|
+
else
|
20
|
+
collection = payload[:collection]
|
22
21
|
end
|
23
22
|
|
23
|
+
# The 1.10.0 version of the mongo driver renamed 'remove' to
|
24
|
+
# 'delete', but for metric consistency with previous versions we
|
25
|
+
# want to keep it as 'remove'.
|
26
|
+
name = 'remove' if name.to_s == 'delete'
|
27
|
+
|
24
28
|
if self.find_one?(name, payload)
|
25
29
|
name = 'findOne'
|
26
30
|
elsif self.find_and_remove?(name, payload)
|
27
31
|
name = 'findAndRemove'
|
28
32
|
elsif self.find_and_modify?(name, payload)
|
29
33
|
name = 'findAndModify'
|
34
|
+
elsif self.create_indexes?(name, payload)
|
35
|
+
name = 'createIndexes'
|
30
36
|
elsif self.create_index?(name, payload)
|
31
37
|
name = 'createIndex'
|
32
38
|
collection = self.collection_name_from_index(payload)
|
@@ -44,9 +50,7 @@ module NewRelic
|
|
44
50
|
collection = collection_name_from_rename_selector(payload)
|
45
51
|
end
|
46
52
|
|
47
|
-
|
48
|
-
|
49
|
-
metrics
|
53
|
+
build_metrics(name, collection, request_type)
|
50
54
|
end
|
51
55
|
|
52
56
|
def self.build_metrics(name, collection, request_type = :web)
|
@@ -70,8 +74,8 @@ module NewRelic
|
|
70
74
|
"Datastore/instance/MongoDB/#{host}:#{port}/#{database}"
|
71
75
|
end
|
72
76
|
|
73
|
-
def self.collection_in_selector?(
|
74
|
-
collection == '$cmd' && payload[:selector]
|
77
|
+
def self.collection_in_selector?(payload)
|
78
|
+
payload[:collection] == '$cmd' && payload[:selector]
|
75
79
|
end
|
76
80
|
|
77
81
|
NAMES_IN_SELECTOR = [
|
@@ -84,6 +88,7 @@ module NewRelic
|
|
84
88
|
|
85
89
|
:distinct,
|
86
90
|
|
91
|
+
:createIndexes,
|
87
92
|
:deleteIndexes,
|
88
93
|
:reIndex,
|
89
94
|
|
@@ -131,6 +136,10 @@ module NewRelic
|
|
131
136
|
name == :findandmodify && payload[:selector] && payload[:selector][:remove]
|
132
137
|
end
|
133
138
|
|
139
|
+
def self.create_indexes?(name, paylod)
|
140
|
+
name == :createIndexes
|
141
|
+
end
|
142
|
+
|
134
143
|
def self.create_index?(name, payload)
|
135
144
|
name == :insert && payload[:collection] == "system.indexes"
|
136
145
|
end
|
@@ -156,11 +165,21 @@ module NewRelic
|
|
156
165
|
end
|
157
166
|
|
158
167
|
def self.collection_name_from_index(payload)
|
159
|
-
if payload[:documents]
|
160
|
-
payload[:documents].
|
161
|
-
|
162
|
-
|
168
|
+
if payload[:documents]
|
169
|
+
if payload[:documents].is_a?(Array)
|
170
|
+
# mongo gem versions pre 1.10.0
|
171
|
+
document = payload[:documents].first
|
172
|
+
else
|
173
|
+
# mongo gem versions 1.10.0 and later
|
174
|
+
document = payload[:documents]
|
175
|
+
end
|
176
|
+
|
177
|
+
if document && document[:ns]
|
178
|
+
return document[:ns].split('.').last
|
179
|
+
end
|
163
180
|
end
|
181
|
+
|
182
|
+
'system.indexes'
|
164
183
|
end
|
165
184
|
|
166
185
|
def self.collection_name_from_group_selector(payload)
|
@@ -24,16 +24,17 @@ module NewRelic
|
|
24
24
|
:selector
|
25
25
|
]
|
26
26
|
|
27
|
-
def self.format(statement)
|
27
|
+
def self.format(statement, operation)
|
28
28
|
return nil unless NewRelic::Agent.config[:'mongo.capture_queries']
|
29
29
|
|
30
|
-
result = {}
|
30
|
+
result = { :operation => operation }
|
31
|
+
|
31
32
|
PLAINTEXT_KEYS.each do |key|
|
32
33
|
result[key] = statement[key] if statement.key?(key)
|
33
34
|
end
|
34
35
|
|
35
36
|
OBFUSCATE_KEYS.each do |key|
|
36
|
-
if statement.key?(key)
|
37
|
+
if statement.key?(key) && statement[key]
|
37
38
|
obfuscated = obfuscate(statement[key])
|
38
39
|
result[key] = obfuscated if obfuscated
|
39
40
|
end
|
@@ -110,7 +110,7 @@ module NewRelic
|
|
110
110
|
if options[:metric] && options[:metric] != ::NewRelic::Agent::UNKNOWN_METRIC
|
111
111
|
"Errors/#{options[:metric]}"
|
112
112
|
else
|
113
|
-
if txn = TransactionState.get.
|
113
|
+
if txn = TransactionState.get.most_recent_transaction
|
114
114
|
"Errors/#{txn.name}"
|
115
115
|
end
|
116
116
|
end
|
@@ -265,7 +265,7 @@ module NewRelic
|
|
265
265
|
return if should_exit_notice_error?(exception)
|
266
266
|
increment_error_count!(exception, options)
|
267
267
|
NewRelic::Agent.instance.events.notify(:notice_error, exception, options)
|
268
|
-
action_path
|
268
|
+
action_path = fetch_from_options(options, :metric, "")
|
269
269
|
exception_options = error_params_from_options(options).merge(exception_info(exception))
|
270
270
|
add_to_error_queue(NewRelic::NoticedError.new(action_path, exception_options, exception))
|
271
271
|
exception
|
@@ -42,14 +42,7 @@ module NewRelic
|
|
42
42
|
event = pop_event(id)
|
43
43
|
event.payload.merge!(payload)
|
44
44
|
|
45
|
-
set_enduser_ignore if event.enduser_ignored?
|
46
|
-
|
47
45
|
if NewRelic::Agent.is_execution_traced? && !event.ignored?
|
48
|
-
event.finalize_metric_name!
|
49
|
-
record_queue_time(event)
|
50
|
-
record_metrics(event)
|
51
|
-
record_apdex(event)
|
52
|
-
record_instance_busy(event)
|
53
46
|
stop_transaction(event)
|
54
47
|
else
|
55
48
|
Agent.instance.pop_trace_execution_flag
|
@@ -58,59 +51,19 @@ module NewRelic
|
|
58
51
|
log_notification_error(e, name, 'finish')
|
59
52
|
end
|
60
53
|
|
61
|
-
def set_enduser_ignore
|
62
|
-
TransactionState.get.request_ignore_enduser = true
|
63
|
-
end
|
64
|
-
|
65
|
-
def record_metrics(event)
|
66
|
-
controller_metric = MetricSpec.new(event.metric_name)
|
67
|
-
txn = Transaction.current
|
68
|
-
metrics = [ 'HttpDispatcher']
|
69
|
-
if txn.has_parent?
|
70
|
-
parent_metric = MetricSpec.new(event.metric_name, StatsEngine::MetricStats::SCOPE_PLACEHOLDER)
|
71
|
-
record_metric_on_parent_transaction(parent_metric, event.duration)
|
72
|
-
end
|
73
|
-
metrics << controller_metric.dup
|
74
|
-
|
75
|
-
Agent.instance.stats_engine.record_metrics(metrics, event.duration)
|
76
|
-
end
|
77
|
-
|
78
|
-
def record_metric_on_parent_transaction(metric, time)
|
79
|
-
NewRelic::Agent::Transaction.parent.stats_hash.record(metric, time)
|
80
|
-
end
|
81
|
-
|
82
|
-
def record_apdex(event)
|
83
|
-
return if event.apdex_ignored?
|
84
|
-
Transaction.record_apdex(event.end, event.exception_encountered?)
|
85
|
-
end
|
86
|
-
|
87
|
-
def record_instance_busy(event)
|
88
|
-
BusyCalculator.dispatcher_start(event.time)
|
89
|
-
BusyCalculator.dispatcher_finish(event.end)
|
90
|
-
end
|
91
|
-
|
92
|
-
def record_queue_time(event)
|
93
|
-
return unless event.queue_start
|
94
|
-
return unless NewRelic::Agent::Transaction.current.root?
|
95
|
-
QueueTime.record_frontend_metrics(event.queue_start, event.time)
|
96
|
-
end
|
97
|
-
|
98
54
|
def start_transaction(event)
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
event.scope = Agent.instance.stats_engine \
|
106
|
-
.push_scope(:action_controller, event.time)
|
55
|
+
Transaction.start(:controller,
|
56
|
+
:request => event.request,
|
57
|
+
:filtered_params => filter(event.payload[:params]),
|
58
|
+
:apdex_start_time => event.queue_start,
|
59
|
+
:transaction_name => event.metric_name)
|
107
60
|
end
|
108
61
|
|
109
62
|
def stop_transaction(event)
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
63
|
+
Transaction.stop(Time.now,
|
64
|
+
:exception_encountered => event.exception_encountered?,
|
65
|
+
:ignore_apdex => event.apdex_ignored?,
|
66
|
+
:ignore_enduser => event.enduser_ignored?)
|
114
67
|
end
|
115
68
|
|
116
69
|
def filter(params)
|
@@ -120,7 +73,7 @@ module NewRelic
|
|
120
73
|
end
|
121
74
|
|
122
75
|
class ControllerEvent < Event
|
123
|
-
attr_accessor :parent
|
76
|
+
attr_accessor :parent
|
124
77
|
attr_reader :queue_start, :request
|
125
78
|
|
126
79
|
def initialize(name, start, ending, transaction_id, payload, request)
|
@@ -140,18 +93,6 @@ module NewRelic
|
|
140
93
|
@metric_name || "Controller/#{metric_path}/#{metric_action}"
|
141
94
|
end
|
142
95
|
|
143
|
-
def finalize_metric_name!
|
144
|
-
txn = NewRelic::Agent::Transaction.current
|
145
|
-
|
146
|
-
# the event provides the default name but the transaction has the final say
|
147
|
-
txn.name ||= metric_name
|
148
|
-
|
149
|
-
# this applies the transaction name rules if not already applied
|
150
|
-
txn.freeze_name
|
151
|
-
@metric_name = txn.name
|
152
|
-
return @metric_name
|
153
|
-
end
|
154
|
-
|
155
96
|
def metric_path
|
156
97
|
@controller_class.controller_path
|
157
98
|
end
|
@@ -14,8 +14,7 @@ module NewRelic
|
|
14
14
|
push_event(event)
|
15
15
|
|
16
16
|
if NewRelic::Agent.is_execution_traced? && event.recordable?
|
17
|
-
event.
|
18
|
-
.push_scope(:action_view, event.time)
|
17
|
+
event.frame = NewRelic::Agent::TracedMethodStack.push_frame(:action_view, event.time)
|
19
18
|
end
|
20
19
|
rescue => e
|
21
20
|
log_notification_error(e, name, 'start')
|
@@ -25,16 +24,15 @@ module NewRelic
|
|
25
24
|
event = pop_event(id)
|
26
25
|
|
27
26
|
if NewRelic::Agent.is_execution_traced? && event.recordable?
|
28
|
-
|
29
|
-
|
30
|
-
record_metrics(event, scope)
|
27
|
+
frame = NewRelic::Agent::TracedMethodStack.pop_frame(event.frame, event.metric_name, event.end)
|
28
|
+
record_metrics(event, frame)
|
31
29
|
end
|
32
30
|
rescue => e
|
33
31
|
log_notification_error(e, name, 'finish')
|
34
32
|
end
|
35
33
|
|
36
|
-
def record_metrics(event,
|
37
|
-
exclusive = event.duration -
|
34
|
+
def record_metrics(event, frame)
|
35
|
+
exclusive = event.duration - frame.children_time
|
38
36
|
metric_specs = [
|
39
37
|
NewRelic::MetricSpec.new(event.metric_name),
|
40
38
|
NewRelic::MetricSpec.new(event.metric_name, StatsEngine::MetricStats::SCOPE_PLACEHOLDER)
|
@@ -42,7 +42,7 @@ module NewRelic
|
|
42
42
|
metric = base_metric(event)
|
43
43
|
|
44
44
|
# enter transaction trace segment
|
45
|
-
|
45
|
+
frame = NewRelic::Agent::TracedMethodStack.push_frame(:active_record, event.time)
|
46
46
|
|
47
47
|
NewRelic::Agent.instance.transaction_sampler \
|
48
48
|
.notice_sql(event.payload[:sql], config,
|
@@ -55,7 +55,7 @@ module NewRelic
|
|
55
55
|
&method(:get_explain_plan))
|
56
56
|
|
57
57
|
# exit transaction trace segment
|
58
|
-
NewRelic::Agent.
|
58
|
+
NewRelic::Agent::TracedMethodStack.pop_frame(frame, metric, event.end)
|
59
59
|
end
|
60
60
|
|
61
61
|
def record_metrics(event)
|
@@ -147,60 +147,67 @@ module NewRelic
|
|
147
147
|
def add_transaction_tracer(method, options={})
|
148
148
|
# The metric path:
|
149
149
|
options[:name] ||= method.to_s
|
150
|
-
# create the argument list:
|
151
|
-
options_arg = []
|
152
|
-
options.each do |key, value|
|
153
|
-
valuestr = case
|
154
|
-
when value.is_a?(Symbol)
|
155
|
-
value.inspect
|
156
|
-
when key == :params
|
157
|
-
value.to_s
|
158
|
-
else
|
159
|
-
%Q["#{value.to_s}"]
|
160
|
-
end
|
161
|
-
options_arg << %Q[:#{key} => #{valuestr}]
|
162
|
-
end
|
163
|
-
traced_method, punctuation = method.to_s.sub(/([?!=])$/, ''), $1
|
164
|
-
visibility = NewRelic::Helper.instance_method_visibility self, method
|
165
150
|
|
166
|
-
|
167
|
-
|
151
|
+
argument_list = generate_argument_list(options)
|
152
|
+
traced_method, punctuation = parse_punctuation(method)
|
153
|
+
with_method_name, without_method_name = build_method_names(traced_method, punctuation)
|
168
154
|
|
169
|
-
if
|
155
|
+
if already_added_transaction_tracer?(self, with_method_name)
|
170
156
|
::NewRelic::Agent.logger.warn("Transaction tracer already in place for class = #{self.name}, method = #{method.to_s}, skipping")
|
171
157
|
return
|
172
158
|
end
|
173
159
|
|
174
160
|
class_eval <<-EOC
|
175
|
-
def #{
|
176
|
-
perform_action_with_newrelic_trace(#{
|
177
|
-
#{
|
161
|
+
def #{with_method_name}(*args, &block)
|
162
|
+
perform_action_with_newrelic_trace(#{argument_list.join(',')}) do
|
163
|
+
#{without_method_name}(*args, &block)
|
178
164
|
end
|
179
165
|
end
|
180
166
|
EOC
|
167
|
+
|
168
|
+
visibility = NewRelic::Helper.instance_method_visibility self, method
|
169
|
+
|
181
170
|
alias_method without_method_name, method.to_s
|
182
171
|
alias_method method.to_s, with_method_name
|
183
172
|
send visibility, method
|
184
173
|
send visibility, with_method_name
|
185
174
|
::NewRelic::Agent.logger.debug("Traced transaction: class = #{self.name}, method = #{method.to_s}, options = #{options.inspect}")
|
186
175
|
end
|
187
|
-
end
|
188
176
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
177
|
+
def parse_punctuation(method)
|
178
|
+
[method.to_s.sub(/([?!=])$/, ''), $1]
|
179
|
+
end
|
180
|
+
|
181
|
+
def generate_argument_list(options)
|
182
|
+
options.map do |key, value|
|
183
|
+
value = if value.is_a?(Symbol)
|
184
|
+
value.inspect
|
185
|
+
elsif key == :params
|
186
|
+
value.to_s
|
187
|
+
else
|
188
|
+
%Q["#{value.to_s}"]
|
189
|
+
end
|
190
|
+
|
191
|
+
%Q[:#{key} => #{value}]
|
196
192
|
end
|
197
193
|
end
|
198
194
|
|
199
|
-
def
|
200
|
-
|
195
|
+
def build_method_names(traced_method, punctuation)
|
196
|
+
[ "#{traced_method.to_s}_with_newrelic_transaction_trace#{punctuation}",
|
197
|
+
"#{traced_method.to_s}_without_newrelic_transaction_trace#{punctuation}" ]
|
198
|
+
end
|
199
|
+
|
200
|
+
def already_added_transaction_tracer?(target, with_method_name)
|
201
|
+
if NewRelic::Helper.instance_methods_include?(target, with_method_name)
|
202
|
+
true
|
203
|
+
else
|
204
|
+
false
|
205
|
+
end
|
201
206
|
end
|
207
|
+
end
|
202
208
|
|
203
|
-
|
209
|
+
class TransactionNamer
|
210
|
+
def self.category_name(type = nil)
|
204
211
|
type ||= Transaction.current && Transaction.current.type
|
205
212
|
case type
|
206
213
|
when :controller, nil then 'Controller'
|
@@ -213,6 +220,19 @@ module NewRelic
|
|
213
220
|
end
|
214
221
|
end
|
215
222
|
|
223
|
+
def initialize(traced_obj)
|
224
|
+
@traced_obj = traced_obj
|
225
|
+
if (@traced_obj.is_a?(Class) || @traced_obj.is_a?(Module))
|
226
|
+
@traced_class_name = @traced_obj.name
|
227
|
+
else
|
228
|
+
@traced_class_name = @traced_obj.class.name
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def name(options={})
|
233
|
+
name = "#{self.class.category_name(options[:category])}/#{path_name(options)}"
|
234
|
+
end
|
235
|
+
|
216
236
|
def path_name(options={})
|
217
237
|
# if we have the path, use the path
|
218
238
|
path = options[:path]
|
@@ -294,8 +314,6 @@ module NewRelic
|
|
294
314
|
#
|
295
315
|
# Seldomly used options:
|
296
316
|
#
|
297
|
-
# * <tt>:force => true</tt> indicates you should capture all
|
298
|
-
# metrics even if the #newrelic_ignore directive was specified
|
299
317
|
# * <tt>:class_name => aClass.name</tt> is used to override the name
|
300
318
|
# of the class when used inside the metric name. Default is the
|
301
319
|
# current class.
|
@@ -322,16 +340,19 @@ module NewRelic
|
|
322
340
|
end
|
323
341
|
end
|
324
342
|
|
325
|
-
|
343
|
+
# If a block was passed in, then the arguments represent options for
|
344
|
+
# the instrumentation, not app method arguments.
|
345
|
+
txn_options = create_transaction_options(block_given? ? args : [])
|
346
|
+
return yield unless NewRelic::Agent.is_execution_traced?
|
347
|
+
|
348
|
+
txn_options[:transaction_name] = TransactionNamer.new(self).name(txn_options)
|
349
|
+
txn_options[:apdex_start_time] = detect_queue_start_time
|
350
|
+
|
326
351
|
begin
|
327
|
-
|
328
|
-
|
329
|
-
options[:metric] = true if options[:metric].nil?
|
330
|
-
options[:deduct_call_time_from_parent] = true if options[:deduct_call_time_from_parent].nil?
|
331
|
-
_, expected_scope = NewRelic::Agent::MethodTracer::TraceExecutionScoped.trace_execution_scoped_header(options, txn.start_time.to_f)
|
352
|
+
txn = Transaction.start(txn_options[:category], txn_options)
|
353
|
+
_record_queue_length
|
332
354
|
|
333
355
|
begin
|
334
|
-
NewRelic::Agent::BusyCalculator.dispatcher_start txn.start_time
|
335
356
|
if block_given?
|
336
357
|
yield
|
337
358
|
else
|
@@ -343,28 +364,12 @@ module NewRelic
|
|
343
364
|
end
|
344
365
|
|
345
366
|
ensure
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
metric_names = Array(recorded_metrics(txn))
|
350
|
-
txn_name = metric_names.shift
|
351
|
-
|
352
|
-
NewRelic::Agent::MethodTracer::TraceExecutionScoped.trace_execution_scoped_footer(txn.start_time.to_f, txn_name, metric_names, expected_scope, options, end_time.to_f)
|
353
|
-
NewRelic::Agent::BusyCalculator.dispatcher_finish(end_time)
|
354
|
-
txn.record_apdex(end_time) unless ignore_apdex?
|
355
|
-
txn = Transaction.stop(txn_name, end_time)
|
356
|
-
|
357
|
-
NewRelic::Agent::TransactionState.get.request_ignore_enduser = true if ignore_enduser?
|
367
|
+
Transaction.stop(Time.now,
|
368
|
+
:ignore_apdex => ignore_apdex?,
|
369
|
+
:ignore_enduser => ignore_enduser?)
|
358
370
|
end
|
359
371
|
end
|
360
372
|
|
361
|
-
def recorded_metrics(txn)
|
362
|
-
metric_parser = NewRelic::MetricParser::MetricParser.for_metric_named(txn.name)
|
363
|
-
metrics = [txn.name]
|
364
|
-
metrics += metric_parser.summary_metrics unless txn.has_parent?
|
365
|
-
metrics
|
366
|
-
end
|
367
|
-
|
368
373
|
protected
|
369
374
|
|
370
375
|
def newrelic_request(args)
|
@@ -417,32 +422,21 @@ module NewRelic
|
|
417
422
|
|
418
423
|
private
|
419
424
|
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
options = {}
|
426
|
-
if args.any?
|
427
|
-
if args.last.is_a?(Hash)
|
428
|
-
options = args.pop
|
425
|
+
def create_transaction_options(txn_args)
|
426
|
+
txn_options = {}
|
427
|
+
if txn_args.any?
|
428
|
+
if txn_args.last.is_a?(Hash)
|
429
|
+
txn_options = txn_args.pop
|
429
430
|
end
|
430
|
-
available_params =
|
431
|
-
|
431
|
+
available_params = txn_options[:params] || {}
|
432
|
+
txn_options[:name] ||= txn_args.first
|
432
433
|
else
|
433
434
|
available_params = self.respond_to?(:params) ? self.params : {}
|
434
435
|
end
|
435
436
|
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
txn = Transaction.start(category, options)
|
440
|
-
txn.name = TransactionNamer.new(self).name(options)
|
441
|
-
|
442
|
-
txn.apdex_start = _detect_upstream_wait(txn)
|
443
|
-
_record_queue_length
|
444
|
-
|
445
|
-
return txn
|
437
|
+
txn_options[:request] ||= self.request if self.respond_to? :request
|
438
|
+
txn_options[:filtered_params] = (respond_to? :filter_parameters) ? filter_parameters(available_params) : available_params
|
439
|
+
txn_options
|
446
440
|
end
|
447
441
|
|
448
442
|
# Filter out a request if it matches one of our parameters for
|
@@ -473,20 +467,10 @@ module NewRelic
|
|
473
467
|
end
|
474
468
|
end
|
475
469
|
|
476
|
-
|
477
|
-
# now is a Time instance to fall back on if no other candidate
|
478
|
-
# for the start time is found.
|
479
|
-
def _detect_upstream_wait(txn)
|
480
|
-
now = txn.start_time
|
481
|
-
return now unless txn.root?
|
470
|
+
def detect_queue_start_time
|
482
471
|
if newrelic_request_headers
|
483
|
-
|
484
|
-
QueueTime.record_frontend_metrics(queue_start, now) if queue_start
|
472
|
+
QueueTime.parse_frontend_timestamp(newrelic_request_headers)
|
485
473
|
end
|
486
|
-
queue_start || now
|
487
|
-
rescue => e
|
488
|
-
::NewRelic::Agent.logger.error("Error detecting upstream wait time:", e)
|
489
|
-
now
|
490
474
|
end
|
491
475
|
end
|
492
476
|
end
|