newrelic_rpm 2.9.9 → 2.10.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of newrelic_rpm might be problematic. Click here for more details.

Files changed (120) hide show
  1. data/CHANGELOG +117 -49
  2. data/bin/mongrel_rpm +2 -2
  3. data/install.rb +42 -33
  4. data/lib/new_relic/agent.rb +149 -39
  5. data/lib/new_relic/agent/agent.rb +139 -122
  6. data/lib/new_relic/agent/busy_calculator.rb +91 -0
  7. data/lib/new_relic/agent/collection_helper.rb +11 -2
  8. data/lib/new_relic/agent/error_collector.rb +33 -27
  9. data/lib/new_relic/agent/instrumentation/active_record_instrumentation.rb +30 -26
  10. data/lib/new_relic/agent/instrumentation/authlogic.rb +8 -0
  11. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +316 -105
  12. data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +22 -0
  13. data/lib/new_relic/agent/instrumentation/memcache.rb +18 -12
  14. data/lib/new_relic/agent/instrumentation/merb/errors.rb +2 -1
  15. data/lib/new_relic/agent/instrumentation/metric_frame.rb +258 -0
  16. data/lib/new_relic/agent/instrumentation/net.rb +7 -11
  17. data/lib/new_relic/agent/instrumentation/passenger_instrumentation.rb +1 -1
  18. data/lib/new_relic/agent/instrumentation/rack.rb +109 -0
  19. data/lib/new_relic/agent/instrumentation/rails/action_controller.rb +6 -5
  20. data/lib/new_relic/agent/instrumentation/rails/errors.rb +7 -7
  21. data/lib/new_relic/agent/instrumentation/sinatra.rb +46 -0
  22. data/lib/new_relic/agent/method_tracer.rb +305 -150
  23. data/lib/new_relic/agent/sampler.rb +34 -0
  24. data/lib/new_relic/agent/samplers/cpu_sampler.rb +11 -1
  25. data/lib/new_relic/agent/samplers/delayed_job_lock_sampler.rb +37 -0
  26. data/lib/new_relic/agent/samplers/memory_sampler.rb +22 -10
  27. data/lib/new_relic/agent/samplers/object_sampler.rb +24 -0
  28. data/lib/new_relic/agent/shim_agent.rb +10 -0
  29. data/lib/new_relic/agent/stats_engine.rb +16 -278
  30. data/lib/new_relic/agent/stats_engine/metric_stats.rb +118 -0
  31. data/lib/new_relic/agent/stats_engine/samplers.rb +81 -0
  32. data/lib/new_relic/agent/stats_engine/transactions.rb +149 -0
  33. data/lib/new_relic/agent/transaction_sampler.rb +73 -67
  34. data/lib/new_relic/agent/worker_loop.rb +69 -68
  35. data/lib/new_relic/commands/deployments.rb +4 -6
  36. data/lib/new_relic/control.rb +121 -60
  37. data/lib/new_relic/control/external.rb +13 -0
  38. data/lib/new_relic/control/merb.rb +2 -0
  39. data/lib/new_relic/control/rails.rb +16 -6
  40. data/lib/new_relic/control/ruby.rb +8 -5
  41. data/lib/new_relic/control/sinatra.rb +18 -0
  42. data/lib/new_relic/delayed_job_injection.rb +25 -0
  43. data/lib/new_relic/histogram.rb +89 -0
  44. data/lib/new_relic/local_environment.rb +64 -30
  45. data/lib/new_relic/metric_data.rb +15 -6
  46. data/lib/new_relic/metric_parser.rb +14 -1
  47. data/lib/new_relic/metric_parser/active_record.rb +14 -0
  48. data/lib/new_relic/metric_parser/controller.rb +5 -2
  49. data/lib/new_relic/metric_parser/external.rb +50 -0
  50. data/lib/new_relic/metric_parser/other_transaction.rb +15 -0
  51. data/lib/new_relic/metric_parser/web_frontend.rb +14 -0
  52. data/lib/new_relic/metric_spec.rb +39 -20
  53. data/lib/new_relic/metrics.rb +9 -7
  54. data/lib/new_relic/noticed_error.rb +6 -8
  55. data/lib/new_relic/rack/metric_app.rb +5 -4
  56. data/lib/new_relic/rack/{newrelic.ru → mongrel_rpm.ru} +4 -4
  57. data/lib/new_relic/rack/newrelic.yml +1 -0
  58. data/lib/new_relic/{rack.rb → rack_app.rb} +0 -0
  59. data/lib/new_relic/recipes.rb +1 -1
  60. data/lib/new_relic/stats.rb +40 -26
  61. data/lib/new_relic/transaction_analysis.rb +5 -2
  62. data/lib/new_relic/transaction_sample.rb +134 -55
  63. data/lib/new_relic/version.rb +27 -20
  64. data/lib/new_relic_api.rb +67 -47
  65. data/lib/newrelic_rpm.rb +5 -5
  66. data/lib/tasks/tests.rake +2 -0
  67. data/newrelic.yml +69 -29
  68. data/test/active_record_fixtures.rb +2 -2
  69. data/test/config/newrelic.yml +4 -7
  70. data/test/config/test_control.rb +1 -2
  71. data/test/new_relic/agent/active_record_instrumentation_test.rb +115 -31
  72. data/test/new_relic/agent/agent_controller_test.rb +274 -0
  73. data/test/new_relic/agent/agent_test_controller.rb +42 -6
  74. data/test/new_relic/agent/busy_calculator_test.rb +79 -0
  75. data/test/new_relic/agent/collection_helper_test.rb +10 -3
  76. data/test/new_relic/agent/error_collector_test.rb +35 -17
  77. data/test/new_relic/agent/method_tracer_test.rb +60 -20
  78. data/test/new_relic/agent/metric_data_test.rb +2 -2
  79. data/test/new_relic/agent/metric_frame_test.rb +51 -0
  80. data/test/new_relic/agent/net_instrumentation_test.rb +77 -0
  81. data/test/new_relic/agent/{agent_test.rb → rpm_agent_test.rb} +26 -5
  82. data/test/new_relic/agent/stats_engine/metric_stats_test.rb +79 -0
  83. data/test/new_relic/{samplers_test.rb → agent/stats_engine/samplers_test.rb} +23 -22
  84. data/test/new_relic/agent/{stats_engine_test.rb → stats_engine/stats_engine_test.rb} +19 -101
  85. data/test/new_relic/agent/task_instrumentation_test.rb +176 -0
  86. data/test/new_relic/agent/transaction_sample_builder_test.rb +2 -2
  87. data/test/new_relic/agent/transaction_sample_test.rb +53 -38
  88. data/test/new_relic/agent/transaction_sampler_test.rb +101 -33
  89. data/test/new_relic/agent/worker_loop_test.rb +16 -14
  90. data/test/new_relic/control_test.rb +26 -13
  91. data/test/new_relic/metric_parser_test.rb +31 -1
  92. data/test/new_relic/metric_spec_test.rb +2 -2
  93. data/test/new_relic/stats_test.rb +0 -8
  94. data/test/new_relic/version_number_test.rb +31 -1
  95. data/test/test_helper.rb +37 -1
  96. data/ui/controllers/newrelic_controller.rb +19 -11
  97. data/ui/helpers/google_pie_chart.rb +5 -11
  98. data/ui/helpers/newrelic_helper.rb +40 -35
  99. data/ui/views/layouts/newrelic_default.rhtml +7 -7
  100. data/ui/views/newrelic/_sample.rhtml +5 -1
  101. data/ui/views/newrelic/images/new-relic-rpm-desktop.gif +0 -0
  102. data/ui/views/newrelic/images/textmate.png +0 -0
  103. data/ui/views/newrelic/index.rhtml +13 -1
  104. data/ui/views/newrelic/show_sample.rhtml +5 -2
  105. data/ui/views/newrelic/stylesheets/style.css +54 -3
  106. metadata +65 -145
  107. data/Manifest +0 -143
  108. data/Rakefile +0 -22
  109. data/init.rb +0 -38
  110. data/lib/new_relic/agent/instrumentation/dispatcher_instrumentation.rb +0 -127
  111. data/lib/new_relic/agent/instrumentation/error_instrumentation.rb +0 -14
  112. data/lib/new_relic/agent/instrumentation/merb/dispatcher.rb +0 -13
  113. data/lib/new_relic/agent/instrumentation/rails/dispatcher.rb +0 -38
  114. data/lib/new_relic/agent/patch_const_missing.rb +0 -125
  115. data/lib/new_relic/agent/samplers/mongrel_sampler.rb +0 -22
  116. data/lib/new_relic/metric_parser/database.rb +0 -23
  117. data/newrelic_rpm.gemspec +0 -35
  118. data/test/new_relic/agent/classloader_patch_test.rb +0 -56
  119. data/test/new_relic/agent/controller_test.rb +0 -107
  120. data/test/new_relic/agent/dispatcher_instrumentation_test.rb +0 -70
