wd_newrelic_rpm 3.5.5 → 3.5.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (146) hide show
  1. data/.gitignore +2 -0
  2. data/CHANGELOG +60 -0
  3. data/Rakefile +14 -18
  4. data/gem-public_cert.pem +20 -0
  5. data/lib/new_relic/agent.rb +3 -0
  6. data/lib/new_relic/agent/agent.rb +86 -97
  7. data/lib/new_relic/agent/agent_logger.rb +9 -1
  8. data/lib/new_relic/agent/busy_calculator.rb +5 -0
  9. data/lib/new_relic/agent/configuration/defaults.rb +3 -3
  10. data/lib/new_relic/agent/configuration/manager.rb +12 -0
  11. data/lib/new_relic/agent/configuration/mask_defaults.rb +1 -0
  12. data/lib/new_relic/agent/configuration/yaml_source.rb +5 -1
  13. data/lib/new_relic/agent/cross_process_monitoring.rb +164 -20
  14. data/lib/new_relic/agent/error_collector.rb +13 -2
  15. data/lib/new_relic/agent/event_listener.rb +39 -0
  16. data/lib/new_relic/agent/instrumentation/browser_monitoring_timings.rb +18 -8
  17. data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +1 -1
  18. data/lib/new_relic/agent/instrumentation/sinatra.rb +8 -1
  19. data/lib/new_relic/agent/new_relic_service.rb +90 -10
  20. data/lib/new_relic/agent/pipe_service.rb +9 -0
  21. data/lib/new_relic/agent/sql_sampler.rb +10 -3
  22. data/lib/new_relic/agent/stats_engine/transactions.rb +1 -0
  23. data/lib/new_relic/agent/thread_profiler.rb +20 -7
  24. data/lib/new_relic/agent/worker_loop.rb +2 -1
  25. data/lib/new_relic/coerce.rb +37 -0
  26. data/lib/new_relic/commands/deployments.rb +1 -1
  27. data/lib/new_relic/control/frameworks/rails.rb +29 -5
  28. data/lib/new_relic/control/frameworks/rails3.rb +2 -11
  29. data/lib/new_relic/control/instance_methods.rb +11 -7
  30. data/lib/new_relic/control/server_methods.rb +5 -37
  31. data/lib/new_relic/latest_changes.rb +31 -0
  32. data/lib/new_relic/local_environment.rb +1 -1
  33. data/lib/new_relic/metric_data.rb +13 -2
  34. data/lib/new_relic/noticed_error.rb +8 -1
  35. data/lib/new_relic/rack/agent_hooks.rb +20 -0
  36. data/lib/new_relic/rack/error_collector.rb +11 -1
  37. data/lib/new_relic/recipes.rb +32 -10
  38. data/lib/new_relic/transaction_sample.rb +12 -3
  39. data/lib/new_relic/transaction_sample/segment.rb +6 -3
  40. data/lib/new_relic/version.rb +10 -15
  41. data/newrelic.yml +12 -19
  42. data/newrelic_rpm.gemspec +22 -464
  43. data/test/multiverse/.gitignore +1 -0
  44. data/test/multiverse/lib/multiverse/environment.rb +1 -1
  45. data/test/multiverse/lib/multiverse/suite.rb +2 -0
  46. data/test/multiverse/suites/active_record/Envfile +3 -3
  47. data/test/multiverse/suites/active_record/ar_method_aliasing.rb +1 -1
  48. data/test/multiverse/suites/active_record/config/newrelic.yml +2 -2
  49. data/test/multiverse/suites/agent_only/Envfile +2 -1
  50. data/test/multiverse/suites/agent_only/config/newrelic.yml +3 -1
  51. data/test/multiverse/suites/agent_only/cross_process_test.rb +56 -0
  52. data/test/multiverse/suites/{logging → agent_only}/logging_test.rb +42 -22
  53. data/test/multiverse/suites/agent_only/no_dns_resolv.rb +17 -0
  54. data/test/multiverse/suites/{rum_auto_instrumentation/sanity_test.rb → agent_only/rum_instrumentation_test.rb} +25 -46
  55. data/test/multiverse/suites/agent_only/service_timeout_test.rb +6 -3
  56. data/test/multiverse/suites/agent_only/ssl_test.rb +22 -0
  57. data/test/multiverse/suites/{no_load → agent_only}/start_up_test.rb +9 -2
  58. data/test/multiverse/suites/agent_only/testing_app.rb +17 -0
  59. data/test/multiverse/suites/agent_only/thread_profiling_test.rb +6 -5
  60. data/test/multiverse/suites/datamapper/config/newrelic.yml +1 -1
  61. data/test/multiverse/suites/{rails_3_queue_time → rails}/Envfile +3 -0
  62. data/test/multiverse/suites/rails/app.rb +49 -0
  63. data/test/multiverse/suites/{rails_3_views → rails}/app/views/foos/_foo.html.haml +0 -0
  64. data/test/multiverse/suites/{rails_3_views/app/views/test → rails/app/views/views}/_a_partial.html.erb +0 -0
  65. data/test/multiverse/suites/{rails_3_views/app/views/test → rails/app/views/views}/_mid_partial.html.erb +0 -0
  66. data/test/multiverse/suites/{rails_3_views/app/views/test → rails/app/views/views}/_top_partial.html.erb +0 -0
  67. data/test/multiverse/suites/{rails_3_views/app/views/test → rails/app/views/views}/deep_partial.html.erb +0 -0
  68. data/test/multiverse/suites/{rails_3_views/app/views/test → rails/app/views/views}/haml_view.html.haml +0 -0
  69. data/test/multiverse/suites/{rails_3_views/app/views/test → rails/app/views/views}/index.html.erb +0 -0
  70. data/test/multiverse/suites/rails/config/newrelic.yml +32 -0
  71. data/test/multiverse/suites/{rails_3_error_tracing → rails}/error_tracing_test.rb +51 -88
  72. data/test/multiverse/suites/rails/gc_instrumentation_test.rb +79 -0
  73. data/test/multiverse/suites/{rails_3_queue_time → rails}/queue_time_test.rb +3 -23
  74. data/test/multiverse/suites/{rails_3_views → rails}/view_instrumentation_test.rb +21 -61
  75. data/test/multiverse/suites/resque/Envfile +7 -4
  76. data/test/multiverse/suites/resque/Rakefile +8 -0
  77. data/test/multiverse/suites/resque/config/newrelic.yml +1 -1
  78. data/test/multiverse/suites/resque/instrumentation_test.rb +118 -41
  79. data/test/multiverse/suites/resque/resque_setup.rb +15 -0
  80. data/test/multiverse/suites/sinatra/config/newrelic.yml +1 -2
  81. data/test/multiverse/suites/sinatra/sinatra_error_tracing_test.rb +38 -0
  82. data/test/multiverse/suites/sinatra/sinatra_test.rb +17 -0
  83. data/test/multiverse/test/suite_examples/one/a/config/newrelic.yml +1 -1
  84. data/test/multiverse/test/suite_examples/one/b/config/newrelic.yml +1 -1
  85. data/test/new_relic/agent/agent/connect_test.rb +24 -100
  86. data/test/new_relic/agent/agent/start_worker_thread_test.rb +3 -3
  87. data/test/new_relic/agent/agent_test.rb +126 -31
  88. data/test/new_relic/agent/browser_monitoring_test.rb +1 -1
  89. data/test/new_relic/agent/busy_calculator_test.rb +8 -0
  90. data/test/new_relic/agent/configuration/manager_test.rb +28 -0
  91. data/test/new_relic/agent/configuration/yaml_source_test.rb +12 -2
  92. data/test/new_relic/agent/cross_process_monitoring_test.rb +144 -31
  93. data/test/new_relic/agent/error_collector_test.rb +16 -0
  94. data/test/new_relic/agent/event_listener_test.rb +46 -0
  95. data/test/new_relic/agent/instrumentation/browser_monitoring_timings_test.rb +57 -30
  96. data/test/new_relic/agent/instrumentation/task_instrumentation_test.rb +1 -0
  97. data/test/new_relic/agent/new_relic_service_test.rb +95 -2
  98. data/test/new_relic/agent/pipe_channel_manager_test.rb +3 -3
  99. data/test/new_relic/agent/pipe_service_test.rb +21 -1
  100. data/test/new_relic/agent/rpm_agent_test.rb +1 -1
  101. data/test/new_relic/agent/sql_sampler_test.rb +20 -0
  102. data/test/new_relic/agent/thread_profiler_test.rb +53 -8
  103. data/test/new_relic/agent/worker_loop_test.rb +19 -16
  104. data/test/new_relic/agent_test.rb +1 -2
  105. data/test/new_relic/coerce_test.rb +65 -0
  106. data/test/new_relic/command/deployments_test.rb +1 -1
  107. data/test/new_relic/control_test.rb +23 -44
  108. data/test/new_relic/fake_collector.rb +34 -6
  109. data/test/new_relic/local_environment_test.rb +1 -1
  110. data/test/new_relic/metric_data_test.rb +29 -0
  111. data/test/new_relic/noticed_error_test.rb +8 -0
  112. data/test/new_relic/rack/agent_hooks_test.rb +30 -0
  113. data/test/new_relic/rack/error_collector_test.rb +16 -0
  114. data/test/new_relic/transaction_sample/segment_test.rb +7 -0
  115. data/test/new_relic/transaction_sample_test.rb +36 -8
  116. data/test/new_relic/version_number_test.rb +6 -30
  117. data/test/script/ci.sh +6 -5
  118. data/test/test_contexts.rb +2 -1
  119. data/test/test_helper.rb +23 -6
  120. data/ui/helpers/google_pie_chart.rb +1 -0
  121. metadata +68 -67
  122. data/newrelic_rpm.gemspec.erb +0 -54
  123. data/test/fixtures/gemspec_no_build.rb +0 -442
  124. data/test/fixtures/gemspec_with_build.rb +0 -442
  125. data/test/fixtures/gemspec_with_build_and_stage.rb +0 -442
  126. data/test/multiverse/suites/logging/Envfile +0 -4
  127. data/test/multiverse/suites/logging/config/newrelic.yml +0 -22
  128. data/test/multiverse/suites/monitor_mode_false/Envfile +0 -2
  129. data/test/multiverse/suites/monitor_mode_false/config/newrelic.yml +0 -25
  130. data/test/multiverse/suites/monitor_mode_false/no_dns_resolv.rb +0 -29
  131. data/test/multiverse/suites/no_load/Envfile +0 -2
  132. data/test/multiverse/suites/no_load/config/newrelic.yml +0 -22
  133. data/test/multiverse/suites/rails_3_error_tracing/Envfile +0 -15
  134. data/test/multiverse/suites/rails_3_error_tracing/config/newrelic.yml +0 -165
  135. data/test/multiverse/suites/rails_3_gc/Envfile +0 -8
  136. data/test/multiverse/suites/rails_3_gc/config/newrelic.yml +0 -167
  137. data/test/multiverse/suites/rails_3_gc/instrumentation_test.rb +0 -92
  138. data/test/multiverse/suites/rails_3_queue_time/config/newrelic.yml +0 -165
  139. data/test/multiverse/suites/rails_3_views/.gitignore +0 -3
  140. data/test/multiverse/suites/rails_3_views/Envfile +0 -16
  141. data/test/multiverse/suites/rails_3_views/config/newrelic.yml +0 -164
  142. data/test/multiverse/suites/resque/dump.rdb +0 -0
  143. data/test/multiverse/suites/rum_auto_instrumentation/Envfile +0 -4
  144. data/test/multiverse/suites/rum_auto_instrumentation/config/newrelic.yml +0 -24
  145. data/test/multiverse/suites/rum_auto_instrumentation/responses/worst_case_small.html +0 -5000
  146. data/test/new_relic/fake_service.rb +0 -53
