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
@@ -1,5 +1,6 @@
1
1
  # Add these methods to TransactionSample that enable performance analysis in the user interface.
2
- module NewRelic::TransactionAnalysis
2
+ module NewRelic
3
+ module TransactionAnalysis
3
4
  def database_time
4
5
  time_percentage(/^Database\/.*/)
5
6
  end
@@ -118,4 +119,6 @@ module NewRelic::TransactionAnalysis
118
119
  # percent value rounded to two digits:
119
120
  return (100 * fraction).round / 100.0
120
121
  end
121
- end
122
+ end
123
+ end
124
+
@@ -16,17 +16,17 @@ module NewRelic
16
16
  ].freeze
17
17
 
18
18
  class TransactionSample
19
+ EMPTY_ARRAY = [].freeze
19
20
 
20
21
  @@start_time = Time.now
21
22
 
22
23
  include TransactionAnalysis
23
24
  class Segment
24
25
 
25
- class << self
26
- @@empty_array = []
27
- end
28
26
 
29
27
  attr_reader :entry_timestamp
28
+ # The exit timestamp will be relative except for the outermost sample which will
29
+ # have a timestamp.
30
30
  attr_reader :exit_timestamp
31
31
  attr_reader :parent_segment
32
32
  attr_reader :metric_name
@@ -34,7 +34,7 @@ module NewRelic
34
34
 
35
35
  def initialize(timestamp, metric_name, segment_id)
36
36
  @entry_timestamp = timestamp
37
- @metric_name = metric_name
37
+ @metric_name = metric_name || '<unknown>'
38
38
  @segment_id = segment_id || object_id
39
39
  end
40
40
 
@@ -66,18 +66,30 @@ module NewRelic
66
66
  map.to_json
67
67
  end
68
68
 
69
- def self.from_json(json)
69
+ def self.from_json(json, id_generator)
70
70
  json = ActiveSupport::JSON.decode(json) if json.is_a?(String)
71
- segment = Segment.new(json["entry_timestamp"].to_f, json["metric_name"], json["segment_id"])
72
- segment.end_trace json["exit_timestamp"].to_f
73
- params = json["params"]
71
+ if json.is_a?(Array)
72
+ entry_timestamp = json[0].to_f / 1000
73
+ exit_timestamp = json[1].to_f / 1000
74
+ metric_name = json[2]
75
+ params = json[3]
76
+ called_segments = json[4]
77
+ else
78
+ entry_timestamp = json["entry_timestamp"].to_f
79
+ exit_timestamp = json["exit_timestamp"].to_f
80
+ metric_name = json["metric_name"]
81
+ params = json["params"]
82
+
83
+ called_segments = json["called_segments"]
84
+ end
85
+ segment = Segment.new(entry_timestamp, metric_name, id_generator.next_id)
86
+ segment.end_trace exit_timestamp
74
87
  if params
75
88
  segment.send :params=, HashWithIndifferentAccess.new(params)
76
89
  end
77
- called_segments = json["called_segments"]
78
90
  if called_segments
79
91
  called_segments.each do |child|
80
- segment.add_called_segment(self.from_json(child))
92
+ segment.add_called_segment(self.from_json(child, id_generator))
81
93
  end
82
94
  end
83
95
  segment
@@ -86,45 +98,42 @@ module NewRelic
86
98
  def path_string
87
99
  "#{metric_name}[#{called_segments.collect {|segment| segment.path_string }.join('')}]"
88
100
  end
89
-
101
+ def to_s_compact
102
+ str = ""
103
+ str << metric_name
104
+ if called_segments.any?
105
+ str << "{#{called_segments.map { | cs | cs.to_s_compact }.join(",")}}"
106
+ end
107
+ str
108
+ end
90
109
  def to_debug_str(depth)
91
- tab = ""
92
- depth.times {tab << " "}
93
-
110
+ tab = " " * depth
94
111
  s = tab.clone
95
- s << ">> #{metric_name}: #{(@entry_timestamp*1000).round}\n"
112
+ s << ">> #{'%3i ms' % (@entry_timestamp*1000)} [#{self.class.name.split("::").last}] #{metric_name} \n"
96
113
  unless params.empty?
97
- s << "#{tab}#{tab}{\n"
98
114
  params.each do |k,v|
