newrelic_rpm 3.3.1 → 3.3.2.beta1

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.

data/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ v3.3.2
2
+ * deployments recipe change: truncate git SHAs to 7 characters
3
+ * Fixes for obfuscation of PostgreSQL and SQLite queries
4
+ * Fix for lost database connections when using a forking framework
5
+ * Workaround for RedHat kernel bug which prevented blocking reads of /proc fs
6
+
1
7
  v3.3.1
2
8
  * improved Ruby 1.8.6 support
3
9
  * fix for issues with RAILS_ROOT deprecation warnings
@@ -187,16 +187,36 @@ module NewRelic
187
187
  end
188
188
 
189
189
  def default_sql_obfuscator(sql)
190
- sql = sql.dup
191
- # This is hardly readable. Use the unit tests.
192
- # remove single quoted strings:
193
- sql.gsub!(/'(.*?[^\\'])??'(?!')/, '?')
194
- # remove double quoted strings:
195
- sql.gsub!(/"(.*?[^\\"])??"(?!")/, '?')
196
- # replace all number literals
197
- sql.gsub!(/\d+/, "?")
198
- sql
190
+ stmt = sql.kind_of?(Statement) ? sql : Statement.new(sql)
191
+ adapter = stmt.adapter
192
+ obfuscated = remove_escaped_quotes(stmt)
193
+ obfuscated = obfuscate_single_quote_literals(obfuscated)
194
+ if !(adapter.to_s =~ /postgres/ || adapter.to_s =~ /sqlite/)
195
+ obfuscated = obfuscate_double_quote_literals(obfuscated)
196
+ end
197
+ obfuscated = obfuscate_numeric_literals(obfuscated)
198
+ obfuscated.to_s # return back to a regular String
199
+ end
200
+
201
+ def remove_escaped_quotes(sql)
202
+ sql.gsub(/\\"/, '').gsub(/\\'/, '')
199
203
  end
204
+
205
+ def obfuscate_single_quote_literals(sql)
206
+ sql.gsub(/'(?:[^']|'')*'/, '?')
207
+ end
208
+
209
+ def obfuscate_double_quote_literals(sql)
210
+ sql.gsub(/"(?:[^"]|"")*"/, '?')
211
+ end
212
+
213
+ def obfuscate_numeric_literals(sql)
214
+ sql.gsub(/\b\d+\b/, "?")
215
+ end
216
+ end
217
+
218
+ class Statement < String
219
+ attr_accessor :adapter
200
220
  end
201
221
  end
202
222
  end
@@ -122,18 +122,17 @@ module NewRelic
122
122
  # Returns the amount of resident memory this process is using in MB
123
123
  #
124
124
  def get_memory
125
- File.open(proc_status_file, "r") do |f|
126
- while !f.eof?
127
- if f.readline =~ /RSS:\s*(\d+) kB/i
128
- return $1.to_f / 1024.0
129
- end
130
- end
125
+ proc_status = File.open(proc_status_file, "r") {|f| f.read_nonblock(4096).strip }
126
+ if proc_status =~ /RSS:\s*(\d+) kB/i
127
+ return $1.to_f / 1024.0
131
128
  end
132
129
  raise "Unable to find RSS in #{proc_status_file}"
133
130
  end
131
+
134
132
  def proc_status_file
135
133
  "/proc/#{$$}/status"
136
134
  end
135
+
137
136
  def to_s
138
137
  "proc status file sampler: #{proc_status_file}"
139
138
  end
@@ -1,6 +1,7 @@
1
1
  require 'new_relic/agent'
2
2
  require 'new_relic/control'
3
3
  require 'new_relic/agent/transaction_sample_builder'
4
+
4
5
  module NewRelic
5
6
  module Agent
6
7
 
@@ -271,8 +272,14 @@ module NewRelic
271
272
  return unless builder
272
273
  segment = builder.current_segment
273
274
  if segment