data/.gitignore CHANGED
@@ -18,3 +18,5 @@ tags
18
18
  /lerg/
19
19
  gems/newrelic_rpm.gemspec
20
20
  gems/newrelic_rpm*.tar.gz
21
+ lib/new_relic/build.rb
22
+ .pryrc
data/CHANGELOG CHANGED
@@ -1,6 +1,66 @@
1
1
 
2
2
  # New Relic Ruby Agent Release Notes #
3
3
 
4
+ ## v3.5.6 ##
5
+
6
+ * Use HTTPS by default
7
+
8
+ The agent now defaults to using SSL when it communicates with New Relic's
9
+ servers. By defaults already configured, New Relic does not transmit any
10
+ sensitive information (e.g. SQL parameters are masked), but SSL adds
11
+ another layer of security. Upgrading customers may need to remove the
12
+ "ssl: false" directive from their newrelic.yml to enable ssl. Customers on
13
+ Jruby may need to install the jruby-openssl gem to take advantage of this
14
+ feature.
15
+
16
+ * Fix two Resque-related issues
17
+
18
+ Fixes a possible hang on exit of an instrumented Resque master process
19
+ (https://github.com/defunkt/resque/issues/578), as well as a file descriptor
20
+ leak that could occur during startup of the Resque master process.
21
+
22
+ * Fix for error graph over 100%
23
+
24
+ Some errors were double counted toward the overall error total. This
25
+ resulted in graphs with error percentages over 100%. This duplication did
26
+ not impact the specific error traces captured, only the total metric.
27
+
28
+ * Notice gracefully handled errors in Sinatra
29
+
30
+ When show_exceptions was set to false in Sinatra, errors weren't caught
31
+ by New Relic's error collector. Now handled errors also have the chance
32
+ to get reported back.
33
+
34
+ * Ruby 2.0 compatibility fixes
35
+
36
+ Ruby 2.0 no longer finds protected methods by default, but will with a flag.
37
+ http://tenderlovemaking.com/2012/09/07/protected-methods-and-ruby-2-0.html
38
+
39
+ Thanks Ravil Bayramgalin and Charlie Somerville for the fixes.
40
+
41
+ * Auto-detect Trinidad as dispatcher
42
+
43
+ Code already existing for detecting Trinidad as a dispatcher, but was only
44
+ accessible via an ENV variable. This now auto-detects on startup. Thanks
45
+ Robert Rasmussen for catching that.
46
+
47
+ * Coercion of types in collector communication
48
+
49
+ Certain metrics can be recorded with a Ruby Rational type, which JSON
50
+ serializes as a string rather than a floating point value. We now treat
51
+ coerce each outgoing value, and log issues before sending the data.
52
+
53
+ * Developer mode fix for chart error
54
+
55
+ Added require to fix a NameError in developer mode for summary page. Thanks
56
+ to Ryan B. Harvey.
57
+
58
+ * Don't touch deprecated RAILS_ROOT if on Rails 3
59
+
60
+ Under some odd startup conditions, we would look for the RAILS_ROOT constant
61
+ after failing to find the ::Rails.root in a Rails 3 app, causing deprecation
62
+ warnings. Thanks for Adrian Irving-Beer for the fix.
63
+
4
64
  ## v3.5.5 ##
5
65
 
6
66
  * Add thread profiling support
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ require "#{File.dirname(__FILE__)}/lib/tasks/all.rb"
5
5
 
6
6
  task :default => :test
7
7
 
8
- task :test => [:gemspec, 'test:newrelic']
8
+ task :test => ['test:newrelic']
9
9
 
10
10
  namespace :test do
11
11
  desc "Run all tests"
@@ -14,7 +14,7 @@ namespace :test do
14
14
  agent_home = File.expand_path(File.dirname(__FILE__))
15
15
 
16
16
  desc "Run functional test suite for newrelic"
17
- task :multiverse, [:suite, :mode] => [:gemspec] do |t, args|
17
+ task :multiverse, [:suite, :mode] => [] do |t, args|
18
18
  args.with_defaults(:suite => "", :mode => "")
19
19
  if args.mode == "run_one"
20
20
  puts `#{agent_home}/test/multiverse/script/run_one #{args.suite}`
@@ -24,7 +24,7 @@ namespace :test do
24
24
  end
25
25
 
26
26
  desc "Test the multiverse testing framework by executing tests in test/multiverse/test. Get meta with it."
27
- task 'multiverse:self', [:suite, :mode] => [:gemspec] do |t, args|
27
+ task 'multiverse:self', [:suite, :mode] => [] do |t, args|
28
28
  args.with_defaults(:suite => "", :mode => "")
29
29
  puts ("Testing the multiverse testing framework...")
30
30
  test_files = FileList['test/multiverse/test/*_test.rb']
@@ -43,20 +43,16 @@ namespace :test do
43
43
 
44
44
  end
45
45
 
46
- desc 'Generate gemspec [ build_number, stage ]'
47
- task :gemspec, [ :build_number, :stage ] do |t, args|
48
- require 'erb'
49
- version = NewRelic::VERSION::STRING.split('.')[0..2]
50
- version << args.build_number.to_s if args.build_number
51
- version << args.stage.to_s if args.stage
52
-
53
- version_string = version.join('.')
54
- gem_version = Gem::VERSION
55
- date = Time.now.strftime('%Y-%m-%d')
56
- files = `git ls-files`.split + ['newrelic_rpm.gemspec']
57
-
58
- template = ERB.new(File.read('newrelic_rpm.gemspec.erb'))
59
- File.open('newrelic_rpm.gemspec', 'w') do |gemspec|
60
- gemspec.write(template.result(binding))
46
+ desc 'Record build number and stage'
47
+ task :record_build, [ :build_number, :stage ] do |t, args|
48
+ build_string = args.build_number
49
+ build_string << ".#{args.stage}" if args.stage
50
+
51
+ gitsha = File.exists?(".git") ? `git rev-parse HEAD` : "Unknown"
52
+ gitsha.chomp!
53
+
54
+ File.open("lib/new_relic/build.rb", "w") do |f|
55
+ f.write("# GITSHA: #{gitsha}\n")
56
+ f.write("module NewRelic; module VERSION; BUILD='#{build_string}'; end; end\n")
61
57
  end
62
58
  end
@@ -0,0 +1,20 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIDODCCAiCgAwIBAgIBADANBgkqhkiG9w0BAQUFADBCMREwDwYDVQQDDAhzZWN1
3
+ cml0eTEYMBYGCgmSJomT8ixkARkWCG5ld3JlbGljMRMwEQYKCZImiZPyLGQBGRYD
4
+ Y29tMB4XDTEzMDIxMjE5MDcwN1oXDTE0MDIxMjE5MDcwN1owQjERMA8GA1UEAwwI
5
+ c2VjdXJpdHkxGDAWBgoJkiaJk/IsZAEZFghuZXdyZWxpYzETMBEGCgmSJomT8ixk
6
+ ARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJyYRvlk1XUo
7
+ 8JhWQcE/v6RmpK//JbeKvTKnmWVUKz5oTDSOg/LKEhzChpJJVSOMJHCxd4OoxkIN
8
+ pjQF5U2af1m5ONeN1j4p4MujbwNeqxsJmixGLK/BZ9xTnbpYAa6xCRN1UfEcu3O9
9
+ jjLHX3c63ghldwRBn/c2ZD6anMtDeq3C5MLiycFs9h7JXOa3cTTHLZknkYIoHMKN
10
+ EFri5zlks50lbeaVvFRm4IMrYWRsEwzLZWaMOy68BVZe0UlBBKSMnzJfWkbdRRcm
11
+ xqu7viu4hrrCGjUmdHKnl6tf7BY7wqQyKjj+O5DhayKmKRuQcEX8QVnsM+ayqiVU
12
+ EtMiwNScUnsCAwEAAaM5MDcwCQYDVR0TBAIwADAdBgNVHQ4EFgQUOauaMsU0Elp6
13
+ hiUisj4l63ZunSUwCwYDVR0PBAQDAgSwMA0GCSqGSIb3DQEBBQUAA4IBAQAuwrHh
14
+ jOjIfAQoEbGakiwHTeImqmC1EjBEWb1+U+rC2OcsSQ3+2Q0mGq2u3lAphAeLa6i5
15
+ WXb5OdQqZY2aI7NgMxRG98/+TcIlAT8tDR0e6/+QBlBuDXP3YI5Nuhp5U4LEvghr
16
+ jEPaEo0AFPc1JpSO/zKmktU+e9VRAE+q55gLthP8fe0uZvtGUn0KgDbXJyOuGlHF
17
+ J93N937OcyA2rD8gR1qkr3/0/we1dwLZnL6kN4p8nGzPgXZgOHsmTdYZ2ryYowtb
18
+ Kc9+v+QxnbZYpu2IaPXOvm3T8G4O6qZvhnLh/Uien++Dj8eFBecTPoM8pVjK3ph5
19
+ n/EwuZCcE6ghtCCM
20
+ -----END CERTIFICATE-----
@@ -123,6 +123,9 @@ module NewRelic
123
123
  # drop it and not try to resend
124
124
  class UnrecoverableServerException < ServerConnectionException; end
125
125
 
126
+ # An unrecoverable client-side error that prevents the agent from continuing
127
+ class UnrecoverableAgentException < ServerConnectionException; end
128
+
126
129
  # Reserved for future use. Meant to represent a problem on the server side.
127
130
  class ServerError < StandardError; end
128
131
 
@@ -24,11 +24,15 @@ module NewRelic
24
24
  @launch_time = Time.now
25
25
 
26
26
  @metric_ids = {}
27
+ @events = NewRelic::Agent::EventListener.new
27
28
  @stats_engine = NewRelic::Agent::StatsEngine.new
28
29
  @transaction_sampler = NewRelic::Agent::TransactionSampler.new
29
30
  @sql_sampler = NewRelic::Agent::SqlSampler.new
30
31
  @thread_profiler = NewRelic::Agent::ThreadProfiler.new
32
+ @cross_process_monitor = NewRelic::Agent::CrossProcessMonitor.new(@events)
31
33
  @error_collector = NewRelic::Agent::ErrorCollector.new
34
+
35
+ @connect_state = :pending
32
36
  @connect_attempts = 0
33
37
 
34
38
  @last_harvest_time = Time.now
@@ -94,6 +98,10 @@ module NewRelic
94
98
  attr_reader :cross_process_encoding_bytes
95
99
  # service for communicating with collector
96
100
  attr_accessor :service
101
+ # Global events dispatcher. This will provides our primary mechanism
102
+ # for agent-wide events, such as finishing configuration, error notification
103
+ # and request before/after from Rack.
104
+ attr_reader :events
97
105
 
98
106
 
99
107
  # Returns the length of the unsent errors array, if it exists,
@@ -175,19 +183,21 @@ module NewRelic
175
183
  @forked = true
176
184
  Agent.config.apply_config(NewRelic::Agent::Configuration::ManualSource.new(options), 1)
177
185
 
178
- # @connected gets false after we fail to connect or have an error
179
- # connecting. @connected has nil if we haven't finished trying to connect.
180
- # or we didn't attempt a connection because this is the master process
181
-
182
186
  if channel_id = options[:report_to_channel]
183
187
  @service = NewRelic::Agent::PipeService.new(channel_id)
184
- @connected_pid = $$
185
- @metric_ids = {}
188
+ if connected?
189
+ @connected_pid = $$
190
+ @metric_ids = {}
191
+ else
192
+ ::NewRelic::Agent.logger.debug("Child process #{$$} not reporting to non-connected parent.")
193
+ @service.shutdown(Time.now)
194
+ disconnect
195
+ end
186
196
  end
187
197
 
188
198
  return if !Agent.config[:agent_enabled] ||
189
199
  !Agent.config[:monitor_mode] ||
190
- @connected == false ||
200
+ disconnected? ||
191
201
  @worker_thread && @worker_thread.alive?
192
202
 
193
203
  ::NewRelic::Agent.logger.debug "Starting the worker thread in #{$$} after forking."
@@ -210,18 +220,11 @@ module NewRelic
210
220
  @started
211
221
  end
212
222
 
213
- # Return nil if not yet connected, true if successfully started
214
- # and false if we failed to start.
215
- def connected?
216
- @connected
217
- end
218
-
219
223
  # Attempt a graceful shutdown of the agent, running the worker
220
224
  # loop if it exists and is running.
221
225
  #
222
226
  # Options:
223
- # :force_send => (true/false) # force the agent to send data
224
- # before shutting down
227
+ # :force_send => (true/false) # force the agent to send data
225
228
  def shutdown(options={})
226
229
  run_loop_before_exit = Agent.config[:force_send]
227
230
  return if not started?
@@ -234,7 +237,6 @@ module NewRelic
234
237
 
235
238
  # if litespeed, then ignore all future SIGUSR1 - it's
236
239
  # litespeed trying to shut us down
237
-
238
240
  if Agent.config[:dispatcher] == :litespeed
239
241
  Signal.trap("SIGUSR1", "IGNORE")
240
242
  Signal.trap("SIGTERM", "IGNORE")
@@ -454,6 +456,14 @@ module NewRelic
454
456
  :info, "Connecting workers after forking.")
