wd_newrelic_rpm 3.5.6 → 3.5.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. data/CHANGELOG +43 -3
  2. data/Gemfile +6 -2
  3. data/LICENSE +23 -0
  4. data/lib/new_relic/agent.rb +50 -3
  5. data/lib/new_relic/agent/agent.rb +40 -60
  6. data/lib/new_relic/agent/configuration/defaults.rb +9 -3
  7. data/lib/new_relic/agent/configuration/server_source.rb +4 -0
  8. data/lib/new_relic/agent/cross_app_monitor.rb +239 -0
  9. data/lib/new_relic/agent/cross_app_tracing.rb +281 -0
  10. data/lib/new_relic/agent/database.rb +28 -10
  11. data/lib/new_relic/agent/error_collector.rb +5 -0
  12. data/lib/new_relic/agent/event_listener.rb +4 -0
  13. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +58 -39
  14. data/lib/new_relic/agent/instrumentation/metric_frame.rb +16 -3
  15. data/lib/new_relic/agent/instrumentation/net.rb +13 -11
  16. data/lib/new_relic/agent/instrumentation/queue_time.rb +50 -192
  17. data/lib/new_relic/agent/instrumentation/rails4/action_controller.rb +145 -0
  18. data/lib/new_relic/agent/instrumentation/rails4/errors.rb +45 -0
  19. data/lib/new_relic/agent/instrumentation/resque.rb +10 -10
  20. data/lib/new_relic/agent/instrumentation/sinatra.rb +19 -9
  21. data/lib/new_relic/agent/new_relic_service.rb +63 -9
  22. data/lib/new_relic/agent/pipe_service.rb +8 -12
  23. data/lib/new_relic/agent/rules_engine.rb +72 -0
  24. data/lib/new_relic/agent/shim_agent.rb +0 -1
  25. data/lib/new_relic/agent/sql_sampler.rb +3 -2
  26. data/lib/new_relic/agent/stats.rb +149 -0
  27. data/lib/new_relic/agent/stats_engine.rb +9 -0
  28. data/lib/new_relic/agent/stats_engine/gc_profiler.rb +1 -24
  29. data/lib/new_relic/agent/stats_engine/metric_stats.rb +84 -185
  30. data/lib/new_relic/agent/stats_engine/stats_hash.rb +58 -0
  31. data/lib/new_relic/agent/stats_engine/transactions.rb +10 -2
  32. data/lib/new_relic/agent/transaction_info.rb +31 -6
  33. data/lib/new_relic/agent/transaction_sample_builder.rb +19 -8
  34. data/lib/new_relic/agent/transaction_sampler.rb +17 -10
  35. data/lib/new_relic/helper.rb +32 -0
  36. data/lib/new_relic/local_environment.rb +24 -32
  37. data/lib/new_relic/okjson.rb +599 -0
  38. data/lib/new_relic/transaction_sample.rb +2 -1
  39. data/lib/new_relic/transaction_sample/segment.rb +2 -1
  40. data/lib/new_relic/version.rb +1 -1
  41. data/newrelic.yml +27 -41
  42. data/test/multiverse/suites/agent_only/Envfile +5 -1
  43. data/test/multiverse/suites/agent_only/audit_log_test.rb +2 -4
  44. data/test/multiverse/suites/agent_only/config/newrelic.yml +1 -2
  45. data/test/multiverse/suites/agent_only/{cross_process_test.rb → cross_application_tracing_test.rb} +3 -3
  46. data/test/multiverse/suites/agent_only/key_transactions_test.rb +66 -0
  47. data/test/multiverse/suites/agent_only/marshaling_test.rb +9 -22
  48. data/test/multiverse/suites/agent_only/rename_rule_test.rb +57 -0
  49. data/test/multiverse/suites/agent_only/start_up_test.rb +1 -1
  50. data/test/multiverse/suites/agent_only/thread_profiling_test.rb +17 -6
  51. data/test/multiverse/suites/rails/error_tracing_test.rb +20 -8
  52. data/test/multiverse/suites/rails/queue_time_test.rb +2 -2
  53. data/test/multiverse/suites/resque/instrumentation_test.rb +4 -3
  54. data/test/multiverse/suites/sinatra/Envfile +2 -0
  55. data/test/multiverse/suites/sinatra/config/newrelic.yml +1 -0
  56. data/test/multiverse/suites/sinatra/sinatra_metric_explosion_test.rb +5 -5
  57. data/test/multiverse/suites/sinatra/sinatra_test.rb +77 -10
  58. data/test/new_relic/agent/agent/connect_test.rb +45 -1
  59. data/test/new_relic/agent/agent/start_worker_thread_test.rb +0 -3
  60. data/test/new_relic/agent/agent_test.rb +20 -40
  61. data/test/new_relic/agent/agent_test_controller_test.rb +27 -60
  62. data/test/new_relic/agent/busy_calculator_test.rb +1 -1
  63. data/test/new_relic/agent/configuration/server_source_test.rb +8 -3
  64. data/test/new_relic/agent/cross_app_monitor_test.rb +237 -0
  65. data/test/new_relic/agent/database_test.rb +60 -16
  66. data/test/new_relic/agent/error_collector_test.rb +28 -4
  67. data/test/new_relic/agent/event_listener_test.rb +23 -2
  68. data/test/new_relic/agent/instrumentation/browser_monitoring_timings_test.rb +1 -1
  69. data/test/new_relic/agent/instrumentation/controller_instrumentation_test.rb +85 -12
  70. data/test/new_relic/agent/instrumentation/metric_frame_test.rb +95 -0
  71. data/test/new_relic/agent/instrumentation/net_instrumentation_test.rb +436 -59
  72. data/test/new_relic/agent/instrumentation/queue_time_test.rb +58 -357
  73. data/test/new_relic/agent/instrumentation/task_instrumentation_test.rb +2 -5
  74. data/test/new_relic/agent/method_tracer_test.rb +4 -2
  75. data/test/new_relic/agent/new_relic_service_test.rb +108 -6
  76. data/test/new_relic/agent/pipe_channel_manager_test.rb +1 -1
  77. data/test/new_relic/agent/pipe_service_test.rb +9 -9
  78. data/test/new_relic/agent/rpm_agent_test.rb +0 -11
  79. data/test/new_relic/agent/rules_engine_test.rb +82 -0
  80. data/test/new_relic/agent/shim_agent_test.rb +0 -4
  81. data/test/new_relic/agent/sql_sampler_test.rb +7 -0
  82. data/test/new_relic/agent/stats_engine/gc_profiler_test.rb +85 -0
  83. data/test/new_relic/agent/stats_engine/metric_stats_test.rb +110 -23
  84. data/test/new_relic/agent/stats_engine_test.rb +1 -46
  85. data/test/new_relic/agent/stats_hash_test.rb +93 -0
  86. data/test/new_relic/agent/stats_test.rb +197 -0
  87. data/test/new_relic/agent/transaction_info_test.rb +63 -11
  88. data/test/new_relic/agent/transaction_sample_builder_test.rb +10 -3
  89. data/test/new_relic/agent/transaction_sampler_test.rb +92 -80
  90. data/test/new_relic/agent/worker_loop_test.rb +1 -1
  91. data/test/new_relic/agent_test.rb +35 -5
  92. data/test/new_relic/control_test.rb +1 -1
  93. data/test/new_relic/fake_collector.rb +87 -9
  94. data/test/new_relic/helper_test.rb +24 -0
  95. data/test/new_relic/metric_data_test.rb +11 -11
  96. data/test/new_relic/metric_spec_test.rb +1 -1
  97. data/test/script/ci.sh +1 -1
  98. data/test/test_contexts.rb +0 -1
  99. data/test/test_helper.rb +21 -3
  100. metadata +34 -41
  101. data/lib/new_relic/agent/cross_process_monitoring.rb +0 -187
  102. data/lib/new_relic/stats.rb +0 -337
  103. data/test/new_relic/agent/cross_process_monitoring_test.rb +0 -190
  104. data/test/new_relic/agent/stats_engine/metric_stats/harvest_test.rb +0 -133
  105. data/test/new_relic/fakes_sending_data.rb +0 -30
  106. data/test/new_relic/stats_test.rb +0 -421