@@ -8,14 +8,37 @@ class NewRelic::ControlTest < Test::Unit::TestCase
8
8
  NewRelic::Agent.manual_start
9
9
  @c = NewRelic::Control.instance
10
10
  end
11
+ def shutdown
12
+ NewRelic::Agent.shutdown
13
+ end
14
+
15
+ def test_monitor_mode
16
+ assert ! @c.monitor_mode?
17
+ @c.settings.delete 'enabled'
18
+ @c.settings.delete 'monitor_mode'
19
+ assert !@c.monitor_mode?
20
+ @c['enabled'] = false
21
+ assert ! @c.monitor_mode?
22
+ @c['enabled'] = true
23
+ assert @c.monitor_mode?
24
+ @c['monitor_mode'] = nil
25
+ assert !@c.monitor_mode?
26
+ @c['monitor_mode'] = false
27
+ assert !@c.monitor_mode?
28
+ @c['monitor_mode'] = true
29
+ assert @c.monitor_mode?
30
+ ensure
31
+ @c['enabled'] = false
32
+ @c['monitor_mode'] = false
33
+ end
11
34
 
12
35
  def test_test_config
13
36
  assert_equal :rails, c.app
14
37
  assert_equal :test, c.framework
15
38
  assert_match /test/i, c.dispatcher_instance_id