455
457
  end
456
458
 
459
+ # Return true if we're using resque and it hasn't had a chance to (potentially)
460
+ # daemonize itself. This avoids hanging when there's a Thread started
461
+ # before Resque calls Process.daemon (Jira RUBY-857)
462
+ def defer_for_resque?
463
+ NewRelic::Agent.config[:dispatcher] == :resque &&
464
+ !NewRelic::Agent::PipeChannelManager.listener.started?
465
+ end
466
+
457
467
  # Sanity-check the agent configuration and start the agent,
458
468
  # setting up the worker thread and the exit handler to shut
459
469
  # down the agent
@@ -471,6 +481,12 @@ module NewRelic
471
481
  # Logs a bunch of data and starts the agent, if needed
472
482
  def start
473
483
  return if already_started? || disabled?
484
+
485
+ if defer_for_resque?
486
+ ::NewRelic::Agent.logger.debug "Deferring startup for Resque in case it daemonizes"
487
+ return
488
+ end
489
+
474
490
  @started = true
475
491
  @local_host = determine_host
476
492
  log_startup
@@ -518,7 +534,7 @@ module NewRelic
518
534
  ::NewRelic::Agent.logger.debug error.message
519
535
  reset_stats
520
536
  @metric_ids = {}
521
- @connected = nil
537
+ @connect_state = :pending
522
538
  sleep 30