99
- s << "#{tab}#{tab}#{k}: #{v}\n"
115
+ s << "#{tab} -#{'%-16s' % k}: #{v.to_s[0..80]}\n"
100
116
  end
101
- s << "#{tab}#{tab}}\n"
102
117
  end
103
118
  called_segments.each do |cs|
104
119
  s << cs.to_debug_str(depth + 1)
105
120
  end
106
- s << tab
107
- s << "<< #{metric_name}: #{@exit_timestamp ? (@exit_timestamp*1000).round : 'n/a'}\n"
108
- s
121
+ s << tab + "<< "
122
+ s << case @exit_timestamp
123
+ when nil then ' n/a'
124
+ when Numeric then '%3i ms' % (@exit_timestamp*1000)
125
+ else @exit_timestamp.to_s
126
+ end
127
+ s << " #{metric_name}\n"
109
128
  end
110
129
 
111
130
  def called_segments
112
- @called_segments || @@empty_array
113
- end
114
-
115
- def freeze
116
- params.freeze
117
- if @called_segments
118
- @called_segments.each do |s|
119
- s.freeze
120
- end
121
- end
122
- super
131
+ @called_segments || EMPTY_ARRAY
123
132
  end
124
133
 
125
134
  # return the total duration of this segment
126
135
  def duration
127
- @exit_timestamp - @entry_timestamp
136
+ (@exit_timestamp - @entry_timestamp).to_f
128
137
  end
129
138
 
130
139
  # return the duration of this segment without
@@ -139,7 +148,28 @@ module NewRelic
139
148
  end
140
149
  d
141
150
  end
142
-
151
+ def count_segments
152
+ count = 1
153
+ @called_segments.each { | seg | count += seg.count_segments } if @called_segments
154
+ count
155
+ end
156
+ # Walk through the tree and truncate the segments
157
+ def truncate(max)
158
+ return max unless @called_segments
159
+ i = 0
160
+ @called_segments.each do | segment |
161
+ max = segment.truncate(max)
162
+ max -= 1
163
+ if max <= 0
164
+ @called_segments = @called_segments[0..i]
165
+ break
166
+ else
167
+ i += 1
168
+ end
169
+ end
170
+ max
171
+ end
172
+
143
173
  def []=(key, value)
144
174
  # only create a parameters field if a parameter is set; this will save
145
175
  # bandwidth etc as most segments have no parameters
@@ -242,7 +272,11 @@ module NewRelic
242
272
  @params = p
243
273
  end
244
274
  end
245
-
275
+
276
+ class FakeSegment < Segment
277
+ public :parent_segment=
278
+ end
279
+
246
280
  class SummarySegment < Segment
247
281
 
248
282
 
@@ -319,8 +353,8 @@ module NewRelic
319
353
  end
320
354
 
321
355
  end
322
-
323
356
 
357
+ attr_accessor :profile
324
358
  attr_reader :root_segment
325
359
  attr_reader :params
326
360
  attr_reader :sample_id
@@ -333,12 +367,29 @@ module NewRelic
333
367
  @params[:request_params] = {}
334
368
  end
335
369
 
370
+ def count_segments
371
+ @root_segment.count_segments - 1 # don't count the root segment
372
+ end
373
+
374
+ def truncate(max)
375
+ original_count = count_segments
376
+
377
+ return if original_count <= max
378
+
379
+ @root_segment.truncate(max-1)
380
+
381
+ if params[:segment_count].nil?
382
+ params[:segment_count] = original_count
383
+ end
384
+ end
385
+
336
386
  # offset from start of app
337
387
  def timestamp
338
388
  @start_time - @@start_time.to_f
339
389
  end
340
390
 
341
- def to_json(options = {})
391
+ # Used in the server only
392
+ def to_json(options = {}) #:nodoc:
342
393
  map = {:sample_id => @sample_id,
343
394
  :start_time => @start_time,
344
395
  :root_segment => @root_segment}
@@ -348,16 +399,33 @@ module NewRelic
348
399
  map.to_json
349
400
  end
350
401
 
351
- def self.from_json(json)
402
+ # Used in the Server only
403
+ def self.from_json(json) #:nodoc:
352
404
  json = ActiveSupport::JSON.decode(json) if json.is_a?(String)
