honkster-newrelic_rpm 2.13.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (174) hide show
  1. data/CHANGELOG +462 -0
  2. data/LICENSE +37 -0
  3. data/README.rdoc +172 -0
  4. data/bin/mongrel_rpm +33 -0
  5. data/bin/newrelic +13 -0
  6. data/bin/newrelic_cmd +5 -0
  7. data/cert/cacert.pem +34 -0
  8. data/install.rb +9 -0
  9. data/lib/new_relic/agent.rb +382 -0
  10. data/lib/new_relic/agent/agent.rb +741 -0
  11. data/lib/new_relic/agent/busy_calculator.rb +91 -0
  12. data/lib/new_relic/agent/chained_call.rb +13 -0
  13. data/lib/new_relic/agent/error_collector.rb +131 -0
  14. data/lib/new_relic/agent/instrumentation/active_merchant.rb +18 -0
  15. data/lib/new_relic/agent/instrumentation/active_record_instrumentation.rb +92 -0
  16. data/lib/new_relic/agent/instrumentation/acts_as_solr.rb +45 -0
  17. data/lib/new_relic/agent/instrumentation/authlogic.rb +8 -0
  18. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +409 -0
  19. data/lib/new_relic/agent/instrumentation/data_mapper.rb +58 -0
  20. data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +22 -0
  21. data/lib/new_relic/agent/instrumentation/memcache.rb +40 -0
  22. data/lib/new_relic/agent/instrumentation/merb/controller.rb +26 -0
  23. data/lib/new_relic/agent/instrumentation/merb/errors.rb +9 -0
  24. data/lib/new_relic/agent/instrumentation/metric_frame.rb +319 -0
  25. data/lib/new_relic/agent/instrumentation/net.rb +17 -0
  26. data/lib/new_relic/agent/instrumentation/passenger_instrumentation.rb +22 -0
  27. data/lib/new_relic/agent/instrumentation/rack.rb +98 -0
  28. data/lib/new_relic/agent/instrumentation/rails/action_controller.rb +59 -0
  29. data/lib/new_relic/agent/instrumentation/rails/action_web_service.rb +27 -0
  30. data/lib/new_relic/agent/instrumentation/rails/errors.rb +24 -0
  31. data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +45 -0
  32. data/lib/new_relic/agent/instrumentation/rails3/errors.rb +21 -0
  33. data/lib/new_relic/agent/instrumentation/sinatra.rb +46 -0
  34. data/lib/new_relic/agent/instrumentation/sunspot.rb +17 -0
  35. data/lib/new_relic/agent/instrumentation/unicorn_instrumentation.rb +10 -0
  36. data/lib/new_relic/agent/method_tracer.rb +350 -0
  37. data/lib/new_relic/agent/sampler.rb +50 -0
  38. data/lib/new_relic/agent/samplers/cpu_sampler.rb +54 -0
  39. data/lib/new_relic/agent/samplers/delayed_job_lock_sampler.rb +37 -0
  40. data/lib/new_relic/agent/samplers/memory_sampler.rb +142 -0
  41. data/lib/new_relic/agent/samplers/object_sampler.rb +24 -0
  42. data/lib/new_relic/agent/shim_agent.rb +25 -0
  43. data/lib/new_relic/agent/stats_engine.rb +24 -0
  44. data/lib/new_relic/agent/stats_engine/metric_stats.rb +118 -0
  45. data/lib/new_relic/agent/stats_engine/samplers.rb +83 -0
  46. data/lib/new_relic/agent/stats_engine/transactions.rb +149 -0
  47. data/lib/new_relic/agent/transaction_sampler.rb +330 -0
  48. data/lib/new_relic/agent/worker_loop.rb +81 -0
  49. data/lib/new_relic/collection_helper.rb +71 -0
  50. data/lib/new_relic/command.rb +85 -0
  51. data/lib/new_relic/commands/deployments.rb +105 -0
  52. data/lib/new_relic/commands/install.rb +81 -0
  53. data/lib/new_relic/control.rb +203 -0
  54. data/lib/new_relic/control/configuration.rb +149 -0
  55. data/lib/new_relic/control/frameworks/external.rb +13 -0
  56. data/lib/new_relic/control/frameworks/merb.rb +24 -0
  57. data/lib/new_relic/control/frameworks/rails.rb +126 -0
  58. data/lib/new_relic/control/frameworks/rails3.rb +60 -0
  59. data/lib/new_relic/control/frameworks/ruby.rb +36 -0
  60. data/lib/new_relic/control/frameworks/sinatra.rb +18 -0
  61. data/lib/new_relic/control/instrumentation.rb +95 -0
  62. data/lib/new_relic/control/logging_methods.rb +74 -0
  63. data/lib/new_relic/control/profiling.rb +24 -0
  64. data/lib/new_relic/control/server_methods.rb +88 -0
  65. data/lib/new_relic/delayed_job_injection.rb +27 -0
  66. data/lib/new_relic/histogram.rb +91 -0
  67. data/lib/new_relic/local_environment.rb +333 -0
  68. data/lib/new_relic/merbtasks.rb +6 -0
  69. data/lib/new_relic/metric_data.rb +42 -0
  70. data/lib/new_relic/metric_parser.rb +136 -0
  71. data/lib/new_relic/metric_parser/action_mailer.rb +9 -0
  72. data/lib/new_relic/metric_parser/active_merchant.rb +26 -0
  73. data/lib/new_relic/metric_parser/active_record.rb +28 -0
  74. data/lib/new_relic/metric_parser/apdex.rb +88 -0
  75. data/lib/new_relic/metric_parser/controller.rb +62 -0
  76. data/lib/new_relic/metric_parser/controller_cpu.rb +38 -0
  77. data/lib/new_relic/metric_parser/errors.rb +6 -0
  78. data/lib/new_relic/metric_parser/external.rb +50 -0
  79. data/lib/new_relic/metric_parser/mem_cache.rb +50 -0
  80. data/lib/new_relic/metric_parser/other_transaction.rb +36 -0
  81. data/lib/new_relic/metric_parser/view.rb +61 -0
  82. data/lib/new_relic/metric_parser/web_frontend.rb +14 -0
  83. data/lib/new_relic/metric_parser/web_service.rb +9 -0
  84. data/lib/new_relic/metric_spec.rb +67 -0
  85. data/lib/new_relic/metrics.rb +9 -0
  86. data/lib/new_relic/noticed_error.rb +24 -0
  87. data/lib/new_relic/rack/developer_mode.rb +257 -0
  88. data/lib/new_relic/rack/metric_app.rb +64 -0
  89. data/lib/new_relic/rack/mongrel_rpm.ru +26 -0
  90. data/lib/new_relic/rack/newrelic.yml +27 -0
  91. data/lib/new_relic/rack_app.rb +6 -0
  92. data/lib/new_relic/recipes.rb +82 -0
  93. data/lib/new_relic/stats.rb +368 -0
  94. data/lib/new_relic/timer_lib.rb +27 -0
  95. data/lib/new_relic/transaction_analysis.rb +119 -0
  96. data/lib/new_relic/transaction_sample.rb +586 -0
  97. data/lib/new_relic/url_rule.rb +14 -0
  98. data/lib/new_relic/version.rb +55 -0
  99. data/lib/new_relic_api.rb +276 -0
  100. data/lib/newrelic_rpm.rb +49 -0
  101. data/lib/tasks/all.rb +4 -0
  102. data/lib/tasks/install.rake +7 -0
  103. data/lib/tasks/tests.rake +15 -0
  104. data/newrelic.yml +246 -0
  105. data/newrelic_rpm.gemspec +254 -0
  106. data/recipes/newrelic.rb +6 -0
  107. data/test/active_record_fixtures.rb +55 -0
  108. data/test/config/newrelic.yml +48 -0
  109. data/test/config/test_control.rb +36 -0
  110. data/test/new_relic/agent/active_record_instrumentation_test.rb +286 -0
  111. data/test/new_relic/agent/agent_controller_test.rb +294 -0
  112. data/test/new_relic/agent/agent_test_controller.rb +77 -0
  113. data/test/new_relic/agent/busy_calculator_test.rb +81 -0
  114. data/test/new_relic/agent/collection_helper_test.rb +125 -0
  115. data/test/new_relic/agent/error_collector_test.rb +163 -0
  116. data/test/new_relic/agent/memcache_instrumentation_test.rb +103 -0
  117. data/test/new_relic/agent/method_tracer_test.rb +340 -0
  118. data/test/new_relic/agent/metric_data_test.rb +53 -0
  119. data/test/new_relic/agent/metric_frame_test.rb +51 -0
  120. data/test/new_relic/agent/mock_scope_listener.rb +23 -0
  121. data/test/new_relic/agent/net_instrumentation_test.rb +77 -0
  122. data/test/new_relic/agent/rpm_agent_test.rb +142 -0
  123. data/test/new_relic/agent/stats_engine/metric_stats_test.rb +79 -0
  124. data/test/new_relic/agent/stats_engine/samplers_test.rb +72 -0
  125. data/test/new_relic/agent/stats_engine/stats_engine_test.rb +184 -0
  126. data/test/new_relic/agent/task_instrumentation_test.rb +188 -0
  127. data/test/new_relic/agent/testable_agent.rb +13 -0
  128. data/test/new_relic/agent/transaction_sample_builder_test.rb +195 -0
  129. data/test/new_relic/agent/transaction_sample_test.rb +192 -0
  130. data/test/new_relic/agent/transaction_sampler_test.rb +385 -0
  131. data/test/new_relic/agent/worker_loop_test.rb +66 -0
  132. data/test/new_relic/control_test.rb +127 -0
  133. data/test/new_relic/deployments_api_test.rb +69 -0
  134. data/test/new_relic/environment_test.rb +75 -0
  135. data/test/new_relic/metric_parser_test.rb +226 -0
  136. data/test/new_relic/metric_spec_test.rb +177 -0
  137. data/test/new_relic/rack/episodes_test.rb +318 -0
  138. data/test/new_relic/shim_agent_test.rb +9 -0
  139. data/test/new_relic/stats_test.rb +312 -0
  140. data/test/new_relic/version_number_test.rb +89 -0
  141. data/test/test_contexts.rb +28 -0
  142. data/test/test_helper.rb +72 -0
  143. data/ui/helpers/developer_mode_helper.rb +359 -0
  144. data/ui/helpers/google_pie_chart.rb +49 -0
  145. data/ui/views/layouts/newrelic_default.rhtml +47 -0
  146. data/ui/views/newrelic/_explain_plans.rhtml +27 -0
  147. data/ui/views/newrelic/_sample.rhtml +20 -0
  148. data/ui/views/newrelic/_segment.rhtml +29 -0
  149. data/ui/views/newrelic/_segment_limit_message.rhtml +1 -0
  150. data/ui/views/newrelic/_segment_row.rhtml +14 -0
  151. data/ui/views/newrelic/_show_sample_detail.rhtml +24 -0
  152. data/ui/views/newrelic/_show_sample_sql.rhtml +20 -0
  153. data/ui/views/newrelic/_show_sample_summary.rhtml +3 -0
  154. data/ui/views/newrelic/_sql_row.rhtml +16 -0
  155. data/ui/views/newrelic/_stack_trace.rhtml +15 -0
  156. data/ui/views/newrelic/_table.rhtml +12 -0
  157. data/ui/views/newrelic/explain_sql.rhtml +43 -0
  158. data/ui/views/newrelic/file/images/arrow-close.png +0 -0
  159. data/ui/views/newrelic/file/images/arrow-open.png +0 -0
  160. data/ui/views/newrelic/file/images/blue_bar.gif +0 -0
  161. data/ui/views/newrelic/file/images/file_icon.png +0 -0
  162. data/ui/views/newrelic/file/images/gray_bar.gif +0 -0
  163. data/ui/views/newrelic/file/images/new-relic-rpm-desktop.gif +0 -0
  164. data/ui/views/newrelic/file/images/new_relic_rpm_desktop.gif +0 -0
  165. data/ui/views/newrelic/file/images/textmate.png +0 -0
  166. data/ui/views/newrelic/file/javascript/jquery-1.4.2.js +6240 -0
  167. data/ui/views/newrelic/file/javascript/transaction_sample.js +120 -0
  168. data/ui/views/newrelic/file/stylesheets/style.css +484 -0
  169. data/ui/views/newrelic/index.rhtml +59 -0
  170. data/ui/views/newrelic/sample_not_found.rhtml +2 -0
  171. data/ui/views/newrelic/show_sample.rhtml +79 -0
  172. data/ui/views/newrelic/show_source.rhtml +3 -0
  173. data/ui/views/newrelic/threads.rhtml +52 -0
  174. metadata +307 -0
