newrelic_rpm 2.12.3 → 2.13.0.beta3

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 (118) hide show
  1. data/CHANGELOG +24 -2
  2. data/README.rdoc +172 -0
  3. data/bin/newrelic +13 -0
  4. data/bin/newrelic_cmd +2 -1
  5. data/install.rb +8 -45
  6. data/lib/new_relic/agent.rb +43 -30
  7. data/lib/new_relic/agent/agent.rb +699 -631
  8. data/lib/new_relic/agent/busy_calculator.rb +81 -81
  9. data/lib/new_relic/agent/error_collector.rb +9 -6
  10. data/lib/new_relic/agent/instrumentation/active_record_instrumentation.rb +2 -2
  11. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +10 -5
  12. data/lib/new_relic/agent/instrumentation/data_mapper.rb +13 -45
  13. data/lib/new_relic/agent/instrumentation/memcache.rb +15 -4
  14. data/lib/new_relic/agent/instrumentation/metric_frame.rb +37 -29
  15. data/lib/new_relic/agent/instrumentation/rack.rb +20 -34
  16. data/lib/new_relic/agent/method_tracer.rb +9 -9
  17. data/lib/new_relic/agent/samplers/delayed_job_lock_sampler.rb +31 -31
  18. data/lib/new_relic/agent/stats_engine/metric_stats.rb +5 -5
  19. data/lib/new_relic/agent/stats_engine/samplers.rb +3 -0
  20. data/lib/new_relic/agent/transaction_sampler.rb +31 -15
  21. data/lib/new_relic/agent/worker_loop.rb +29 -28
  22. data/lib/new_relic/collection_helper.rb +4 -2
  23. data/lib/new_relic/command.rb +85 -0
  24. data/lib/new_relic/commands/deployments.rb +74 -114
  25. data/lib/new_relic/commands/install.rb +81 -0
  26. data/lib/new_relic/control.rb +54 -379
  27. data/lib/new_relic/control/configuration.rb +149 -0
  28. data/lib/new_relic/control/{external.rb → frameworks/external.rb} +2 -2
  29. data/lib/new_relic/control/{merb.rb → frameworks/merb.rb} +1 -1
  30. data/lib/new_relic/control/frameworks/rails.rb +126 -0
  31. data/lib/new_relic/control/{rails3.rb → frameworks/rails3.rb} +11 -10
  32. data/lib/new_relic/control/{ruby.rb → frameworks/ruby.rb} +1 -1
  33. data/lib/new_relic/control/{sinatra.rb → frameworks/sinatra.rb} +2 -2
  34. data/lib/new_relic/control/instrumentation.rb +84 -0
  35. data/lib/new_relic/control/logging_methods.rb +74 -0
  36. data/lib/new_relic/control/profiling.rb +24 -0
  37. data/lib/new_relic/control/server_methods.rb +88 -0
  38. data/lib/new_relic/local_environment.rb +3 -3
  39. data/lib/new_relic/metric_parser.rb +13 -2
  40. data/lib/new_relic/metric_parser/active_record.rb +4 -1
  41. data/lib/new_relic/metric_parser/apdex.rb +53 -0
  42. data/lib/new_relic/metric_parser/controller.rb +13 -5
  43. data/lib/new_relic/metric_parser/mem_cache.rb +1 -1
  44. data/lib/new_relic/metric_parser/other_transaction.rb +21 -0
  45. data/lib/new_relic/metric_spec.rb +3 -3
  46. data/lib/new_relic/noticed_error.rb +1 -1
  47. data/lib/new_relic/rack/developer_mode.rb +257 -0
  48. data/lib/new_relic/rack/metric_app.rb +56 -50
  49. data/lib/new_relic/rack/mongrel_rpm.ru +7 -6
  50. data/lib/new_relic/rack/newrelic.yml +4 -3
  51. data/lib/new_relic/rack_app.rb +2 -1
  52. data/lib/new_relic/recipes.rb +7 -7
  53. data/lib/new_relic/stats.rb +6 -14
  54. data/lib/new_relic/timer_lib.rb +27 -0
  55. data/lib/new_relic/transaction_analysis.rb +2 -7
  56. data/lib/new_relic/transaction_sample.rb +17 -85
  57. data/lib/new_relic/url_rule.rb +14 -0
  58. data/lib/new_relic/version.rb +3 -3
  59. data/lib/newrelic_rpm.rb +5 -9
  60. data/newrelic.yml +26 -9
  61. data/newrelic_rpm.gemspec +67 -32
  62. data/test/config/newrelic.yml +5 -0
  63. data/test/config/test_control.rb +6 -8
  64. data/test/new_relic/agent/active_record_instrumentation_test.rb +5 -6
  65. data/test/new_relic/agent/agent_controller_test.rb +18 -4
  66. data/test/new_relic/agent/agent_test_controller.rb +1 -6
  67. data/test/new_relic/agent/busy_calculator_test.rb +2 -0
  68. data/test/new_relic/agent/collection_helper_test.rb +6 -6
  69. data/test/new_relic/agent/error_collector_test.rb +13 -21
  70. data/test/new_relic/agent/metric_data_test.rb +3 -6
  71. data/test/new_relic/agent/rpm_agent_test.rb +121 -117
  72. data/test/new_relic/agent/task_instrumentation_test.rb +128 -133
  73. data/test/new_relic/agent/transaction_sample_test.rb +176 -170
  74. data/test/new_relic/agent/worker_loop_test.rb +24 -18
  75. data/test/new_relic/control_test.rb +13 -3
  76. data/test/new_relic/deployments_api_test.rb +7 -7
  77. data/test/new_relic/environment_test.rb +1 -1
  78. data/test/new_relic/metric_parser_test.rb +58 -4
  79. data/test/new_relic/rack/episodes_test.rb +317 -0
  80. data/test/new_relic/stats_test.rb +3 -2
  81. data/test/test_contexts.rb +28 -0
  82. data/test/test_helper.rb +24 -5
  83. data/ui/helpers/{newrelic_helper.rb → developer_mode_helper.rb} +63 -23
  84. data/ui/views/layouts/newrelic_default.rhtml +6 -6
  85. data/ui/views/newrelic/_explain_plans.rhtml +4 -4
  86. data/ui/views/newrelic/_sample.rhtml +18 -17
  87. data/ui/views/newrelic/_segment.rhtml +1 -0
  88. data/ui/views/newrelic/_segment_row.rhtml +8 -8
  89. data/ui/views/newrelic/_show_sample_detail.rhtml +1 -1
  90. data/ui/views/newrelic/_show_sample_sql.rhtml +2 -2
  91. data/ui/views/newrelic/_sql_row.rhtml +8 -3
  92. data/ui/views/newrelic/_stack_trace.rhtml +9 -24
  93. data/ui/views/newrelic/_table.rhtml +1 -1
  94. data/ui/views/newrelic/explain_sql.rhtml +3 -2
  95. data/ui/views/newrelic/{images → file/images}/arrow-close.png +0 -0
  96. data/ui/views/newrelic/{images → file/images}/arrow-open.png +0 -0
  97. data/ui/views/newrelic/{images → file/images}/blue_bar.gif +0 -0
  98. data/ui/views/newrelic/{images → file/images}/file_icon.png +0 -0
  99. data/ui/views/newrelic/{images → file/images}/gray_bar.gif +0 -0
  100. data/ui/views/newrelic/{images → file/images}/new-relic-rpm-desktop.gif +0 -0
  101. data/ui/views/newrelic/{images → file/images}/new_relic_rpm_desktop.gif +0 -0
  102. data/ui/views/newrelic/{images → file/images}/textmate.png +0 -0
  103. data/ui/views/newrelic/file/javascript/jquery-1.4.2.js +6240 -0
  104. data/ui/views/newrelic/file/javascript/transaction_sample.js +120 -0
  105. data/ui/views/newrelic/{stylesheets → file/stylesheets}/style.css +0 -0
  106. data/ui/views/newrelic/index.rhtml +7 -5
  107. data/ui/views/newrelic/sample_not_found.rhtml +1 -1
  108. data/ui/views/newrelic/show_sample.rhtml +5 -6
  109. metadata +92 -34
  110. data/README.md +0 -138
  111. data/lib/new_relic/commands/new_relic_commands.rb +0 -30
  112. data/lib/new_relic/control/rails.rb +0 -151
  113. data/test/new_relic/agent/mock_ar_connection.rb +0 -40
  114. data/test/ui/newrelic_controller_test.rb +0 -14
  115. data/test/ui/newrelic_helper_test.rb +0 -53
  116. data/ui/controllers/newrelic_controller.rb +0 -220
  117. data/ui/views/newrelic/javascript/prototype-scriptaculous.js +0 -7288
  118. data/ui/views/newrelic/javascript/transaction_sample.js +0 -107