@@ -300,17 +300,30 @@ module NewRelic
300
300
  end
301
301
 
302
302
  def self.record_apdex(current_metric, action_duration, total_duration, is_error)
303
- summary_stat = agent.stats_engine.get_custom_stats("Apdex", NewRelic::ApdexStats)
304
- controller_stat = agent.stats_engine.get_custom_stats(current_metric.apdex_metric_path, NewRelic::ApdexStats)
303
+ summary_stat = agent.stats_engine.lookup_stats("Apdex") ||
304
+ initialize_apdex("Apdex")
305
305
  update_apdex(summary_stat, total_duration, is_error)
306
+
307
+ controller_stat = agent.stats_engine.lookup_stats(current_metric.apdex_metric_path) ||
308
+ initialize_apdex(current_metric.apdex_metric_path)
306
309
  update_apdex(controller_stat, action_duration, is_error)
307
310
  end
308
311
 
312
+ # Apdex min and max values should be initialized to the
313
+ # current apdex_t
314
+ def self.initialize_apdex(metric_name)
315
+ stats = agent.stats_engine.get_stats_no_scope(metric_name)
316
+ apdex_t = TransactionInfo.get.apdex_t
317
+ stats.min_call_time = apdex_t
318
+ stats.max_call_time = apdex_t
319
+ return stats
320
+ end
321
+
309
322
  # Record an apdex value for the given stat. when `failed`