16
39
  assert_equal nil, c.dispatcher
17
-
18
- assert_equal false, c['enabled']
40
+ assert !c['enabled']
41
+ assert_equal false, c['monitor_mode']
19
42
  c.local_env
20
43
  end
21
44
 
@@ -26,8 +49,6 @@ class NewRelic::ControlTest < Test::Unit::TestCase
26
49
 
27
50
  def test_info
28
51
  props = NewRelic::Control.instance.local_env.snapshot
29
- list = props.assoc('Plugin List').last.sort
30
- assert_not_nil list # can't really guess what might be in here.
31
52
  assert_match /jdbc|postgres|mysql|sqlite/, props.assoc('Database adapter').last
32
53
  end
33
54
 
@@ -51,7 +72,7 @@ class NewRelic::ControlTest < Test::Unit::TestCase
51
72
  assert_equal c['sval'], 'sure'
52
73
  end
53
74
  def test_config_apdex
54
- assert_equal 1.1, c['apdex_t']
75
+ assert_equal 1.1, c.apdex_t
55
76
  end
56
77
  def test_transaction_threshold
57
78
  assert_equal 'Apdex_f', c['transaction_tracer']['transaction_threshold']
@@ -60,14 +81,6 @@ class NewRelic::ControlTest < Test::Unit::TestCase
60
81
  def test_log_file_name