523
539
  end
524
540
 
@@ -577,7 +593,7 @@ module NewRelic
577
593
  # just exit the thread. If it returns nil
578
594
  # that means it didn't try to connect because we're in the master.
579
595
  connect(connection_options)
580
- if @connected
596
+ if connected?
581
597
  log_worker_loop_start
582
598
  create_and_run_worker_loop
583
599
  # never reaches here unless there is a problem or
@@ -610,60 +626,41 @@ module NewRelic
610
626
  # method - all of its methods are used in that context, so it
611
627
  # can be refactored at will. It should be fully tested
612
628
  module Connect
613
- # the frequency with which we should try to connect to the
614
- # server at the moment.
615
- attr_accessor :connect_retry_period
616
629
  # number of attempts we've made to contact the server
617
630
  attr_accessor :connect_attempts
618
631
 
619
632
  # Disconnect just sets connected to false, which prevents
620
633
  # the agent from trying to connect again
621
634
  def disconnect
622
- @connected = false
635
+ @connect_state = :disconnected
623
636
  true
624
637
  end
625
638
 
626
- # We've tried to connect if @connected is not nil, or if we
627
- # are forcing reconnection (i.e. in the case of an
628
- # after_fork with long running processes)
629
- def tried_to_connect?(options)
630
- !(@connected.nil? || options[:force_reconnect])
639
+ def connected?
640
+ @connect_state == :connected
641
+ end
642
+
643
+ def disconnected?
644
+ @connect_state == :disconnected
631
645
  end