310
323
  # the apdex should be recorded as a failure regardless of duration.
311
324
  def self.update_apdex(stat, duration, failed)
312
325
  duration = duration.to_f
313
- apdex_t = Agent.config[:apdex_t]
326
+ apdex_t = TransactionInfo.get.apdex_t
314
327
  case
315
328
  when failed
316
329
  stat.record_apdex_f
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  DependencyDetection.defer do
2
4
  @name = :net
3
5
 
@@ -7,23 +9,23 @@ DependencyDetection.defer do
7
9
 
8
10
  executes do
9
11
  ::NewRelic::Agent.logger.info 'Installing Net instrumentation'
12
+ require 'new_relic/agent/cross_app_tracing'
10
13
  end
11
-
14
+
12
15
  executes do
13
- Net::HTTP.class_eval do
14
- def request_with_newrelic_trace(*args, &block)
15
- metrics = ["External/#{@address}/Net::HTTP/#{args[0].method}", "External/#{@address}/all", "External/all"]
16
- if NewRelic::Agent::Instrumentation::MetricFrame.recording_web_transaction?
17
- metrics << "External/allWeb"
18
- else
19
- metrics << "External/allOther"
20
- end
21
- self.class.trace_execution_scoped metrics do
22
- request_without_newrelic_trace(*args, &block)
16
+ class Net::HTTP
17
+
18
+ # Instrument outgoing HTTP requests and fire associated events back
19
+ # into the Agent.
20
+ def request_with_newrelic_trace(request, *args, &block)
21
+ NewRelic::Agent::CrossAppTracing.trace_http_request( self, request ) do
22
+ request_without_newrelic_trace( request, *args, &block )
23
23
  end
24
24
  end
25
+
25
26
  alias request_without_newrelic_trace request
26
27
  alias request request_with_newrelic_trace
28
+
27
29
  end
28
30
  end
29
31
  end
@@ -1,210 +1,68 @@
1
1
  module NewRelic
2
2
  module Agent
3
3
  module Instrumentation
4
+ # https://newrelic.com/docs/features/tracking-front-end-time
5
+ # Record queue time metrics based on any of three headers
6
+ # which can be set on the request.
4
7
  module QueueTime