61
82
  assert_match /newrelic_agent.log$/, c.instance_variable_get('@log_file')
62
83
  end
63
- def test_environment_info
64
- NewRelic::Control.instance.send :append_environment_info
65
- snapshot = NewRelic::Control.instance.local_env.snapshot
66
- assert snapshot.assoc('Plugin List').last.include?('newrelic_rpm'), snapshot.inspect
67
- end
68
- def test_config_apdex
69
- assert_equal 1.1, c['apdex_t']
70
- end
71
84
 
72
85
  def test_transaction_threshold__apdex
73
86
  forced_start
@@ -47,7 +47,7 @@ class MetricParserTest < Test::Unit::TestCase
47
47
  assert !m.is_web_service?
48
48
 
49
49
  assert_not_nil m.base_metric_name
50
- assert m.base_metric_name.starts_with?('Controller/')
50
+ assert_equal 0, m.base_metric_name.index('Controller/')
51
51
  end
52
52
 
53
53
  end
@@ -139,4 +139,34 @@ class MetricParserTest < Test::Unit::TestCase
139
139
  m = NewRelic::MetricParser.for_metric_named("Errors/Type/MyType")
140
140
  assert_equal m.short_name, 'MyType'
141
141
  end
142
+ def test_external
143
+ m = NewRelic::MetricParser.for_metric_named("External/all")
144
+ assert m.all?
145
+ assert !m.hosts_all?
146
+ assert_equal "All External", m.developer_name
147
+ assert_equal "calls to external systems", m.tooltip_name
148
+ assert_equal "External Services", m.legend_name
149
+ assert_nil m.operation
150
+ assert_nil m.library
151
+
152
+ m = NewRelic::MetricParser.for_metric_named("External/venus/all")
153
+ assert !m.all?
154
+ assert m.hosts_all?
155
+ assert_equal "venus", m.developer_name
156
+ assert_equal "calls to venus", m.tooltip_name
157
+ assert_equal "All venus calls", m.legend_name
158
+ assert_nil m.operation
159
+ assert_equal 'all', m.library
160
+
161
+ m = NewRelic::MetricParser.for_metric_named("External/venus/Net::Http/get")
162
+ assert !m.all?
163
+ assert !m.hosts_all?
164
+ assert_equal "Net::Http[venus]: get", m.developer_name
165
+ assert_equal "calls to Net::Http[venus]: get", m.tooltip_name
166
+ assert_equal "Net::Http[venus]: get", m.legend_name
167
+ assert_equal 'get', m.operation
168
+ assert_equal 'Net::Http', m.library
169
+
170
+
171
+ end
142
172
  end
@@ -1,6 +1,6 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__),'..', 'test_helper'))
2
2
  ##require "new_relic/stats"
3
- class NewRelic::StatsTest < Test::Unit::TestCase
3
+ class NewRelic::MetricSpecTest < Test::Unit::TestCase
4
4
 
5
5
  def test_simple
6
6
  stats = NewRelic::MethodTraceStats.new
@@ -20,7 +20,7 @@ class NewRelic::StatsTest < Test::Unit::TestCase
20
20
 
21
21
  assert spec1.eql?(NewRelic::MetricSpec.new('Controller'))
22
22
  assert spec2.eql?(NewRelic::MetricSpec.new('Controller', nil))
23
- assert !spec1.eql?(spec2)
23
+ assert spec1.eql?(spec2)
24
24
  assert !spec2.eql?(NewRelic::MetricSpec.new('Controller', '/dude'))
25
25
  end
26
26
 
@@ -93,14 +93,6 @@ class NewRelic::StatsTest < Test::Unit::TestCase
93
93
  assert_equal(s1.calls_per_minute, 2)
94
94
  end
95
95
 
96
- def test_calls_per_second
97
- s1 = NewRelic::TestObjectForStats.new
98
- s1.call_count = 90
99
- s1.begin_time = Time.at(0)
100
- s1.end_time = Time.at(30)
101
- assert_equal(s1.calls_per_second, 3)
102
- end
103
-
104
96
  def test_total_call_time_per_minute