632
646
 
633
- # We keep trying by default, but you can disable it with the
634
- # :keep_retrying option set to false
635
- def should_keep_retrying?(options)
636
- @keep_retrying = (options[:keep_retrying].nil? || options[:keep_retrying])
647
+ # Don't connect if we're already connected, or if we tried to connect
648
+ # and were rejected with prejudice because of a license issue, unless
649
+ # we're forced to by force_reconnect.
650
+ def should_connect?(force=false)
651
+ force || (!connected? && !disconnected?)
637
652
  end
638
653
 
639
654
  # Retry period is a minute for each failed attempt that
640
655
  # we've made. This should probably do some sort of sane TCP
641
656
  # backoff to prevent hammering the server, but a minute for
642
657
  # each attempt seems to work reasonably well.
643
- def get_retry_period
644
- return 600 if self.connect_attempts > 6
645
- connect_attempts * 60
646
- end
647
-
648
- def increment_retry_period! #:nodoc:
649
- self.connect_retry_period=(get_retry_period)
658
+ def connect_retry_period
659
+ [600, connect_attempts * 60].min
650
660
  end
651
661
 
652
- # We should only retry when there has not been a more
653
- # serious condition that would prevent it. We increment the
654
- # connect attempts and the retry period, to prevent constant
655
- # connection attempts, and tell the user what we're doing by
656
- # logging.
657
- def should_retry?
658
- if @keep_retrying
659
- self.connect_attempts=(connect_attempts + 1)
660
- increment_retry_period!
661
- ::NewRelic::Agent.logger.warn "Will re-attempt in #{connect_retry_period} seconds"
662
- true
663
- else
664
- disconnect
665
- false
666
- end
662
+ def note_connect_failure
663
+ self.connect_attempts += 1
667
664
  end