5
- unless defined?(MAIN_HEADER)
6
- MAIN_HEADER = 'HTTP_X_REQUEST_START'
7
- MIDDLEWARE_HEADER = 'HTTP_X_MIDDLEWARE_START'
8
- QUEUE_HEADER = 'HTTP_X_QUEUE_START'
9
- ALT_QUEUE_HEADER = 'HTTP_X_QUEUE_TIME'
10
- HEROKU_QUEUE_HEADER = 'HTTP_X_HEROKU_QUEUE_WAIT_TIME'
11
- APP_HEADER = 'HTTP_X_APPLICATION_START'
12
-
13
- HEADER_REGEX = /([^\s\/,(t=)]+)? ?t=([0-9\.]+)/
14
- SERVER_METRIC = 'WebFrontend/WebServer/'
15
- MIDDLEWARE_METRIC = 'Middleware/'
16
- # no individual queue metric - more than one queue?!
17
- ALL_SERVER_METRIC = 'WebFrontend/WebServer/all'
18
- ALL_MIDDLEWARE_METRIC = 'Middleware/all'
19
- ALL_QUEUE_METRIC = 'WebFrontend/QueueTime'
20
- end
21
-
22
- def parse_frontend_headers(headers)
23
- # these methods add internal state, so we dup so other parts
24
- # of the app don't have to worry about it.
25
- # May have performance implications with very large env hashes
26
- env = headers.dup
27
- add_end_time_header(Time.now, env)
28
- middleware_start = parse_middleware_time_from(env)
29
- queue_start = parse_queue_time_from(env)
30
- server_start = parse_server_time_from(env)
31
- # returned for the controller instrumentation
32
- [middleware_start, queue_start, server_start].min
33
- end
34
-
35
- private
36
-
37
- # main method to extract server time info from env hash,
38
- # records individual server metrics and one roll-up for all servers
39
- def parse_server_time_from(env)
40
- end_time = parse_end_time(env)
41
- matches = get_matches_from_header(MAIN_HEADER, env)
42
-
43
- record_individual_server_stats(end_time, matches)
44
- record_rollup_server_stat(end_time, matches)
45
- end
46
-
47
- def parse_middleware_time_from(env)
48
- end_time = parse_end_time(env)
49
- matches = get_matches_from_header(MIDDLEWARE_HEADER, env)
50
-
51
- record_individual_middleware_stats(end_time, matches)
52
- oldest_time = record_rollup_middleware_stat(end_time, matches)
53
- # notice this bit: we reset the end time to the earliest
54
- # middleware tag so that other frontend metrics don't
55
- # include this time.
56
- add_end_time_header(oldest_time, env)
57
- oldest_time
58
- end
59
-
60
- def parse_queue_time_from(env)
61
- oldest_time = nil
62
- end_time = parse_end_time(env)
63
- alternate_length = check_for_alternate_queue_length(env)
64
- if alternate_length
65
- # skip all that fancy-dan stuff
66
- NewRelic::Agent.get_stats(ALL_QUEUE_METRIC).trace_call(alternate_length)
67
- oldest_time = (end_time - alternate_length) # should be a time
68
- else
69
- matches = get_matches_from_header(QUEUE_HEADER, env)
70
- oldest_time = record_rollup_queue_stat(end_time, matches)
8
+ unless defined?(REQUEST_START_HEADER)
9
+ REQUEST_START_HEADER = 'HTTP_X_REQUEST_START'
10
+ QUEUE_START_HEADER = 'HTTP_X_QUEUE_START'
11
+ QUEUE_DURATION_HEADER = 'HTTP_X_QUEUE_TIME'
12
+ MIDDLEWARE_START_HEADER = 'HTTP_X_MIDDLEWARE_START'
13
+ ALL_QUEUE_METRIC = 'WebFrontend/QueueTime'
14
+ # any timestamps before this are thrown out and the parser
15
+ # will try again with a larger unit (2000/1/1 UTC)
16
+ EARLIEST_ACCEPTABLE_TIMESTAMP = 946684800
17
+ end
18
+
19
+ module_function
20
+
21
+ def parse_frontend_timestamp(headers, now=Time.now)
22
+ candidate_headers = [ REQUEST_START_HEADER, QUEUE_START_HEADER,
23
+ MIDDLEWARE_START_HEADER ]
24
+ earliest = candidate_headers.map do |header|
25
+ if headers[header]
26
+ parse_timestamp(timestamp_string_from_header_value(headers[header]))
27
+ end
28
+ end.compact.min
29
+
30
+ if earliest && earliest > now
31
+ NewRelic::Agent.logger.debug("Negative queue time detected, treating as zero: start=#{earliest.to_f} > now=#{now.to_f}")
32
+ earliest = now
71
33
  end