105
97
  s1 = NewRelic::TestObjectForStats.new
106
98
  s1.begin_time = Time.at(0)
@@ -19,15 +19,33 @@ class NewRelic::VersionNumberTest < Test::Unit::TestCase
19
19
  assert v1 > v3
20
20
  assert v3 < v0
21
21
  end
22
+ def test_bug
23
+ v0 = NewRelic::VersionNumber.new '2.8.999'
24
+ v1 = NewRelic::VersionNumber.new '2.9.10'
25
+ assert v1 > v0
26
+ assert v0 <= v1
27
+ end
22
28
  def test_long_version
23
29
  v0 = NewRelic::VersionNumber.new '1.2.3.4'
24
30
  v1 = NewRelic::VersionNumber.new '1.2.3.3'
25
31
  v3 = NewRelic::VersionNumber.new '1.3'
26
32
  assert v0 > v1
33
+ assert v0 < '1.2.3.5'
34
+ assert ! (v0 < '1.2.3.4')
27
35
  assert v3 > v0
28
36
  end
29
37
  def test_sort
30
- values = %w[1.1.1 2.6.5 2.7 2.7.1]
38
+ values = %w[1.1.1
39
+ 1.1.99
40
+ 1.1.999
41
+ 2.0.6
42
+ 2.6.5
43
+ 2.7
44
+ 2.7.1
45
+ 2.7.2
46
+ 2.7.2.0
47
+ 3
48
+ 999]
31
49
  assert_equal values, values.map{|v| NewRelic::VersionNumber.new v}.sort.map(&:to_s)
32
50
  end
33
51
  def test_compare_string
@@ -39,6 +57,18 @@ class NewRelic::VersionNumberTest < Test::Unit::TestCase
39
57
  assert v3 < '1.2.0'
40
58
  assert v0 == '1.2.0'
41
59
  end
60
+ def test_4_numbers
61
+ v0 = NewRelic::VersionNumber.new '1.2.0'
62
+ v1 = NewRelic::VersionNumber.new '1.2.0.1'
63
+ v2 = NewRelic::VersionNumber.new '1.2.1.0'
64
+ v3 = NewRelic::VersionNumber.new '1.2.1.1'
65
+ assert v0 < v1
66
+ assert v1 < v2
67
+ assert v2 < v3
68
+ assert v0 < v3
69
+ assert v0 < '1.2.0.1'
70
+ assert v0 > '1.1.0.1'
71
+ end
42
72
  def test_string
43
73
  assert_equal '1.2.0', NewRelic::VersionNumber.new('1.2.0').to_s
44
74
  assert_equal '1.2', NewRelic::VersionNumber.new('1.2').to_s
@@ -1,5 +1,6 @@
1
1
  module NewRelic; TEST = true; end unless defined? NewRelic::TEST
2
-
2
+ #ENV['NEWRELIC_ENABLE'] = 'true'
3
+ ENV['RAILS_ENV'] = 'test'
3
4
  NEWRELIC_PLUGIN_DIR = File.expand_path(File.join(File.dirname(__FILE__),".."))
4
5
  $LOAD_PATH << File.join(NEWRELIC_PLUGIN_DIR,"test")
5
6
  $LOAD_PATH << File.join(NEWRELIC_PLUGIN_DIR,"ui/helpers")
@@ -15,3 +16,38 @@ def assert_between(floor, ceiling, value, message = nil)
15
16
  assert floor <= value && value <= ceiling,
16
17
  message || "expected #{floor} <= #{value} <= #{ceiling}"
17
18
  end