668
665
 
669
666
  # When we have a problem connecting to the server, we need
@@ -687,6 +684,12 @@ module NewRelic
687
684
  disconnect
688
685
  end
689
686
 
687
+ def handle_unrecoverable_agent_error(error)
688
+ ::NewRelic::Agent.logger.error(error.message)
689
+ disconnect
690
+ shutdown
691
+ end
692
+
690
693
  # Checks whether we should send environment info, and if so,
691
694
  # returns the snapshot from the local environment
692
695
  def environment_for_connect
@@ -744,24 +747,12 @@ module NewRelic
744
747
  Agent.config.apply_config(server_config, 1)
745
748
  log_connection!(config_data) if @service
746
749
 
747
- @cross_process_id = Agent.config[:cross_process_id]
748
- @cross_process_encoding_key = Agent.config[:encoding_key]
749
- @cross_process_encoding_bytes = get_bytes(@cross_process_encoding_key) unless @cross_process_encoding_key.nil?
750
+ # If you're adding something else here to respond to the server-side config,
751
+ # use Agent.instance.events.subscribe(:finished_configuring) callback instead!
750
752
 
751
753
  @beacon_configuration = BeaconConfiguration.new
752
754
  end
753
755
 
754
- # Ruby 1.8.6 doesn't support the bytes method on strings.
755
- def get_bytes(value)
756
- return [] if value.nil?
757
-
758
- bytes = []
759
- value.each_byte do |b|
760
- bytes << b
761
- end
762
- bytes
763
- end
764
-
765
756
  # Logs when we connect to the server, for debugging purposes
