newrelic_rpm 3.6.0.83 → 3.6.1.85.beta
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +27 -0
- data/Gemfile +2 -7
- data/README.md +1 -1
- data/lib/new_relic/agent/agent.rb +3 -2
- data/lib/new_relic/agent/autostart.rb +56 -0
- data/lib/new_relic/agent/browser_monitoring.rb +19 -14
- data/lib/new_relic/agent/configuration/defaults.rb +12 -2
- data/lib/new_relic/agent/configuration/environment_source.rb +4 -1
- data/lib/new_relic/agent/cross_app_monitor.rb +2 -1
- data/lib/new_relic/agent/cross_app_tracing.rb +19 -10
- data/lib/new_relic/agent/error_collector.rb +5 -4
- data/lib/new_relic/agent/instrumentation/action_controller_subscriber.rb +204 -0
- data/lib/new_relic/agent/instrumentation/action_view_subscriber.rb +88 -0
- data/lib/new_relic/agent/instrumentation/active_record.rb +1 -1
- data/lib/new_relic/agent/instrumentation/active_record_helper.rb +1 -1
- data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +84 -0
- data/lib/new_relic/agent/instrumentation/browser_monitoring_timings.rb +3 -2
- data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +104 -87
- data/lib/new_relic/agent/instrumentation/evented_subscriber.rb +91 -0
- data/lib/new_relic/agent/instrumentation/memcache.rb +4 -4
- data/lib/new_relic/agent/instrumentation/merb/errors.rb +4 -4
- data/lib/new_relic/agent/instrumentation/rack.rb +1 -1
- data/lib/new_relic/agent/instrumentation/rails/action_controller.rb +20 -20
- data/lib/new_relic/agent/instrumentation/rails/errors.rb +5 -5
- data/lib/new_relic/agent/instrumentation/rails3/errors.rb +3 -3
- data/lib/new_relic/agent/instrumentation/rails4/action_controller.rb +3 -25
- data/lib/new_relic/agent/instrumentation/rails4/action_view.rb +2 -115
- data/lib/new_relic/agent/instrumentation/rails4/active_record.rb +2 -82
- data/lib/new_relic/agent/instrumentation/rails4/errors.rb +3 -4
- data/lib/new_relic/agent/method_tracer.rb +93 -56
- data/lib/new_relic/agent/null_logger.rb +6 -0
- data/lib/new_relic/agent/samplers/cpu_sampler.rb +9 -4
- data/lib/new_relic/agent/sql_sampler.rb +10 -6
- data/lib/new_relic/agent/stats_engine/metric_stats.rb +19 -3
- data/lib/new_relic/agent/stats_engine/transactions.rb +53 -34
- data/lib/new_relic/agent/system_info.rb +54 -0
- data/lib/new_relic/agent/thread.rb +2 -2
- data/lib/new_relic/agent/transaction/pop.rb +52 -0
- data/lib/new_relic/agent/transaction.rb +388 -0
- data/lib/new_relic/agent/transaction_info.rb +5 -13
- data/lib/new_relic/agent/transaction_sample_builder.rb +13 -20
- data/lib/new_relic/agent/transaction_sampler.rb +13 -15
- data/lib/new_relic/agent/uri_util.rb +35 -0
- data/lib/new_relic/agent.rb +54 -11
- data/lib/new_relic/build.rb +2 -2
- data/lib/new_relic/control/frameworks/rails.rb +0 -1
- data/lib/new_relic/control/frameworks/rails3.rb +2 -0
- data/lib/new_relic/control/frameworks/rails4.rb +0 -4
- data/lib/new_relic/control/instance_methods.rb +5 -19
- data/lib/new_relic/control/server_methods.rb +2 -0
- data/lib/new_relic/environment_report.rb +4 -34
- data/lib/new_relic/latest_changes.rb +1 -1
- data/lib/new_relic/local_environment.rb +0 -6
- data/lib/new_relic/metric_spec.rb +2 -2
- data/lib/new_relic/rack/error_collector.rb +6 -4
- data/lib/new_relic/transaction_sample.rb +7 -1
- data/lib/new_relic/version.rb +1 -1
- data/lib/newrelic_rpm.rb +2 -2
- data/newrelic.yml +20 -20
- data/test/config/test_control.rb +2 -2
- data/test/multiverse/suites/agent_only/audit_log_test.rb +1 -1
- data/test/multiverse/suites/agent_only/cross_application_tracing_test.rb +0 -2
- data/test/multiverse/suites/agent_only/logging_test.rb +1 -1
- data/test/multiverse/suites/agent_only/marshaling_test.rb +5 -3
- data/test/multiverse/suites/agent_only/rename_rule_test.rb +2 -0
- data/test/multiverse/suites/agent_only/set_transaction_name_test.rb +96 -0
- data/test/multiverse/suites/agent_only/testing_app.rb +1 -0
- data/test/multiverse/suites/rails/error_tracing_test.rb +17 -29
- data/test/multiverse/suites/rails/queue_time_test.rb +8 -2
- data/test/multiverse/suites/rails/view_instrumentation_test.rb +6 -3
- data/test/multiverse/suites/resque/instrumentation_test.rb +1 -1
- data/test/multiverse/suites/sinatra/sinatra_error_tracing_test.rb +8 -0
- data/test/new_relic/agent/agent/connect_test.rb +2 -1
- data/test/new_relic/agent/agent/start_test.rb +0 -10
- data/test/new_relic/agent/agent_logger_test.rb +15 -0
- data/test/new_relic/agent/agent_test_controller.rb +6 -2
- data/test/new_relic/agent/agent_test_controller_test.rb +20 -69
- data/test/new_relic/agent/autostart_test.rb +67 -0
- data/test/new_relic/agent/browser_monitoring_test.rb +60 -38
- data/test/new_relic/agent/configuration/environment_source_test.rb +19 -17
- data/test/new_relic/agent/cross_app_monitor_test.rb +8 -0
- data/test/new_relic/agent/error_collector/notice_error_test.rb +0 -5
- data/test/new_relic/agent/error_collector_test.rb +8 -9
- data/test/new_relic/agent/instrumentation/action_controller_subscriber_test.rb +228 -0
- data/test/new_relic/agent/instrumentation/action_view_subscriber_test.rb +18 -34
- data/test/new_relic/agent/instrumentation/active_record_instrumentation_test.rb +5 -5
- data/test/new_relic/agent/instrumentation/active_record_subscriber_test.rb +8 -9
- data/test/new_relic/agent/instrumentation/browser_monitoring_timings_test.rb +1 -1
- data/test/new_relic/agent/instrumentation/controller_instrumentation_test.rb +24 -38
- data/test/new_relic/agent/instrumentation/net_instrumentation_test.rb +126 -178
- data/test/new_relic/agent/instrumentation/rack_test.rb +1 -1
- data/test/new_relic/agent/instrumentation/task_instrumentation_test.rb +135 -151
- data/test/new_relic/agent/method_tracer/instance_methods/trace_execution_scoped_test.rb +153 -81
- data/test/new_relic/agent/method_tracer_test.rb +42 -33
- data/test/new_relic/agent/mock_scope_listener.rb +4 -4
- data/test/new_relic/agent/pipe_channel_manager_test.rb +4 -2
- data/test/new_relic/agent/rpm_agent_test.rb +86 -89
- data/test/new_relic/agent/sql_sampler_test.rb +18 -19
- data/test/new_relic/agent/stats_engine/gc_profiler_test.rb +5 -8
- data/test/new_relic/agent/stats_engine/metric_stats_test.rb +20 -8
- data/test/new_relic/agent/stats_engine/samplers_test.rb +31 -14
- data/test/new_relic/agent/stats_engine_test.rb +53 -60
- data/test/new_relic/agent/thread_test.rb +7 -7
- data/test/new_relic/agent/transaction/pop_test.rb +96 -0
- data/test/new_relic/agent/transaction_info_test.rb +6 -17
- data/test/new_relic/agent/transaction_sample_builder_test.rb +10 -18
- data/test/new_relic/agent/transaction_sampler_test.rb +80 -75
- data/test/new_relic/agent/{instrumentation/metric_frame_test.rb → transaction_test.rb} +76 -42
- data/test/new_relic/agent/uri_util_test.rb +75 -0
- data/test/new_relic/agent_test.rb +115 -9
- data/test/test_helper.rb +138 -9
- data.tar.gz.sig +0 -0
- metadata +37 -74
- metadata.gz.sig +0 -0
- data/lib/new_relic/agent/instrumentation/metric_frame/pop.rb +0 -84
- data/lib/new_relic/agent/instrumentation/metric_frame.rb +0 -353
- data/test/new_relic/agent/instrumentation/metric_frame/pop_test.rb +0 -175
- data/test/test_contexts.rb +0 -34
data/CHANGELOG
CHANGED
@@ -1,6 +1,33 @@
|
|
1
1
|
|
2
2
|
# New Relic Ruby Agent Release Notes #
|
3
3
|
|
4
|
+
## v3.6.1 ##
|
5
|
+
|
6
|
+
* Full URIs for HTTP requests are recorded in transaction traces
|
7
|
+
|
8
|
+
When recording a transaction trace node for an outgoing HTTP call via
|
9
|
+
Net::HTTP, the agent will now save the full URI (instead of just the hostname)
|
10
|
+
for the request. Embedded credentials, the query string, and the fragment will
|
11
|
+
be stripped from the URI before it is saved.
|
12
|
+
|
13
|
+
* Simplify Agent Autostart Logic
|
14
|
+
|
15
|
+
Previously the agent would only start when it detected a supported
|
16
|
+
"Dispatcher", meaning a known web server or background task framework. This
|
17
|
+
was problematic for customers using webservers that the agent was not
|
18
|
+
configured to detect (e.g. Puma). Now the agent will attempt to report any
|
19
|
+
time it detects it is running in a monitored environment (e.g. production).
|
20
|
+
There are two exceptions to this. The agent will not autostart in a rails
|
21
|
+
console or irb session or when the process was invoked by a rake task (e.g.
|
22
|
+
rake assets:precompile). The NEWRELIC_ENABLE environment variable can be set
|
23
|
+
to true or false to force the agent to start or not start.
|
24
|
+
|
25
|
+
* Don't attempt to resolve collector hostname when proxy is in use
|
26
|
+
|
27
|
+
When a proxy is configured, the agent will not attempt to lookup and cache the
|
28
|
+
IP address of New Relic server to which it is sending data, since DNS may not
|
29
|
+
be available in some environments. Thanks to Bill Kirtley for the contribution
|
30
|
+
|
4
31
|
## v3.6.0 ##
|
5
32
|
|
6
33
|
* Sidekiq supprt
|
data/Gemfile
CHANGED
@@ -5,15 +5,10 @@ group :development do
|
|
5
5
|
# There's problems with the test task in rake 10
|
6
6
|
# https://github.com/jimweirich/rake/issues/144
|
7
7
|
gem 'rake', '0.9.6'
|
8
|
-
|
9
|
-
gem 'mocha', '~>0.13.0', :require => false
|
10
|
-
else
|
11
|
-
gem 'mocha', '~>0.12.0'
|
12
|
-
end
|
13
|
-
gem 'shoulda', '~>3.0.1'
|
8
|
+
gem 'mocha', '~>0.13.0', :require => false
|
14
9
|
gem 'sdoc-helpers'
|
15
10
|
gem 'rdoc', '>= 2.4.2'
|
16
|
-
gem 'rails', '~>3.2.
|
11
|
+
gem 'rails', '~>3.2.13'
|
17
12
|
gem 'sqlite3', :platform => 'mri'
|
18
13
|
gem 'activerecord-jdbcsqlite3-adapter', :platform => 'jruby'
|
19
14
|
gem 'jruby-openssl', :platform => 'jruby'
|
data/README.md
CHANGED
@@ -8,6 +8,7 @@ require 'net/http'
|
|
8
8
|
require 'logger'
|
9
9
|
require 'zlib'
|
10
10
|
require 'stringio'
|
11
|
+
require 'new_relic/agent/autostart'
|
11
12
|
require 'new_relic/agent/new_relic_service'
|
12
13
|
require 'new_relic/agent/pipe_service'
|
13
14
|
require 'new_relic/agent/configuration/manager'
|
@@ -141,7 +142,7 @@ module NewRelic
|
|
141
142
|
metric_info = NewRelic::MetricParser::MetricParser.for_metric_named(metric)
|
142
143
|
|
143
144
|
if metric_info.is_web_transaction?
|
144
|
-
NewRelic::Agent::
|
145
|
+
NewRelic::Agent::Transaction.record_apdex(metric_info, duration_seconds, duration_seconds, is_error)
|
145
146
|
end
|
146
147
|
metrics = metric_info.summary_metrics
|
147
148
|
|
@@ -337,7 +338,7 @@ module NewRelic
|
|
337
338
|
# assist with proper dispatcher detection
|
338
339
|
def log_dispatcher
|
339
340
|
dispatcher_name = Agent.config[:dispatcher].to_s
|
340
|
-
return if log_if(dispatcher_name.empty?, :
|
341
|
+
return if log_if(dispatcher_name.empty?, :info, "No known dispatcher detected.")
|
341
342
|
::NewRelic::Agent.logger.info "Dispatcher: #{dispatcher_name}"
|
342
343
|
end
|
343
344
|
|
@@ -0,0 +1,56 @@
|
|
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
|
+
# A singleton responsible for determining if the agent should start
|
8
|
+
# monitoring.
|
9
|
+
#
|
10
|
+
# If the agent is in a monitored environment (e.g. production) it will
|
11
|
+
# attempt to avoid starting at "inapproriate" times, for example in an IRB
|
12
|
+
# session. On Heroku, logs typically go to STDOUT so agent logs can spam
|
13
|
+
# the console during interactive sessions.
|
14
|
+
#
|
15
|
+
# It should be possible to override Autostart logic with an explicit
|
16
|
+
# configuration, for example the NEWRELIC_ENABLE environment variable or
|
17
|
+
# agent_enabled key in newrelic.yml
|
18
|
+
module Autostart
|
19
|
+
extend self
|
20
|
+
|
21
|
+
|
22
|
+
# The constants and execuatables (i.e. $0) used can be configured with
|
23
|
+
# via the config keys 'autostart.blacklisted_constants' and
|
24
|
+
# 'autostart.blacklisted_executables'
|
25
|
+
def agent_should_start?
|
26
|
+
!::NewRelic::Agent.config['autostart.blacklisted_constants'] \
|
27
|
+
.split(/\s*,\s*/).any?{ |name| constant_is_defined?(name) } &&
|
28
|
+
!::NewRelic::Agent.config['autostart.blacklisted_executables'] \
|
29
|
+
.split(/\s*,\s*/).any?{ |bin| File.basename($0) == bin } &&
|
30
|
+
!in_blacklisted_rake_task?
|
31
|
+
end
|
32
|
+
|
33
|
+
# Lookup whether namespaced constants (e.g. ::Foo::Bar::Baz) are in the
|
34
|
+
# environment.
|
35
|
+
def constant_is_defined?(const_name)
|
36
|
+
const_name.to_s.sub(/\A::/,'').split('::').inject(Object) do |namespace, name|
|
37
|
+
begin
|
38
|
+
namespace.const_get(name)
|
39
|
+
rescue NameError
|
40
|
+
false
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def in_blacklisted_rake_task?
|
46
|
+
tasks = begin
|
47
|
+
Rake.application.top_level_tasks
|
48
|
+
rescue => e
|
49
|
+
::NewRelic::Agent.logger.debug("Not in Rake environment so skipping blacklisted_rake_tasks check: #{e}")
|
50
|
+
[]
|
51
|
+
end
|
52
|
+
!(tasks & ::NewRelic::Agent.config['autostart.blacklisted_rake_tasks'].split(/\s*,\s*/)).empty?
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -9,7 +9,7 @@ module NewRelic
|
|
9
9
|
# This module contains support for Real User Monitoring - the
|
10
10
|
# javascript generation and configuration
|
11
11
|
module BrowserMonitoring
|
12
|
-
class
|
12
|
+
class DummyTransaction
|
13
13
|
def initialize
|
14
14
|
@attributes = {}
|
15
15
|
end
|
@@ -21,9 +21,13 @@ module NewRelic
|
|
21
21
|
def queue_time
|
22
22
|
0.0
|
23
23
|
end
|
24
|
+
|
25
|
+
def name
|
26
|
+
'(unknown)'
|
27
|
+
end
|
24
28
|
end
|
25
29
|
|
26
|
-
@@
|
30
|
+
@@dummy_txn = DummyTransaction.new
|
27
31
|
|
28
32
|
# This method returns a string suitable for inclusion in a page
|
29
33
|
# - known as 'manual instrumentation' for Real User
|
@@ -52,6 +56,7 @@ module NewRelic
|
|
52
56
|
# page as is reasonably possible.
|
53
57
|
def browser_timing_footer
|
54
58
|
if insert_js?
|
59
|
+
NewRelic::Agent::Transaction.freeze_name
|
55
60
|
generate_footer_js(NewRelic::Agent.instance.beacon_configuration)
|
56
61
|
else
|
57
62
|
""
|
@@ -73,19 +78,19 @@ module NewRelic
|
|
73
78
|
end
|
74
79
|
|
75
80
|
def browser_monitoring_transaction_name
|
76
|
-
|
81
|
+
current_transaction.name || '(unknown)'
|
77
82
|
end
|
78
83
|
|
79
84
|
def browser_monitoring_queue_time
|
80
|
-
clamp_to_positive((
|
85
|
+
clamp_to_positive((current_transaction.queue_time.to_f * 1000.0).round)
|
81
86
|
end
|
82
87
|
|
83
88
|
def browser_monitoring_app_time
|
84
89
|
clamp_to_positive(((Time.now - browser_monitoring_start_time).to_f * 1000.0).round)
|
85
90
|
end
|
86
91
|
|
87
|
-
def
|
88
|
-
|
92
|
+
def current_transaction
|
93
|
+
NewRelic::Agent::TransactionInfo.get.transaction || @@dummy_txn
|
89
94
|
end
|
90
95
|
|
91
96
|
def clamp_to_positive(value)
|
@@ -99,7 +104,7 @@ module NewRelic
|
|
99
104
|
|
100
105
|
def self.timings
|
101
106
|
NewRelic::Agent::Instrumentation::BrowserMonitoringTimings.new(
|
102
|
-
|
107
|
+
current_transaction.queue_time,
|
103
108
|
NewRelic::Agent::TransactionInfo.get)
|
104
109
|
end
|
105
110
|
|
@@ -163,13 +168,13 @@ module NewRelic
|
|
163
168
|
end
|
164
169
|
end
|
165
170
|
|
166
|
-
def
|
167
|
-
|
171
|
+
def transaction_attribute(key)
|
172
|
+
current_transaction.user_attributes[key] || ""
|
168
173
|
end
|
169
174
|
|
170
175
|
def tt_guid
|
171
|
-
|
172
|
-
return
|
176
|
+
transaction = NewRelic::Agent::TransactionInfo.get
|
177
|
+
return transaction.guid if transaction.include_guid?
|
173
178
|
""
|
174
179
|
end
|
175
180
|
|
@@ -180,9 +185,9 @@ module NewRelic
|
|
180
185
|
def footer_js_string(config)
|
181
186
|
obfuscated_transaction_name = obfuscate(config, browser_monitoring_transaction_name)
|
182
187
|
|
183
|
-
user = obfuscate(config,
|
184
|
-
account = obfuscate(config,
|
185
|
-
product = obfuscate(config,
|
188
|
+
user = obfuscate(config, transaction_attribute(:user))
|
189
|
+
account = obfuscate(config, transaction_attribute(:account))
|
190
|
+
product = obfuscate(config, transaction_attribute(:product))
|
186
191
|
|
187
192
|
html_safe_if_needed(%'<script type="text/javascript">#{config.browser_timing_static_footer}NREUMQ.push(["#{config.finish_command}","#{Agent.config[:beacon]}","#{Agent.config[:browser_key]}","#{Agent.config[:application_id]}","#{obfuscated_transaction_name}",#{browser_monitoring_queue_time},#{browser_monitoring_app_time},new Date().getTime(),"#{tt_guid}","#{tt_token}","#{user}","#{account}","#{product}"]);</script>')
|
188
193
|
end
|
@@ -48,11 +48,21 @@ module NewRelic
|
|
48
48
|
end,
|
49
49
|
:enabled => true,
|
50
50
|
:monitor_mode => Proc.new { self[:enabled] },
|
51
|
+
|
52
|
+
# agent_enabled determines whether the agent should try to start and
|
53
|
+
# report data.
|
51
54
|
:agent_enabled => Proc.new do
|
52
55
|
self[:enabled] &&
|
53
56
|
(self[:developer_mode] || self[:monitor_mode] || self[:monitor_daemons]) &&
|
54
|
-
|
57
|
+
::NewRelic::Agent::Autostart.agent_should_start?
|
55
58
|
end,
|
59
|
+
# Don't autostart the agent if we're in IRB or Rails console.
|
60
|
+
# This config option accepts a comma seperated list of constants.
|
61
|
+
:'autostart.blacklisted_constants' => 'Rails::Console',
|
62
|
+
# Comma seperated list of executables that you don't want to trigger
|
63
|
+
# agents start. e.g. 'rake,my_ruby_script.rb'
|
64
|
+
:'autostart.blacklisted_executables' => 'irb',
|
65
|
+
:'autostart.blacklisted_rake_tasks' => 'about,assets:clean,assets:clobber,assets:environment,assets:precompile,db:create,db:drop,db:fixtures:load,db:migrate,db:migrate:status,db:rollback,db:schema:cache:clear,db:schema:cache:dump,db:schema:dump,db:schema:load,db:seed,db:setup,db:structure:dump,db:version,doc:app,log:clear,middleware,notes,notes:custom,rails:template,rails:update,routes,secret,spec,spec:controllers,spec:helpers,spec:models,spec:rcov,stats,test,test:all,test:all:db,test:recent,test:single,test:uncommitted,time:zones:all,tmp:clear,tmp:create',
|
56
66
|
:developer_mode => Proc.new { self[:developer] },
|
57
67
|
:developer => false,
|
58
68
|
:apdex_t => 0.5,
|
@@ -117,7 +127,7 @@ module NewRelic
|
|
117
127
|
|
118
128
|
:'error_collector.enabled' => true,
|
119
129
|
:'error_collector.capture_source' => true,
|
120
|
-
:'error_collector.ignore_errors' => 'ActionController::RoutingError',
|
130
|
+
:'error_collector.ignore_errors' => 'ActionController::RoutingError,Sinatra::NotFound',
|
121
131
|
|
122
132
|
:'rum.enabled' => true,
|
123
133
|
:'rum.jsonp' => true,
|
@@ -29,7 +29,10 @@ module NewRelic
|
|
29
29
|
end
|
30
30
|
|
31
31
|
boolean_map = {
|
32
|
-
'NEWRELIC_ENABLE' => :agent_enabled
|
32
|
+
'NEWRELIC_ENABLE' => :agent_enabled,
|
33
|
+
'NEWRELIC_ENABLED' => :agent_enabled,
|
34
|
+
'NEW_RELIC_ENABLE' => :agent_enabled,
|
35
|
+
'NEW_RELIC_ENABLED' => :agent_enabled
|
33
36
|
}.each do |key, val|
|
34
37
|
if ENV[key].to_s =~ /false|off|no/i
|
35
38
|
self[val] = false
|
@@ -87,7 +87,7 @@ module NewRelic
|
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
90
|
-
events.subscribe(:start_transaction) do
|
90
|
+
events.subscribe(:start_transaction) do
|
91
91
|
set_transaction_custom_parameters
|
92
92
|
end
|
93
93
|
|
@@ -138,6 +138,7 @@ module NewRelic
|
|
138
138
|
|
139
139
|
def insert_response_header(request_headers, response_headers)
|
140
140
|
unless client_cross_app_id.nil?
|
141
|
+
NewRelic::Agent::Transaction.freeze_name
|
141
142
|
timings = NewRelic::Agent::BrowserMonitoring.timings
|
142
143
|
content_length = content_length_from_request(request_headers)
|
143
144
|
|
@@ -52,7 +52,7 @@ module NewRelic
|
|
52
52
|
|
53
53
|
# Create a segment and time the call
|
54
54
|
t0 = Time.now
|
55
|
-
segment = stats_engine.push_scope(
|
55
|
+
segment = stats_engine.push_scope( :net_http, t0 )
|
56
56
|
|
57
57
|
return t0, segment
|
58
58
|
rescue => err
|
@@ -78,13 +78,13 @@ module NewRelic
|
|
78
78
|
stats_engine.record_metrics(scoped_metric, duration, :scoped => true)
|
79
79
|
|
80
80
|
# Add TT custom parameters
|
81
|
-
|
82
|
-
|
81
|
+
segment.name = scoped_metric
|
82
|
+
add_transaction_trace_parameters(http, request, response)
|
83
83
|
end
|
84
84
|
ensure
|
85
85
|
# We always need to pop the scope stack to avoid an inconsistent
|
86
86
|
# state, which will prevent tracing of the whole transaction.
|
87
|
-
stats_engine.pop_scope( segment,
|
87
|
+
stats_engine.pop_scope( segment, scoped_metric, t1 )
|
88
88
|
end
|
89
89
|
rescue NewRelic::Agent::CrossAppTracing::Error => err
|
90
90
|
NewRelic::Agent.logger.debug "while cross app tracing", err
|
@@ -124,15 +124,21 @@ module NewRelic
|
|
124
124
|
NewRelic::Agent.logger.debug "Not injecting x-process header", err
|
125
125
|
end
|
126
126
|
|
127
|
+
def add_transaction_trace_parameters(http, request, response)
|
128
|
+
filtered_uri = NewRelic::Agent::URIUtil.filtered_uri_for(http, request)
|
129
|
+
transaction_sampler.add_segment_parameters(:uri => filtered_uri)
|
130
|
+
if response_is_crossapp?( response )
|
131
|
+
add_cat_transaction_trace_parameters( response )
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
127
135
|
|
128
136
|
# Extract any custom parameters from +response+ if it's cross-application and
|
129
137
|
# add them to the current TT node.
|
130
|
-
def
|
131
|
-
|
138
|
+
def add_cat_transaction_trace_parameters( response )
|
132
139
|
appdata = extract_appdata( response )
|
133
|
-
|
134
|
-
|
135
|
-
|
140
|
+
transaction_sampler.add_segment_parameters( \
|
141
|
+
:transaction_guid => appdata[APPDATA_TXN_GUID_INDEX] )
|
136
142
|
end
|
137
143
|
|
138
144
|
|
@@ -164,7 +170,7 @@ module NewRelic
|
|
164
170
|
metrics = [ "External/all" ]
|
165
171
|
metrics << "External/#{http.address}/all"
|
166
172
|
|
167
|
-
if NewRelic::Agent::
|
173
|
+
if NewRelic::Agent::Transaction.recording_web_transaction?
|
168
174
|
metrics << "External/allWeb"
|
169
175
|
else
|
170
176
|
metrics << "External/allOther"
|
@@ -246,6 +252,9 @@ module NewRelic
|
|
246
252
|
NewRelic::Agent.instance.stats_engine
|
247
253
|
end
|
248
254
|
|
255
|
+
def transaction_sampler
|
256
|
+
NewRelic::Agent.instance.transaction_sampler
|
257
|
+
end
|
249
258
|
|
250
259
|
# Check the given +id+ to ensure it conforms to the format of a cross-application
|
251
260
|
# ID. Raises an NewRelic::Agent::CrossAppTracing::Error if it doesn't.
|
@@ -110,13 +110,14 @@ module NewRelic
|
|
110
110
|
|
111
111
|
# Increments a statistic that tracks total error rate
|
112
112
|
# Be sure not to double-count same exception. This clears per harvest.
|
113
|
-
def increment_error_count!(exception)
|
113
|
+
def increment_error_count!(exception, options={})
|
114
114
|
return if seen?(exception)
|
115
115
|
tag_as_seen(exception)
|
116
116
|
|
117
|
-
txn_info = NewRelic::Agent::TransactionInfo.get
|
118
117
|
metric_names = ["Errors/all"]
|
119
|
-
|
118
|
+
if options[:metric] && options[:metric] != '(unknown)'
|
119
|
+
metric_names << "Errors/#{options[:metric]}"
|
120
|
+
end
|
120
121
|
stats_engine = NewRelic::Agent.agent.stats_engine
|
121
122
|
stats_engine.record_metrics(metric_names) do |stats|
|
122
123
|
stats.increment_count
|
@@ -129,7 +130,6 @@ module NewRelic
|
|
129
130
|
def should_exit_notice_error?(exception)
|
130
131
|
if enabled?
|
131
132
|
if !error_is_ignored?(exception)
|
132
|
-
increment_error_count!(exception)
|
133
133
|
return exception.nil? # exit early if the exception is nil
|
134
134
|
end
|
135
135
|
end
|
@@ -251,6 +251,7 @@ module NewRelic
|
|
251
251
|
# If exception is nil, the error count is bumped and no traced error is recorded
|
252
252
|
def notice_error(exception, options={})
|
253
253
|
return if should_exit_notice_error?(exception)
|
254
|
+
increment_error_count!(exception, options)
|
254
255
|
NewRelic::Agent.instance.events.notify(:notice_error, exception, options)
|
255
256
|
action_path = fetch_from_options(options, :metric, (NewRelic::Agent.instance.stats_engine.scope_name || ''))
|
256
257
|
exception_options = error_params_from_options(options).merge(exception_info(exception))
|
@@ -0,0 +1,204 @@
|
|
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
|
+
require 'new_relic/agent/instrumentation/evented_subscriber'
|
5
|
+
begin
|
6
|
+
require 'rack'
|
7
|
+
rescue LoadError => e
|
8
|
+
Agent.logger.debug(e)
|
9
|
+
end
|
10
|
+
|
11
|
+
module NewRelic
|
12
|
+
module Agent
|
13
|
+
module Instrumentation
|
14
|
+
class ActionControllerSubscriber < EventedSubscriber
|
15
|
+
def initialize
|
16
|
+
super
|
17
|
+
NewRelic::Agent.instance.events.subscribe(:before_call) do |env|
|
18
|
+
|
19
|
+
request = begin
|
20
|
+
::Rack::Request.new(env)
|
21
|
+
rescue => e
|
22
|
+
Agent.logger.debug("Error creating Rack::Request object: #{e}")
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
TransactionInfo.reset(request)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def start(name, id, payload)
|
30
|
+
payload[:request] = TransactionInfo.get.request
|
31
|
+
event = ControllerEvent.new(name, Time.now, nil, id, payload)
|
32
|
+
push_event(event)
|
33
|
+
|
34
|
+
if NewRelic::Agent.is_execution_traced? && !event.ignored?
|
35
|
+
start_transaction(event)
|
36
|
+
else
|
37
|
+
# if this transaction is ignored, make sure child
|
38
|
+
# transaction are also ignored
|
39
|
+
NewRelic::Agent.instance.push_trace_execution_flag(false)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def finish(name, id, payload)
|
44
|
+
event = pop_event(id)
|
45
|
+
event.payload.merge!(payload)
|
46
|
+
|
47
|
+
set_enduser_ignore if event.enduser_ignored?
|
48
|
+
|
49
|
+
if NewRelic::Agent.is_execution_traced? && !event.ignored?
|
50
|
+
event.finalize_metric_name!
|
51
|
+
record_queue_time(event)
|
52
|
+
record_metrics(event)
|
53
|
+
record_apdex(event)
|
54
|
+
record_instance_busy(event)
|
55
|
+
stop_transaction(event)
|
56
|
+
else
|
57
|
+
Agent.instance.pop_trace_execution_flag
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def set_enduser_ignore
|
62
|
+
TransactionInfo.get.ignore_end_user = 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
|
+
controller_metric.scope = StatsEngine::MetricStats::SCOPE_PLACEHOLDER
|
71
|
+
record_metric_on_parent_transaction(controller_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
|
+
Agent.instance.stats_engine.transaction_stats_stack[-2] \
|
80
|
+
.record(metric, time)
|
81
|
+
end
|
82
|
+
|
83
|
+
def record_apdex(event)
|
84
|
+
return if event.apdex_ignored?
|
85
|
+
metric_parser = MetricParser::MetricParser \
|
86
|
+
.for_metric_named(event.metric_name)
|
87
|
+
duration_plus_queue_time = event.end - (event.queue_start || event.time)
|
88
|
+
Transaction.record_apdex(metric_parser,
|
89
|
+
event.duration,
|
90
|
+
duration_plus_queue_time,
|
91
|
+
event.exception_encountered?)
|
92
|
+
end
|
93
|
+
|
94
|
+
def record_instance_busy(event)
|
95
|
+
BusyCalculator.dispatcher_start(event.time)
|
96
|
+
BusyCalculator.dispatcher_finish(event.end)
|
97
|
+
end
|
98
|
+
|
99
|
+
def record_queue_time(event)
|
100
|
+
return unless event.queue_start
|
101
|
+
QueueTime.record_frontend_metrics(event.queue_start, event.time)
|
102
|
+
end
|
103
|
+
|
104
|
+
def start_transaction(event)
|
105
|
+
txn = Transaction.start(:controller,
|
106
|
+
:request => event.payload[:request],
|
107
|
+
:filtered_params => filter(event.payload[:params]))
|
108
|
+
txn.apdex_start = (event.queue_start || event.time)
|
109
|
+
event.scope = Agent.instance.stats_engine \
|
110
|
+
.push_scope(:action_controller, event.time)
|
111
|
+
end
|
112
|
+
|
113
|
+
def stop_transaction(event)
|
114
|
+
TransactionInfo.get.transaction.name = event.metric_name
|
115
|
+
Agent.instance.stats_engine \
|
116
|
+
.pop_scope(event.scope, event.metric_name, event.end)
|
117
|
+
Transaction.stop
|
118
|
+
end
|
119
|
+
|
120
|
+
def filter(params)
|
121
|
+
filters = Rails.application.config.filter_parameters
|
122
|
+
ActionDispatch::Http::ParameterFilter.new(filters).filter(params)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
class ControllerEvent < Event
|
127
|
+
attr_accessor :parent, :scope
|
128
|
+
attr_reader :queue_start
|
129
|
+
|
130
|
+
def initialize(name, start, ending, transaction_id, payload)
|
131
|
+
super
|
132
|
+
|
133
|
+
@controller_class = payload[:controller].split('::') \
|
134
|
+
.inject(Object){|m,o| m.const_get(o)}
|
135
|
+
|
136
|
+
if payload[:request] && payload[:request].respond_to?(:env)
|
137
|
+
@queue_start = QueueTime.parse_frontend_timestamp(payload[:request].env, self.time)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def metric_name
|
142
|
+
@metric_name || "Controller/#{metric_path}/#{metric_action}"
|
143
|
+
end
|
144
|
+
|
145
|
+
def finalize_metric_name!
|
146
|
+
txn = NewRelic::Agent::Transaction.current
|
147
|
+
|
148
|
+
# the event provides the default name but the transaction has the final say
|
149
|
+
txn.name ||= metric_name
|
150
|
+
|
151
|
+
# this applies the transaction name rules if not already applied
|
152
|
+
txn.freeze_name
|
153
|
+
@metric_name = txn.name
|
154
|
+
return @metric_name
|
155
|
+
end
|
156
|
+
|
157
|
+
def metric_path
|
158
|
+
@controller_class.controller_path
|
159
|
+
end
|
160
|
+
|
161
|
+
def metric_action
|
162
|
+
payload[:action]
|
163
|
+
end
|
164
|
+
|
165
|
+
def ignored?
|
166
|
+
_is_filtered?('do_not_trace')
|
167
|
+
end
|
168
|
+
|
169
|
+
def apdex_ignored?
|
170
|
+
_is_filtered?('ignore_apdex')
|
171
|
+
end
|
172
|
+
|
173
|
+
def enduser_ignored?
|
174
|
+
_is_filtered?('ignore_enduser')
|
175
|
+
end
|
176
|
+
|
177
|
+
def exception_encountered?
|
178
|
+
payload[:exception]
|
179
|
+
end
|
180
|
+
|
181
|
+
# FIXME: shamelessly ripped from ControllerInstrumentation
|
182
|
+
def _is_filtered?(key)
|
183
|
+
if @controller_class.respond_to? :newrelic_read_attr
|
184
|
+
ignore_actions = @controller_class.newrelic_read_attr(key)
|
185
|
+
end
|
186
|
+
|
187
|
+
case ignore_actions
|
188
|
+
when nil; false
|
189
|
+
when Hash
|
190
|
+
only_actions = Array(ignore_actions[:only])
|
191
|
+
except_actions = Array(ignore_actions[:except])
|
192
|
+
only_actions.include?(metric_action.to_sym) || (except_actions.any? && !except_actions.include?(metric_action.to_sym))
|
193
|
+
else
|
194
|
+
true
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def to_s
|
199
|
+
"#<NewRelic::Agent::Instrumentation::ControllerEvent:#{object_id} name: \"#{name}\" id: #{transaction_id} payload: #{payload}}>"
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|