newrelic_rpm 2.8.1 → 2.8.2

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.

@@ -6,10 +6,6 @@ require 'singleton'
6
6
  require 'zlib'
7
7
  require 'stringio'
8
8
 
9
-
10
- # This must be turned off before we ship
11
- VALIDATE_BACKGROUND_THREAD_LOADING = false
12
-
13
9
  # The NewRelic Agent collects performance data from ruby applications in realtime as the
14
10
  # application runs, and periodically sends that data to the NewRelic server.
15
11
  module NewRelic::Agent
@@ -24,6 +20,8 @@ module NewRelic::Agent
24
20
  # Reserved for future use
25
21
  class ServerError < StandardError; end
26
22
 
23
+ class BackgroundLoadingError < StandardError; end
24
+
27
25
  # add some convenience methods for easy access to the Agent singleton.
28
26
  # the following static methods all point to the same Agent instance:
29
27
  #
@@ -171,13 +169,15 @@ module NewRelic::Agent
171
169
  def start(environment, identifier, force=false)
172
170
 
173
171
  if @started
174
- log! "Agent Started Already!"
172
+ config.log! "Agent Started Already!"
175
173
  return
176
174
  end
177
175
  @environment = environment
178
176
  @identifier = identifier && identifier.to_s
179
177
  if @identifier
180
178
  start_reporting(force)
179
+ config.log! "New Relic RPM Agent #{NewRelic::VERSION::STRING} Initialized: pid = #{$$}"
180
+ config.log! "Agent Log is found in #{NewRelic::Config.instance.log_file}"
181
181
  return true
182
182
  else
183
183
  return false
@@ -323,7 +323,7 @@ module NewRelic::Agent
323
323
  # note if the agent attempts to report more frequently than the specified
324
324
  # report data, then it will be ignored.
325
325
 
326
- log! "Reporting performance data every #{@report_period} seconds"
326
+ config.log! "Reporting performance data every #{@report_period} seconds"
327
327
  @worker_loop.add_task(@report_period) do
328
328
  harvest_and_send_timeslice_data
329
329
  end
@@ -358,22 +358,21 @@ module NewRelic::Agent
358
358
 
359
359
  @worker_loop = WorkerLoop.new(log)
360
360
 
361
- if VALIDATE_BACKGROUND_THREAD_LOADING
361
+ if config['check_bg_loading']
362
362
  require 'new_relic/agent/patch_const_missing'
363
- self.class.newrelic_enable_warning
363
+ log.warn "Agent background loading checking turned on"
364
+ ClassLoadingWatcher.enable_warning
364
365
  end
365
366
 
366
367
  @worker_thread = Thread.new do
367
368
  begin
368
- if VALIDATE_BACKGROUND_THREAD_LOADING
369
- self.class.newrelic_set_agent_thread(Thread.current)
370
- end
369
+ ClassLoadingWatcher.set_background_thread(Thread.current) if config['check_bg_loading']
371
370
  run_worker_loop
372
371
  rescue IgnoreSilentlyException
373
- log! "Unable to establish connection with the server. Run with log level set to debug for more information."
372
+ config.log! "Unable to establish connection with the server. Run with log level set to debug for more information."
374
373
  rescue StandardError => e
375
- log! e
376
- log! e.backtrace.join("\n")
374
+ config.log! e
375
+ config.log! e.backtrace.join("\n")
377
376
  end
378
377
  end
379
378
 
@@ -381,7 +380,7 @@ module NewRelic::Agent
381
380
  # by stopping the foreground thread after the background thread is created. Turn on dependency loading logging
382
381
  # and make sure that no loading occurs.
383
382
  #
384
- # log! "FINISHED AGENT INIT"
383
+ # config.log! "FINISHED AGENT INIT"
385
384
  # while true
386
385
  # sleep 1
387
386
  # end
@@ -438,7 +437,7 @@ module NewRelic::Agent
438
437
  # make sure the license key exists and is likely to be really a license key
439
438
  # by checking it's string length (license keys are 40 character strings.)
440
439
  if @prod_mode_enabled && (!@license_key || @license_key.length != 40)