19
+
20
+ def compare_metrics expected_list, actual_list
21
+ actual = Set.new actual_list
22
+ actual.delete('GC/cumulative') # in case we are in REE
23
+ expected = Set.new expected_list
24
+ assert_equal expected.to_a.sort, actual.to_a.sort, "extra: #{(actual - expected).to_a.join(", ")}; missing: #{(expected - actual).to_a.join(", ")}"
25
+ end
26
+ =begin Enable this to see test names as they run
27
+ Test::Unit::TestCase.class_eval do
28
+ def run_with_info *args, &block
29
+ puts "#{self.class.name.underscore}/#{@method_name}"
30
+ run_without_info *args, &block
31
+ end
32
+ alias_method_chain :run, :info
33
+ end
34
+ =end
35
+ module TransactionSampleTestHelper
36
+ def make_sql_transaction(*sql)
37
+ sampler = NewRelic::Agent::TransactionSampler.new
38
+ sampler.notice_first_scope_push Time.now.to_f
39
+ sampler.notice_transaction '/path', nil, :jim => "cool"
40
+ sampler.notice_push_scope "a"
41
+
42
+ sampler.notice_transaction '/path/2', nil, :jim => "cool"
43
+
44
+ sql.each {|sql_statement| sampler.notice_sql(sql_statement, {:adapter => "test"}, 0 ) }
45
+
46
+ sleep 1.0
47
+ yield if block_given?
48
+ sampler.notice_pop_scope "a"
49
+ sampler.notice_scope_empty
50
+
51
+ sampler.samples[0]
52
+ end
53
+ end
@@ -40,20 +40,28 @@ class NewrelicController < ActionController::Base
40
40
 
41
41
  write_inheritable_attribute('do_not_trace', true)
42
42
 
43
- def css
44
- forward_to_file '/newrelic/stylesheets/', 'text/css'
45
- end
46
-
47
- def image
48
- forward_to_file '/newrelic/images/', params[:content_type]
43
+ def profile
44
+ NewRelic::Control.instance.profiling = params['start'] == 'true'
45
+ get_samples
46
+ redirect_to :action => 'index'
49
47
  end
50
48
 
51
- def javascript
52
- forward_to_file '/newrelic/javascript/', 'text/javascript'
49
+ def file
50
+ file_name=params[:file].join
51
+ file_name=~/^.*[.]([^.]*)$/
52
+ ext=$1
53
+ case ext
54
+ when 'css' then
55
+ forward_to_file '/newrelic/stylesheets/', 'text/css'
56
+ when 'gif','jpg','png' then
57
+ forward_to_file '/newrelic/images/', "image/#{ext}"
58
+ when 'js' then
59
+ forward_to_file '/newrelic/javascript/', 'text/javascript'
60
+ else
61
+ raise "Unknown type '#{ext}' (#{file_name})"
62
+ end
53
63
  end
54
-
55
-
56
-
64
+
57
65
  def index
58
66
  get_samples
59
67
  end
@@ -7,7 +7,6 @@ class GooglePieChart
7
7
  def initialize
8
8
  # an array of [label, value]
9
9
  @data = []
10
-
11
10
  self.width = 300
12
11
  self.height = 200
13
12
  end
@@ -20,18 +19,13 @@ class GooglePieChart
20
19
  # render the chart to html by creating an image object and
21
20
  # placing the correct URL to the google charts api
22
21
  def render
23
- labels = ''
24
- values = ''
22
+ labels = []
23
+ values = []
25
24
  @data.each do |label, value|
26
- labels << CGI::escape(label) + '|'
27
- values << (value * 100 / @max).round.to_s + ","
25
+ labels << CGI::escape(label)
26
+ values << (value > 0 ? value * 100 / @max : value).round.to_s
28
27
  end
29
-
30
- # strip of the last separator char for labels and values
31
- labels = labels[0..-2]
32
- values = values[0..-2]
33
-
34
- params = {:cht => 'p', :chs => "#{width}x#{height}", :chd => "t:#{values}", :chl => labels }
28
+ params = {:cht => 'p', :chs => "#{width}x#{height}", :chd => "t:#{values.join(',')}", :chl => labels.join('|') }
35
29
  params['chco'] = color if color