353
- sample = TransactionSample.new(json["start_time"].to_f, json["sample_id"].to_i)
354
- params = json["params"]
405
+
406
+ if json.is_a?(Array)
407
+ start_time = json[0].to_f / 1000
408
+ custom_params = HashWithIndifferentAccess.new(json[2])
409
+ params = {:request_params => HashWithIndifferentAccess.new(json[1]),
410
+ :custom_params => custom_params}
411
+ cpu_time = custom_params.delete(:cpu_time)
412
+ sample_id = nil
413
+ params[:cpu_time] = cpu_time.to_f / 1000 if cpu_time
414
+ root = json[3]
415
+ else
416
+ start_time = json["start_time"].to_f
417
+ sample_id = json["sample_id"].to_i
418
+ params = json["params"]
419
+ root = json["root_segment"]
420
+ end
421
+
422
+ sample = TransactionSample.new(start_time, sample_id)
423
+
355
424
  if params
356
425
  sample.send :params=, HashWithIndifferentAccess.new(params)
357
426
  end
358
- root = json["root_segment"]
359
427
  if root
360
- sample.send :root_segment=, Segment.from_json(root)
428
+ sample.send :root_segment=, Segment.from_json(root, IDGenerator.new)
361
429
  end
362
430
  sample
363
431
  end
@@ -370,17 +438,11 @@ module NewRelic
370
438
  @root_segment.path_string
371
439
  end
372
440
 
373
- def create_segment (relative_timestamp, metric_name, segment_id = nil)
441
+ def create_segment(relative_timestamp, metric_name, segment_id = nil)
374
442
  raise TypeError.new("Frozen Transaction Sample") if frozen?
375
443
  NewRelic::TransactionSample::Segment.new(relative_timestamp, metric_name, segment_id)
376
444
  end
377
445
 
378
- def freeze
379
- @root_segment.freeze
380
- params.freeze
381
- super
382
- end
383
-
384
446
  def duration
385
447
  root_segment.duration
386
448
  end
@@ -389,6 +451,10 @@ module NewRelic
389
451
  @root_segment.each_segment(&block)
390
452
  end
391
453
 
454
+ def to_s_compact
455
+ @root_segment.to_s_compact
456
+ end
457
+
392
458
  def find_segment(id)
393
459
  @root_segment.find_segment(id)
394
460
  end
@@ -402,9 +468,12 @@ module NewRelic
402
468
  next if k == :path
403
469
  s << " #{k}: " <<
404
470
  case v
405
- when Enumerable; v.map(&:to_s).sort.join("; ")
471
+ when Enumerable then v.map(&:to_s).sort.join("; ")
472
+ when String then v
473
+ when Float then '%6.3s' % v
474
+ when nil then ''
406
475
  else
407
- v
476
+ raise "unexpected value type for #{k}: '#{v}' (#{v.class})"
408
477
  end << "\n"
409
478
  end
410
479
  s << " }\n\n"
@@ -424,8 +493,9 @@ module NewRelic
424
493
  params.each {|k,v| sample.params[k] = v}
425
494
 
426
495
  delta = build_segment_with_omissions(sample, 0.0, @root_segment, sample.root_segment, regex)
427
- sample.root_segment.end_trace(@root_segment.exit_timestamp - delta)
428
- sample.freeze
496
+ sample.root_segment.end_trace(@root_segment.exit_timestamp - delta)
497
+ sample.profile = self.profile
498
+ sample
429
499
  end
430
500
 
431
501
  # return a new transaction sample that can be sent to the RPM service.
@@ -446,7 +516,7 @@ module NewRelic
446
516
  end
447
517
 
448
518
  sample.root_segment.end_trace(@root_segment.exit_timestamp)
449
- sample.freeze
519
+ sample
450
520
  end
451
521
 
452
522
  def analyze
@@ -501,7 +571,6 @@ module NewRelic
501
571
 
502
572
  def summarize_segments(like_segments)
503
573
  if like_segments.length > COLLAPSE_SEGMENTS_THRESHOLD
504
- puts "#{like_segments.first.path_string} #{like_segments.length}"
505
574
  [CompositeSegment.new(like_segments)]
506
575
  else
507
576
  like_segments
@@ -571,5 +640,15 @@ module NewRelic
571
640
  target_called_segment.end_trace(source_called_segment.exit_timestamp)
572
641
  end
573
642
  end