766
757
  # - makes sure we know if an agent has not connected
767
758
  def log_connection!(config_data)
@@ -813,11 +804,9 @@ module NewRelic
813
804
  @traces = transaction_traces
814
805
  end
815
806
  end
816
- if errors && errors.respond_to?(:any?) && errors.any?
817
- if @unsent_errors
818
- @unsent_errors = @unsent_errors + errors
819
- else
820
- @unsent_errors = errors
807
+ if errors && errors.respond_to?(:each)
808
+ errors.each do |err|
809
+ @error_collector.add_to_error_queue(err)
821
810
  end
822
811
  end
823
812
  end
@@ -825,7 +814,7 @@ module NewRelic
825
814
  public :merge_data_from
826
815
 
827
816
  # Connect to the server and validate the license. If successful,
828
- # @connected has true when finished. If not successful, you can
817
+ # connected? returns true when finished. If not successful, you can
829
818
  # keep calling this. Return false if we could not establish a
830
819
  # connection with the server and we should not retry, such as if
831
820
  # there's a bad license key.
@@ -840,25 +829,29 @@ module NewRelic
840
829
  # * <tt>force_reconnect => true</tt> if you want to establish a new connection
841
830
  # to the server before running the worker loop. This means you get a separate
842
831
  # agent run and New Relic sees it as a separate instance (default is false).