441
- log! "No license key found. Please edit your newrelic.yml file and insert your license key"
440
+ config.log! "No license key found. Please edit your newrelic.yml file and insert your license key"
442
441
  return
443
442
  end
444
443
 
@@ -504,7 +503,7 @@ module NewRelic::Agent
504
503
  config.settings
505
504
  @report_period = invoke_remote :get_data_report_period, @agent_id
506
505
 
507
- log! "Connected to NewRelic Service at #{config.server}"
506
+ config.log! "Connected to NewRelic Service at #{config.server}"
508
507
  log.debug "Agent ID = #{@agent_id}."
509
508
 
510
509
  # Ask the server for permission to send transaction samples. determined by subscription license.
@@ -519,8 +518,8 @@ module NewRelic::Agent
519
518
  @connected = true
520
519
 
521
520
  rescue LicenseException => e
522
- log! e.message, :error
523
- log! "Visit NewRelic.com to obtain a valid license key, or to upgrade your account."
521
+ config.log! e.message, :error
522
+ config.log! "Visit NewRelic.com to obtain a valid license key, or to upgrade your account."
524
523
  @invalid_license = true
525
524
  return false
526
525
 
@@ -576,12 +575,12 @@ module NewRelic::Agent
576
575
  @harvest_thread ||= Thread.current
577
576
 
578
577
  if @harvest_thread != Thread.current
579
- log! "ERROR - two harvest threads are running (current=#{Thread.current}, havest=#{@harvest_thread}"
578
+ config.log! "ERROR - two harvest threads are running (current=#{Thread.current}, havest=#{@harvest_thread}"
580
579
  @harvest_thread = Thread.current
581
580
  end
582
581
 
583
582
  # Fixme: remove this check
584
- log! "Agent sending data too frequently - #{now - @last_harvest_time} seconds" if (now.to_f - @last_harvest_time.to_f) < 45
583
+ config.log! "Agent sending data too frequently - #{now - @last_harvest_time} seconds" if (now.to_f - @last_harvest_time.to_f) < 45
585
584
 
586
585
  @unsent_timeslice_data ||= {}
587
586
  @unsent_timeslice_data = @stats_engine.harvest_timeslice_data(@unsent_timeslice_data, @metric_ids)
@@ -697,9 +696,9 @@ module NewRelic::Agent
697
696
  raise IgnoreSilentlyException
698
697
  end
699
698
  rescue ForceDisconnectException => e
700
- log! "RPM forced this agent to disconnect", :error
701
- log! e.message, :error
702
- log! "Restart this process to resume RPM's agent communication with NewRelic.com"
699
+ config.log! "RPM forced this agent to disconnect", :error
700
+ config.log! e.message, :error
701
+ config.log! "Restart this process to resume RPM's agent communication with NewRelic.com"
703
702
  # when a disconnect is requested, stop the current thread, which is the worker thread that
704
703
  # gathers data and talks to the server.
705
704
  @connected = false
@@ -710,14 +709,6 @@ module NewRelic::Agent
710
709
  raise IgnoreSilentlyException
711
710
  end
712
711
 
713
- # send the given message to STDERR as well as the agent log, so that it shows
714
- # up in the console. This should be used for important informational messages at boot
715
- def log!(msg, level = :info)
716
- # only log to stderr when we are running as a mongrel process, so it doesn't
717
- # muck with daemons and the like.
718
- config.log!(msg, level)
719
- end
720
-
721
712
  def graceful_disconnect
722
713
  if @connected && !(config.server.host == "localhost" && @identifier == '3000')
723
714
  begin
@@ -3,19 +3,19 @@ module NewRelic::Agent::CollectionHelper
3
3
  # strings
4
4
  def normalize_params(params)
5
5
  case params
6
- when Symbol, FalseClass, TrueClass, nil:
6
+ when Symbol, FalseClass, TrueClass, nil
7
7
  params
8
8
  when Numeric
9
9
  truncate(params.to_s)
10
10
  when String
11
11
  truncate(params)
12
- when Hash:
12
+ when Hash
13
13
  new_params = {}
14
14
  params.each do | key, value |
15
15
  new_params[truncate(normalize_params(key),32)] = normalize_params(value)