643
+
644
+ # Generates segment ids for json transaction segments
645
+ class IDGenerator
646
+ def initialize
647
+ @next_id = 0
648
+ end
649
+ def next_id
650
+ @next_id += 1
651
+ end
652
+ end
574
653
  end
575
654
  end
@@ -2,46 +2,53 @@
2
2
  module NewRelic
3
3
  module VERSION #:nodoc:
4
4
  MAJOR = 2
5
- MINOR = 9
6
- TINY = 9
7
- STRING = [MAJOR, MINOR, TINY].join('.')
5
+ MINOR = 10
6
+ TINY = 3
7
+ EXPERIMENTAL = nil
8
+ STRING = [MAJOR, MINOR, TINY, EXPERIMENTAL].compact.join('.')
8
9
  end
9
10
 
10
11
  # Helper class for managing version comparisons
11
12
  class VersionNumber
12
- attr_reader :major_version, :minor_version, :tiny_version
13
+ attr_reader :parts
13
14
  include Comparable
14
15
  def initialize(version_string)
15
16
  version_string ||= '1.0.0'
16
17
  @parts = version_string.split('.').map{|n| n.to_i }
17
- @major_version, @minor_version, @tiny_version = (version_string.split('.') + %w[0 0 0]).map(&:to_i)
18
18
  end
19
19
  def major_version; @parts[0]; end
20
20
  def minor_version; @parts[1]; end
21
21
  def tiny_version; @parts[2]; end
22
22
 
23
23
  def <=>(other)
24
- other = VersionNumber.new(other) if other.is_a?(String)
25
- self.scalar_value <=> other.scalar_value
26
- end
27
-
28
- def eql?(other)
29
- return self.scalar_value == other.scalar_value rescue nil
24
+ other = self.class.new(other) if other.is_a? String
25
+ self.class.compare(self.parts, other.parts)
30
26
  end
31
27
 
32
28
  def to_s
33
29
  @parts.join(".")
34
30
  end
35
- def scalar_value
36
- if !@scalar_value
37
- bits = 24
38
- @scalar_value = @parts.inject(0) do | value, part |
39
- bits -= 6
40
- value + (part << bits)
41
- end
31
+
32
+ def hash
33
+ @parts.hash
34
+ end
35
+
36
+ def eql? other
37
+ (self <=> other) == 0
38
+ end
39
+
40
+ private
41
+ def self.compare(parts1, parts2)
42
+ a, b = parts1.first, parts2.first
43
+ case
44
+ when a.nil? && b.nil? then 0
45
+ when a.nil? then -1
46
+ when b.nil? then 1
47
+ when a == b
48
+ compare(parts1[1..-1], parts2[1..-1])
49
+ else
50
+ a <=> b
42
51
  end
43
- @scalar_value
44
52
  end
45
- alias hash scalar_value
46
53
  end
47
54
  end
@@ -6,10 +6,10 @@
6
6
  #
7
7
  # Authentication is handled using your agent license key or HTTP Basic Authentication. To authenticate
8
8
  # using your license key your newrelic.yml configuration file must be in your application config directory
9
- # and contain your license key. The New Relic account associated with the license key must allow api access.
9
+ # and contain your license key. The New Relic account associated with the license key must allow api access.
10
10
  # Log into RPM, click Account at the top of the page and check the "Make my account data accessible" checkbox.
11
11
  #
12
- # Basic authentication uses your site credentials to authenticate.
12
+ # Basic authentication uses your site credentials to authenticate.
13
13
  #
14
14
  # # To authenticate using basic authentication, make this call with your username and password:
15
15
  # NewRelicApi.authenticate('user@example.com', 'test')
@@ -20,7 +20,7 @@
20
20
  #
21
21
  # # Fetching the list of applications for an account
22
22
  # NewRelicApi::Account.find(:first).applications
23
- #
23
+ #
24
24
  # # Fetching the health values for all account applications
25
25
  # NewRelicApi::Account.application_health
26
26
  #
@@ -32,9 +32,9 @@
32
32
  #
33
33
 
34
34
  module NewRelicApi
35
-
35
+
36
36
  # This mixin defines ActiveRecord style associations (like has_many) for ActiveResource objects.
37
- # ActiveResource objects using this mixin must define the method 'query_params'.
37
+ # ActiveResource objects using this mixin must define the method 'query_params'.
38
38
  module ActiveResourceAssociations #:nodoc:
39
39
  class << self
40
40
  protected