@@ -1,7 +1,6 @@
1
1
  # This is a class for executing commands related to deployment
2
2
  # events. It runs without loading the rails environment
3
3
 
4
- $LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__),"..",".."))
5
4
  require 'yaml'
6
5
  require 'net/http'
7
6
  require 'rexml/document'
@@ -11,135 +10,96 @@ require 'rexml/document'
11
10
  # it won't load it twice, something it does when run inside a test
12
11
  require 'new_relic/control' unless defined? NewRelic::Control
13
12
 
14
- module NewRelic
15
- module Commands
16
- # Capture a failure to execute the command.
17
- # Ask it for a return status to exit the vm with,
18
- # if appropriate.
19
- class CommandFailure < StandardError
20
- attr_reader :exit_code
21
- def initialize message, return_status=nil
22
- super message
23
- @exit_code = return_status || 0
24
- end
25
- end
26
-
27
- class Deployments
28
-
29
- attr_reader :config
30
- def self.command; "deployments"; end
31
-
32
- # Initialize the deployment uploader with command line args.
33
- # Use -h to see options.
34
- # When command_line_args is a hash, we are invoking directly and
35
- # it's treated as an options with optional sttring values for
36
- # :user, :description, :appname, :revision, :environment,
37
- # and :changes.
38
- #
39
- # Will throw CommandFailed exception if there's any error.
40
- #
41
- def initialize command_line_args
42
- @config = NewRelic::Control.instance
43
- @user = ENV['USER']
44
- if Hash === command_line_args
45
- # command line args is an options hash
46
- command_line_args.each do | key, value |
47
- if %w[user environment description appname revision changelog].include? key.to_s
48
- instance_variable_set "@#{key}", value.to_s if value
49
- else
50
- raise "Unrecognized option #{key}=#{value}"
51
- end
52
- end
53
- else
54
- # parse command line args. Throw an exception on a bad arg.
55
- @description = options.parse(command_line_args).join " "
56
- end
57
- config.env = @environment if @environment
58
- @appname ||= config.app_names[0] || config.env || 'development'
59
- end
60
-
61
- # Run the Deployment upload in RPM via Active Resource.
62
- # Will possibly print errors and exit the VM
63
- def run
64
- begin
65
- @description = nil if @description && @description.strip.empty?
66
- create_params = {}
67
- {
13
+ class NewRelic::Command::Deployments < NewRelic::Command
14
+ attr_reader :config
15
+ def self.command; "deployments"; end
16
+
17
+ # Initialize the deployment uploader with command line args.
18
+ # Use -h to see options.
19
+ # When command_line_args is a hash, we are invoking directly and
20
+ # it's treated as an options with optional sttring values for
21
+ # :user, :description, :appname, :revision, :environment,
22
+ # and :changes.
23
+ #
24
+ # Will throw CommandFailed exception if there's any error.
25
+ #
26
+ def initialize command_line_args
27
+ @config = NewRelic::Control.instance
28
+ super(command_line_args)
29
+ @description ||= @leftover && @leftover.join(" ")
30
+ @user ||= ENV['USER']
31
+ config.env = @environment if @environment
32
+ @appname ||= config.app_names[0] || config.env || 'development'
33
+ end
34
+
35
+ # Run the Deployment upload in RPM via Active Resource.
36
+ # Will possibly print errors and exit the VM
37
+ def run
38
+ begin
39
+ @description = nil if @description && @description.strip.empty?
40
+ create_params = {}
41
+ {
68
42
  :application_id => @appname,
69
43
  :host => Socket.gethostname,
70
44
  :description => @description,
71
45
  :user => @user,
72
46
  :revision => @revision,
73
47
  :changelog => @changelog
74
- }.each do |k, v|
75
- create_params["deployment[#{k}]"] = v unless v.nil? || v == ''
76
- end
77
- http = config.http_connection(config.api_server)
78
-
79
- uri = "/deployments.xml"
80
-
81
- raise "license_key was not set in newrelic.yml for #{config.env}" if config['license_key'].nil?
82
- request = Net::HTTP::Post.new(uri, {'x-license-key' => config['license_key']})
83
- request.content_type = "application/octet-stream"
84
-
85
- request.set_form_data(create_params)
86
-
87
- response = http.request(request)
88
-
89
- if response.is_a? Net::HTTPSuccess
90
- info "Recorded deployment to '#{@appname}' (#{@description || Time.now })"
91
- else
92
- err_string = [ "Unexpected response from server: #{response.code}: #{response.message}" ]
93
- begin
94
- doc = REXML::Document.new(response.body)
95
- doc.elements.each('errors/error') do |error|
96
- err_string << "Error: #{error.text}"
97
- end
98
- rescue
99
- end
100
- raise CommandFailure.new(err_string.join("\n"), -1)
101
- end
102
- rescue SystemCallError, SocketError => e
103
- # These include Errno connection errors
104
- err_string = "Transient error attempting to connect to #{config.api_server} (#{e})"
105
- raise CommandFailure.new(err_string, -1)
106
- rescue CommandFailure
107
- raise
108
- rescue Exception => e
109
- err "Unexpected error attempting to connect to #{config.api_server}"
110
- info "#{e}: #{e.backtrace.join("\n ")}"
111
- raise CommandFailure.new(e.to_s, -1)
112
- end
48
+ }.each do |k, v|
49
+ create_params["deployment[#{k}]"] = v unless v.nil? || v == ''
113
50
  end