16
16
  end
17
17
  new_params
18
- when Enumerable:
18
+ when Enumerable
19
19
  # We only want the first 20 values of any enumerable. Invoking to_a.first(20) works but
20
20
  # the to_a call might be expensive, so we'll just build it manually, even though it's
21
21
  # more verbose.
@@ -78,4 +78,4 @@ module NewRelic::Agent::CollectionHelper
78
78
  truncate(flatten(string), len)
79
79
  end
80
80
  end
81
- end
81
+ end
@@ -73,7 +73,7 @@ module NewRelic::Agent::Instrumentation
73
73
  # Skip instrumentation based on the value of 'do_not_trace' and if
74
74
  # we aren't calling directly with a block.
75
75
  should_skip = !block_given? && case ignore_actions
76
- when nil: false
76
+ when nil; false
77
77
  when Hash
78
78
  only_actions = Array(ignore_actions[:only])
79
79
  except_actions = Array(ignore_actions[:except])
@@ -1,31 +1,105 @@
1
1
  # This class is for debugging purposes only.
2
- #
3
- class Module
4
- @@newrelic_agent_thread = nil
5
- def new_relic_const_missing(*args)
6
- if Thread.current == @@newrelic_agent_thread
7
- msg = "Agent background thread shouldn't be calling const_missing (#{args.inspect}) \n"
8
- msg << caller[0..4].join(" \n")
9
- NewRelic::Config.instance.log.warn msg
10
- end
11
- original_const_missing(*args)
2
+ # It inserts instrumentation into class loading to verify
3
+ # that no classes are being loaded on the new relic thread,
4
+ # which can cause problems in the class loader code.
5
+
6
+ module ClassLoadingWatcher
7
+
8
+ extend self
9
+ @@background_thread = nil
10
+
11
+ def background_thread
12
+ @@background_thread
12
13
  end
13
14
 
14
- def newrelic_enable_warning
15
+ def set_background_thread(thread)
16
+ @@background_thread = thread
17
+
18
+ # these tests that check is working...
19
+ # begin
20
+ # bad = Bad
21
+ # rescue
22
+ # end
23
+
24
+ # require 'new_relic/agent/patch_const_missing'
25
+ # load 'new_relic/agent/patch_const_missing.rb'
26
+ end
27
+ module SanityCheck
28
+ def new_relic_check_for_badness(*args)
29
+
30
+ if Thread.current == ClassLoadingWatcher.background_thread
31
+ msg = "Agent background thread shouldn't be loading classes (#{args.inspect})\n"
32
+
33
+ exception = NewRelic::Agent::BackgroundLoadingError.new(msg.clone)
34
+ exception.set_backtrace(caller)
35
+
36
+ NewRelic::Agent.instance.error_collector.notice_error(nil, nil, [], exception)
37
+ msg << caller.join("\n")
38
+
39
+ NewRelic::Config.instance.log.error msg
40
+ end
41
+ end
42
+ end
43
+ def enable_warning
44
+ Object.class_eval do
45
+ if !defined?(non_new_relic_require)
46
+ alias_method :non_new_relic_require, :require
47
+ alias_method :require, :new_relic_require
48
+ end
49
+
50
+ if !defined?(non_new_relic_load)
51
+ alias_method :non_new_relic_load, :load
52
+ alias_method :load, :new_relic_load
53
+ end
54
+ end
15
55
  Module.class_eval do
16
- if !defined?(original_const_missing)
17
- alias_method :original_const_missing, :const_missing
56
+ if !defined?(non_new_relic_const_missing)
57
+ alias_method :non_new_relic_const_missing, :const_missing
18
58
  alias_method :const_missing, :new_relic_const_missing
19
59
  end
20
60
  end
21
61
  end
22
- def newrelic_disable_warning
62
+
63
+ def disable_warning
64
+ Object.class_eval do
65
+ if defined?(non_new_relic_require)
66
+ alias_method :require, :non_new_relic_require
67
+ undef non_new_relic_require
68
+ end
69
+
70
+ if defined?(non_new_relic_load)
71
+ alias_method :load, :non_new_relic_load
72
+ undef non_new_relic_load
73
+ end
74
+ end
23
75
  Module.class_eval do