@@ -46,10 +46,10 @@ module NewRelicApi
46
46
  define_method association do |*args|
47
47
  val = attributes[association.to_s] # if we've already fetched the relationship in the initial fetch, return it
48
48
  return val if val
49
-
49
+
50
50
  options = args.extract_options!
51
51
  type = args.first || :all
52
-
52
+
53
53
  begin
54
54
  # look for the class definition within the current class
55
55
  clazz = ( self.class.name + '::' + association.to_s.camelize.singularize).constantize
@@ -60,38 +60,39 @@ module NewRelicApi
60
60
  params = (options[:params] || {}).update(self.query_params)
61
61
  options[:params] = params
62
62
  clazz.find(type, options)
63
-
63
+
64
64
  #clazz.find(type, :params => options.update(self.query_params))
65
65
  end
66
66
  end
67
- end
67
+ end
68
68
  end
69
69
  end
70
70
  end
71
-
71
+
72
72
  end
73
73
  class << self
74
74
  attr_accessor :email, :password, :license_key, :ssl, :host, :port
75
-
75
+
76
76
  # Sets up basic authentication credentials for all the resources. This is not necessary if you are
77
77
  # using agent license key authentication.
78
78
  def authenticate(email, password)
79
79
  @password = password
80
80
  @email = email
81
81
  end
82
-
82
+
83
83
  # Resets the base path of all resources. This should be called when overridding the newrelic.yml settings
84
84
  # using the ssl, host or port accessors.
85
85
  def reset!
86
86
  @classes.each {|klass| klass.reset!} if @classes
87
87
  NewRelicApi::Account.site_url
88
88
  end
89
-
90
-
89
+
90
+
91
91
  def track_resource(klass) #:nodoc:
92
92
  (@classes ||= []) << klass
93
93
  end
94
94
  end
95
+
95
96
  class BaseResource < ActiveResource::Base #:nodoc:
96
97
  include ActiveResourceAssociations
97
98
 
@@ -99,25 +100,25 @@ module NewRelicApi
99
100
  def inherited(klass) #:nodoc:
100
101
  NewRelicApi.track_resource(klass)
101
102
  end
102
-
103
+
103
104
  def headers
104
105
  h = {'x-license-key' => NewRelicApi.license_key || NewRelic::Control.instance['license_key']}
105
106
  h['Authorization'] = 'Basic ' + ["#{NewRelicApi.email}:#{NewRelicApi.password}"].pack('m').delete("\r\n") if NewRelicApi.email
106
107
  h
107
108
  end
108
-
109
+
109
110
  def site_url
110
111
  host = NewRelicApi.host || NewRelic::Control.instance.api_server.name
111
112
  port = NewRelicApi.port || NewRelic::Control.instance.api_server.port
112
113
  "#{port == 443 ? 'https' : 'http'}://#{host}:#{port}"
113
114
  end
114
-
115
+
115
116
  def reset!
116
117
  self.site = self.site_url
117
118
  end
118
-
119
+
119
120
  protected
120
-
121
+
121
122
  def fix_fields(*fields)
122
123
  fields.to_a.each do |field|
123
124
  define_method field do
@@ -125,22 +126,22 @@ module NewRelicApi
125
126
  end
126
127
  end
127
128
  end
128
-
129
+
129
130
  def fix_integer_fields(*fields)
130
131
  fix_fields(*fields) { |sup| sup.to_i }
131
132
  end
132
-
133
+
133
134
  def fix_float_fields(*fields)
134
135
  fix_fields(*fields) { |sup| sup.to_f }
135
136
  end
136
-
137
+
137
138
  end
138
139
  self.site = self.site_url
139
140
  end
140
141
  ACCOUNT_RESOURCE_PATH = '/accounts/:account_id/' #:nodoc:
141
142
  ACCOUNT_AGENT_RESOURCE_PATH = ACCOUNT_RESOURCE_PATH + 'agents/:agent_id/' #:nodoc:
142
143
  ACCOUNT_APPLICATION_RESOURCE_PATH = ACCOUNT_RESOURCE_PATH + 'applications/:application_id/' #:nodoc:
143
-
144
+
144
145
  module AccountResource #:nodoc:
145
146
  def account_id
146
147
  prefix_options[:account_id]
@@ -148,45 +149,44 @@ module NewRelicApi
148
149
  def account_query_params(extra_params = {})