274
- segment[key] = truncate_message(append_new_message(segment[key],
275
- message))
275
+ new_message = truncate_message(append_new_message(segment[key],
276
+ message))
277
+ if key == :sql && config.respond_to?(:has_key?) && config.has_key?(:adapter)
278
+ segment[key] = Database::Statement.new(new_message)
279
+ segment[key].adapter = config[:adapter]
280
+ else
281
+ segment[key] = new_message
282
+ end
276
283
  segment[config_key] = config if config_key
277
284
  append_backtrace(segment, duration)
278
285
  end
@@ -336,6 +343,7 @@ module NewRelic
336
343
  @harvest_count += 1
337
344
  if (@harvest_count.to_i % @sampling_rate.to_i) == 0
338
345
  result << @random_sample if @random_sample
346
+ @harvest_count = 0
339
347
  end
340
348
  nil # don't assume this method returns anything
341
349
  end
@@ -10,7 +10,7 @@ module NewRelic
10
10
  class Rails3 < NewRelic::Control::Frameworks::Rails
11
11
 
12
12
  def env
13
- ::Rails.env.to_s
13
+ @env ||= ::Rails.env.to_s
14
14
  end
15
15
 
16
16
  # Rails can return an empty string from this method, causing
@@ -27,8 +27,9 @@ module NewRelic::LanguageSupport
27
27
  def self.included(base)
28
28
  # need to use syck rather than psych when possible
29
29
  if defined?(::YAML::ENGINE)
30
- unless NewRelic::LanguageSupport.using_engine?('jruby') &&
31
- NewRelic::LanguageSupport.using_version?('1.9')
30
+ if !NewRelic::LanguageSupport.using_engine?('jruby') &&
31
+ (NewRelic::LanguageSupport.using_version?('1.9.1') ||
32
+ NewRelic::LanguageSupport.using_version?('1.9.2'))
32
33
  base.class_eval do
33
34
  def load_newrelic_yml(*args)
34
35
  yamler = ::YAML::ENGINE.yamler
@@ -106,7 +106,9 @@ module NewRelic
106
106
  def gather_cpu_info
107
107
  return unless File.readable? '/proc/cpuinfo'
108
108
  @processors = append_environment_value('Processors') do
109
- processors = File.readlines('/proc/cpuinfo').select { |line| line =~ /^processor\s*:/ }.size
109
+ cpuinfo = File.open("/proc/cpuinfo") {|f| f.read_nonblock(4096).strip }
110
+ processors = cpuinfo.split("\n").select {|line| line =~ /^processor\s*:/ }.size
111
+
110
112
  raise "Cannot determine the number of processors in /proc/cpuinfo" unless processors > 0
111
113
  processors
112
114
  end
@@ -156,9 +158,6 @@ module NewRelic
156
158
  end
157
159
  end
158
160
  end
159
- append_environment_value 'Database schema version' do
160
- ActiveRecord::Migrator.current_version
161
- end
162
161
  end
163
162
 
164
163
  # Datamapper version
@@ -15,13 +15,13 @@ module NewRelic::Rack
15
15
  # NewRelic::Agent::TransactionInfo.get.force_persist = true
16
16
  # NewRelic::Agent::TransactionInfo.get.capture_deep_tt = true
17
17
  # end
18
-
18
+
19
19
  # if req.params['nr_capture_tt']
20
20
  # NewRelic::Agent::TransactionInfo.get.force_persist = true
21
21
  # end
22
-
22
+
23
23
  result = @app.call(env) # [status, headers, response]
24
-
24
+
25
25
  if (NewRelic::Agent.browser_timing_header != "") && should_instrument?(result[0], result[1])
26
26
  response_string = autoinstrument_source(result[2], result[1])
27
27
 
@@ -37,24 +37,25 @@ module NewRelic::Rack
37
37
  end
38
38
 
39
39
  def should_instrument?(status, headers)
40
- status == 200 && headers["Content-Type"] && headers["Content-Type"].include?("text/html")
40
+ status == 200 && headers["Content-Type"] && headers["Content-Type"].include?("text/html") &&
41
+ !headers['Content-Disposition'].to_s.include?('attachment')
41
42
  end
42
43
 
43
44
  def autoinstrument_source(response, headers)
44
45
  source = nil
