newrelic_rpm 4.0.0.332 → 4.1.0.333

Sign up to get free protection for your applications and to get access to all the features.
Files changed (167) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +0 -1
  3. data/CHANGELOG.md +22 -0
  4. data/LICENSE +1 -27
  5. data/README.md +4 -57
  6. data/lib/new_relic/agent.rb +0 -1
  7. data/lib/new_relic/agent/attribute_filter.rb +0 -1
  8. data/lib/new_relic/agent/configuration/default_source.rb +3 -32
  9. data/lib/new_relic/agent/error_collector.rb +0 -2
  10. data/lib/new_relic/agent/http_clients/curb_wrappers.rb +1 -1
  11. data/lib/new_relic/agent/http_clients/typhoeus_wrappers.rb +1 -1
  12. data/lib/new_relic/agent/http_clients/uri_util.rb +12 -7
  13. data/lib/new_relic/agent/stats.rb +0 -14
  14. data/lib/new_relic/agent/stats_engine.rb +171 -3
  15. data/lib/new_relic/agent/supported_versions.rb +9 -9
  16. data/lib/new_relic/agent/traced_method_stack.rb +1 -1
  17. data/lib/new_relic/agent/transaction/attributes.rb +0 -2
  18. data/lib/new_relic/agent/transaction/external_request_segment.rb +1 -5
  19. data/lib/new_relic/agent/transaction/trace_node.rb +0 -10
  20. data/lib/new_relic/agent/transaction_sample_builder.rb +0 -3
  21. data/lib/new_relic/agent/transaction_sampler.rb +3 -13
  22. data/lib/new_relic/collection_helper.rb +0 -18
  23. data/lib/new_relic/control/frameworks/rails.rb +1 -21
  24. data/lib/new_relic/control/frameworks/rails3.rb +1 -1
  25. data/lib/new_relic/noticed_error.rb +1 -0
  26. data/lib/new_relic/version.rb +1 -1
  27. data/newrelic.yml +0 -4
  28. data/newrelic_rpm.gemspec +1 -1
  29. data/test/config/newrelic.yml +1 -1
  30. data/test/multiverse/lib/multiverse/runner.rb +9 -1
  31. data/test/multiverse/suites/active_record/config/newrelic.yml +0 -1
  32. data/test/multiverse/suites/agent_only/config/newrelic.yml +0 -1
  33. data/test/multiverse/suites/capistrano/config/newrelic.yml +0 -1
  34. data/test/multiverse/suites/capistrano2/config/newrelic.yml +0 -1
  35. data/test/multiverse/suites/curb/config/newrelic.yml +0 -1
  36. data/test/multiverse/suites/datamapper/config/newrelic.yml +0 -1
  37. data/test/multiverse/suites/deferred_instrumentation/config/newrelic.yml +0 -1
  38. data/test/multiverse/suites/delayed_job/config/newrelic.yml +0 -1
  39. data/test/multiverse/suites/excon/config/newrelic.yml +0 -1
  40. data/test/multiverse/suites/grape/config/newrelic.yml +0 -1
  41. data/test/multiverse/suites/high_security/config/newrelic.yml +0 -1
  42. data/test/multiverse/suites/httpclient/config/newrelic.yml +0 -1
  43. data/test/multiverse/suites/httprb/config/newrelic.yml +0 -1
  44. data/test/multiverse/suites/json/config/newrelic.yml +0 -1
  45. data/test/multiverse/suites/marshalling/config/newrelic.yml +0 -1
  46. data/test/multiverse/suites/mongo/config/newrelic.yml +0 -1
  47. data/test/multiverse/suites/net_http/config/newrelic.yml +0 -1
  48. data/test/multiverse/suites/padrino/config/newrelic.yml +0 -1
  49. data/test/multiverse/suites/rack/config/newrelic.yml +0 -1
  50. data/test/multiverse/suites/rails/config/newrelic.yml +0 -1
  51. data/test/multiverse/suites/rake/config/newrelic.yml +0 -1
  52. data/test/multiverse/suites/redis/config/newrelic.yml +0 -1
  53. data/test/multiverse/suites/resque/config/newrelic.yml +0 -1
  54. data/test/multiverse/suites/sequel/config/newrelic.yml +0 -1
  55. data/test/multiverse/suites/sidekiq/config/newrelic.yml +0 -1
  56. data/test/multiverse/suites/sinatra/config/newrelic.yml +0 -1
  57. data/test/multiverse/suites/typhoeus/config/newrelic.yml +0 -1
  58. data/test/multiverse/suites/yajl/config/newrelic.yml +0 -1
  59. data/test/multiverse/test/suite_examples/one/a/config/newrelic.yml +0 -1
  60. data/test/multiverse/test/suite_examples/one/b/config/newrelic.yml +0 -1
  61. data/test/new_relic/agent/agent/connect_test.rb +3 -12
  62. data/test/new_relic/agent/agent/start_test.rb +4 -2
  63. data/test/new_relic/agent/busy_calculator_test.rb +13 -5
  64. data/test/new_relic/agent/pipe_channel_manager_test.rb +3 -4
  65. data/test/new_relic/agent/stats_engine_test.rb +313 -1
  66. data/test/new_relic/agent/stats_test.rb +0 -20
  67. data/test/new_relic/agent/traced_method_stack_test.rb +2 -5
  68. data/test/new_relic/agent/transaction/external_request_segment_test.rb +5 -0
  69. data/test/new_relic/agent/transaction/trace_node_test.rb +0 -19
  70. data/test/new_relic/agent/transaction_sampler_test.rb +3 -6
  71. data/test/new_relic/collection_helper_test.rb +0 -39
  72. data/test/new_relic/control_test.rb +2 -4
  73. data/test/new_relic/license_test.rb +4 -14
  74. data/test/performance/suites/external_segment.rb +0 -2
  75. data/test/performance/suites/rack_middleware.rb +1 -3
  76. data/test/performance/suites/transaction_tracing.rb +0 -1
  77. metadata +2 -94
  78. data/lib/conditional_vendored_metric_parser.rb +0 -9
  79. data/lib/new_relic/agent/instrumentation/rubyprof.rb +0 -26
  80. data/lib/new_relic/agent/stats_engine/metric_stats.rb +0 -188
  81. data/lib/new_relic/agent/transaction/developer_mode_sample_buffer.rb +0 -62
  82. data/lib/new_relic/merbtasks.rb +0 -10
  83. data/lib/new_relic/rack/developer_mode.rb +0 -321
  84. data/lib/new_relic/rack/developer_mode/segment_summary.rb +0 -56
  85. data/test/new_relic/agent/stats_engine/metric_stats_test.rb +0 -328
  86. data/test/new_relic/agent/transaction/developer_mode_sample_buffer_test.rb +0 -75
  87. data/test/new_relic/metric_parser/metric_parser_test.rb +0 -17
  88. data/test/new_relic/rack/developer_mode/segment_summary_test.rb +0 -96
  89. data/test/new_relic/rack/developer_mode_helper_test.rb +0 -136
  90. data/test/new_relic/rack/developer_mode_test.rb +0 -96
  91. data/ui/helpers/developer_mode_helper.rb +0 -325
  92. data/ui/helpers/google_pie_chart.rb +0 -54
  93. data/ui/views/layouts/newrelic_default.rhtml +0 -48
  94. data/ui/views/newrelic/_explain_plans.rhtml +0 -27
  95. data/ui/views/newrelic/_sample.rhtml +0 -20
  96. data/ui/views/newrelic/_segment.rhtml +0 -28
  97. data/ui/views/newrelic/_segment_limit_message.rhtml +0 -1
  98. data/ui/views/newrelic/_segment_row.rhtml +0 -12
  99. data/ui/views/newrelic/_show_sample_detail.rhtml +0 -24
  100. data/ui/views/newrelic/_show_sample_sql.rhtml +0 -24
  101. data/ui/views/newrelic/_show_sample_summary.rhtml +0 -3
  102. data/ui/views/newrelic/_sql_row.rhtml +0 -16
  103. data/ui/views/newrelic/_stack_trace.rhtml +0 -15
  104. data/ui/views/newrelic/_table.rhtml +0 -12
  105. data/ui/views/newrelic/explain_sql.rhtml +0 -43
  106. data/ui/views/newrelic/file/images/arrow-close.png +0 -0
  107. data/ui/views/newrelic/file/images/arrow-open.png +0 -0
  108. data/ui/views/newrelic/file/images/blue_bar.gif +0 -0
  109. data/ui/views/newrelic/file/images/file_icon.png +0 -0
  110. data/ui/views/newrelic/file/images/gray_bar.gif +0 -0
  111. data/ui/views/newrelic/file/images/new-relic-rpm-desktop.gif +0 -0
  112. data/ui/views/newrelic/file/images/new_relic_rpm_desktop.gif +0 -0
  113. data/ui/views/newrelic/file/images/textmate.png +0 -0
  114. data/ui/views/newrelic/file/javascript/jquery-1.4.2.js +0 -6243
  115. data/ui/views/newrelic/file/javascript/transaction_sample.js +0 -123
  116. data/ui/views/newrelic/file/stylesheets/style.css +0 -490
  117. data/ui/views/newrelic/index.rhtml +0 -70
  118. data/ui/views/newrelic/sample_not_found.rhtml +0 -2
  119. data/ui/views/newrelic/show_sample.rhtml +0 -81
  120. data/ui/views/newrelic/threads.rhtml +0 -45
  121. data/vendor/gems/metric_parser-0.1.0.pre1/.specification +0 -116
  122. data/vendor/gems/metric_parser-0.1.0.pre1/lib/metric_parser.rb +0 -5
  123. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser.rb +0 -70
  124. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/action_mailer.rb +0 -18
  125. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/active_merchant.rb +0 -35
  126. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/active_record.rb +0 -37
  127. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/apdex.rb +0 -93
  128. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/background_transaction.rb +0 -11
  129. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/client.rb +0 -50
  130. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/controller.rb +0 -71
  131. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/controller_cpu.rb +0 -47
  132. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/controller_ext.rb +0 -21
  133. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/database.rb +0 -52
  134. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/database_pool.rb +0 -28
  135. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/dot_net.rb +0 -32
  136. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/dot_net_parser.rb +0 -21
  137. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/errors.rb +0 -15
  138. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/external.rb +0 -59
  139. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/frontend.rb +0 -44
  140. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/gc.rb +0 -24
  141. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/hibernate_session.rb +0 -11
  142. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/java.rb +0 -35
  143. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/java_parser.rb +0 -21
  144. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/jsp.rb +0 -38
  145. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/jsp_tag.rb +0 -11
  146. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/mem_cache.rb +0 -56
  147. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/metric_parser.rb +0 -138
  148. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/middleware.rb +0 -33
  149. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/nested.rb +0 -23
  150. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/orm.rb +0 -31
  151. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/other_transaction.rb +0 -44
  152. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/servlet.rb +0 -11
  153. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/servlet_context_listener.rb +0 -11
  154. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/servlet_filter.rb +0 -11
  155. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/servlet_init.rb +0 -11
  156. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/solr.rb +0 -31
  157. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/solr_request_handler.rb +0 -19
  158. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/spring.rb +0 -58
  159. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/spring_controller.rb +0 -10
  160. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/spring_view.rb +0 -10
  161. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/struts_action.rb +0 -24
  162. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/struts_result.rb +0 -24
  163. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/version.rb +0 -9
  164. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/view.rb +0 -74
  165. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/web_frontend.rb +0 -22
  166. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/web_service.rb +0 -18
  167. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/web_transaction.rb +0 -137