36
30
 
37
31
  url = "http://chart.apis.google.com/chart?#{to_query(params)}"
@@ -15,17 +15,13 @@ module NewrelicHelper
15
15
  end
16
16
 
17
17
  def trace_row_display_limit_reached
18
- (!@detail_segment_count.nil? && @detail_segment_count > trace_row_display_limit) || @sample.sql_segments.length > trace_row_display_limit
18
+ (!@detail_segment_count.nil? && @detail_segment_count > trace_row_display_limit) || @sample.sql_segments.length > trace_row_display_limit
19
19
  end
20
20
 
21
21
  # return the sample but post processed to strip out segments that normally don't show
22
22
  # up in production (after the first execution, at least) such as application code loading
23
23
  def stripped_sample(sample = @sample)
24
- if session[:newrelic_strip_code_loading] || true
25
- sample.omit_segments_with('(Rails/Application Code Loading)|(Database/.*/.+ Columns)')
26
- else
27
- sample
28
- end
24
+ sample.omit_segments_with('(Rails/Application Code Loading)|(Database/.*/.+ Columns)')
29
25
  end
30
26
 
31
27
  # return the highest level in the call stack for the trace that is not rails or
@@ -48,11 +44,11 @@ module NewrelicHelper
48
44
  exclude_file_from_stack_trace?(file, include_rails)
49
45
  end
50
46
  end
51
-
47
+
52
48
  def render_backtrace
53
49
  if @segment[:backtrace]
54
50
  content_tag('h3', 'Application Stack Trace') +
55
- render(:partial => agent_views_path('stack_trace'), :locals => {:segment => @segment})
51
+ render(:partial => agent_views_path('stack_trace'), :locals => {:segment => @segment})
56
52
  end
57
53
  end
58
54
 
@@ -76,7 +72,7 @@ module NewrelicHelper
76
72
  rescue
77
73
  # catch all other exceptions. We're going to create an invalid link below, but that's okay.
78
74
  end
79
-
75
+
80
76
  if using_textmate?
81
77
  "txmt://open?url=file://#{file}&line=#{line}"
82
78
  else
@@ -109,10 +105,10 @@ module NewrelicHelper
109
105
  def write_stack_trace_line(trace_line)
110
106
  link_to h(trace_line), url_for_source(trace_line)
111
107
  end
112
-
108
+
113
109
  # write a link to the source for a trace
114
110
  def link_to_source(trace)
115
- image_url = url_for(:controller => :newrelic, :action => :image, :file => (using_textmate? ? "textmate.png" : "file_icon.png"), :content_type => 'image/png')
111
+ image_url = url_for(:controller => :newrelic, :action => :file, :file => (using_textmate? ? "textmate.png" : "file_icon.png"))
116
112
 
117
113
  link_to image_tag(image_url, :alt => (title = 'View Source'), :title => title), url_for_source(application_caller(trace))
118
114
  end
@@ -125,7 +121,7 @@ module NewrelicHelper
125
121
  def format_timestamp(time)
126
122
  time.strftime("%H:%M:%S")
127
123
  end
128
-
124
+
129
125
  def colorize(value, yellow_threshold = 0.05, red_threshold = 0.15, s=to_ms(value))
130
126
  if value > yellow_threshold
131
127
  color = (value > red_threshold ? 'red' : 'orange')
@@ -136,11 +132,11 @@ module NewrelicHelper
136
132
  end
137
133
 
138
134
  def expanded_image_path()
139
- url_for(:controller => :newrelic, :action => :image, :file => 'arrow-open.png')
135
+ url_for(:controller => :newrelic, :action => :file, :file => 'arrow-open.png')
140
136
  end
141
137
 
142
138
  def collapsed_image_path()
143
- url_for(:controller => :newrelic, :action => :image, :file => 'arrow-close.png')
139
+ url_for(:controller => :newrelic, :action => :file, :file => 'arrow-close.png')
144
140
  end