72
- # notice this bit: we reset the end time to the earliest
73
- # queue tag or the start time minus the queue time so that
74
- # other frontend metrics don't include this time.
75
- add_end_time_header(oldest_time, env)
76
- oldest_time
77
- end
78
34
 
79
- def check_for_alternate_queue_length(env)
80
- heroku_length = check_for_heroku_queue_length(env)
81
- return heroku_length if heroku_length
82
- header = env[ALT_QUEUE_HEADER]
83
- return nil unless header
84
- (header.gsub('t=', '').to_i / 1_000_000.0)
35
+ earliest
85
36
  end
86
37
 
87
- def check_for_heroku_queue_length(env)
88
- header = env[HEROKU_QUEUE_HEADER]
89
- return nil unless header
90
- (header.gsub(/[^0-9]/, '').to_i / 1_000.0)
38
+ def record_frontend_metrics(start_time, now=Time.now)
39
+ NewRelic::Agent.instance.stats_engine.get_stats(ALL_QUEUE_METRIC) \
40
+ .record_data_point((now - start_time).to_f)
91
41
  end
92
42
 
93
- def get_matches_from_header(header, env)
94
- return [] if env.nil?
95
- get_matches(env[header]).map do |name, time|
96
- convert_to_name_time_pair(name, time.sub('.', ''))
43
+ def timestamp_string_from_header_value(value)
44
+ case value
45
+ when /^\s*([\d+\.]+)\s*$/ then $1
46
+ # following regexp intentionally unanchored to handle
47
+ # (ie ignore) leading server names
48
+ when /t=([\d+\.]+)/ then $1
97
49
  end
98
50
  end
99
51
 