@@ -0,0 +1,81 @@
1
+ require 'thread'
2
+ module NewRelic
3
+ module Agent
4
+
5
+ # A worker loop executes a set of registered tasks on a single thread.
6
+ # A task is a proc or block with a specified call period in seconds.
7
+ class WorkerLoop
8
+
9
+ def initialize
10
+ @log = log
11
+ @should_run = true
12
+ @next_invocation_time = Time.now
13
+ @period = 60.0
14
+ end
15
+
16
+ def lock
17
+ @@lock ||= Mutex.new
18
+ end
19
+
20
+ def log
21
+ NewRelic::Control.instance.log
22
+ end
23
+ # Run infinitely, calling the registered tasks at their specified
24
+ # call periods. The caller is responsible for creating the thread
25
+ # that runs this worker loop. This will run the task immediately.
26
+ def run(period=nil, &block)
27
+ @period = period if period
28
+ @next_invocation_time = Time.now
29
+ @task = block
30
+ while keep_running do
31
+ now = Time.now
32
+ while now < @next_invocation_time
33
+ # sleep until this next task's scheduled invocation time
34
+ sleep_time = @next_invocation_time - now
35
+ sleep sleep_time if sleep_time > 0
36
+ now = Time.now
37
+ end
38
+ run_task if keep_running
39
+ end
40
+ end
41
+
42
+ def keep_running
43
+ @should_run
44
+ end
45
+
46
+ def stop
47
+ @should_run = false
48
+ end
49
+
50
+ def run_task
51
+ begin
52
+ lock.synchronize do
53
+ @task.call
54
+ end
55
+ rescue ServerError => e
56
+ log.debug "Server Error: #{e}"
57
+ rescue NewRelic::Agent::ForceRestartException, NewRelic::Agent::ForceDisconnectException
58
+ # blow out the loop
59
+ raise
60
+ rescue RuntimeError => e
61
+ # This is probably a server error which has been logged in the server along
62
+ # with your account name.
63
+ log.error "Error running task in worker loop, likely a server error (#{e})"
64
+ log.debug e.backtrace.join("\n")
65
+ rescue Timeout::Error, NewRelic::Agent::ServerConnectionException
66
+ # Want to ignore these because they are handled already
67
+ rescue SystemExit, NoMemoryError, SignalException
68
+ raise
69
+ rescue Exception => e
70
+ # Don't blow out the stack for anything that hasn't already propagated
71
+ log.error "Error running task in Agent Worker Loop '#{e}': #{e.backtrace.first}"
72
+ log.debug e.backtrace.join("\n")
73
+ end
74
+ now = Time.now
75
+ while @next_invocation_time <= now && @period > 0
76
+ @next_invocation_time += @period
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,71 @@
1
+ module NewRelic
2
+ module CollectionHelper
3
+ DEFAULT_TRUNCATION_SIZE=256
4
+ DEFAULT_ARRAY_TRUNCATION_SIZE=1024
5
+ # Transform parameter hash into a hash whose values are strictly
6
+ # strings
7
+ def normalize_params(params)
8
+ case params
9
+ when Symbol, FalseClass, TrueClass, nil
10
+ params
11
+ when Numeric
12
+ truncate(params.to_s)
13
+ when String
14
+ truncate(params)
15
+ when Hash
16
+ new_params = {}
17
+ params.each do | key, value |
18
+ new_params[truncate(normalize_params(key),32)] = normalize_params(value)
19
+ end
20
+ new_params
21
+ when Array
22
+ params.first(DEFAULT_ARRAY_TRUNCATION_SIZE).map{|item| normalize_params(item)}
23
+ else
24
+ truncate(flatten(params))
25
+ end
26
+ end
27
+
28
+ # Return an array of strings (backtrace), cleaned up for readability
29
+ # Return nil if there is no backtrace
30
+
31
+ def strip_nr_from_backtrace(backtrace)
32
+ if backtrace
33
+ # this is for 1.9.1, where strings no longer have Enumerable
34
+ backtrace = backtrace.split("\n") if String === backtrace
35
+ # strip newrelic from the trace
36
+ backtrace = backtrace.reject {|line| line =~ /new_relic\/agent\// }
37
+ # rename methods back to their original state
38
+ # GJV - 4/6/10 - adding .to_s call since we were seeing line as a Fixnum in some cases
39
+ backtrace = backtrace.collect {|line| line.to_s.gsub(/_without_(newrelic|trace)/, "")}
40
+ end
41
+ backtrace
42
+ end
43
+
44
+ private
45
+
46
+ # Convert any kind of object to a short string.
47
+ def flatten(object)
48
+ s = case object
49
+ when nil then ''
50
+ when object.instance_of?(String) then object
51
+ when String then String.new(object) # convert string subclasses to strings
52
+ else "#<#{object.class.to_s}>"
53
+ end
54
+ end
55
+ def truncate(string, len=DEFAULT_TRUNCATION_SIZE)
56
+ case string
57
+ when Symbol then string
58
+ when nil then ""
59
+ when String
60
+ real_string = flatten(string)
61
+ if real_string.size > len
62
+ real_string = real_string.slice(0...len)
63
+ real_string << "..."
64
+ end
65
+ real_string
66
+ else
67
+ truncate(flatten(string), len)
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,85 @@
1
+ require 'optparse'
2
+
3
+ # Run the command given by the first argument. Right
4
+ # now all we have is deployments. We hope to have other
5
+ # kinds of events here later.
6
+ $LOAD_PATH << "#{File.dirname(__FILE__)}/.."
7
+ module NewRelic
8
+ class Command
9
+ attr_accessor :leftover
10
+ # Capture a failure to execute the command.
11
+ class CommandFailure < StandardError
12
+ attr_reader :options
13
+ def initialize message, opt_parser=nil
14
+ super message
15
+ @options = opt_parser
16
+ end
17
+ end
18
+
19
+ def info(message)
20
+ STDOUT.puts message
21
+ end
22
+
23
+ def err(message)
24
+ STDERR.puts message
25
+ end
26
+
27
+ def initialize(command_line_args)
28
+ if Hash === command_line_args
29
+ # command line args is an options hash
30
+ command_line_args.each do | key, value |
31
+ instance_variable_set "@#{key}", value.to_s if value
32
+ end
33
+ else
34
+ # parse command line args. Throw an exception on a bad arg.
35
+ @options = options do | opts |
36
+ opts.on("-h", "Show this help") { raise CommandFailure, opts.to_s }
37
+ end
38
+ @leftover = @options.parse(command_line_args)
39
+ end
40
+ rescue OptionParser::ParseError => e
41
+ raise CommandFailure.new e.message, @options
42
+ end
43
+
44
+ @commands = []
45
+ def self.inherited(subclass)
46
+ @commands << subclass
47
+ end
48
+
49
+ cmds = File.expand_path(File.join(File.dirname(__FILE__), 'commands', '*.rb'))
50
+ Dir[cmds].each{|command| require command }
51
+
52
+ def self.run
53
+
54
+ @command_names = @commands.map{ |c| c.command }
55
+
56
+ extra = []
57
+ options = ARGV.options do |opts|
58
+ script_name = File.basename($0)
59
+ if script_name =~ /newrelic_cmd$/
60
+ $stdout.puts "warning: the 'newrelic_cmd' script has been renamed 'newrelic'"
61
+ script_name = 'newrelic'
62
+ end
63
+ opts.banner = "Usage: #{script_name} [ #{ @command_names.join(" | ")} ] [options]"
64
+ opts.separator "use '#{script_name} <command> -h' to see detailed command options"
65
+ opts
66
+ end
67
+ extra = options.order!
68
+ command = extra.shift
69
+ # just make it a little easier on them
70
+ command = 'deployments' if command =~ /deploy/
71
+ if command.nil?
72
+ STDERR.puts options
73
+ elsif !@command_names.include?(command)
74
+ STDERR.puts "Unrecognized command: #{command}"
75
+ STDERR.puts options
76
+ else
77
+ command_class = @commands.find{ |c| c.command == command}
78
+ command_class.new(extra).run
79
+ end
80
+ rescue OptionParser::InvalidOption => e
81
+ raise NewRelic::Command::CommandFailure, e.message
82
+ end
83
+ end
84
+
85
+ end
@@ -0,0 +1,105 @@
1
+ # This is a class for executing commands related to deployment
2
+ # events. It runs without loading the rails environment
3
+
4
+ require 'yaml'
5
+ require 'net/http'
6
+ require 'rexml/document'
7
+
8
+ # We need to use the Control object but we don't want to load
9
+ # the rails/merb environment. The defined? clause is so that
10
+ # it won't load it twice, something it does when run inside a test
11
+ require 'new_relic/control' unless defined? NewRelic::Control
12
+
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
+ {
42
+ :application_id => @appname,
43
+ :host => Socket.gethostname,
44
+ :description => @description,
45
+ :user => @user,
46
+ :revision => @revision,
47
+ :changelog => @changelog
48
+ }.each do |k, v|
49
+ create_params["deployment[#{k}]"] = v unless v.nil? || v == ''
50
+ end
51
+ http = config.http_connection(config.api_server)
52
+
53
+ uri = "/deployments.xml"
54
+
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"
58
+
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,
88
+ "Set the application name.",
89
+ "Default is app_name setting in newrelic.yml") { | e | @appname = e }
90
+ o.on("-e", "--environment=name", String,
91
+ "Override the (RAILS|MERB|RUBY|RACK)_ENV setting",
92
+ "currently: #{config.env}") { | e | @environment = e }
93
+ o.on("-u", "--user=USER", String,
94
+ "Specify the user deploying, for information only",
95
+ "Default: #{@user || '<none>'}") { | u | @user = u }
96
+ o.on("-r", "--revision=REV", String,
97
+ "Specify the revision being deployed") { | r | @revision = r }
98
+ o.on("-c", "--changes",
99
+ "Read in a change log from the standard input") { @changelog = STDIN.read }
100
+ yield o if block_given?
101
+ end
102
+ 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
@@ -0,0 +1,203 @@
1
+ require 'yaml'
2
+ require 'new_relic/local_environment'
3
+ require 'singleton'
4
+ require 'erb'
5
+ require 'socket'
6
+ require 'net/https'
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'
13
+
14
+ module NewRelic
15
+
16
+ # The Control is a singleton responsible for the startup and
17
+ # initialization sequence. The initializer uses a LocalEnvironment to
18
+ # detect the framework and instantiates the framework specific
19
+ # subclass.
20
+ #
21
+ # The Control also implements some of the public API for the agent.
22
+ #
23
+ class Control
24
+ # used for framework-specific subclasses
25
+ module Frameworks; end
26
+
27
+ include Profiling
28
+ include LoggingMethods
29
+ include Configuration
30
+ include ServerMethods
31
+ include Instrumentation
32
+
33
+ # The env is the setting used to identify which section of the newrelic.yml
34
+ # to load. This defaults to a framework specific value, such as ENV['RAILS_ENV']
35
+ # but can be overridden as long as you set it before calling #init_plugin
36
+ attr_writer :env
37
+
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
73
+ end
74
+ extend ClassMethods
75
+
76
+ # Initialize the plugin/gem and start the agent. This does the necessary configuration based on the
77
+ # framework environment and determines whether or not to start the agent. If the
78
+ # agent is not going to be started then it loads the agent shim which has stubs
79
+ # for all the external api.
80
+ #
81
+ # This may be invoked multiple times, as long as you don't attempt to uninstall
82
+ # the agent after it has been started.
83
+ #
84
+ # If the plugin is initialized and it determines that the agent is not enabled, it
85
+ # will skip starting it and install the shim. But if you later call this with
86
+ # <tt>:agent_enabled => true</tt>, then it will install the real agent and start it.
87
+ #
88
+ # What determines whether the agent is launched is the result of calling agent_enabled?
89
+ # This will indicate whether the instrumentation should/will be installed. If we're
90
+ # in a mode where tracers are not installed then we should not start the agent.
91
+ #
92
+ # Subclasses are not allowed to override, but must implement init_config({}) which
93
+ # is called one or more times.
94
+ #
95
+ def init_plugin(options={})
96
+ options['app_name'] = ENV['NEWRELIC_APP_NAME'] if ENV['NEWRELIC_APP_NAME']
97
+
98
+ require 'new_relic/agent'
99
+
100
+ # Load the DJ injection now. If you do it sooner, DJ might not be loaded and
101
+ # you'll miss it.
102
+ require 'new_relic/delayed_job_injection'
103
+
104
+ # Merge the stringified options into the config as overrides:
105
+ logger_override = options.delete(:log)
106
+ environment_name = options.delete(:env) and self.env = environment_name
107
+ dispatcher = options.delete(:dispatcher) and @local_env.dispatcher = dispatcher
108
+ dispatcher_instance_id = options.delete(:dispatcher_instance_id) and @local_env.dispatcher_instance_id = dispatcher_instance_id
109
+
110
+ # Clear out the settings, if they've already been loaded. It may be that
111
+ # between calling init_plugin the first time and the second time, the env
112
+ # has been overridden
113
+ @settings = nil
114
+ settings
115
+ merge_options(options)
116
+ if logger_override
117
+ @log = logger_override
118
+ # Try to grab the log filename
119
+ @log_file = @log.instance_eval { @logdev.filename rescue nil }
120
+ end
121
+ # An artifact of earlier implementation, we put both #add_method_tracer and #trace_execution
122
+ # methods in the module methods.
123
+ Module.send :include, NewRelic::Agent::MethodTracer::ClassMethods
124
+ Module.send :include, NewRelic::Agent::MethodTracer::InstanceMethods
125
+ init_config(options)
126
+ NewRelic::Agent.agent = NewRelic::Agent::Agent.instance
127
+ if agent_enabled? && !NewRelic::Agent.instance.started?
128
+ setup_log unless logger_override
129
+ start_agent
130
+ install_instrumentation
131
+ load_samplers unless self['disable_samplers']
132
+ local_env.gather_environment_info
133
+ append_environment_info
134
+ elsif !agent_enabled?
135
+ install_shim
136
+ end
137
+ end
138
+
139
+ # Install the real agent into the Agent module, and issue the start command.
140
+ def start_agent
141
+ NewRelic::Agent.agent.start
142
+ end
143
+
144
+ # True if dev mode or monitor mode are enabled, and we are running
145
+ # inside a valid dispatcher like mongrel or passenger. Can be overridden
146
+ # by NEWRELIC_ENABLE env variable, monitor_daemons config option when true, or
147
+ # agent_enabled config option when true or false.
148
+ def agent_enabled?
149
+ return false if !developer_mode? && !monitor_mode?
150
+ return self['agent_enabled'].to_s =~ /true|on|yes/i if !self['agent_enabled'].nil? && self['agent_enabled'] != 'auto'
151
+ return false if ENV['NEWRELIC_ENABLE'].to_s =~ /false|off|no/i
152
+ return true if self['monitor_daemons'].to_s =~ /true|on|yes/i
153
+ return true if ENV['NEWRELIC_ENABLE'].to_s =~ /true|on|yes/i
154
+ # When in 'auto' mode the agent is enabled if there is a known
155
+ # dispatcher running
156
+ return true if @local_env.dispatcher != nil
157
+ end
158
+
159
+ def app
160
+ @local_env.framework
161
+ end
162
+ alias framework app
163
+
164
+ def to_s
165
+ "Control[#{self.app}]"
166
+ end
167
+
168
+ protected
169
+
170
+ # Append framework specific environment information for uploading to
171
+ # the server for change detection. Override in subclasses
172
+ def append_environment_info; end
173
+
174
+ def config_file
175
+ File.expand_path(File.join(root,"config","newrelic.yml"))
176
+ end
177
+
178
+ def initialize local_env, config_file_override=nil
179
+ @local_env = local_env
180
+ @instrumentation_files = []
181
+ newrelic_file = config_file_override || config_file
182
+ # Next two are for populating the newrelic.yml via erb binding, necessary
183
+ # when using the default newrelic.yml file
184
+ generated_for_user = ''
185
+ license_key=''
186
+ if !File.exists?(newrelic_file)
187
+ log! "Cannot find read #{newrelic_file}."
188
+ @yaml = {}
189
+ else
190
+ @yaml = YAML.load(ERB.new(File.read(newrelic_file)).result(binding))
191
+ end
192
+ rescue ScriptError, StandardError => e
193
+ puts e
194
+ puts e.backtrace.join("\n")
195
+ raise "Error reading newrelic.yml file: #{e}"
196
+ end
197
+
198
+ def newrelic_root
199
+ self.class.newrelic_root
200
+ end
201
+
202
+ end
203
+ end