wd_newrelic_rpm 3.5.5 → 3.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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)