145
141
 
146
142
  def explain_sql_url(segment)
@@ -202,17 +198,17 @@ module NewrelicHelper
202
198
  classes = []
203
199
 
204
200
  classes << "segment#{segment.parent_segment.segment_id}" if depth > 1
205
-
206
- classes << "view_segment" if segment.metric_name.starts_with?('View')
201
+
202
+ classes << "view_segment" if segment.metric_name.index('View') == 0
207
203
  classes << "summary_segment" if segment.is_a?(NewRelic::TransactionSample::CompositeSegment)
208
-
204
+
209
205
  classes.join(' ')
210
206
  end
211
-
207
+
212
208
  # render_segment_details should be called before calling this method
213
209
  def render_indentation_classes(depth)
214
210
  styles = []
215
- (1..depth).each do |d|
211
+ (1..depth).each do |d|
216
212
  styles << ".segment_indent_level#{d} { display: inline-block; margin-left: #{(d-1)*20}px }"
217
213
  end
218
214
  content_tag("style", styles.join(' '))
@@ -240,17 +236,16 @@ module NewrelicHelper
240
236
  end
241
237
  end
242
238
 
243
- private
239
+ private
244
240
  def file_and_line(stack_trace_line)
245
241
  stack_trace_line.match(/(.*):(\d+)/)[1..2]
246
242
  end
247
243
 
248
244
  def using_textmate?
249
- # For now, disable textmate integration
250
- false
245
+ NewRelic::Control.instance.use_textmate?
251
246
  end
252
247
 
253
-
248
+
254
249
  def render_segment_details(segment, depth=0)
255
250
  @detail_segment_count ||= 0
256
251
  @detail_segment_count += 1
@@ -273,17 +268,20 @@ private
273
268
 
274
269
  html
275
270
  end
276
-
271
+
277
272
  def exclude_file_from_stack_trace?(file, include_rails)
278
- !include_rails && (
279
- file =~ /\/active(_)*record\// ||
280
- file =~ /\/action(_)*controller\// ||
281
- file =~ /\/activesupport\// ||
282
- file =~ /\/lib\/mongrel/ ||
283
- file =~ /\/actionpack\// ||
284
- file =~ /\/passenger\// ||
285
- file =~ /\/benchmark.rb/ ||
286
- file !~ /\.rb/) # must be a .rb file, otherwise it's a script of something else...we could have gotten trickier and tried to see if this file exists...
273
+ return false if include_rails
274
+ return true if file !~ /\.(rb|java)/
275
+ %w[/actionmailer/
276
+ /activerecord
277
+ /activeresource
278
+ /activesupport
279
+ /lib/mongrel
280
+ /actionpack
281
+ /passenger/
282
+ /railties
283
+ benchmark.rb].each { |s| return true if file.include? s }
284
+ false
287
285
  end
288
286
 
289
287
  def show_view_link(title, page_name)
@@ -297,14 +295,14 @@ private
297
295
  when 'jpg'; 'image/jpg'
298
296
  when 'css'; 'text/css'
299
297
  when 'js'; 'text/javascript'
300
- else 'text/plain'
298
+ else 'text/plain'
301
299
  end
302
300
  end
303
301
  def to_ms(number)
304
302
  (number*1000).round
305
303
  end
306
304
  def to_percentage(value)
307
- (value * 100).round if value
305
+ (value * 100).round if value
308
306
  end
309
307
  def with_delimiter(val)
310
308
  return '0' if val.nil?
@@ -312,4 +310,11 @@ private
312
310
  parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1,")
313
311
  parts.join '.'
314
312
  end
313
+
314
+ def profile_table(profile)
315
+ out = StringIO.new
316
+ printer = RubyProf::GraphHtmlPrinter.new(profile)
317
+ printer.print(out, :min_percent=>0.5)
318
+ out.string[/<body>(.*)<\/body>/im, 0].gsub('<table>', '<table class=profile>')
319
+ end
315
320
  end