@@ -1,188 +0,0 @@
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
- require 'new_relic/language_support'
6
-
7
- module NewRelic
8
- module Agent
9
- # @api public
10
- class StatsEngine
11
- # Handles methods related to actual Metric collection
12
- # @api public
13
- module MetricStats
14
- SCOPE_PLACEHOLDER = '__SCOPE__'.freeze
15
-
16
- # Update the unscoped metrics given in metric_names.
17
- # metric_names may be either a single name, or an array of names.
18
- #
19
- # This is an internal method, subject to change at any time. Client apps
20
- # and gems should use the public API (NewRelic::Agent.record_metric)
21
- # instead.
22
- #
23
- # There are four ways to use this method:
24
- #
25
- # 1. With a numeric value, it will update the Stats objects associated
26
- # with the given metrics by calling record_data_point(value, aux).
27
- # aux will be treated in this case as the exclusive time associated
28
- # with the call being recorded.
29
- #
30
- # 2. With a value of :apdex_s, :apdex_t, or :apdex_f, it will treat the
31
- # associated stats as an Apdex metric, updating it to reflect the
32
- # occurrence of a transaction falling into the given category.
33
- # The aux value in this case should be the apdex threshold used in
34
- # bucketing the request.
35
- #
36
- # 3. If a block is given, value and aux will be ignored, and instead the
37
- # Stats object associated with each named unscoped metric will be
38
- # yielded to the block for customized update logic.
39
- #
40
- # 4. If value is a Stats instance, it will be merged into the Stats
41
- # associated with each named unscoped metric.
42
- #
43
- # If this method is called during a transaction, the metrics will be
44
- # attached to the Transaction, and not merged into the global set until
45
- # the end of the transaction.
46
- #
47
- # Otherwise, the metrics will be recorded directly into the global set
48
- # of metrics, under a lock.
49
- #
50
- # @api private
51
- #
52
- def tl_record_unscoped_metrics(metric_names, value=nil, aux=nil, &blk)
53
- state = NewRelic::Agent::TransactionState.tl_get
54
- record_unscoped_metrics(state, metric_names, value, aux, &blk)
55
- end
56
-
57
- def record_unscoped_metrics(state, metric_names, value=nil, aux=nil, &blk)
58
- txn = state.current_transaction
59
- if txn
60
- txn.metrics.record_unscoped(metric_names, value, aux, &blk)
61
- else
62
- specs = coerce_to_metric_spec_array(metric_names, nil)
63
- with_stats_lock do
64
- @stats_hash.record(specs, value, aux, &blk)
65
- end
66
- end
67
- end
68
-
69
- # Like tl_record_unscoped_metrics, but records a scoped metric as well.
70
- #
71
- # This is an internal method, subject to change at any time. Client apps
72
- # and gems should use the public API (NewRelic::Agent.record_metric)
73
- # instead.
74
- #
75
- # The given scoped_metric will be recoded as both a scoped *and* an
76
- # unscoped metric. The summary_metrics will be recorded as unscoped
77
- # metrics only.
78
- #
79
- # If called during a transaction, all metrics will be attached to the
80
- # Transaction, and not merged into the global set of metrics until the
81
- # end of the transaction.
82
- #
83
- # If called outside of a transaction, only the *unscoped* metrics will
84
- # be recorded, directly into the global set of metrics (under a lock).
85
- #
86
- # @api private
87
- #
88
- def tl_record_scoped_and_unscoped_metrics(scoped_metric, summary_metrics=nil, value=nil, aux=nil, &blk)
89
- state = NewRelic::Agent::TransactionState.tl_get
90
- record_scoped_and_unscoped_metrics(state, scoped_metric, summary_metrics, value, aux, &blk)
91
- end
92
-
93
- def record_scoped_and_unscoped_metrics(state, scoped_metric, summary_metrics=nil, value=nil, aux=nil, &blk)
94
- txn = state.current_transaction
95
- if txn
96
- txn.metrics.record_scoped_and_unscoped(scoped_metric, value, aux, &blk)
97
- if summary_metrics
98
- txn.metrics.record_unscoped(summary_metrics, value, aux, &blk)
99
- end
100
- else
101
- specs = coerce_to_metric_spec_array(scoped_metric, nil)
102
- if summary_metrics
103
- specs.concat(coerce_to_metric_spec_array(summary_metrics, nil))
104
- end
105
- with_stats_lock do
106
- @stats_hash.record(specs, value, aux, &blk)
107
- end
108
- end
109
- end
110
-
111
- # Helper for recording a straight value into the count
112
- def tl_record_supportability_metric_count(metric, value)
113
- real_name = "Supportability/#{metric}"
114
- tl_record_unscoped_metrics(real_name) do |stat|
115
- stat.call_count = value
116
- end
117
- end
118
-
119
- def reset!
120
- with_stats_lock do
121
- old = @stats_hash
122
- @stats_hash = StatsHash.new
123
- old
124
- end
125
- end
126
-
127
- # merge data from previous harvests into this stats engine
128
- def merge!(other_stats_hash)
129
- with_stats_lock do
130
- @stats_hash.merge!(other_stats_hash)
131
- @stats_hash
132
- end
133
- end
134
-
135
- def merge_transaction_metrics!(txn_metrics, scope)
136
- with_stats_lock do
137
- @stats_hash.merge_transaction_metrics!(txn_metrics, scope)
138
- end
139
- end
140
-
141
- def harvest!
142
- now = Time.now
143
- snapshot = reset!
144
- snapshot = apply_rules_to_metric_data(@metric_rules, snapshot)
145
- snapshot.harvested_at = now
146
- snapshot
147
- end
148
-
149
- def apply_rules_to_metric_data(rules_engine, stats_hash)
150
- renamed_stats = NewRelic::Agent::StatsHash.new(stats_hash.started_at)
151
- stats_hash.each do |spec, stats|
152
- new_name = rules_engine.rename(spec.name)
153
- unless new_name.nil?
154
- new_spec = NewRelic::MetricSpec.new(new_name, spec.scope)
155
- renamed_stats[new_spec].merge!(stats)
156
- end
157
- end
158
- renamed_stats
159
- end
160
-
161
- def coerce_to_metric_spec_array(metric_names_or_specs, scope)
162
- specs = []
163
- Array(metric_names_or_specs).map do |name_or_spec|
164
- case name_or_spec
165
- when String
166
- specs << NewRelic::MetricSpec.new(name_or_spec)
167
- specs << NewRelic::MetricSpec.new(name_or_spec, scope) if scope
168
- when NewRelic::MetricSpec
169
- specs << name_or_spec
170
- end
171
- end
172
- specs
173
- end
174
-
175
- # For use by test code only.
176
- def clear_stats
177
- reset!
178
- NewRelic::Agent::BusyCalculator.reset
179
- end
180
-
181
- # For use by test code only.
182
- def to_h
183
- with_stats_lock { @stats_hash.to_h }
184
- end
185
- end
186
- end
187
- end
188
- end
@@ -1,62 +0,0 @@
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
- require 'new_relic/agent/transaction/transaction_sample_buffer'
6
-
7
- module NewRelic
8
- module Agent
9
- class Transaction
10
- class DeveloperModeSampleBuffer < TransactionSampleBuffer
11
-
12
- CAPACITY = 100
13
-
14
- def capacity
15
- max_capacity
16
- end
17
-
18
- # Dev mode is allowed more than the typical upper limit.
19
- # Sidestep normal cap by overriding max_capacity.
20
- def max_capacity
21
- CAPACITY
22
- end
23
-
24
- def harvest_samples
25
- NO_SAMPLES
26
- end
27
-
28
- def enabled?
29
- Agent.config[:developer_mode]
30
- end
31
-
32
- # Truncate to the last capacity samples we've received
33
- def truncate_samples
34
- @samples = @samples.last(capacity)
35
- end
36
-
37
- # We don't hold onto previously trapped transactions on harvest
38
- # We've already got all the traces we want, thank you!
39
- def store_previous(*)
40
- end
41
-
42
- # Captures the stack trace for a node
43
- # This is expensive and not for production mode
44
- def visit_node(node)
45
- return unless enabled? && node
46
-
47
- trace = strip_newrelic_frames(caller)
48
- trace = trace.first(40) if trace.length > 40
49
- node[:backtrace] = trace
50
- end
51
-
52
- def strip_newrelic_frames(trace)
53
- while trace.first =~/\/lib\/new_relic\/agent\//
54
- trace.shift
55
- end
56
- trace
57
- end
58
-
59
- end
60
- end
61
- end
62
- end
@@ -1,10 +0,0 @@
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
- namespace :newrelic do
6
- desc "Install the developer mode newrelic.yml file"
7
- task :default do
8
- load File.expand_path(File.join(__FILE__,"..","..","install.rb"))
9
- end
10
- end
@@ -1,321 +0,0 @@
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 'rack/request'
5
- require 'rack/response'
6
- require 'rack/file'
7
-
8
- require 'conditional_vendored_metric_parser'
9
- require 'new_relic/collection_helper'
10
- require 'new_relic/metric_parser/metric_parser'
11
- require 'new_relic/rack/agent_middleware'
12
- require 'new_relic/agent/instrumentation/middleware_proxy'
13
-
14
- module NewRelic
15
- module Rack
16
- # This middleware provides the 'developer mode' feature of newrelic_rpm,
17
- # which allows you to see data about local web transactions in development
18
- # mode immediately without needing to send this data to New Relic's servers.
19
- #
20
- # Enabling developer mode has serious performance and security impact, and
21
- # thus you should never use this middleware in a production or non-local
22
- # environment.
23
- #
24
- # This middleware should be automatically inserted in most contexts, but if
25
- # automatic middleware insertion fails, you may manually insert it into your
26
- # middleware chain.
27
- #
28
- # @api public
29
- #
30
- class DeveloperMode < AgentMiddleware
31
-
32
- VIEW_PATH = File.expand_path('../../../../ui/views/' , __FILE__)
33
- HELPER_PATH = File.expand_path('../../../../ui/helpers/', __FILE__)
34
- require File.join(HELPER_PATH, 'developer_mode_helper.rb')
35
- require 'new_relic/rack/developer_mode/segment_summary'
36
-
37
- include NewRelic::DeveloperModeHelper
38
-
39
- class << self
40
- attr_writer :profiling_enabled
41
- end
42
-
43
- def self.profiling_enabled?
44
- @profiling_enabled
45
- end
46
-
47
- def traced_call(env)
48
- return @app.call(env) unless /^\/newrelic/ =~ ::Rack::Request.new(env).path_info
49
- dup._call(env)
50
- end
51
-
52
- protected
53
-
54
- def _call(env)
55
- NewRelic::Agent.ignore_transaction
56
-
57
- @req = ::Rack::Request.new(env)
58
- @rendered = false
59
- case @req.path_info
60
- when /profile/
61
- profile
62
- when /file/
63
- ::Rack::File.new(VIEW_PATH).call(env)
64
- when /index/
65
- index
66
- when /threads/
67
- threads
68
- when /reset/
69
- reset
70
- when /show_sample_detail/
71
- show_sample_data
72
- when /show_sample_summary/
73
- show_sample_data
74
- when /show_sample_sql/
75
- show_sample_data
76
- when /explain_sql/
77
- explain_sql
78
- when /^\/newrelic\/?$/
79
- index
80
- else
81
- @app.call(env)
82
- end
83
- end
84
-
85
- private
86
-
87
- def index
88
- get_samples
89
- render(:index)
90
- end
91
-
92
- def reset
93
- NewRelic::Agent.instance.transaction_sampler.reset!
94
- NewRelic::Agent.instance.sql_sampler.reset!
95
- ::Rack::Response.new{|r| r.redirect('/newrelic/')}.finish
96
- end
97
-
98
- def explain_sql
99
- get_segment
100
-
101
- return render(:sample_not_found) unless @sample
102
-
103
- @sql = @segment[:sql]
104
- @trace = @segment[:backtrace]
105
-
106
- if NewRelic::Agent.agent.record_sql == :obfuscated
107
- @obfuscated_sql = @segment.obfuscated_sql
108
- end
109
-
110
- _headers, explanations = @segment.explain_sql
111
- if explanations
112
- @explanation = explanations
113
- if !@explanation.blank?
114
- first_row = @explanation.first
115
- # Show the standard headers if it looks like a mysql explain plan
116
- # Otherwise show blank headers
117
- if first_row.length < NewRelic::MYSQL_EXPLAIN_COLUMNS.length
118
- @row_headers = nil
119
- else
120
- @row_headers = NewRelic::MYSQL_EXPLAIN_COLUMNS
121
- end
122
- end
123
- end
124
- render(:explain_sql)
125
- end
126
-
127
- def profile
128
- should_be_on = (params['start'] == 'true')
129
- NewRelic::Rack::DeveloperMode.profiling_enabled = should_be_on
130
-
131
- index
132
- end
133
-
134
- def threads
135
- render(:threads)
136
- end
137
-
138
- def render(view, layout=true)
139
- add_rack_array = true
140
- if view.is_a? Hash
141
- layout = false
142
- if view[:object]
143
- # object *is* used here, as it is capture in the binding below
144
- object = view[:object]
145
- end
146
-
147
- if view[:collection]
148
- return view[:collection].map do |obj|
149
- render({:partial => view[:partial], :object => obj})
150
- end.join(' ')
151
- end
152
-
153
- if view[:partial]
154
- add_rack_array = false
155
- view = "_#{view[:partial]}"
156
- end
157
- end
158
- binding = Proc.new {}.binding
159
- if layout
160
- body = render_with_layout(view) do
161
- render_without_layout(view, binding)
162
- end
163
- else
164
- body = render_without_layout(view, binding)
165
- end
166
- if add_rack_array
167
- ::Rack::Response.new(body, 200, {'Content-Type' => 'text/html'}).finish
168
- else
169
- body
170
- end
171
- end
172
-
173
- # You have to call this with a block - the contents returned from
174
- # that block are interpolated into the layout
175
- def render_with_layout(view)
176
- body = ERB.new(File.read(File.join(VIEW_PATH, 'layouts/newrelic_default.rhtml')))
177
- body.result(Proc.new {}.binding)
178
- end
179
-
180
- # you have to pass a binding to this (a proc) so that ERB can have
181
- # access to helper functions and local variables
182
- def render_without_layout(view, binding)
183
- ERB.new(File.read(File.join(VIEW_PATH, 'newrelic', view.to_s + '.rhtml')), nil, nil, 'frobnitz').result(binding)
184
- end
185
-
186
- def content_tag(tag, contents, opts={})
187
- opt_values = opts.map {|k, v| "#{k}=\"#{v}\"" }.join(' ')
188
- "<#{tag} #{opt_values}>#{contents}</#{tag}>"
189
- end
190
-
191
- def sample
192
- @sample || @samples[0]
193
- end
194
-
195
- def params
196
- @req.params
197
- end
198
-
199
- def segment
200
- @segment
201
- end
202
-
203
- def show_sample_data
204
- get_sample
205
-
206
- return render(:sample_not_found) unless @sample
207
-
208
- @request_params = request_attributes_for(@sample)
209
- @custom_params = custom_attributes_for(@sample)
210
-
211
- controller_metric = @sample.transaction_name
212
-
213
- metric_parser = NewRelic::MetricParser::MetricParser.for_metric_named controller_metric
214
- @sample_controller_name = metric_parser.controller_name
215
- @sample_action_name = metric_parser.action_name
216
-
217
- @sql_segments = sql_segments(@sample)
218
- if params['d']
219
- @sql_segments.sort!{|a,b| b.duration <=> a.duration }
220
- end
221
-
222
- sort_method = params['sort'] || :total_time
223
- @profile_options = {:min_percent => 0.5, :sort_method => sort_method.to_sym}
224
-
225
- render(:show_sample)
226
- end
227
-
228
- def get_samples
229
- @samples = NewRelic::Agent.instance.transaction_sampler.dev_mode_sample_buffer.samples.select do |sample|
230
- sample.transaction_name != nil
231
- end
232
-
233
- return @samples = @samples.sort_by(&:duration).reverse if params['h']
234
- return @samples = @samples.sort{|x,y| x.params[:uri] <=> y.params[:uri]} if params['u']
235
- @samples = @samples.reverse
236
- end
237
-
238
- def get_sample
239
- get_samples
240
- id = params['id']
241
- sample_id = id.to_i
242
- @samples.each do |s|
243
- if s.sample_id == sample_id
244
- @sample = s
245
- return
246
- end
247
- end
248
- end
249
-
250
- def get_segment
251
- get_sample
252
- return unless @sample
253
-
254
- segment_id = params['segment'].to_i
255
- @segment = @sample.root_node.find_node(segment_id)
256
- end
257
-
258
- def custom_attributes_for(sample)
259
- sample.attributes.custom_attributes_for(NewRelic::Agent::AttributeFilter::DST_DEVELOPER_MODE)
260
- end
261
-
262
- REQUEST_PARAMETERS_PREFIX = "request.parameters".freeze
263
-
264
- def request_attributes_for(sample)
265
- agent_attributes = sample.attributes.agent_attributes_for(NewRelic::Agent::AttributeFilter::DST_DEVELOPER_MODE)
266
- agent_attributes.inject({}) do |memo, (key, value)|
267
- memo[key] = value if key.to_s.start_with?(REQUEST_PARAMETERS_PREFIX)
268
- memo
269
- end
270
- end
271
-
272
- def breakdown_data(sample, limit = nil)
273
- metric_hash = {}
274
- sample.each_node_with_nest_tracking do |node|
275
- unless node == sample.root_node
276
- metric_name = node.metric_name
277
- metric_hash[metric_name] ||= SegmentSummary.new(metric_name, sample)
278
- metric_hash[metric_name] << node
279
- metric_hash[metric_name]
280
- end
281
- end
282
-
283
- data = metric_hash.values
284
-
285
- data.sort! do |x,y|
286
- y.exclusive_time <=> x.exclusive_time
287
- end
288
-
289
- if limit && data.length > limit
290
- data = data[0..limit - 1]
291
- end
292
-
293
- # add one last node for the remaining time if any
294
- remainder = sample.duration
295
- data.each do |node|
296
- remainder -= node.exclusive_time
297
- end
298
-
299
- if (remainder*1000).round > 0
300
- remainder_summary = SegmentSummary.new('Remainder', sample)
301
- remainder_summary.total_time = remainder_summary.exclusive_time = remainder
302
- remainder_summary.call_count = 1
303
- data << remainder_summary
304
- end
305
-
306
- data
307
- end
308
-
309
- # return an array of sql statements executed by this transaction
310
- # each element in the array contains [sql, parent_segment_metric_name, duration]
311
- def sql_segments(sample, show_non_sql_segments = true)
312
- segments = []
313
- sample.each_node do |segment|
314
- segments << segment if segment[:sql] || segment[:sql_obfuscated] || (show_non_sql_segments && segment[:key])
315
- end
316
- segments
317
- end
318
-
319
- end
320
- end
321
- end