45
46
  response.each {|fragment| source ? (source << fragment.to_s) : (source = fragment.to_s)}
46
47
  return nil unless source
47
-
48
+
48
49
  body_start = source.index("<body")
49
50
  body_close = source.rindex("</body>")
50
51
 
51
52
  if body_start && body_close
52
53
  footer = NewRelic::Agent.browser_timing_footer
53
54
  header = NewRelic::Agent.browser_timing_header
54
-
55
+
55
56
  if source.include?('X-UA-Compatible')
56
57
  # put at end of header if UA-Compatible meta tag found
57
- head_pos = source.index("</head>")
58
+ head_pos = source.index("</head>")
58
59
  elsif head_open = source.index("<head")
59
60
  # put at the beginning of the header
60
61
  head_pos = source.index(">", head_open) + 1
@@ -71,5 +72,5 @@ module NewRelic::Rack
71
72
  source
72
73
  end
73
74
  end
74
-
75
+
75
76
  end
@@ -83,9 +83,9 @@ module NewRelic
83
83
  @obfuscated_sql = @segment.obfuscated_sql
84
84
  end
85
85
 
86
- explanations = @segment.explain_sql
86
+ headers, explanations = @segment.explain_sql
87
87
  if explanations
88
- @explanation = explanations.first
88
+ @explanation = explanations
89
89
  if !@explanation.blank?
90
90
  first_row = @explanation.first
91
91
  # Show the standard headers if it looks like a mysql explain plan
@@ -33,10 +33,14 @@ make_notify_task = Proc.new do
33
33
  end
34
34
  changelog = `#{log_command}`
35
35
  end
36
- new_revision = rev || source.query_revision(source.head()) do |cmd|
37
- logger.debug "executing locally: '#{cmd}'"
38
- `#{cmd}`
36
+ if rev.nil?
37
+ rev = source.query_revision(source.head()) do |cmd|
38
+ logger.debug "executing locally: '#{cmd}'"
39
+ `#{cmd}`
40
+ end
41
+ rev = rev[0..6] if scm == :git
39
42
  end
