newrelic_rpm 3.9.9.275 → 3.10.0.279
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 +51 -0
- data/config.dot +0 -3
- data/lib/new_relic/agent.rb +7 -5
- data/lib/new_relic/agent/agent.rb +4 -4
- data/lib/new_relic/agent/instrumentation/active_job.rb +5 -8
- data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +17 -34
- data/lib/new_relic/agent/instrumentation/grape.rb +60 -23
- data/lib/new_relic/agent/instrumentation/merb/controller.rb +10 -2
- data/lib/new_relic/agent/instrumentation/middleware_tracing.rb +33 -21
- data/lib/new_relic/agent/instrumentation/rails/action_controller.rb +7 -3
- data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +0 -9
- data/lib/new_relic/agent/instrumentation/sinatra.rb +9 -12
- data/lib/new_relic/agent/javascript_instrumentor.rb +1 -0
- data/lib/new_relic/agent/new_relic_service.rb +9 -6
- data/lib/new_relic/agent/parameter_filtering.rb +37 -0
- data/lib/new_relic/agent/supported_versions.rb +7 -0
- data/lib/new_relic/agent/traced_method_stack.rb +1 -1
- data/lib/new_relic/agent/transaction.rb +182 -186
- data/lib/new_relic/agent/vm/rubinius_vm.rb +93 -3
- data/lib/new_relic/control/frameworks/rails.rb +1 -0
- data/lib/new_relic/rack/agent_hooks.rb +15 -23
- data/lib/new_relic/version.rb +2 -2
- data/newrelic_rpm.gemspec +12 -5
- data/test/agent_helper.rb +26 -14
- data/test/multiverse/lib/multiverse/suite.rb +1 -5
- data/test/multiverse/suites/activemerchant/Envfile +4 -1
- data/test/multiverse/suites/agent_only/cross_application_tracing_test.rb +2 -12
- data/test/multiverse/suites/agent_only/logging_test.rb +1 -1
- data/test/multiverse/suites/agent_only/set_transaction_name_test.rb +4 -0
- data/test/multiverse/suites/agent_only/synthetics_test.rb +1 -8
- data/test/multiverse/suites/agent_only/testing_app.rb +1 -7
- data/test/multiverse/suites/agent_only/xray_sessions_test.rb +11 -11
- data/test/multiverse/suites/deferred_instrumentation/sinatra_test.rb +4 -0
- data/test/multiverse/suites/grape/Envfile +1 -3
- data/test/multiverse/suites/grape/grape_test.rb +87 -6
- data/test/multiverse/suites/grape/grape_test_api.rb +5 -0
- data/test/multiverse/suites/grape/grape_versioning_test.rb +67 -0
- data/test/multiverse/suites/grape/grape_versioning_test_api.rb +72 -0
- data/test/multiverse/suites/rack/example_app.rb +31 -1
- data/test/multiverse/suites/rack/rack_auto_instrumentation_test.rb +11 -10
- data/test/multiverse/suites/rack/rack_cascade_test.rb +46 -0
- data/test/multiverse/suites/rack/rack_parameter_filtering_test.rb +40 -0
- data/test/multiverse/suites/rails/Envfile +8 -0
- data/test/multiverse/suites/rails/activejob_test.rb +16 -0
- data/test/multiverse/suites/rails/gc_instrumentation_test.rb +4 -2
- data/test/multiverse/suites/rails/parameter_capture_test.rb +49 -0
- data/test/multiverse/suites/rails/rails3_app/app_rails3_plus.rb +12 -1
- data/test/multiverse/suites/sinatra/sinatra_classic_test.rb +4 -0
- data/test/multiverse/suites/sinatra/sinatra_modular_test.rb +4 -0
- data/test/multiverse/suites/sinatra/sinatra_test_cases.rb +11 -0
- data/test/new_relic/agent/instrumentation/controller_instrumentation_test.rb +0 -58
- data/test/new_relic/agent/instrumentation/middleware_proxy_test.rb +49 -0
- data/test/new_relic/agent/instrumentation/middleware_tracing_test.rb +26 -14
- data/test/new_relic/agent/parameter_filtering_test.rb +39 -0
- data/test/new_relic/agent/stats_engine/gc_profiler_test.rb +1 -1
- data/test/new_relic/agent/transaction_test.rb +106 -2
- data/test/new_relic/agent/vm/rubinius_vm_test.rb +38 -37
- data/test/new_relic/agent_test.rb +8 -3
- data/test/new_relic/filtering_test_app.rb +18 -0
- data/test/new_relic/latest_changes_test.rb +1 -1
- data/test/new_relic/rack/browser_monitoring_test.rb +4 -4
- data/test/performance/lib/performance/instrumentation/gc_stats.rb +6 -4
- data/test/performance/lib/performance/platform.rb +1 -0
- data/test/performance/suites/thread_profiling.rb +12 -0
- metadata +38 -15
- metadata.gz.sig +2 -1
@@ -95,10 +95,14 @@ DependencyDetection.defer do
|
|
95
95
|
ActionController::Base.class_eval do
|
96
96
|
include NewRelic::Agent::Instrumentation::ControllerInstrumentation
|
97
97
|
|
98
|
-
|
99
|
-
|
98
|
+
def perform_action_with_newrelic_trace_wrapper
|
99
|
+
options = {}
|
100
|
+
options[:params] = (respond_to?(:filter_parameters)) ? filter_parameters(params) : params
|
101
|
+
perform_action_with_newrelic_trace(options) { perform_action_without_newrelic_trace }
|
102
|
+
end
|
103
|
+
|
100
104
|
alias_method :perform_action_without_newrelic_trace, :perform_action
|
101
|
-
alias_method :perform_action, :
|
105
|
+
alias_method :perform_action, :perform_action_with_newrelic_trace_wrapper
|
102
106
|
private :perform_action
|
103
107
|
|
104
108
|
# determine the path that is used in the metric name for
|
@@ -19,15 +19,6 @@ module NewRelic
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def process_action(*args) #THREAD_LOCAL_ACCESS
|
22
|
-
# skip instrumentation if we are in an ignored action
|
23
|
-
if _is_filtered?(ControllerInstrumentation::NR_DO_NOT_TRACE_KEY)
|
24
|
-
txn = NewRelic::Agent::Transaction.tl_current
|
25
|
-
txn.ignore! if txn
|
26
|
-
NewRelic::Agent.disable_all_tracing do
|
27
|
-
return super
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
22
|
perform_action_with_newrelic_trace(:category => :controller, :name => self.action_name, :path => newrelic_metric_path, :params => request.filtered_parameters, :class_name => self.class.name) do
|
32
23
|
super
|
33
24
|
end
|
@@ -85,8 +85,11 @@ module NewRelic
|
|
85
85
|
|
86
86
|
module ClassMethods
|
87
87
|
def newrelic_middlewares
|
88
|
-
[
|
89
|
-
|
88
|
+
middlewares = [NewRelic::Rack::BrowserMonitoring]
|
89
|
+
if NewRelic::Rack::AgentHooks.needed?
|
90
|
+
middlewares << NewRelic::Rack::AgentHooks
|
91
|
+
end
|
92
|
+
middlewares
|
90
93
|
end
|
91
94
|
|
92
95
|
def build_with_newrelic(*args, &block)
|
@@ -126,7 +129,7 @@ module NewRelic
|
|
126
129
|
txn_name = TransactionNamer.transaction_name_for_route(env, request)
|
127
130
|
unless txn_name.nil?
|
128
131
|
::NewRelic::Agent::Transaction.set_default_transaction_name(
|
129
|
-
"#{self.class.name}/#{txn_name}", :
|
132
|
+
"#{self.class.name}/#{txn_name}", :sinatra)
|
130
133
|
end
|
131
134
|
rescue => e
|
132
135
|
::NewRelic::Agent.logger.debug("Failed during route_eval to set transaction name", e)
|
@@ -136,19 +139,13 @@ module NewRelic
|
|
136
139
|
end
|
137
140
|
|
138
141
|
def dispatch_with_newrelic #THREAD_LOCAL_ACCESS
|
139
|
-
if ignore_request?
|
140
|
-
env['newrelic.ignored'] = true
|
141
|
-
txn = ::NewRelic::Agent::Transaction.tl_current
|
142
|
-
txn.ignore! if txn
|
143
|
-
return dispatch_without_newrelic
|
144
|
-
end
|
145
|
-
|
146
142
|
request_params = get_request_params
|
143
|
+
filtered_params = ParameterFiltering::apply_filters(request.env, request_params || {})
|
147
144
|
|
148
145
|
name = TransactionNamer.initial_transaction_name(request)
|
149
146
|
perform_action_with_newrelic_trace(:category => :sinatra,
|
150
147
|
:name => name,
|
151
|
-
:params =>
|
148
|
+
:params => filtered_params) do
|
152
149
|
dispatch_and_notice_errors_with_newrelic
|
153
150
|
end
|
154
151
|
end
|
@@ -171,7 +168,7 @@ module NewRelic
|
|
171
168
|
::NewRelic::Agent.notice_error(env['sinatra.error']) if had_error
|
172
169
|
end
|
173
170
|
|
174
|
-
def
|
171
|
+
def do_not_trace?
|
175
172
|
Ignorer.should_ignore?(self, :routes)
|
176
173
|
end
|
177
174
|
|
@@ -469,6 +469,8 @@ module NewRelic
|
|
469
469
|
end
|
470
470
|
end
|
471
471
|
|
472
|
+
log_response(response)
|
473
|
+
|
472
474
|
case response
|
473
475
|
when Net::HTTPSuccess
|
474
476
|
true # do nothing
|
@@ -488,16 +490,17 @@ module NewRelic
|
|
488
490
|
response
|
489
491
|
end
|
490
492
|
|
493
|
+
def log_response(response)
|
494
|
+
::NewRelic::Agent.logger.debug "Received response, status: #{response.code}, encoding: '#{response['content-encoding']}'"
|
495
|
+
end
|
496
|
+
|
491
497
|
# Decompresses the response from the server, if it is gzip
|
492
498
|
# encoded, otherwise returns it verbatim
|
493
499
|
def decompress_response(response)
|
494
|
-
if response['content-encoding']
|
495
|
-
::
|
496
|
-
response.body
|
500
|
+
if response['content-encoding'] == 'gzip'
|
501
|
+
Zlib::GzipReader.new(StringIO.new(response.body)).read
|
497
502
|
else
|
498
|
-
|
499
|
-
i = Zlib::GzipReader.new(StringIO.new(response.body))
|
500
|
-
i.read
|
503
|
+
response.body
|
501
504
|
end
|
502
505
|
end
|
503
506
|
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# This file is distributed under New Relic"s license terms.
|
3
|
+
# See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
|
4
|
+
|
5
|
+
module NewRelic
|
6
|
+
module Agent
|
7
|
+
module ParameterFiltering
|
8
|
+
extend self
|
9
|
+
|
10
|
+
def apply_filters(env, params)
|
11
|
+
params = filter_using_rails(env, params)
|
12
|
+
params = filter_rack_file_data(env, params)
|
13
|
+
params
|
14
|
+
end
|
15
|
+
|
16
|
+
def filter_using_rails(env, params)
|
17
|
+
return params unless defined?(ActionDispatch::Http::ParameterFilter) && env.key?("action_dispatch.parameter_filter")
|
18
|
+
filters = env["action_dispatch.parameter_filter"]
|
19
|
+
ActionDispatch::Http::ParameterFilter.new(filters).filter(params)
|
20
|
+
end
|
21
|
+
|
22
|
+
def filter_rack_file_data(env, params)
|
23
|
+
content_type = env["CONTENT_TYPE"]
|
24
|
+
multipart = content_type && content_type.start_with?("multipart")
|
25
|
+
|
26
|
+
params.inject({}) do |memo, (k,v)|
|
27
|
+
if multipart && v.is_a?(Hash) && v[:tempfile]
|
28
|
+
memo[k] = "[FILE]"
|
29
|
+
else
|
30
|
+
memo[k] = v
|
31
|
+
end
|
32
|
+
memo
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -113,6 +113,13 @@ module NewRelic
|
|
113
113
|
:url => "https://rubygems.org/gems/rack",
|
114
114
|
:feed => "https://rubygems.org/gems/rack/versions.atom"
|
115
115
|
},
|
116
|
+
:grape =>
|
117
|
+
{
|
118
|
+
:type => :web,
|
119
|
+
:supported => [">= 0.2.0"],
|
120
|
+
:url => "https://rubygems.org/gems/grape",
|
121
|
+
:feed => "https://rubygems.org/gems/grape/versions.atom"
|
122
|
+
},
|
116
123
|
|
117
124
|
# Database
|
118
125
|
:activerecord =>
|
@@ -6,7 +6,7 @@ module NewRelic
|
|
6
6
|
module Agent
|
7
7
|
class TracedMethodFrame
|
8
8
|
attr_reader :tag
|
9
|
-
attr_accessor :name, :start_time, :children_time
|
9
|
+
attr_accessor :name, :start_time, :children_time
|
10
10
|
def initialize(tag, start_time)
|
11
11
|
@tag = tag
|
12
12
|
@start_time = start_time
|
@@ -22,16 +22,21 @@ module NewRelic
|
|
22
22
|
TASK_PREFIX = 'OtherTransaction/Background/'.freeze
|
23
23
|
RACK_PREFIX = 'Controller/Rack/'.freeze
|
24
24
|
SINATRA_PREFIX = 'Controller/Sinatra/'.freeze
|
25
|
+
GRAPE_PREFIX = 'Controller/Grape/'.freeze
|
25
26
|
OTHER_TRANSACTION_PREFIX = 'OtherTransaction/'.freeze
|
26
27
|
|
27
28
|
CONTROLLER_MIDDLEWARE_PREFIX = 'Controller/Middleware/Rack'.freeze
|
28
29
|
|
29
30
|
NESTED_TRACE_STOP_OPTIONS = { :metric => true }.freeze
|
30
|
-
WEB_TRANSACTION_CATEGORIES = [:controller, :uri, :rack, :sinatra, :middleware].freeze
|
31
|
+
WEB_TRANSACTION_CATEGORIES = [:controller, :uri, :rack, :sinatra, :grape, :middleware].freeze
|
32
|
+
TRANSACTION_NAMING_SOURCES = [:child, :api].freeze
|
31
33
|
|
32
34
|
MIDDLEWARE_SUMMARY_METRICS = ['Middleware/all'.freeze].freeze
|
33
35
|
EMPTY_SUMMARY_METRICS = [].freeze
|
34
36
|
|
37
|
+
TRACE_OPTIONS_SCOPED = { :metric => true, :scoped_metric => true }.freeze
|
38
|
+
TRACE_OPTIONS_UNSCOPED = { :metric => true, :scoped_metric => false }.freeze
|
39
|
+
|
35
40
|
# A Time instance for the start time, never nil
|
36
41
|
attr_accessor :start_time
|
37
42
|
|
@@ -43,7 +48,8 @@ module NewRelic
|
|
43
48
|
attr_accessor :exceptions,
|
44
49
|
:filtered_params,
|
45
50
|
:jruby_cpu_start,
|
46
|
-
:process_cpu_start
|
51
|
+
:process_cpu_start,
|
52
|
+
:http_response_code
|
47
53
|
|
48
54
|
# Give the current transaction a request context. Use this to
|
49
55
|
# get the URI and referer. The request is interpreted loosely
|
@@ -58,7 +64,8 @@ module NewRelic
|
|
58
64
|
:metrics,
|
59
65
|
:gc_start_snapshot,
|
60
66
|
:category,
|
61
|
-
:
|
67
|
+
:frame_stack,
|
68
|
+
:cat_path_hashes
|
62
69
|
|
63
70
|
# Populated with the trace sample once this transaction is completed.
|
64
71
|
attr_reader :transaction_trace
|
@@ -71,63 +78,46 @@ module NewRelic
|
|
71
78
|
TransactionState.tl_get.current_transaction
|
72
79
|
end
|
73
80
|
|
74
|
-
def self.set_default_transaction_name(name,
|
81
|
+
def self.set_default_transaction_name(name, category = nil, segment_name = nil) #THREAD_LOCAL_ACCESS
|
75
82
|
txn = tl_current
|
76
|
-
name = txn.make_transaction_name(name,
|
77
|
-
|
78
|
-
|
79
|
-
txn.set_default_transaction_name(name, options)
|
80
|
-
else
|
81
|
-
txn.frame_stack.last.name = name
|
82
|
-
txn.frame_stack.last.category = options[:category] if options[:category]
|
83
|
-
end
|
83
|
+
name = txn.make_transaction_name(name, category)
|
84
|
+
txn.name_last_frame(segment_name || name)
|
85
|
+
txn.set_default_transaction_name(name, category)
|
84
86
|
end
|
85
87
|
|
86
|
-
def self.set_overriding_transaction_name(name,
|
88
|
+
def self.set_overriding_transaction_name(name, category = nil) #THREAD_LOCAL_ACCESS
|
87
89
|
txn = tl_current
|
88
90
|
return unless txn
|
89
91
|
|
90
|
-
name = txn.make_transaction_name(name,
|
92
|
+
name = txn.make_transaction_name(name, category)
|
91
93
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
txn.frame_stack.last.name = name
|
96
|
-
txn.frame_stack.last.category = options[:category] if options[:category]
|
94
|
+
txn.name_last_frame(name)
|
95
|
+
txn.set_overriding_transaction_name(name, category)
|
96
|
+
end
|
97
97
|
|
98
|
-
|
99
|
-
|
100
|
-
child_is_web_category = transaction_category_is_web?(txn.frame_stack.last.category)
|
101
|
-
txn_is_web_category = transaction_category_is_web?(txn.category)
|
98
|
+
def self.wrap(state, name, category, options = {})
|
99
|
+
Transaction.start(state, category, options.merge(:transaction_name => name))
|
102
100
|
|
103
|
-
|
104
|
-
|
105
|
-
|
101
|
+
begin
|
102
|
+
# We shouldn't raise from Transaction.start, but only wrap the yield
|
103
|
+
# to be absolutely sure we don't report agent problems as app errors
|
104
|
+
yield
|
105
|
+
rescue => e
|
106
|
+
Transaction.notice_error(e)
|
107
|
+
raise e
|
108
|
+
ensure
|
109
|
+
Transaction.stop(state)
|
106
110
|
end
|
107
111
|
end
|
108
112
|
|
109
|
-
def make_transaction_name(name, category=nil)
|
110
|
-
namer = Instrumentation::ControllerInstrumentation::TransactionNamer
|
111
|
-
"#{namer.prefix_for_category(self, category)}#{name}"
|
112
|
-
end
|
113
|
-
|
114
113
|
def self.start(state, category, options)
|
115
114
|
category ||= :controller
|
116
115
|
txn = state.current_transaction
|
117
116
|
|
118
117
|
if txn
|
119
|
-
|
120
|
-
txn.filtered_params = options[:filtered_params]
|
121
|
-
end
|
122
|
-
|
123
|
-
nested_frame = NewRelic::Agent::MethodTracerHelpers.trace_execution_scoped_header(state, Time.now.to_f)
|
124
|
-
nested_frame.name = options[:transaction_name]
|
125
|
-
nested_frame.category = category
|
126
|
-
txn.frame_stack << nested_frame
|
118
|
+
txn.create_nested_frame(state, category, options)
|
127
119
|
else
|
128
|
-
txn =
|
129
|
-
state.reset(txn)
|
130
|
-
txn.start(state)
|
120
|
+
txn = start_new_transaction(state, category, options)
|
131
121
|
end
|
132
122
|
|
133
123
|
txn
|
@@ -136,6 +126,13 @@ module NewRelic
|
|
136
126
|
nil
|
137
127
|
end
|
138
128
|
|
129
|
+
def self.start_new_transaction(state, category, options)
|
130
|
+
txn = Transaction.new(category, options)
|
131
|
+
state.reset(txn)
|
132
|
+
txn.start(state)
|
133
|
+
txn
|
134
|
+
end
|
135
|
+
|
139
136
|
FAILED_TO_STOP_MESSAGE = "Failed during Transaction.stop because there is no current transaction"
|
140
137
|
|
141
138
|
def self.stop(state, end_time=Time.now)
|
@@ -146,22 +143,12 @@ module NewRelic
|
|
146
143
|
return
|
147
144
|
end
|
148
145
|
|
146
|
+
nested_frame = txn.frame_stack.pop
|
147
|
+
|
149
148
|
if txn.frame_stack.empty?
|
150
|
-
txn.stop(state, end_time)
|
149
|
+
txn.stop(state, end_time, nested_frame)
|
151
150
|
state.reset
|
152
151
|
else
|
153
|
-
nested_frame = txn.frame_stack.pop
|
154
|
-
|
155
|
-
# Parent transaction inherits the name of the first child
|
156
|
-
# to complete, if they are both/neither web transactions.
|
157
|
-
nested_is_web_category = transaction_category_is_web?(nested_frame.category)
|
158
|
-
txn_is_web_category = transaction_category_is_web?(txn.category)
|
159
|
-
|
160
|
-
if (nested_is_web_category == txn_is_web_category)
|
161
|
-
# first child to finish wins
|
162
|
-
txn.name_from_child ||= nested_frame.name
|
163
|
-
end
|
164
|
-
|
165
152
|
nested_name = nested_transaction_name(nested_frame.name)
|
166
153
|
|
167
154
|
if nested_name.start_with?(MIDDLEWARE_PREFIX)
|
@@ -195,6 +182,88 @@ module NewRelic
|
|
195
182
|
end
|
196
183
|
end
|
197
184
|
|
185
|
+
# Indicate that you don't want to keep the currently saved transaction
|
186
|
+
# information
|
187
|
+
def self.abort_transaction! #THREAD_LOCAL_ACCESS
|
188
|
+
state = NewRelic::Agent::TransactionState.tl_get
|
189
|
+
txn = state.current_transaction
|
190
|
+
txn.abort_transaction!(state) if txn
|
191
|
+
end
|
192
|
+
|
193
|
+
# If we have an active transaction, notice the error and increment the error metric.
|
194
|
+
# Options:
|
195
|
+
# * <tt>:request</tt> => Request object to get the uri and referer
|
196
|
+
# * <tt>:uri</tt> => The request path, minus any request params or query string.
|
197
|
+
# * <tt>:referer</tt> => The URI of the referer
|
198
|
+
# * <tt>:metric</tt> => The metric name associated with the transaction
|
199
|
+
# * <tt>:request_params</tt> => Request parameters, already filtered if necessary
|
200
|
+
# * <tt>:custom_params</tt> => Custom parameters
|
201
|
+
# Anything left over is treated as custom params
|
202
|
+
|
203
|
+
def self.notice_error(e, options={}) #THREAD_LOCAL_ACCESS
|
204
|
+
options = extract_request_options(options)
|
205
|
+
state = NewRelic::Agent::TransactionState.tl_get
|
206
|
+
txn = state.current_transaction
|
207
|
+
if txn
|
208
|
+
txn.notice_error(e, options)
|
209
|
+
else
|
210
|
+
NewRelic::Agent.instance.error_collector.notice_error(e, options)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def self.extract_request_options(options)
|
215
|
+
req = options.delete(:request)
|
216
|
+
if req
|
217
|
+
options[:uri] = uri_from_request(req)
|
218
|
+
options[:referer] = referer_from_request(req)
|
219
|
+
end
|
220
|
+
options
|
221
|
+
end
|
222
|
+
|
223
|
+
# Returns truthy if the current in-progress transaction is considered a
|
224
|
+
# a web transaction (as opposed to, e.g., a background transaction).
|
225
|
+
#
|
226
|
+
# @api public
|
227
|
+
#
|
228
|
+
def self.recording_web_transaction? #THREAD_LOCAL_ACCESS
|
229
|
+
txn = tl_current
|
230
|
+
txn && txn.recording_web_transaction?
|
231
|
+
end
|
232
|
+
|
233
|
+
# Make a safe attempt to get the referer from a request object, generally successful when
|
234
|
+
# it's a Rack request.
|
235
|
+
def self.referer_from_request(req)
|
236
|
+
if req && req.respond_to?(:referer)
|
237
|
+
req.referer.to_s.split('?').first
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
# Make a safe attempt to get the URI, without the host and query string.
|
242
|
+
def self.uri_from_request(req)
|
243
|
+
approximate_uri = case
|
244
|
+
when req.respond_to?(:fullpath ) then req.fullpath
|
245
|
+
when req.respond_to?(:path ) then req.path
|
246
|
+
when req.respond_to?(:request_uri) then req.request_uri
|
247
|
+
when req.respond_to?(:uri ) then req.uri
|
248
|
+
when req.respond_to?(:url ) then req.url
|
249
|
+
end
|
250
|
+
return approximate_uri[%r{^(https?://.*?)?(/[^?]*)}, 2] || '/' if approximate_uri
|
251
|
+
end
|
252
|
+
|
253
|
+
|
254
|
+
def self.apdex_bucket(duration, failed, apdex_t)
|
255
|
+
case
|
256
|
+
when failed
|
257
|
+
:apdex_f
|
258
|
+
when duration <= apdex_t
|
259
|
+
:apdex_s
|
260
|
+
when duration <= 4 * apdex_t
|
261
|
+
:apdex_t
|
262
|
+
else
|
263
|
+
:apdex_f
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
198
267
|
@@java_classes_loaded = false
|
199
268
|
|
200
269
|
if defined? JRuby
|
@@ -207,16 +276,13 @@ module NewRelic
|
|
207
276
|
end
|
208
277
|
end
|
209
278
|
|
210
|
-
attr_reader :frame_stack, :cat_path_hashes
|
211
|
-
attr_accessor :http_response_code
|
212
|
-
|
213
279
|
def initialize(category, options)
|
214
280
|
@frame_stack = []
|
281
|
+
@has_children = false
|
215
282
|
|
216
|
-
|
217
|
-
@
|
218
|
-
@
|
219
|
-
@frozen_name = nil
|
283
|
+
self.default_name = options[:transaction_name]
|
284
|
+
@overridden_name = nil
|
285
|
+
@frozen_name = nil
|
220
286
|
|
221
287
|
@category = category
|
222
288
|
@start_time = Time.now
|
@@ -240,57 +306,67 @@ module NewRelic
|
|
240
306
|
@noticed_error_ids ||= []
|
241
307
|
end
|
242
308
|
|
243
|
-
def
|
244
|
-
@
|
309
|
+
def overridden_name=(name)
|
310
|
+
@overridden_name = Helper.correctly_encoded(name)
|
245
311
|
end
|
246
312
|
|
247
|
-
def
|
248
|
-
@
|
313
|
+
def default_name=(name)
|
314
|
+
@default_name = Helper.correctly_encoded(name)
|
249
315
|
end
|
250
316
|
|
251
|
-
def
|
252
|
-
|
253
|
-
|
317
|
+
def create_nested_frame(state, category, options)
|
318
|
+
@has_children = true
|
319
|
+
if options[:filtered_params] && !options[:filtered_params].empty?
|
320
|
+
@filtered_params = options[:filtered_params]
|
254
321
|
end
|
255
322
|
|
256
|
-
|
323
|
+
frame_stack.push NewRelic::Agent::MethodTracerHelpers.trace_execution_scoped_header(state, Time.now.to_f)
|
324
|
+
name_last_frame(options[:transaction_name])
|
325
|
+
|
326
|
+
set_default_transaction_name(options[:transaction_name], category)
|
257
327
|
end
|
258
328
|
|
259
|
-
def
|
260
|
-
|
261
|
-
|
329
|
+
def make_transaction_name(name, category=nil)
|
330
|
+
namer = Instrumentation::ControllerInstrumentation::TransactionNamer
|
331
|
+
"#{namer.prefix_for_category(self, category)}#{name}"
|
262
332
|
end
|
263
333
|
|
264
|
-
def
|
265
|
-
|
266
|
-
|
334
|
+
def set_default_transaction_name(name, category)
|
335
|
+
return log_frozen_name(name) if name_frozen?
|
336
|
+
if influences_transaction_name?(category)
|
337
|
+
self.default_name = name
|
338
|
+
@category = category if category
|
339
|
+
end
|
267
340
|
end
|
268
341
|
|
269
|
-
def
|
270
|
-
if
|
271
|
-
|
272
|
-
|
273
|
-
|
342
|
+
def set_overriding_transaction_name(name, category)
|
343
|
+
return log_frozen_name(name) if name_frozen?
|
344
|
+
if influences_transaction_name?(category)
|
345
|
+
self.overridden_name = name
|
346
|
+
@category = category if category
|
274
347
|
end
|
275
348
|
end
|
276
349
|
|
277
|
-
def
|
278
|
-
|
279
|
-
|
350
|
+
def name_last_frame(name)
|
351
|
+
frame_stack.last.name = name
|
352
|
+
end
|
280
353
|
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
end
|
354
|
+
def log_frozen_name(name)
|
355
|
+
NewRelic::Agent.logger.warn("Attempted to rename transaction to '#{name}' after transaction name was already frozen as '#{@frozen_name}'.")
|
356
|
+
nil
|
357
|
+
end
|
286
358
|
|
287
|
-
|
359
|
+
def influences_transaction_name?(category)
|
360
|
+
!category || frame_stack.size == 1 || similar_category?(category)
|
361
|
+
end
|
288
362
|
|
289
|
-
|
363
|
+
def best_name
|
364
|
+
@frozen_name || @overridden_name ||
|
365
|
+
@default_name || NewRelic::Agent::UNKNOWN_METRIC
|
290
366
|
end
|
291
367
|
|
292
368
|
def name_set?
|
293
|
-
(@
|
369
|
+
(@overridden_name || @default_name) ? true : false
|
294
370
|
end
|
295
371
|
|
296
372
|
def promoted_transaction_name(name)
|
@@ -324,8 +400,6 @@ module NewRelic
|
|
324
400
|
@frozen_name ? true : false
|
325
401
|
end
|
326
402
|
|
327
|
-
# Indicate that we are entering a measured controller action or task.
|
328
|
-
# Make sure you unwind every push with a pop call.
|
329
403
|
def start(state)
|
330
404
|
return if !state.is_execution_traced?
|
331
405
|
|
@@ -334,16 +408,8 @@ module NewRelic
|
|
334
408
|
NewRelic::Agent.instance.events.notify(:start_transaction)
|
335
409
|
NewRelic::Agent::BusyCalculator.dispatcher_start(start_time)
|
336
410
|
|
337
|
-
|
338
|
-
@
|
339
|
-
end
|
340
|
-
|
341
|
-
# Indicate that you don't want to keep the currently saved transaction
|
342
|
-
# information
|
343
|
-
def self.abort_transaction! #THREAD_LOCAL_ACCESS
|
344
|
-
state = NewRelic::Agent::TransactionState.tl_get
|
345
|
-
txn = state.current_transaction
|
346
|
-
txn.abort_transaction!(state) if txn
|
411
|
+
frame_stack.push NewRelic::Agent::MethodTracerHelpers.trace_execution_scoped_header(state, start_time.to_f)
|
412
|
+
name_last_frame @default_name
|
347
413
|
end
|
348
414
|
|
349
415
|
# For the current web transaction, return the path of the URI minus the host part and query string, or nil.
|
@@ -385,16 +451,17 @@ module NewRelic
|
|
385
451
|
name.start_with?(MIDDLEWARE_PREFIX)
|
386
452
|
end
|
387
453
|
|
388
|
-
def stop(state, end_time)
|
454
|
+
def stop(state, end_time, outermost_frame)
|
389
455
|
return if !state.is_execution_traced?
|
390
456
|
freeze_name_and_execute_if_not_ignored
|
391
457
|
ignore! if user_defined_rules_ignore?
|
392
458
|
|
393
|
-
if @
|
394
|
-
name = Transaction.nested_transaction_name(
|
395
|
-
|
459
|
+
if @has_children
|
460
|
+
name = Transaction.nested_transaction_name(outermost_frame.name)
|
461
|
+
trace_options = TRACE_OPTIONS_SCOPED
|
396
462
|
else
|
397
463
|
name = @frozen_name
|
464
|
+
trace_options = TRACE_OPTIONS_UNSCOPED
|
398
465
|
end
|
399
466
|
|
400
467
|
# These metrics are recorded here instead of in record_summary_metrics
|
@@ -411,8 +478,8 @@ module NewRelic
|
|
411
478
|
start_time.to_f,
|
412
479
|
name,
|
413
480
|
summary_metrics_with_exclusive_time,
|
414
|
-
|
415
|
-
|
481
|
+
outermost_frame,
|
482
|
+
trace_options,
|
416
483
|
end_time.to_f)
|
417
484
|
|
418
485
|
NewRelic::Agent::BusyCalculator.dispatcher_finish(end_time)
|
@@ -606,37 +673,6 @@ module NewRelic
|
|
606
673
|
end
|
607
674
|
end
|
608
675
|
|
609
|
-
# If we have an active transaction, notice the error and increment the error metric.
|
610
|
-
# Options:
|
611
|
-
# * <tt>:request</tt> => Request object to get the uri and referer
|
612
|
-
# * <tt>:uri</tt> => The request path, minus any request params or query string.
|
613
|
-
# * <tt>:referer</tt> => The URI of the referer
|
614
|
-
# * <tt>:metric</tt> => The metric name associated with the transaction
|
615
|
-
# * <tt>:request_params</tt> => Request parameters, already filtered if necessary
|
616
|
-
# * <tt>:custom_params</tt> => Custom parameters
|
617
|
-
# Anything left over is treated as custom params
|
618
|
-
|
619
|
-
def self.notice_error(e, options={}) #THREAD_LOCAL_ACCESS
|
620
|
-
options = extract_request_options(options)
|
621
|
-
state = NewRelic::Agent::TransactionState.tl_get
|
622
|
-
txn = state.current_transaction
|
623
|
-
if txn
|
624
|
-
txn.notice_error(e, options)
|
625
|
-
else
|
626
|
-
NewRelic::Agent.instance.error_collector.notice_error(e, options)
|
627
|
-
end
|
628
|
-
end
|
629
|
-
|
630
|
-
def self.extract_request_options(options)
|
631
|
-
req = options.delete(:request)
|
632
|
-
if req
|
633
|
-
options[:uri] = uri_from_request(req)
|
634
|
-
options[:referer] = referer_from_request(req)
|
635
|
-
end
|
636
|
-
options
|
637
|
-
end
|
638
|
-
|
639
|
-
|
640
676
|
# Do not call this. Invoke the class method instead.
|
641
677
|
def notice_error(error, options={}) # :nodoc:
|
642
678
|
options[:uri] ||= uri if uri
|
@@ -746,56 +782,16 @@ module NewRelic
|
|
746
782
|
alias_method :user_attributes, :custom_parameters
|
747
783
|
alias_method :set_user_attributes, :add_custom_parameters
|
748
784
|
|
749
|
-
# Returns truthy if the current in-progress transaction is considered a
|
750
|
-
# a web transaction (as opposed to, e.g., a background transaction).
|
751
|
-
#
|
752
|
-
# @api public
|
753
|
-
#
|
754
|
-
def self.recording_web_transaction? #THREAD_LOCAL_ACCESS
|
755
|
-
txn = tl_current
|
756
|
-
txn && txn.recording_web_transaction?
|
757
|
-
end
|
758
|
-
|
759
|
-
def self.transaction_category_is_web?(category)
|
760
|
-
WEB_TRANSACTION_CATEGORIES.include?(category)
|
761
|
-
end
|
762
|
-
|
763
785
|
def recording_web_transaction?
|
764
|
-
|
765
|
-
end
|
766
|
-
|
767
|
-
# Make a safe attempt to get the referer from a request object, generally successful when
|
768
|
-
# it's a Rack request.
|
769
|
-
def self.referer_from_request(req)
|
770
|
-
if req && req.respond_to?(:referer)
|
771
|
-
req.referer.to_s.split('?').first
|
772
|
-
end
|
786
|
+
web_category?(@category)
|
773
787
|
end
|
774
788
|
|
775
|
-
|
776
|
-
|
777
|
-
approximate_uri = case
|
778
|
-
when req.respond_to?(:fullpath ) then req.fullpath
|
779
|
-
when req.respond_to?(:path ) then req.path
|
780
|
-
when req.respond_to?(:request_uri) then req.request_uri
|
781
|
-
when req.respond_to?(:uri ) then req.uri
|
782
|
-
when req.respond_to?(:url ) then req.url
|
783
|
-
end
|
784
|
-
return approximate_uri[%r{^(https?://.*?)?(/[^?]*)}, 2] || '/' if approximate_uri
|
789
|
+
def web_category?(category)
|
790
|
+
WEB_TRANSACTION_CATEGORIES.include?(category)
|
785
791
|
end
|
786
792
|
|
787
|
-
|
788
|
-
|
789
|
-
case
|
790
|
-
when failed
|
791
|
-
:apdex_f
|
792
|
-
when duration <= apdex_t
|
793
|
-
:apdex_s
|
794
|
-
when duration <= 4 * apdex_t
|
795
|
-
:apdex_t
|
796
|
-
else
|
797
|
-
:apdex_f
|
798
|
-
end
|
793
|
+
def similar_category?(category)
|
794
|
+
web_category?(@category) == web_category?(category)
|
799
795
|
end
|
800
796
|
|
801
797
|
def cpu_burn
|