843
- def connect(options)
844
- # Don't proceed if we already connected (@connected=true) or if we tried
845
- # to connect and were rejected with prejudice because of a license issue
846
- # (@connected=false), unless we're forced to by force_reconnect.
847
- return if tried_to_connect?(options)
832
+ def connect(options={})
833
+ defaults = {
834
+ :keep_retrying => true,
835
+ :force_reconnect => false
836
+ }
837
+ opts = defaults.merge(options)
848
838
 
849
- # wait a few seconds for the web server to boot, necessary in development
850
- @connect_retry_period = should_keep_retrying?(options) ? 10 : 0
839
+ return unless should_connect?(opts[:force_reconnect])
851
840
 
852
- sleep connect_retry_period
853
841
  ::NewRelic::Agent.logger.debug "Connecting Process to New Relic: #$0"
854
842
  query_server_for_configuration
855
843
  @connected_pid = $$
856
- @connected = true
844
+ @connect_state = :connected
857
845
  rescue NewRelic::Agent::LicenseException => e
858
846
  handle_license_error(e)
847
+ rescue NewRelic::Agent::UnrecoverableAgentException => e
848
+ handle_unrecoverable_agent_error(e)
859
849
  rescue Timeout::Error, StandardError => e
860
850
  log_error(e)
861
- if should_retry?
851
+ if opts[:keep_retrying]
852
+ note_connect_failure
853
+ ::NewRelic::Agent.logger.warn "Will re-attempt in #{connect_retry_period} seconds"
854
+ sleep connect_retry_period
862
855
  retry
863
856
  else
864
857
  disconnect
@@ -876,13 +869,6 @@ module NewRelic
876
869
  control.root
877
870
  end
878
871
 
879
- # Checks whether this process is a Passenger or Unicorn
880
- # spawning server - if so, we probably don't intend to report
881
- # statistics from this process
882
- def is_application_spawner?
883
- $0 =~ /ApplicationSpawner|^unicorn\S* master/
884
- end
885
-
886
872
  # calls the busy harvester and collects timeslice data to
887
873
  # send later
888
874
  def harvest_timeslice_data(time=Time.now)
@@ -1042,13 +1028,16 @@ module NewRelic
1042
1028
  def transmit_data(disconnecting=false)
1043
1029
  now = Time.now
1044
1030
  ::NewRelic::Agent.logger.debug "Sending data to New Relic Service"
1045
- harvest_and_send_errors
1046
- harvest_and_send_slowest_sample
1047
- harvest_and_send_slowest_sql
1048
- harvest_and_send_timeslice_data
1049
- harvest_and_send_thread_profile(disconnecting)
1050
1031
 
1051
- check_for_agent_commands
1032
+ @service.session do # use http keep-alive
1033
+ harvest_and_send_errors
1034
+ harvest_and_send_slowest_sample
1035
+ harvest_and_send_slowest_sql
1036
+ harvest_and_send_timeslice_data
1037
+ harvest_and_send_thread_profile(disconnecting)
1038
+
1039
+ check_for_agent_commands
1040
+ end
1052
1041
  rescue => e
1053
1042
  retry_count ||= 0
1054
1043
  retry_count += 1
@@ -1071,7 +1060,7 @@ module NewRelic
1071
1060
  # If this process comes from a parent process, it will not
1072
1061
  # disconnect, so that the parent process can continue to send data
1073
1062
  def graceful_disconnect
1074
- if @connected
1063
+ if connected?
1075
1064
  begin
1076
1065
  @service.request_timeout = 10
1077
1066
  transmit_data(true)