51
+ http = config.http_connection(config.api_server)
52
+
53
+ uri = "/deployments.xml"
114
54
 
115
- private
55
+ raise "license_key was not set in newrelic.yml for #{config.env}" if config['license_key'].nil?
56
+ request = Net::HTTP::Post.new(uri, {'x-license-key' => config['license_key']})
57
+ request.content_type = "application/octet-stream"
116
58
 
117
- def options
118
- OptionParser.new %Q{Usage: #{$0} [OPTIONS] ["description"] }, 40 do |o|
119
- o.separator "OPTIONS:"
120
- o.on("-a", "--appname=NAME", String,
59
+ request.set_form_data(create_params)
60
+
61
+ response = http.request(request)
62
+
63
+ if response.is_a? Net::HTTPSuccess
64
+ info "Recorded deployment to '#{@appname}' (#{@description || Time.now })"
65
+ else
66
+ err_string = REXML::Document.new(response.body).elements['errors/error'].map(&:to_s).join("; ") rescue response.message
67
+ raise NewRelic::Command::CommandFailure, "Deployment not recorded: #{err_string}"
68
+ end
69
+ rescue SystemCallError, SocketError => e
70
+ # These include Errno connection errors
71
+ err_string = "Transient error attempting to connect to #{config.api_server} (#{e})"
72
+ raise NewRelic::Command::CommandFailure.new(err_string)
73
+ rescue NewRelic::Command::CommandFailure
74
+ raise
75
+ rescue Exception => e
76
+ err "Unexpected error attempting to connect to #{config.api_server}"
77
+ info "#{e}: #{e.backtrace.join("\n ")}"
78
+ raise NewRelic::Command::CommandFailure.new(e.to_s)
79
+ end
80
+ end
81
+
82
+ private
83
+
84
+ def options
85
+ OptionParser.new %Q{Usage: #{$0} #{self.class.command} [OPTIONS] ["description"] }, 40 do |o|
86
+ o.separator "OPTIONS:"
87
+ o.on("-a", "--appname=NAME", String,
121
88
  "Set the application name.",
122
89
  "Default is app_name setting in newrelic.yml") { | e | @appname = e }
123
- o.on("-e", "--environment=name", String,
90
+ o.on("-e", "--environment=name", String,
124
91
  "Override the (RAILS|MERB|RUBY|RACK)_ENV setting",
125
92
  "currently: #{config.env}") { | e | @environment = e }
126
- o.on("-u", "--user=USER", String,
93
+ o.on("-u", "--user=USER", String,
127
94
  "Specify the user deploying, for information only",
128
95
  "Default: #{@user || '<none>'}") { | u | @user = u }
129
- o.on("-r", "--revision=REV", String,
96
+ o.on("-r", "--revision=REV", String,
130
97
  "Specify the revision being deployed") { | r | @revision = r }
131
- o.on("-c", "--changes",
98
+ o.on("-c", "--changes",
132
99
  "Read in a change log from the standard input") { @changelog = STDIN.read }
133
- o.on("-h", "--help", "Print this help") { raise CommandFailure.new(o.help, 0) }
134
- end
135
- end
136
-
137
- def info message
138
- STDOUT.puts message
139
- end
140
- def err message
141
- STDERR.puts message
142
- end
100
+ yield o if block_given?
143
101
  end
144
102
  end
145
- end
103
+
104
+
105
+ end
@@ -0,0 +1,81 @@
1
+ require 'fileutils'
2
+ require 'new_relic/version'
3
+ require 'erb'
4
+
5
+ class NewRelic::Command::Install < NewRelic::Command
6
+
7
+ NO_LICENSE_KEY = "<PASTE LICENSE KEY HERE>"
8
+
9
+ def self.command; "install"; end
10
+
11
+ # Use -h to see options.
12
+ # When command_line_args is a hash, we are invoking directly and
13
+ # it's treated as an options with optional string values for
14
+ # :user, :description, :appname, :revision, :environment,
15
+ # and :changes.
16
+ #
17
+ # Will throw CommandFailed exception if there's any error.
18
+ #
19
+ attr_reader :dest_dir, :license_key, :generated_for_user, :quiet, :src_file, :app_name
20
+ def initialize command_line_args={}
21
+ super command_line_args
22
+ if !@dest_dir
23
+ # Install a newrelic.yml file into the local config directory.
24
+ if File.directory? "config"
25
+ @dest_dir = "config"
26
+ else
27
+ @dest_dir = "."
28
+ end
29
+ end
30
+ @license_key ||= NO_LICENSE_KEY
31
+ @app_name ||= @leftover
32
+ raise CommandFailure.new("Application name required.", @options) unless @app_name && @app_name.size > 0
33
+ @generated_for_user ||= @user_string || ""
34
+ end
35
+
36
+ def run
37
+ dest_file = File.expand_path(@dest_dir + "/newrelic.yml")
38
+ if File.exist?(dest_file)
39
+ raise NewRelic::Command::CommandFailure, "newrelic.yml file already exists. Move it out of the way."
40
+ end
41
+ File.open(dest_file, 'w') { | out | out.puts(content) }
42
+
43
+ puts <<-EOF unless quiet
44
+
45
+ Installed a default configuration file at
46
+ #{dest_file}.
47
+ EOF
48
+ puts <<-EOF unless quiet || @license_key != NO_LICENSE_KEY
49
+
50
+ To monitor your application in production mode, sign up for an account
51
+ at www.newrelic.com, and replace the newrelic.yml file with the one
52
+ you receive upon registration.
53
+ EOF
54
+ puts <<-EOF unless quiet
55
+
56
+ E-mail support@newrelic.com with any problems or questions.
57
+
58
+ EOF
59
+
60
+ end
61
+
62
+ def content
63
+ @src_file ||= File.expand_path(File.join(File.dirname(__FILE__),"..","..","..","newrelic.yml"))
64
+ template = File.read(@src_file)
65
+ ERB.new(template).result(binding)
66
+ end
67
+
68
+ private
69
+
70
+ def options
71
+ OptionParser.new "Usage: #{$0} #{self.class.command} [ OPTIONS] 'application name'", 40 do |o|
72
+ o.on("-l", "--license_key=NAME", String,
73
+ "Use the given license key") { | e | @license_key = e }
74
+ o.on("-d", "--destdir=name", String,
75
+ "Write the newrelic.yml to the given directory, default is '.'") { | e | @dest_dir = e }
76
+ yield o if block_given?
77
+ end
78
+ end
79
+
80
+
81
+ end
@@ -5,6 +5,11 @@ require 'erb'
5
5
  require 'socket'
6
6
  require 'net/https'
7
7
  require 'logger'
8
+ require 'new_relic/control/profiling'
9
+ require 'new_relic/control/logging_methods'
10
+ require 'new_relic/control/configuration'
11
+ require 'new_relic/control/server_methods'
12
+ require 'new_relic/control/instrumentation'
8
13
 
9
14
  module NewRelic
10
15
 
@@ -16,43 +21,57 @@ module NewRelic
16
21
  # The Control also implements some of the public API for the agent.
17
22
  #
18
23
  class Control
24
+ # used for framework-specific subclasses
25
+ module Frameworks; end
19
26
 
20
- # A flag used in dev mode to indicate if profiling is available
21
- def profiling?
22
- @profiling
23
- end
24
-
25
- def profiling_available?
26
- @profiling_available ||=
27
- begin
28
- require 'ruby-prof'
29
- true
30
- rescue LoadError; end
31
- end
32
- # Set the flag for capturing profiles in dev mode. If RubyProf is not
33
- # loaded a true value is ignored.
34
- def profiling=(val)
35
- @profiling = profiling_available? && val && defined?(RubyProf)
36
- end
27
+ include Profiling
28
+ include LoggingMethods
29
+ include Configuration
30
+ include ServerMethods
31
+ include Instrumentation
37
32
 
38
- attr_accessor :log_file
39
33
  # The env is the setting used to identify which section of the newrelic.yml
40
34
  # to load. This defaults to a framework specific value, such as ENV['RAILS_ENV']
41
35
  # but can be overridden as long as you set it before calling #init_plugin
42
36
  attr_writer :env
43
- attr_reader :local_env
44
-
45
- # Structs holding info for the remote server and proxy server
46
- class Server < Struct.new :name, :port, :ip #:nodoc:
47
- def to_s; "#{name}:#{port}"; end
48
- end
49
-
50
- ProxyServer = Struct.new :name, :port, :user, :password #:nodoc:
51
37
 
52
- # Access the Control singleton, lazy initialized
53
- def self.instance
54
- @instance ||= new_instance
38
+ attr_reader :local_env
39
+
40
+ module ClassMethods
41
+ # Access the Control singleton, lazy initialized
42
+ def instance
43
+ @instance ||= new_instance
44
+ end
45
+
46
+ # Create the concrete class for environment specific behavior:
47
+ def new_instance
48
+ @local_env = NewRelic::LocalEnvironment.new
49
+ if @local_env.framework == :test
50
+ # You can set this env var if you want to run the tests
51
+ # without Rails.
52
+ config = File.expand_path("../../../test/config/newrelic.yml", __FILE__)
53
+ if ENV['SKIP_RAILS']
54
+ require "new_relic/control/frameworks/ruby.rb"
55
+ NewRelic::Control::Frameworks::Ruby.new @local_env, config
56
+ else
57
+ require "config/test_control"
58
+ NewRelic::Control::Frameworks::Test.new @local_env, config
59
+ end
60
+ else
61
+ begin
62
+ require "new_relic/control/frameworks/#{@local_env.framework}.rb"
63
+ rescue LoadError
64
+ end
65
+ NewRelic::Control::Frameworks.const_get(@local_env.framework.to_s.capitalize).new @local_env
66
+ end
67
+ end
68
+
69
+ # The root directory for the plugin or gem
70
+ def newrelic_root
71
+ File.expand_path("../../..", __FILE__)
72
+ end
55
73
  end
74
+ extend ClassMethods
56
75
 
57
76
  # Initialize the plugin/gem and start the agent. This does the necessary configuration based on the
58
77
  # framework environment and determines whether or not to start the agent. If the
@@ -75,7 +94,7 @@ module NewRelic
75
94
  #
76
95
  def init_plugin(options={})
77
96
  options['app_name'] = ENV['NEWRELIC_APP_NAME'] if ENV['NEWRELIC_APP_NAME']
78
-
97
+
79
98
  require 'new_relic/agent'
80
99
 
81
100
  # Load the DJ injection now. If you do it sooner, DJ might not be loaded and
@@ -122,77 +141,6 @@ module NewRelic
122
141
  NewRelic::Agent.agent.start
123
142
  end
124
143
 
125
- def [](key)
126
- fetch(key)
127
- end
128
-
129
- def settings
130
- unless @settings
131
- @settings = (@yaml && merge_defaults(@yaml[env])) || {}
132
- # At the time we bind the settings, we also need to run this little piece
133
- # of magic which allows someone to augment the id with the app name, necessary
134
- if self['multi_homed'] && app_names.size > 0
135
- if @local_env.dispatcher_instance_id
136
- @local_env.dispatcher_instance_id << ":#{app_names.first}"
137
- else
138
- @local_env.dispatcher_instance_id = app_names.first
139
- end
140
- end
141
-
142
- end
143
- @settings
144
- end
145
-
146
- def []=(key, value)
147
- settings[key] = value
148
- end
149
-
150
- def fetch(key, default=nil)
151
- settings.fetch(key, default)
152
- end
153
- # Add your own environment value to track for change detection.
154
- # The name and value should be stable and not vary across app processes on
155
- # the same host.
156
- def append_environment_info(name, value)
157
- local_env.record_environment_info(name,value)
158
- end
159
-
160
- ###################################
161
- # Agent config conveniences
162
-
163
- def apdex_t
164
- # Always initialized with a default
165
- fetch('apdex_t').to_f
166
- end
167
- def license_key
168
- fetch('license_key')
169
- end
170
- def capture_params
171
- fetch('capture_params')
172
- end
173
- # True if we are sending data to the server, monitoring production
174
- def monitor_mode?
175
- fetch('monitor_mode', fetch('enabled'))
176
- end
177
- # True if we are capturing data and displaying in /newrelic
178
- def developer_mode?
179
- fetch('developer_mode', fetch('developer'))
180
- end
181
- # True if the app runs in multi-threaded mode
182
- def multi_threaded?
183
- fetch('multi_threaded')
184
- end
185
- # True if we should view files in textmate
186
- def use_textmate?
187
- fetch('textmate')
188
- end
189
- def post_size_limit
190
- fetch('post_size_limit', 2 * 1024 * 1024)
191
- end
192
-
193
- def sync_startup
194
- fetch('sync_startup', false)
195
- end
196
144
  # True if dev mode or monitor mode are enabled, and we are running
197
145
  # inside a valid dispatcher like mongrel or passenger. Can be overridden
198
146
  # by NEWRELIC_ENABLE env variable, monitor_daemons config option when true, or
@@ -212,275 +160,34 @@ module NewRelic
212
160
  @local_env.framework
213
161
  end
214
162
  alias framework app
215
-
216
- def dispatcher_instance_id
217
- self['dispatcher_instance_id'] || @local_env.dispatcher_instance_id
218
- end
219
- def dispatcher
220
- (self['dispatcher'] && self['dispatcher'].to_sym) || @local_env.dispatcher
221
- end
222
- def app_names
223
- self['app_name'] ? self['app_name'].split(';') : []
224
- end
225
- def validate_seed
226
- self['validate_seed'] || ENV['NR_VALIDATE_SEED']
227
- end
228
- def validate_token
229
- self['validate_token'] || ENV['NR_VALIDATE_TOKEN']
230
- end
231
-
232
- def use_ssl?
233
- @use_ssl ||= fetch('ssl', false)
234
- end
235
-
236
- def verify_certificate?
237
- #this can only be on when SSL is enabled
238
- @verify_certificate ||= ( use_ssl? ? fetch('verify_certificate', false) : false)
239
- end
240
163
 
241
- def server
242
- @remote_server ||= server_from_host(nil)
243
- end
244
-
245
- def api_server
246
- api_host = self['api_host'] || 'rpm.newrelic.com'
247
- @api_server ||=
248
- NewRelic::Control::Server.new \
249
- api_host,
250
- (self['api_port'] || self['port'] || (use_ssl? ? 443 : 80)).to_i,
251
- nil
252
- end
253
-
254
- def proxy_server
255
- @proxy_server ||=
256
- NewRelic::Control::ProxyServer.new self['proxy_host'], self['proxy_port'], self['proxy_user'], self['proxy_pass']
257
- end
258
-
259
- def server_from_host(hostname=nil)
260
- host = hostname || self['host'] || 'collector.newrelic.com'
261
-
262
- # if the host is not an IP address, turn it into one
263
- NewRelic::Control::Server.new host, (self['port'] || (use_ssl? ? 443 : 80)).to_i, convert_to_ip_address(host)
264
- end
265
-
266
- # Return the Net::HTTP with proxy configuration given the NewRelic::Control::Server object.
267
- # Default is the collector but for api calls you need to pass api_server
268
- #
269
- # Experimental support for SSL verification:
270
- # swap 'VERIFY_NONE' for 'VERIFY_PEER' line to try it out
271
- # If verification fails, uncomment the 'http.ca_file' line
272
- # and it will use the included certificate.
273
- def http_connection(host = nil)
274
- host ||= server
275
- # Proxy returns regular HTTP if @proxy_host is nil (the default)
276
- http_class = Net::HTTP::Proxy(proxy_server.name, proxy_server.port,
277
- proxy_server.user, proxy_server.password)
278
- http = http_class.new(host.ip || host.name, host.port)
279
- log.debug("Http Connection opened to #{host.ip||host.name}:#{host.port}")
280
- if use_ssl?
281
- http.use_ssl = true
282
- if verify_certificate?
283
- http.verify_mode = OpenSSL::SSL::VERIFY_PEER
284
- http.ca_file = File.join(File.dirname(__FILE__), '..', '..', 'cert', 'cacert.pem')
285
- else
286
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
287
- end
288
- end
289
- http
290
- end
291
164
  def to_s
292
165
  "Control[#{self.app}]"
293
166
  end
294
167
 
295
- def log
296
- # If we try to get a log before one has been set up, return a stdout log
297
- unless @log
298
- l = Logger.new(STDOUT)
299
- l.level = Logger::INFO
300
- return l
301
- end
302
- @log
303
- end
304
-
305
- # send the given message to STDOUT so that it shows
306
- # up in the console. This should be used for important informational messages at boot.
307
- # The to_stdout may be implemented differently by different config subclasses.
308
- # This will NOT print anything if tracers are not enabled
309
- def log!(msg, level=:info)
310
- return if @settings && !agent_enabled?
311
- to_stdout msg
312
- log.send level, msg if @log
313
- end
314
-
315
- # Install stubs to the proper location so the app code will not fail
316
- # if the agent is not running.
317
- def install_shim
318
- # Once we install instrumentation, you can't undo that by installing the shim.
319
- raise "Cannot install the Agent shim after instrumentation has already been installed!" if @instrumented
320
- NewRelic::Agent.agent = NewRelic::Agent::ShimAgent.instance
321
- end
322
-
323
- # Add instrumentation. Don't call this directly. Use NewRelic::Agent#add_instrumentation.
324
- # This will load the file synchronously if we've already loaded the default
325
- # instrumentation.
326
- #
327
- def add_instrumentation pattern
328
- if @instrumented
329
- load_instrumentation_files pattern
330
- else
331
- @instrumentation_files << pattern
332
- end
333
- end
334
- def install_instrumentation
335
- return if @instrumented
336
-
337
- @instrumented = true
338
-
339
- # Instrumentation for the key code points inside rails for monitoring by NewRelic.
340
- # note this file is loaded only if the newrelic agent is enabled (through config/newrelic.yml)
341
- instrumentation_path = File.join(File.dirname(__FILE__), 'agent','instrumentation')
342
- @instrumentation_files <<
343
- File.join(instrumentation_path, '*.rb') <<
344
- File.join(instrumentation_path, app.to_s, '*.rb')
345
- @instrumentation_files.each { | pattern | load_instrumentation_files pattern }
346
- log.debug "Finished instrumentation"
347
- end
348
-
349
- def load_samplers
350
- agent = NewRelic::Agent.instance
351
- NewRelic::Agent::Sampler.sampler_classes.each do | subclass |
352
- begin
353
- log.debug "#{subclass.name} not supported on this platform." and next if not subclass.supported_on_this_platform?
354
- sampler = subclass.new
355
- if subclass.use_harvest_sampler?
356
- agent.stats_engine.add_harvest_sampler sampler
357
- log.debug "Registered #{subclass.name} for harvest time sampling"
358
- else
359
- agent.stats_engine.add_sampler sampler
360
- log.debug "Registered #{subclass.name} for periodic sampling"
361
- end
362
- rescue NewRelic::Agent::Sampler::Unsupported => e
363
- log.info "#{subclass} sampler not available: #{e}"
364
- rescue => e
365
- log.error "Error registering sampler: #{e}, #{e.backtrace.join("\n")}"
366
- end
367
- end
368
- end
369
-
370
168
  protected
371
169
 
372
170
  # Append framework specific environment information for uploading to
373
171
  # the server for change detection. Override in subclasses
374
172
  def append_environment_info; end
375
173
 
376
- # Look up the ip address of the host using the pure ruby lookup
377
- # to prevent blocking. If that fails, fall back to the regular
378
- # IPSocket library. Return nil if we can't find the host ip
379
- # address and don't have a good default.
380
- def convert_to_ip_address(host)
381
- # here we leave it as a host name since the cert verification
382
- # needs it in host form
383
- return host if verify_certificate?
384
- return nil if host.nil? || host.downcase == "localhost"
385
- # Fall back to known ip address in the common case
386
- ip_address = '65.74.177.195' if host.downcase == 'collector.newrelic.com'
387
- begin
388
- ip_address = Resolv.getaddress(host)
389
- log.info "Resolved #{host} to #{ip_address}"
390
- rescue => e
391
- log.warn "DNS Error caching IP address: #{e}"
392
- log.debug e.backtrace.join("\n ")
393
- ip_address = IPSocket::getaddress host rescue ip_address
394
- end
395
- ip_address
396
- end
397
-
398
- def merge_defaults(settings_hash)
399
- s = {
400
- 'host' => 'collector.newrelic.com',
401
- 'ssl' => false,
402
- 'log_level' => 'info',
403
- 'apdex_t' => 1.0
404
- }
405
- s.merge! settings_hash if settings_hash
406
- # monitor_daemons replaced with agent_enabled
407
- s['agent_enabled'] = s.delete('monitor_daemons') if s['agent_enabled'].nil? && s.include?('monitor_daemons')
408
- s
409
- end
410
-
411
- # Control subclasses may override this, but it can be called multiple times.
412
- def setup_log
413
- @log_file = "#{log_path}/#{log_file_name}"
414
- @log = Logger.new @log_file
415
-
416
- # change the format just for our logger
417
-
418
- def @log.format_message(severity, timestamp, progname, msg)
419
- "[#{timestamp.strftime("%m/%d/%y %H:%M:%S %z")} #{Socket.gethostname} (#{$$})] #{severity} : #{msg}\n"
420
- end
421
-
422
- # set the log level as specified in the config file
423
- case fetch("log_level","info").downcase
424
- when "debug" then @log.level = Logger::DEBUG
425
- when "info" then @log.level = Logger::INFO
426
- when "warn" then @log.level = Logger::WARN
427
- when "error" then @log.level = Logger::ERROR
428
- when "fatal" then @log.level = Logger::FATAL
429
- else @log.level = Logger::INFO
430
- end
431
- @log
432
- end
433
-
434
- def to_stdout(msg)
435
- STDOUT.puts "** [NewRelic] " + msg
436
- end
437
-
438
174
  def config_file
439
175
  File.expand_path(File.join(root,"config","newrelic.yml"))
440
176
  end
441
177
 
442
- def log_path
443
- @log_path ||= begin
444
- path = self['log_file_path'] || File.join(root,'log')
445
- unless File.directory? path
446
- path = '.'
447
- end
448
- File.expand_path(path)
449
- end
450
- end
451
-
452
- def log_file_name
453
- @log_file_name ||= fetch('log_file_name', 'newrelic_agent.log')
454
- end
455
-
456
- # Create the concrete class for environment specific behavior:
457
- def self.new_instance
458
- @local_env = NewRelic::LocalEnvironment.new
459
- if @local_env.framework == :test
460
- require File.join(newrelic_root, "test", "config", "test_control.rb")
461
- NewRelic::Control::Test.new @local_env
462
- else
463
- begin
464
- require "new_relic/control/#{@local_env.framework}.rb"
465
- rescue LoadError
466
- end
467
- NewRelic::Control.const_get(@local_env.framework.to_s.capitalize).new @local_env
468
- end
469
- end
470
-
471
- def initialize local_env
178
+ def initialize local_env, config_file_override=nil
472
179
  @local_env = local_env
473
180
  @instrumentation_files = []
474
- newrelic_file = config_file
181
+ newrelic_file = config_file_override || config_file
475
182
  # Next two are for populating the newrelic.yml via erb binding, necessary
476
183
  # when using the default newrelic.yml file
477
184
  generated_for_user = ''
478
185
  license_key=''
479
- if !File.exists?(config_file)
480
- log! "Cannot find newrelic.yml file at #{config_file}."
186
+ if !File.exists?(newrelic_file)
187
+ log! "Cannot find read #{newrelic_file}."
481
188
  @yaml = {}
482
189
  else
483
- @yaml = YAML.load(ERB.new(File.read(config_file)).result(binding))
190
+ @yaml = YAML.load(ERB.new(File.read(newrelic_file)).result(binding))
484
191
  end
485
192
  rescue ScriptError, StandardError => e
486
193
  puts e
@@ -488,41 +195,9 @@ module NewRelic
488
195
  raise "Error reading newrelic.yml file: #{e}"
489
196
  end
490
197
 
491
- # The root directory for the plugin or gem
492
- def self.newrelic_root
493
- File.expand_path(File.join(File.dirname(__FILE__),"..",".."))
494
- end
495
198
  def newrelic_root
496
199
  self.class.newrelic_root
497
200
  end
498
201
 
499
- # Merge the given options into the config options.
500
- # They might be a nested hash
501
- def merge_options(options, hash=self)
502
- options.each do |key, val |
503
- case
504
- when key == :config then next
505
- when val.is_a?(Hash)
506
- merge_options(val, hash[key.to_s] ||= {})
507
- when val.nil?
508
- hash.delete(key.to_s)
509
- else
510
- hash[key.to_s] = val
511
- end
512
- end
513
- end
514
-
515
- def load_instrumentation_files pattern
516
- Dir.glob(pattern) do |file|
517
- begin
518
- log.debug "Processing instrumentation file '#{file}'"
519
- require file
520
- rescue => e
521
- log.error "Error loading instrumentation file '#{file}': #{e}"
522
- log.debug e.backtrace.join("\n")
523
- end
524
- end
525
- end
526
-
527
202
  end
528
203
  end