100
- def get_matches(string)
101
- string.to_s.scan(HEADER_REGEX)
102
- end
103
-
104
- def convert_to_name_time_pair(name, time)
105
- [name, convert_from_microseconds(time.to_i)]
106
- end
107
-
108
- def record_individual_stat_of_type(type, end_time, matches)
109
- matches = matches.sort_by {|name, time| time }
110
- matches.reverse!
111
- matches.inject(end_time) {|end_time, pair|
112
- name, time = pair
113
- self.send(type, name, time, end_time) if name
114
- time
115
- }
116
- end
117
-
118
- # goes through the list of servers and records each one in
119
- # reverse order, subtracting the time for each successive
120
- # server from the earlier ones in the list.
121
- # an example because it's complicated:
122
- # start data:
123
- # [['a', Time.at(1000)], ['b', Time.at(1001)]], start time: Time.at(1002)
124
- # initial run: Time.at(1002), ['b', Time.at(1001)]
125
- # next: Time.at(1001), ['a', Time.at(1000)]
126
- # see tests for more
127
- def record_individual_server_stats(end_time, matches) # (Time, [[String, Time]]) -> nil
128
- record_individual_stat_of_type(:record_server_time_for, end_time, matches)
129
- end
130
-
131
- def record_individual_middleware_stats(end_time, matches)
132
- record_individual_stat_of_type(:record_middleware_time_for, end_time, matches)
133
- end
134
-
135
- # records the total time for all servers in a rollup metric
136
- def record_rollup_server_stat(end_time, matches) # (Time, [String, Time]) -> nil
137
- record_rollup_stat_of_type(ALL_SERVER_METRIC, end_time, matches)
138
- end
139
-
140
- def record_rollup_middleware_stat(end_time, matches)
141
- record_rollup_stat_of_type(ALL_MIDDLEWARE_METRIC, end_time, matches)
142
- end
143
-
144
- def record_rollup_queue_stat(end_time, matches)
145
- record_rollup_stat_of_type(ALL_QUEUE_METRIC, end_time, matches)
146
- end
147
-
148
- def record_rollup_stat_of_type(metric, end_time, matches)
149
- oldest_time = find_oldest_time(matches) || end_time
150
- record_time_stat(metric, oldest_time, end_time)
151
- oldest_time
152
- end
153
-
154
- # searches for the first server to touch a request
155
- def find_oldest_time(matches) # [[String, Time]] -> Time
156
- matches.map do |name, time|
157
- time
158
- end.min
159
- end
160
-
161
- # basically just assembles the metric name
162
- def record_server_time_for(name, start_time, end_time) # (Maybe String, Time, Time) -> nil
163
- record_time_stat(SERVER_METRIC + name, start_time, end_time) if name
164
- end
165
-
166
- def record_middleware_time_for(name, start_time, end_time)
167
- record_time_stat(MIDDLEWARE_METRIC + name, start_time, end_time)
168
- end
169
-
170
- # Checks that the time is not negative, and does the actual
171
- # data recording
172
- def record_time_stat(name, start_time, end_time) # (String, Time, Time) -> nil
173
- total_time = end_time - start_time
174
- if total_time < 0
175
- raise "should not provide an end time less than start time: #{end_time.strftime('%s.%N')} is less than #{start_time.strftime('%s.%N')}. total time is #{total_time}."
176
- else
177
- NewRelic::Agent.get_stats(name).trace_call(total_time)
178
- end
179
- end
180
-
181
- def add_end_time_header(end_time, env) # (Time, Env) -> nil
182
- return unless end_time
183
- env[APP_HEADER] = "t=#{convert_to_microseconds(end_time)}"
184
- end
185
-
186
- def parse_end_time(env)
187
- header = env[APP_HEADER]
188
- return Time.now unless header
189
- convert_from_microseconds(header.gsub('t=', '').to_i)
190
- end
191
-
192
- # convert a time to the value provided by the header, for convenience
193
- def convert_to_microseconds(time) # Time -> Int
194
- raise TypeError.new('Cannot convert a non-time into microseconds') unless time.is_a?(Time) || time.is_a?(Numeric)
195
- return time if time.is_a?(Numeric)
196
- (time.to_f * 1_000_000).to_i
197
- end
198
-
199
- # convert a time from the header value (time in microseconds)
200
- # into a ruby time object
201
- def convert_from_microseconds(int) # Int -> Time
202
- raise TypeError.new('Cannot convert a non-number into a time') unless int.is_a?(Time) || int.is_a?(Numeric)
203
- return int if int.is_a?(Time)
204
- Time.at((int / 1_000_000.0))
52
+ def parse_timestamp(string)
53
+ cut_off = Time.at(EARLIEST_ACCEPTABLE_TIMESTAMP)
54
+ [1_000_000, 1_000, 1].map do |divisor|
55
+ begin
56
+ Time.at(string.to_f / divisor)
57
+ rescue RangeError
58
+ # On Ruby versions built with a 32-bit time_t, attempting to
59
+ # instantiate a Time object in the far future raises a RangeError,
60
+ # in which case we know we've chosen the wrong divisor.
61
+ nil
62
+ end
63
+ end.compact.find { |candidate| candidate > cut_off }
205
64
  end
206
65
  end
207
66
  end
208
67
  end
209
68
  end