24
- alias_method :const_missing, :original_const_missing if defined?(original_const_missing)
76
+ if defined?(non_new_relic_const_missing)
77
+ alias_method :const_missing, :non_new_relic_const_missing
78
+ undef non_new_relic_const_missing
79
+ end
25
80
  end
26
81
  end
82
+ end
83
+
84
+ class Object
85
+ include ClassLoadingWatcher::SanityCheck
86
+
87
+ def new_relic_require(*args)
88
+ new_relic_check_for_badness("Object require", *args)
89
+ non_new_relic_require(*args)
90
+ end
91
+
92
+ def new_relic_load(*args)
93
+ new_relic_check_for_badness("Object load", *args)
94
+ non_new_relic_load(*args)
95
+ end
96
+ end
97
+
98
+ class Module
99
+ include ClassLoadingWatcher::SanityCheck
27
100
 
28
- def newrelic_set_agent_thread(thread)
29
- @@newrelic_agent_thread = thread
101
+ def new_relic_const_missing(*args)
102
+ new_relic_check_for_badness("Module #{self.name} const_missing", *args)
103
+ non_new_relic_const_missing(*args)
30
104
  end
31
105
  end
@@ -11,6 +11,8 @@ require 'net/https'
11
11
  module NewRelic
12
12
 
13
13
  class Config
14
+
15
+ attr_accessor :log_file
14
16
 
15
17
  # Structs holding info for the remote server and proxy server
16
18
  class Server < Struct.new :host, :port
@@ -137,8 +139,8 @@ module NewRelic
137
139
  end
138
140
 
139
141
  def setup_log(identifier)
140
- log_file = "#{log_path}/#{log_file_name(identifier)}"
141
- @log = Logger.new log_file
142
+ @log_file = "#{log_path}/#{log_file_name(identifier)}"
143
+ @log = Logger.new @log_file
142
144
 
143
145
  # change the format just for our logger
144
146
 
@@ -148,15 +150,13 @@ module NewRelic
148
150
 
149
151
  # set the log level as specified in the config file
150
152
  case fetch("log_level","info").downcase
151
- when "debug": @log.level = Logger::DEBUG
152
- when "info": @log.level = Logger::INFO
153
- when "warn": @log.level = Logger::WARN
154
- when "error": @log.level = Logger::ERROR
155
- when "fatal": @log.level = Logger::FATAL
153
+ when "debug"; @log.level = Logger::DEBUG
154
+ when "info"; @log.level = Logger::INFO
155
+ when "warn"; @log.level = Logger::WARN
156
+ when "error"; @log.level = Logger::ERROR
157
+ when "fatal"; @log.level = Logger::FATAL
156
158
  else @log.level = Logger::INFO
157
159
  end
158
- log! "New Relic RPM Agent #{NewRelic::VERSION::STRING} Initialized: pid = #{$$}"
159
- log! "Agent Log is found in #{log_file}"
160
160
  @log
161
161
  end
162
162
 
@@ -329,7 +329,7 @@ module NewRelic
329
329
  next if k == :path
330
330
  s << " #{k}: " <<
331
331
  case v
332
- when Enumerable: v.map(&:to_s).sort.join("; ")
332
+ when Enumerable; v.map(&:to_s).sort.join("; ")
333
333
  else
334
334
  v
335
335
  end << "\n"
@@ -3,7 +3,7 @@ module NewRelic
3
3
  module VERSION #:nodoc:
4
4
  MAJOR = 2
5
5
  MINOR = 8
6
- TINY = 1
6
+ TINY = 2
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  def self.changes
9
9
  puts "NewRelic RPM Plugin Version: #{NewRelic::VERSION::STRING}"
@@ -12,6 +12,10 @@ module NewRelic
12
12
 
13
13
  CHANGELOG = <<EOF
14
14
 
15
+ 2009-02-07 version 2.8.2
16
+ * fix Ruby 1.9 syntax compatibility errors
17
+ * update the class loading sanity check, will notify server of errors
18
+ * fix agent output on script and rake task execution
15
19
  2009-01-27 version 2.8.1