149
150
  {:account_id => account_id}.merge(extra_params)
150
151
  end
151
-
152
+
152
153
  def query_params#:nodoc:
153
154
  account_query_params
154
155
  end
155
-
156
156
  end
157
-
157
+
158
158
  module AgentResource #:nodoc:
159
159
  include ActiveResourceAssociations
160
160
  end
161
-
161
+
162
162
  # An application has many:
163
163
  # +agents+:: the agent instances associated with this app
164
164
  # +threshold_values+:: the health indicators for this application.
165
165
  class Application < BaseResource
166
166
  include AccountResource
167
167
  include AgentResource
168
-
168
+
169
169
  has_many :agents, :threshold_values
170
-
170
+
171
171
  self.prefix = ACCOUNT_RESOURCE_PATH
172
-
172
+
173
173
  def query_params#:nodoc:
174
174
  account_query_params(:application_id => id)
175
175
  end
176
-
176
+
177
177
  class Agent < BaseResource
178
178
  include AccountResource
179
179
  include AgentResource
180
-
180
+
181
181
  self.prefix = ACCOUNT_APPLICATION_RESOURCE_PATH
182
-
182
+
183
183
  def query_params#:nodoc:
184
184
  super.merge(:application_id => cluster_agent_id)
185
185
  end
186
186
  end
187
-
187
+
188
188
  end
189
-
189
+
190
190
  # A threshold value represents a single health indicator for an application such as CPU, memory or response time.
191
191
  #
192
192
  # ==Fields
@@ -196,10 +196,10 @@ module NewRelicApi
196
196
  class ThresholdValue < BaseResource
197
197
  self.prefix = ACCOUNT_APPLICATION_RESOURCE_PATH
198
198
  # attr_reader :name, :begin_time, :metric_value, :threshold_value
199
-
199
+
200
200
  fix_integer_fields :threshold_value
201
201
  fix_float_fields :metric_value
202
-
202
+
203
203
  # Returns the color value for this threshold (Gray, Green, Yellow or Red).
204
204
  def color_value
205
205
  case threshold_value
@@ -209,17 +209,17 @@ module NewRelicApi
209
209
  else 'Gray'
210
210
  end
211
211
  end
212
-
212
+
213
213
  def to_s #:nodoc:
214
214
  "#{name}: #{color_value} (#{formatted_metric_value})"
215
215
  end
216
216
  end
217
-
217
+
218
218
  # An account contains your basic account information.
219
219
  #
220
220
  # Accounts have many
221
221
  # +applications+:: the applications contained within the account
222
- #
222
+ #
223
223
  # Find Accounts
224
224
  #
225
225
  # NewRelicApi::Account.find(:all) # find all accounts for the current user.
@@ -227,18 +227,33 @@ module NewRelicApi
227
227
  #
228
228
  class Account < BaseResource
229
229
  has_many :applications
230
-
230
+ has_many :account_views
231
+
231
232
  def query_params #:nodoc:
232
233
  {:account_id => id}
233
234
  end
234
-
235
+
235
236
  # Returns an account including all of its applications and the threshold values for each application.
236
237
  def self.application_health(type = :first)
237
238
  find(type, :params => {:include => :application_health})
238
239
  end
240
+
241
+ class AccountView < BaseResource
242
+ self.prefix = ACCOUNT_RESOURCE_PATH
243
+
244
+ def query_params(extra_params = {}) #:nodoc:
245
+ {:account_id => account_id}.merge(extra_params)
246
+ end
247
+
248
+ def user
249
+ @attributes['user']
250
+ end
251
+ end
252
+
253
+ class AccountUsage < BaseResource
254
+ end
239
255
  end
240
-
241
-
256
+
242
257
  # This model is used to mark production deployments in RPM
243
258
  # Only create is supported.
244
259
  # ==Examples
@@ -247,10 +262,15 @@ module NewRelicApi
247
262
  #
248
263
  class Deployment < BaseResource
249
264
  end
250
-
251
- class User < BaseResource
252
- end
265
+
253
266
  class Subscription < BaseResource
267
+ def query_params(extra_params = {}) #:nodoc:
268
+ {:account_id => account_id}.merge(extra_params)
269
+ end
254
270
  end
271
+
272
+ class User < BaseResource
273
+ end
274
+
255
275
  end
256
276