210
-
@@ -0,0 +1,145 @@
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 Instrumentation
8
+ module Rails4
9
+ module ActionController
10
+ def self.newrelic_write_attr(attr_name, value) # :nodoc:
11
+ write_inheritable_attribute(attr_name, value)
12
+ end
13
+
14
+ def self.newrelic_read_attr(attr_name) # :nodoc:
15
+ read_inheritable_attribute(attr_name)
16
+ end
17
+
18
+ # determine the path that is used in the metric name for
19
+ # the called controller action
20
+ def newrelic_metric_path(action_name_override = nil)
21
+ action_part = action_name_override || action_name
22
+ if action_name_override || self.class.action_methods.include?(action_part)
23
+ "#{self.class.controller_path}/#{action_part}"
24
+ else
25
+ "#{self.class.controller_path}/(other)"
26
+ end
27
+ end
28
+
29
+ def process_action(*args)
30
+ # skip instrumentation if we are in an ignored action
31
+ if _is_filtered?('do_not_trace')
32
+ NewRelic::Agent.disable_all_tracing do
33
+ return super
34
+ end
35
+ end
36
+
37
+ 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
38
+ super
39
+ end
40
+ end
41
+
42
+ end
43
+
44
+ module ActionView
45
+ module NewRelic
46
+ extend self
47
+ def template_metric(identifier, options = {})
48
+ if options[:file]
49
+ "file"
50
+ elsif identifier.nil?
51
+ "(unknown)"
52
+ elsif identifier.include? '/' # this is a filepath
53
+ identifier.split('/')[-2..-1].join('/')
54
+ else
55
+ identifier
56
+ end
57
+ end
58
+ def render_type(file_path)
59
+ file = File.basename(file_path)
60
+ if file.starts_with?('_')
61
+ return 'Partial'
62
+ else
63
+ return 'Rendering'
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ DependencyDetection.defer do
74
+ @name = :rails4_controller
75
+
76
+ depends_on do
77
+ defined?(::Rails) && ::Rails::VERSION::MAJOR.to_i == 4
78
+ end
79
+
80
+ depends_on do
81
+ defined?(ActionController) && defined?(ActionController::Base)
82
+ end
83
+
84
+ executes do
85
+ ::NewRelic::Agent.logger.info 'Installing Rails 4 Controller instrumentation'
86
+ end
87
+
88
+ executes do
89
+ class ActionController::Base
90
+ include NewRelic::Agent::Instrumentation::ControllerInstrumentation
91
+ include NewRelic::Agent::Instrumentation::Rails4::ActionController
92
+ end
93
+ end
94
+ end
95
+
96
+ DependencyDetection.defer do
97
+ @name = :rails40_view
98
+
99
+ depends_on do
100
+ defined?(::Rails) && ::Rails::VERSION::MAJOR.to_i == 4
101
+ end
102
+
103
+ depends_on do
104
+ !NewRelic::Agent.config[:disable_view_instrumentation]
105
+ end
106
+
107
+ executes do
108
+ ::NewRelic::Agent.logger.info 'Installing Rails 4 view instrumentation'
109
+ end
110
+
111
+ executes do
112
+ ActionView::TemplateRenderer.class_eval do
113
+ include NewRelic::Agent::MethodTracer
114
+ # namespaced helper methods
115
+
116
+ def render_with_newrelic(context, options)
117
+ @details = extract_details(options) if respond_to? :extract_details, true
118
+ identifier = determine_template(options) ? determine_template(options).identifier : nil
119
+ str = "View/#{NewRelic::Agent::Instrumentation::Rails4::ActionView::NewRelic.template_metric(identifier, options)}/Rendering"
120
+ trace_execution_scoped str do
121
+ render_without_newrelic(context, options)
122
+ end
123
+ end
124
+
125
+ alias_method :render_without_newrelic, :render
126
+ alias_method :render, :render_with_newrelic
127
+ end
128
+
129
+ ActionView::PartialRenderer.class_eval do
130
+ include NewRelic::Agent::MethodTracer
131
+
132
+ def render_with_newrelic(*args, &block)
133
+ setup(*args, &block)
134
+ identifier = find_partial ? find_partial.identifier : nil
135
+ str = "View/#{NewRelic::Agent::Instrumentation::Rails4::ActionView::NewRelic.template_metric(identifier)}/Partial"
136
+ trace_execution_scoped str do
137
+ render_without_newrelic(*args, &block)
138
+ end
139
+ end
140
+
141
+ alias_method :render_without_newrelic, :render
142
+ alias_method :render, :render_with_newrelic
143
+ end
144
+ end
145
+ end