16
20
  * Convert the deployment information upload script to an executable
17
21
  and put in the bin directory. When installed as a gem this command
@@ -1,7 +1,7 @@
1
1
  # Initialization script for the gem.
2
2
  # Add
3
- # #require 'new_relic'
4
- # to your initialization sequence, as late as possible.
3
+ # config.gem 'newrelic_rpm'
4
+ # to your initialization sequence.
5
5
  #
6
6
  require 'new_relic/config'
7
7
 
@@ -59,19 +59,55 @@ class AgentTests < ActiveSupport::TestCase
59
59
 
60
60
  def test_classloading_patch
61
61
  require 'new_relic/agent/patch_const_missing'
62
- NewRelic::Agent::Agent.newrelic_set_agent_thread(Thread.current)
63
- # try loading some non-existent class
64
- NewRelic::Config.instance.log.expects(:warn).at_least_once.with{|args| args =~ /calling const_missing.*:FooBar/}
65
- NewRelic::Config.instance.log.expects(:warn).with{|args| args =~ /calling const_missing.*:FooBaz/}.never
66
- NewRelic::Agent::Agent.newrelic_enable_warning
62
+ ClassLoadingWatcher.set_background_thread(Thread.current)
63
+
64
+ NewRelic::Config.instance.log.expects(:error).at_least_once.with{|args| args =~ /Agent background thread.*:FooBar/}
65
+ NewRelic::Config.instance.log.expects(:error).with{|args| args =~ /Agent background thread.*:FooBaz/}.never
66
+
67
+ ClassLoadingWatcher.enable_warning
67
68
  assert_raise NameError do
68
69
  FooBar::Bat
69
70
  end
70
- NewRelic::Agent::Agent.newrelic_disable_warning
71
+ ClassLoadingWatcher.disable_warning
71
72
  assert_raise NameError do
72
73
  FooBaz::Bat
73
74
  end
74
75
  end
76
+
77
+ def test_require
78
+ require 'new_relic/agent/patch_const_missing'
79
+ ClassLoadingWatcher.set_background_thread(Thread.current)
80
+
81
+ # try loading some non-existent class
82
+ NewRelic::Config.instance.log.expects(:error).at_least_once.with{|args| args =~ /Agent background thread.*net/}
83
+ NewRelic::Config.instance.log.expects(:error).with{|args| args =~ /Agent background thread.*net/}.never
84
+
85
+ ClassLoadingWatcher.enable_warning
86
+
87
+ require 'net/http'
88
+
89
+ ClassLoadingWatcher.disable_warning
90
+
91
+ require 'net/http'
92
+ end
93
+
94
+ def test_load
95
+ require 'new_relic/agent/patch_const_missing'
96
+ ClassLoadingWatcher.set_background_thread(Thread.current)
97
+
98
+ # try loading some non-existent class
99
+ NewRelic::Config.instance.log.expects(:error).at_least_once.with{|args| args =~ /Agent background thread.*/}
100
+ NewRelic::Config.instance.log.expects(:error).with{|args| args =~ /Agent background thread.*/}.never
101
+
102
+ ClassLoadingWatcher.enable_warning
103
+
104
+ load 'net/http.rb'
105
+
106
+ ClassLoadingWatcher.disable_warning
107
+
108
+ load 'net/http.rb'
109
+ end
110
+
75
111
  def test_info
76
112
  props = NewRelic::Config.instance.app_config_info
77
113
  list = props.assoc('Plugin List').last.sort
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: newrelic_rpm
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.8.1
4
+ version: 2.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bill Kayser
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-01-29 00:00:00 -08:00
12
+ date: 2009-02-05 00:00:00 -08:00
13
13
  default_executable: newrelic_cmd
14
14
  dependencies: []
15
15
 
@@ -175,7 +175,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
175
175
  requirements: []
176
176
 
177
177
  rubyforge_project: newrelic
178
- rubygems_version: 1.3.0
178
+ rubygems_version: 1.3.1
179
179
  signing_key:
180
180
  specification_version: 2
181
181
  summary: New Relic Ruby Performance Monitoring Agent