43
+ new_revision = rev
40
44
  deploy_options = { :environment => rails_env,
41
45
  :revision => new_revision,
42
46
  :changelog => changelog,
@@ -104,43 +104,6 @@ module NewRelic
104
104
  stats.merge!(other_stats)
105
105
  end
106
106
 
107
- # split into an array of timeslices whose
108
- # time boundaries start on (begin_time + (n * duration)) and whose
109
- # end time ends on (begin_time * (n + 1) * duration), except for the
110
- # first and last elements, whose begin time and end time are the begin
111
- # and end times of this stats instance, respectively. Yield to caller
112
- # for the code that creates the actual stats instance
113
- def split(rollup_begin_time, rollup_period)
114
- rollup_begin_time = rollup_begin_time.to_f
115
- rollup_begin_time += ((self.begin_time - rollup_begin_time) / rollup_period).floor * rollup_period
116
-
117
- current_begin_time = self.begin_time
118
- current_end_time = rollup_begin_time + rollup_period
119
-
120
- return [self] if current_end_time >= self.end_time
121
-
122
- timeslices = []
123
- while current_end_time < self.end_time do
124
- ts = yield(current_begin_time, current_end_time)
125
- if ts
126
- ts.fraction_of(self)
127
- timeslices << ts
128
- end
129
- current_begin_time = current_end_time
130
- current_end_time = current_begin_time + rollup_period
131
- end
132
-
133
- if self.end_time > current_begin_time
134
- percentage = rollup_period / self.duration + (self.begin_time - rollup_begin_time) / rollup_period
135
- ts = yield(current_begin_time, self.end_time)
136
- if ts
137
- ts.fraction_of(self)
138
- timeslices << ts
139
- end
140
- end
141
-
142
- timeslices
143
- end
144
107
 
145
108
  def is_reset?
146
109
  call_count == 0 && total_call_time == 0.0 && total_exclusive_time == 0.0
@@ -216,22 +179,6 @@ module NewRelic
216
179
  "[#{Time.at(begin_time.to_f).utc.strftime(format)} UTC, #{'%2.3fs' % duration.to_f}; #{'%2i' % call_count.to_i} calls #{'%4i' % average_call_time.to_f}s]"
217
180
  end
218
181
 
219
- # calculate this set of stats to be a percentage fraction
220
- # of the provided stats, which has an overlapping time window.
221
- # used as a key part of the split algorithm
222
- def fraction_of(s)
223
- min_end = (end_time < s.end_time ? end_time : s.end_time)
224
- max_begin = (begin_time > s.begin_time ? begin_time : s.begin_time)
225
- percentage = (min_end - max_begin) / s.duration
226
-
227
- self.total_exclusive_time = s.total_exclusive_time * percentage
228
- self.total_call_time = s.total_call_time * percentage
229
- self.min_call_time = s.min_call_time
230
- self.max_call_time = s.max_call_time
231
- self.call_count = s.call_count * percentage
232
- self.sum_of_squares = (s.sum_of_squares || 0) * percentage
233
- end
234
-
235
182
  # multiply the total time and rate by the given percentage
236
183
  def multiply_by(percentage)
237
184
  self.total_call_time = total_call_time * percentage
@@ -234,7 +234,7 @@ module NewRelic
234
234
  when :raw then v
235
235
  when :obfuscated then NewRelic::Agent::Database.obfuscate_sql(v)
236
236
  else raise "Invalid value for record_sql: #{options[:record_sql]}"
237
- end if options[:record_sql]
237
+ end.to_s if options[:record_sql]
238
238
  when :connection_config
239
239
  # don't copy it
240
240
  else
@@ -3,8 +3,8 @@ module NewRelic
3
3
  module VERSION #:nodoc:
4
4
  MAJOR = 3
5
5
  MINOR = 3
6
- TINY = 1
7
- BUILD = nil # Set to nil for a release, 'beta1', 'alpha', etc for prerelease builds
6
+ TINY = 2
7
+ BUILD = 'beta1' # Set to nil for a release, 'beta1', 'alpha', etc for prerelease builds
8
8
  STRING = [MAJOR, MINOR, TINY, BUILD].compact.join('.')
9
9
  end
10
10
 
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{newrelic_rpm}
8
- s.version = "3.3.1"
8
+ s.version = "3.3.2.beta1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Bill Kayser", "Jon Guymon", "Justin George", "Darin Swanson"]
12
- s.date = %q{2011-12-15}
12
+ s.date = %q{2012-01-20}
13
13
  s.description = %q{New Relic is a performance management system, developed by New Relic,
14
14
  Inc (http://www.newrelic.com). New Relic provides you with deep
15
15
  information about the performance of your web application as it runs
@@ -83,59 +83,46 @@ class NewRelic::Agent::DatabaseTest < Test::Unit::TestCase
83
83
  raise(fake_error)
84
84
  end
85
85
  end
86
+
87
+ def test_obfuscation_mysql_basic
88
+ insert = %q[INSERT INTO `X` values("test",0, 1 , 2, 'test')]
89
+ assert_equal("INSERT INTO `X` values(?,?, ? , ?, ?)",
90
+ NewRelic::Agent::Database.obfuscate_sql(insert))
91
+ select = %q[SELECT `table`.`column` FROM `table` WHERE `table`.`column` = 'value' AND `table`.`other_column` = "other value" LIMIT 1]
92
+ assert_equal(%q[SELECT `table`.`column` FROM `table` WHERE `table`.`column` = ? AND `table`.`other_column` = ? LIMIT ?],
93
+ NewRelic::Agent::Database.obfuscate_sql(select))
94
+ end
86
95
 
87
- def test_sql_normalization
88
- # basic statement
89
- assert_equal "INSERT INTO X values(?,?, ? , ?)",
90
- NewRelic::Agent::Database.obfuscate_sql("INSERT INTO X values('test',0, 1 , 2)")
91
-
92
- # escaped literals
93
- assert_equal "INSERT INTO X values(?, ?,?, ? , ?)",
94
- NewRelic::Agent::Database.obfuscate_sql("INSERT INTO X values('', 'jim''s ssn',0, 1 , 'jim''s son''s son')")
95
-
96
- # multiple string literals
97
- assert_equal "INSERT INTO X values(?,?,?, ? , ?)",
98
- NewRelic::Agent::Database.obfuscate_sql("INSERT INTO X values('jim''s ssn','x',0, 1 , 2)")
99
-
100
- # empty string literal
101
- # NOTE: the empty string literal resolves to empty string, which for our purposes is acceptable
102
- assert_equal "INSERT INTO X values(?,?,?, ? , ?)",
103
- NewRelic::Agent::Database.obfuscate_sql("INSERT INTO X values('','x',0, 1 , 2)")
104
-
105
- # try a select statement
106
- assert_equal "select * from table where name=? and ssn=?",
107
- NewRelic::Agent::Database.obfuscate_sql("select * from table where name='jim gochee' and ssn=0012211223")
108
-
109
- # number literals embedded in sql - oh well
110
- assert_equal "select * from table_? where name=? and ssn=?",
111
- NewRelic::Agent::Database.obfuscate_sql("select * from table_007 where name='jim gochee' and ssn=0012211223")
96
+ def test_obfuscation_postgresql_basic
97
+ insert = NewRelic::Agent::Database::Statement.new(%q[INSERT INTO "X" values('test',0, 1 , 2, 'test')])
98
+ insert.adapter = :postgresql
99
+ assert_equal('INSERT INTO "X" values(?,?, ? , ?, ?)',
100
+ NewRelic::Agent::Database.obfuscate_sql(insert))
101
+ select = NewRelic::Agent::Database::Statement.new(%q[SELECT "table"."column" FROM "table" WHERE "table"."column" = 'value' AND "table"."other_column" = 'other value' LIMIT 1])
102
+ select.adapter = :postgresql
103
+ assert_equal(%q[SELECT "table"."column" FROM "table" WHERE "table"."column" = ? AND "table"."other_column" = ? LIMIT ?],
104
+ NewRelic::Agent::Database.obfuscate_sql(select))
112
105
  end
113
106
 
114
- def test_sql_normalization__single_quotes
115
- assert_equal "INSERT ? into table",
116
- NewRelic::Agent::Database.obfuscate_sql("INSERT 'this isn''t a real value' into table")
117
- assert_equal "INSERT ? into table",
118
- NewRelic::Agent::Database.obfuscate_sql(%q[INSERT '"' into table])
119
- assert_equal "INSERT ? into table",
120
- NewRelic::Agent::Database.obfuscate_sql(%q[INSERT ' "some text" \" ' into table])
121
- # could not get this one licked. no biggie
122
- # assert_equal "INSERT ? into table",
123
- # @agent.send(:default_sql_obfuscator, %q[INSERT '\'' into table])
124
- assert_equal "INSERT ? into table",
125
- NewRelic::Agent::Database.obfuscate_sql(%q[INSERT ''' ' into table])
107
+ def test_obfuscation_escaped_literals
108
+ insert = %q[INSERT INTO X values('', 'jim''s ssn',0, 1 , 'jim''s son''s son', """jim''s"" hat", "\"jim''s secret\"")]
109
+ assert_equal("INSERT INTO X values(?, ?,?, ? , ?, ?, ?)",
110
+ NewRelic::Agent::Database.obfuscate_sql(insert))
126
111
  end
127
112
 
128
- def test_sql_normalization__double_quotes
129
- assert_equal "INSERT ? into table",
130
- NewRelic::Agent::Database.obfuscate_sql(%q[INSERT "this isn't a real value" into table])
131
- assert_equal "INSERT ? into table",
132
- NewRelic::Agent::Database.obfuscate_sql(%q[INSERT "'" into table])
133
- assert_equal "INSERT ? into table",
134
- NewRelic::Agent::Database.obfuscate_sql(%q[INSERT " \" " into table])
135
- assert_equal "INSERT ? into table",
136
- NewRelic::Agent::Database.obfuscate_sql(%q[INSERT " 'some text' " into table])
113
+ def test_obfuscation_mysql_integers_in_identifiers
114
+ select = %q[SELECT * FROM `table_007` LIMIT 1]
115
+ assert_equal(%q[SELECT * FROM `table_007` LIMIT ?],
116
+ NewRelic::Agent::Database.obfuscate_sql(select))
137
117
  end
138
118
 
119
+ def test_obfuscation_postgresql_integers_in_identifiers
120
+ select = NewRelic::Agent::Database::Statement.new(%q[SELECT * FROM "table_007" LIMIT 1])
121
+ select.adapter = :postgresql
122
+ assert_equal(%q[SELECT * FROM "table_007" LIMIT ?],
123
+ NewRelic::Agent::Database.obfuscate_sql(select))
124
+ end
125
+
139
126
  def test_sql_obfuscation_filters
140
127
  NewRelic::Agent::Database.set_sql_obfuscator(:replace) do |string|
141
128
  "1" + string
@@ -15,7 +15,7 @@ end
15
15
  if middleware_supported?
16
16
  class BrowserMonitoringTest < Test::Unit::TestCase
17
17
  include Rack::Test::Methods
18
-
18
+
19
19
  class TestApp
20
20
  def self.doc=(other)
21
21
  @@doc = other
@@ -38,11 +38,11 @@ EOL
38
38
  end
39
39
  include NewRelic::Agent::Instrumentation::Rack
40
40
  end
41
-
41
+
42
42
  def app
43
43
  NewRelic::Rack::BrowserMonitoring.new(TestApp.new)
44
44
  end
45
-
45
+
46
46
  def setup
47
47
  super
48
48
  clear_cookies
@@ -54,36 +54,40 @@ EOL
54
54
  NewRelic::Agent.instance.stubs(:beacon_configuration).returns(config)
55
55
  NewRelic::Agent.stubs(:is_transaction_traced?).returns(true)
56
56
  end
57
-
57
+
58
58
  def teardown
59
59
  super
60
60
  clear_cookies
61
61
  mocha_teardown
62
62
  TestApp.doc = nil
63
63
  end
64
-
64
+
65
65
  def test_make_sure_header_is_set
66
66
  assert NewRelic::Agent.browser_timing_header.size > 0
67
67
  end
68
-
68
+
69
69
  def test_make_sure_footer_is_set
70
70
  assert NewRelic::Agent.browser_timing_footer.size > 0
71
71
  end
72
-
72
+
73
73
  def test_should_only_instrument_successfull_html_requests
74
74
  assert app.should_instrument?(200, {'Content-Type' => 'text/html'})
75
75
  assert !app.should_instrument?(500, {'Content-Type' => 'text/html'})
76
76
  assert !app.should_instrument?(200, {'Content-Type' => 'text/xhtml'})
77
77
  end
78
78
 
79
+ def test_should_not_instrument_when_content_disposition
80
+ assert !app.should_instrument?(200, {'Content-Type' => 'text/html', 'Content-Disposition' => 'attachment; filename=test.html'})
81
+ end
82
+
79
83
  def test_insert_timing_header_right_after_open_head_if_no_meta_tags
80
84
  get '/'
81
-
85
+
82
86
  assert(last_response.body.include?("head>#{NewRelic::Agent.browser_timing_header}"),
83
87
  last_response.body)
84
88
  TestApp.doc = nil
85
- end
86
-
89
+ end
90
+
87
91
  def test_insert_timing_header_right_before_head_close_if_ua_compatible_found
88
92
  TestApp.doc = <<-EOL
89
93
  <html>
@@ -98,30 +102,30 @@ EOL
98
102
  </html>
99
103
  EOL
100
104
  get '/'
101
-
105
+
102
106
  assert(last_response.body.include?("#{NewRelic::Agent.browser_timing_header}</head>"),
103
107
  last_response.body)
104
108
  end
105
-
109
+
106
110
  def test_insert_timing_footer_right_before_html_body_close
107
111
  get '/'
108
-
112
+
109
113
  assert_match(/.*NREUMQ\.push.*new Date\(\)\.getTime\(\),"","","","",""\]\)<\/script><\/body>/,
110
114
  last_response.body)
111
115
  end
112
-
116
+
113
117
  def test_should_not_throw_exception_on_empty_reponse
114
118
  TestApp.doc = ''
115
119
  get '/'
116
120
 
117
121
  assert last_response.ok?
118
122
  end
119
-
123
+
120
124
  def test_token_is_set_in_footer_when_set_by_cookie
121
125
  token = '1234567890987654321'
122
126
  set_cookie "NRAGENT=tk=#{token}"
123
127
  get '/'
124
-
128
+
125
129
  assert(last_response.body.include?(token), last_response.body)
126
130
  end
127
131
 
@@ -40,4 +40,35 @@ class DeveloperModeTest < Test::Unit::TestCase
40
40
  assert last_response.body.include?('SandwichesController')
41
41
  assert last_response.body.include?('index')
42
42
  end
43
+
44
+ def test_explain_sql_displays_query_plan
45
+ sample = @sampler.samples[0]
46
+ sql_segment = sample.sql_segments[0]
47
+ explain_results = NewRelic::Agent::Database.process_resultset(example_explain_as_hashes)
48
+
49
+ NewRelic::TransactionSample::Segment.any_instance.expects(:explain_sql).returns(explain_results)
50
+ get "/newrelic/explain_sql?id=#{sample.sample_id}&segment=#{sql_segment.segment_id}"
51
+
52
+ assert last_response.ok?
53
+ assert last_response.body.include?('PRIMARY')
54
+ assert last_response.body.include?('Key Length')
55
+ assert last_response.body.include?('Using index')
56
+ end
57
+
58
+ private
59
+
60
+ def example_explain_as_hashes
61
+ [{
62
+ 'Id' => '1',
63
+ 'Select Type' => 'SIMPLE',
64
+ 'Table' => 'sandwiches',
65
+ 'Type' => 'range',
66
+ 'Possible Keys' => 'PRIMARY',
67
+ 'Key' => 'PRIMARY',
68
+ 'Key Length' => '4',
69
+ 'Ref' => '',
70
+ 'Rows' => '1',
71
+ 'Extra' => 'Using index'
72
+ }]
73
+ end
43
74
  end
@@ -172,21 +172,6 @@ class NewRelic::StatsTest < Test::Unit::TestCase
172
172
  assert_equal(s1.time_str(20000), "20.0 s")
173
173
  end
174
174
 
175
- def test_fraction_of
176
- s1 = NewRelic::MethodTraceStats.new
177
- s2 = NewRelic::MethodTraceStats.new
178
- s1.trace_call 10
179
- s2.trace_call 20
180
- assert_equal(s1.fraction_of(s2).to_s, 'NaN')
181
- end
182
-
183
- def test_fraction_of2
184
- s1 = NewRelic::MethodTraceStats.new
185
- s1.trace_call 10
186
- s2 = NewRelic::MethodTraceStats.new
187
- assert_equal(s1.fraction_of(s2).to_s, 'NaN')
188
- end
189
-
190
175
  def test_multiply_by
191
176
  s1 = NewRelic::MethodTraceStats.new
192
177
  s1.trace_call 10
metadata CHANGED
@@ -1,13 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: newrelic_rpm
3
3
  version: !ruby/object:Gem::Version
4
- hash: 9
5
- prerelease:
4
+ hash: 62196449
5
+ prerelease: 6
6
6
  segments:
7
7
  - 3
8
8
  - 3
9
+ - 2
10
+ - beta
9
11
  - 1
10
- version: 3.3.1
12
+ version: 3.3.2.beta1
11
13
  platform: ruby
12
14
  authors:
13
15
  - Bill Kayser
@@ -18,7 +20,7 @@ autorequire:
18
20
  bindir: bin
19
21
  cert_chain: []
20
22
 
21
- date: 2011-12-15 00:00:00 -08:00
23
+ date: 2012-01-20 00:00:00 -08:00
22
24
  default_executable:
23
25
  dependencies:
24
26
  - !ruby/object:Gem::Dependency