newrelic_rpm 3.6.2.96 → 3.6.3.103.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. data/.gitignore +3 -0
  2. data/CHANGELOG +33 -1
  3. data/README.md +7 -7
  4. data/lib/new_relic/agent/agent.rb +51 -22
  5. data/lib/new_relic/agent/agent_logger.rb +22 -11
  6. data/lib/new_relic/agent/configuration/defaults.rb +6 -1
  7. data/lib/new_relic/agent/instrumentation/action_controller_subscriber.rb +1 -6
  8. data/lib/new_relic/agent/instrumentation/action_view_subscriber.rb +1 -1
  9. data/lib/new_relic/agent/instrumentation/active_record.rb +8 -48
  10. data/lib/new_relic/agent/instrumentation/active_record_helper.rb +9 -1
  11. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +4 -3
  12. data/lib/new_relic/agent/instrumentation/data_mapper.rb +4 -4
  13. data/lib/new_relic/agent/instrumentation/metric_frame.rb +10 -8
  14. data/lib/new_relic/agent/instrumentation/padrino.rb +32 -0
  15. data/lib/new_relic/agent/instrumentation/sinatra/ignorer.rb +52 -0
  16. data/lib/new_relic/agent/instrumentation/sinatra/transaction_namer.rb +56 -0
  17. data/lib/new_relic/agent/instrumentation/sinatra.rb +113 -48
  18. data/lib/new_relic/agent/new_relic_service.rb +6 -0
  19. data/lib/new_relic/agent/pipe_channel_manager.rb +13 -8
  20. data/lib/new_relic/agent/request_sampler.rb +205 -0
  21. data/lib/new_relic/agent/sampler.rb +0 -1
  22. data/lib/new_relic/agent/stats_engine/samplers.rb +0 -1
  23. data/lib/new_relic/agent/stats_engine/transactions.rb +12 -16
  24. data/lib/new_relic/agent/transaction.rb +27 -4
  25. data/lib/new_relic/agent/transaction_sample_builder.rb +47 -6
  26. data/lib/new_relic/agent/transaction_sampler.rb +0 -5
  27. data/lib/new_relic/agent.rb +17 -0
  28. data/lib/new_relic/build.rb +2 -2
  29. data/lib/new_relic/coerce.rb +3 -1
  30. data/lib/new_relic/rack/agent_hooks.rb +17 -3
  31. data/lib/new_relic/rack/browser_monitoring.rb +8 -3
  32. data/lib/new_relic/rack/error_collector.rb +2 -0
  33. data/lib/new_relic/transaction_sample/segment.rb +0 -23
  34. data/lib/new_relic/transaction_sample.rb +0 -9
  35. data/lib/new_relic/version.rb +1 -1
  36. data/test/agent_helper.rb +204 -0
  37. data/test/config/newrelic.yml +0 -1
  38. data/test/config/test_control.rb +3 -1
  39. data/test/multiverse/suites/agent_only/key_transactions_test.rb +8 -5
  40. data/test/multiverse/suites/agent_only/logging_test.rb +1 -1
  41. data/test/multiverse/suites/agent_only/thread_profiling_test.rb +7 -8
  42. data/test/multiverse/suites/datamapper/Envfile +7 -0
  43. data/test/multiverse/suites/datamapper/datamapper_test.rb +105 -0
  44. data/test/multiverse/suites/padrino/Envfile +16 -0
  45. data/test/multiverse/suites/padrino/config/newrelic.yml +24 -0
  46. data/test/multiverse/suites/padrino/padrino_test.rb +54 -0
  47. data/test/multiverse/suites/rails/Envfile +5 -5
  48. data/test/multiverse/suites/rails/app.rb +1 -0
  49. data/test/multiverse/suites/rails/request_statistics_test.rb +118 -0
  50. data/test/multiverse/suites/sinatra/Envfile +8 -2
  51. data/test/multiverse/suites/sinatra/ignoring_test.rb +185 -0
  52. data/test/multiverse/suites/sinatra/sinatra_classic_test.rb +92 -0
  53. data/test/multiverse/suites/sinatra/sinatra_metric_explosion_test.rb +0 -3
  54. data/test/multiverse/suites/sinatra/sinatra_modular_test.rb +89 -0
  55. data/test/multiverse/suites/sinatra/sinatra_test_cases.rb +120 -0
  56. data/test/new_relic/agent/agent_logger_test.rb +149 -56
  57. data/test/new_relic/agent/agent_test.rb +23 -0
  58. data/test/new_relic/agent/agent_test_controller_test.rb +8 -1
  59. data/test/new_relic/agent/autostart_test.rb +10 -6
  60. data/test/new_relic/agent/instrumentation/action_controller_subscriber_test.rb +36 -31
  61. data/test/new_relic/agent/instrumentation/action_view_subscriber_test.rb +7 -0
  62. data/test/new_relic/agent/instrumentation/active_record_helper_test.rb +20 -4
  63. data/test/new_relic/agent/instrumentation/active_record_instrumentation_test.rb +20 -9
  64. data/test/new_relic/agent/instrumentation/active_record_subscriber_test.rb +23 -19
  65. data/test/new_relic/agent/instrumentation/sequel_test.rb +118 -79
  66. data/test/new_relic/agent/instrumentation/sinatra/transaction_namer_test.rb +55 -0
  67. data/test/new_relic/agent/instrumentation/sinatra_test.rb +60 -11
  68. data/test/new_relic/agent/method_tracer_test.rb +7 -4
  69. data/test/new_relic/agent/new_relic_service_test.rb +6 -0
  70. data/test/new_relic/agent/pipe_channel_manager_test.rb +6 -2
  71. data/test/new_relic/agent/request_sampler_test.rb +159 -0
  72. data/test/new_relic/agent/stats_engine/samplers_test.rb +1 -5
  73. data/test/new_relic/agent/stats_engine_test.rb +14 -0
  74. data/test/new_relic/agent/transaction_sample_builder_test.rb +43 -6
  75. data/test/new_relic/agent/transaction_sampler_test.rb +31 -1
  76. data/test/new_relic/agent/transaction_test.rb +29 -0
  77. data/test/new_relic/agent_test.rb +7 -0
  78. data/test/new_relic/coerce_test.rb +13 -0
  79. data/test/new_relic/fake_collector.rb +31 -1
  80. data/test/new_relic/metric_spec_test.rb +14 -10
  81. data/test/new_relic/rack/agent_hooks_test.rb +9 -2
  82. data/test/new_relic/rack/browser_monitoring_test.rb +16 -7
  83. data/test/new_relic/rack/developer_mode_test.rb +7 -0
  84. data/test/new_relic/rack/error_collector_test.rb +10 -6
  85. data/test/new_relic/transaction_sample/segment_test.rb +0 -61
  86. data/test/new_relic/transaction_sample_subtest_test.rb +0 -19
  87. data/test/script/ci.sh +14 -0
  88. data/test/test_helper.rb +79 -203
  89. data.tar.gz.sig +0 -0
  90. metadata +50 -18
  91. metadata.gz.sig +0 -0
  92. data/test/multiverse/suites/datamapper/encoding_test.rb +0 -40
  93. data/test/multiverse/suites/sinatra/sinatra_test.rb +0 -143
@@ -207,10 +207,10 @@ module NewRelic
207
207
  NewRelic::Agent.instance.transaction_sampler.notice_sql(msg.query, nil, duration)
208
208
 
209
209
  # Record query duration associated with each of the desired metrics.
210
- metrics = [ "ActiveRecord/#{operation}", 'ActiveRecord/all' ]
211
- metrics.each do |metric|
212
- NewRelic::Agent.record_metric(metric, duration)
213
- end
210
+ metric = "ActiveRecord/#{operation}"
211
+ rollup_metrics = ActiveRecordHelper.rollup_metrics_for(metric)
212
+ metrics = [metric] + rollup_metrics
213
+ NewRelic::Agent.instance.stats_engine.record_metrics(metrics, duration)
214
214
  ensure
215
215
  super
216
216
  end
@@ -2,26 +2,28 @@
2
2
  # This file is distributed under New Relic's license terms.
3
3
  # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
4
 
5
- # This is a legacy support shim now that the MetricFrame functionality has
6
- # moved over to the Transaction class instead.
7
- #
8
- # This class is deprecated and will be removed in a future agent version.
9
- #
10
- # This class is not part of the public API. Avoid making calls on it directly.
11
- #
12
5
  module NewRelic
13
6
  module Agent
14
7
  module Instrumentation
8
+ # This is a legacy support shim now that the +MetricFrame+ functionality
9
+ # has moved over to the +Transaction+ class instead.
10
+ #
11
+ # This class is deprecated and will be removed in a future agent version.
12
+ #
13
+ # This class is not part of the public API. Avoid making calls on it directly.
14
+ #
15
+ # @deprecated
15
16
  class MetricFrame
16
17
 
18
+ # @deprecated
17
19
  def self.recording_web_transaction?
18
20
  Transaction.recording_web_transaction?
19
21
  end
20
22
 
23
+ # @deprecated
21
24
  def self.abort_transaction!
22
25
  Transaction.abort_transaction!
23
26
  end
24
-
25
27
  end
26
28
  end
27
29
  end
@@ -0,0 +1,32 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under New Relic's license terms.
3
+ # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
+
5
+ require 'new_relic/agent/instrumentation/sinatra'
6
+
7
+ DependencyDetection.defer do
8
+ @name = :padrino
9
+
10
+ depends_on do
11
+ !NewRelic::Agent.config[:disable_sinatra] &&
12
+ defined?(::Padrino) && defined?(::Padrino::Routing::InstanceMethods)
13
+ end
14
+
15
+ executes do
16
+ ::NewRelic::Agent.logger.info 'Installing Padrino instrumentation'
17
+
18
+ # Our Padrino instrumentation relies heavily on the fact that Padrino is
19
+ # built on Sinatra. Although it wires up a lot of its own routing logic,
20
+ # we only need to patch into Padrino's dispatch to get things started.
21
+ #
22
+ # Parts of the Sinatra instrumentation (such as the TransactionNamer) are
23
+ # aware of Padrino as a potential target in areas where both Sinatra and
24
+ # Padrino run through the same code.
25
+ module ::Padrino::Routing::InstanceMethods
26
+ include NewRelic::Agent::Instrumentation::Sinatra
27
+
28
+ alias dispatch_without_newrelic dispatch!
29
+ alias dispatch! dispatch_with_newrelic
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,52 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under New Relic's license terms.
3
+ # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
+
5
+ module NewRelic
6
+ module Agent
7
+ module Instrumentation
8
+ module Sinatra
9
+ module Ignorer
10
+
11
+ def self.should_ignore?(app, type)
12
+ return false if !app.settings.respond_to?(:newrelic_ignores)
13
+
14
+ app.settings.newrelic_ignores[type].any? do |pattern|
15
+ pattern.match(app.request.path_info)
16
+ end
17
+ end
18
+
19
+ def newrelic_ignore(*routes)
20
+ set_newrelic_ignore(:routes, *routes)
21
+ end
22
+
23
+ def newrelic_ignore_apdex(*routes)
24
+ set_newrelic_ignore(:apdex, *routes)
25
+ end
26
+
27
+ def newrelic_ignore_enduser(*routes)
28
+ set_newrelic_ignore(:enduser, *routes)
29
+ end
30
+
31
+ private
32
+
33
+ def set_newrelic_ignore(type, *routes)
34
+ # Important to default this in the context of the actual app
35
+ # If it's done at register time, ignores end up shared between apps.
36
+ set :newrelic_ignores, Hash.new([]) if !respond_to?(:newrelic_ignores)
37
+
38
+ # If we call an ignore without a route, it applies to the whole app
39
+ routes = ["*"] if routes.empty?
40
+
41
+ settings.newrelic_ignores[type] += routes.map do |r|
42
+ # Ugly sending to private Base#compile, but we want to mimic
43
+ # exactly Sinatra's mapping of route text to regex
44
+ send(:compile, r).first
45
+ end
46
+ end
47
+
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,56 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under New Relic's license terms.
3
+ # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
+
5
+ module NewRelic
6
+ module Agent
7
+ module Instrumentation
8
+ module Sinatra
9
+ module TransactionNamer
10
+ extend self
11
+
12
+ def transaction_name_for_route(env, request)
13
+ name = route_for_sinatra(env)
14
+ name = route_name_for_padrino(request) if name.nil?
15
+
16
+ transaction_name(name, request) unless name.nil?
17
+ end
18
+
19
+ def initial_transaction_name(request)
20
+ transaction_name(::NewRelic::Agent::UNKNOWN_METRIC, request)
21
+ end
22
+
23
+ def transaction_name(route_text, request)
24
+ verb = http_verb(request)
25
+
26
+ route_text = route_text.source if route_text.is_a?(Regexp)
27
+ name = route_text.gsub(%r{^[/^\\A]*(.*?)[/\$\?\\z]*$}, '\1')
28
+ name = "#{verb} #{name}" unless verb.nil?
29
+ name
30
+ rescue => e
31
+ ::NewRelic::Agent.logger.debug("#{e.class} : #{e.message} - Error encountered trying to identify Sinatra transaction name")
32
+ ::NewRelic::Agent::UNKNOWN_METRIC
33
+ end
34
+
35
+ def http_verb(request)
36
+ request.request_method if request.respond_to?(:request_method)
37
+ end
38
+
39
+ # For bare Sinatra, our override on process_route captures the last
40
+ # route into the environment for us to use later on
41
+ def route_for_sinatra(env)
42
+ env["newrelic.last_route"]
43
+ end
44
+
45
+ # For Padrino, the request object has a copy of the matched route
46
+ # on it when we go to evaluating, so we can just retrieve that
47
+ def route_name_for_padrino(request)
48
+ request.route_obj.original_path
49
+ rescue => e
50
+ nil
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -3,14 +3,18 @@
3
3
  # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
4
 
5
5
  require 'new_relic/agent/instrumentation/controller_instrumentation'
6
+ require 'new_relic/agent/instrumentation/sinatra/transaction_namer'
7
+ require 'new_relic/agent/instrumentation/sinatra/ignorer'
6
8
 
7
9
  DependencyDetection.defer do
8
10
  @name = :sinatra
9
11
 
10
12
  depends_on do
11
- defined?(::Sinatra) && defined?(::Sinatra::Base) &&
13
+ !NewRelic::Agent.config[:disable_sinatra] &&
14
+ defined?(::Sinatra) && defined?(::Sinatra::Base) &&
12
15
  Sinatra::Base.private_method_defined?(:dispatch!) &&
13
- Sinatra::Base.private_method_defined?(:process_route)
16
+ Sinatra::Base.private_method_defined?(:process_route) &&
17
+ Sinatra::Base.private_method_defined?(:route_eval)
14
18
  end
15
19
 
16
20
  executes do
@@ -20,12 +24,43 @@ DependencyDetection.defer do
20
24
  executes do
21
25
  ::Sinatra::Base.class_eval do
22
26
  include NewRelic::Agent::Instrumentation::Sinatra
27
+
23
28
  alias dispatch_without_newrelic dispatch!
24
29
  alias dispatch! dispatch_with_newrelic
30
+
31
+ alias process_route_without_newrelic process_route
32
+ alias process_route process_route_with_newrelic
33
+
34
+ alias route_eval_without_newrelic route_eval
35
+ alias route_eval route_eval_with_newrelic
36
+
37
+ register NewRelic::Agent::Instrumentation::Sinatra::Ignorer
38
+ end
39
+
40
+ module ::Sinatra
41
+ register NewRelic::Agent::Instrumentation::Sinatra::Ignorer
25
42
  end
26
43
  end
27
- end
28
44
 
45
+ executes do
46
+ if Sinatra::Base.respond_to?(:build)
47
+ # These requires are inside an executes block because they require rack, and
48
+ # we can't be sure that rack is available when this file is first required.
49
+ require 'new_relic/rack/agent_hooks'
50
+ require 'new_relic/rack/browser_monitoring'
51
+ require 'new_relic/rack/error_collector'
52
+
53
+ ::Sinatra::Base.class_eval do
54
+ class << self
55
+ alias build_without_newrelic build
56
+ alias build build_with_newrelic
57
+ end
58
+ end
59
+ else
60
+ ::NewRelic::Agent.logger.info("Skipping auto-injection of middleware for Sinatra - requires Sinatra 1.2.1+")
61
+ end
62
+ end
63
+ end
29
64
 
30
65
  module NewRelic
31
66
  module Agent
@@ -35,25 +70,78 @@ module NewRelic
35
70
  # and transaction traces.
36
71
  #
37
72
  # The actions in the UI will correspond to the pattern expression used
38
- # to match them. HTTP operations are not distinguished. Multiple matches
39
- # will all be tracked as separate actions.
73
+ # to match them, not directly to full URL's.
40
74
  module Sinatra
41
75
  include ::NewRelic::Agent::Instrumentation::ControllerInstrumentation
42
76
 
43
- def dispatch_with_newrelic
44
- # We're trying to determine the transaction name via Sinatra's
45
- # process_route, but calling it here misses Sinatra's normal error handling.
46
- #
47
- # Relies on transaction_name to always safely return a value for us
48
- txn_name = NewRelic.transaction_name(self.class.routes, @request) do |pattern, keys, conditions|
49
- result = process_route(pattern, keys, conditions) do
50
- pattern.source
77
+ # Expected method for supporting ControllerInstrumentation
78
+ def newrelic_request_headers
79
+ request.env
80
+ end
81
+
82
+ def self.included(clazz)
83
+ clazz.extend(ClassMethods)
84
+ end
85
+
86
+ module ClassMethods
87
+ def newrelic_middlewares
88
+ [ NewRelic::Rack::AgentHooks,
89
+ NewRelic::Rack::BrowserMonitoring,
90
+ NewRelic::Rack::ErrorCollector ]
91
+ end
92
+
93
+ def build_with_newrelic(*args, &block)
94
+ unless NewRelic::Agent.config[:disable_sinatra_auto_middleware]
95
+ newrelic_middlewares.each do |middleware_class|
96
+ try_to_use(self, middleware_class)
97
+ end
51
98
  end
52
- result if result.class == String
99
+ build_without_newrelic(*args, &block)
100
+ end
101
+
102
+ def try_to_use(app, clazz)
103
+ has_middleware = app.middleware.any? { |info| info[0] == clazz }
104
+ app.use(clazz) unless has_middleware
105
+ end
106
+ end
107
+
108
+ # Capture last route we've seen. Will set for transaction on route_eval
109
+ def process_route_with_newrelic(*args, &block)
110
+ begin
111
+ env["newrelic.last_route"] = args[0]
112
+ rescue => e
113
+ ::NewRelic::Agent.logger.debug("Failed determining last route in Sinatra", e)
114
+ end
115
+
116
+ process_route_without_newrelic(*args, &block)
117
+ end
118
+
119
+ # If a transaction name is already set, this call will tromple over it.
120
+ # This is intentional, as typically passing to a separate route is like
121
+ # an entirely separate transaction, so we pick up the new name.
122
+ #
123
+ # If we're ignored, this remains safe, since set_transaction_name
124
+ # care for the gating on the transaction's existence for us.
125
+ def route_eval_with_newrelic(*args, &block)
126
+ begin
127
+ txn_name = TransactionNamer.transaction_name_for_route(env, request)
128
+ ::NewRelic::Agent.set_transaction_name("#{self.class.name}/#{txn_name}") unless txn_name.nil?
129
+ rescue => e
130
+ ::NewRelic::Agent.logger.debug("Failed during route_eval to set transaction name", e)
131
+ end
132
+
133
+ route_eval_without_newrelic(*args, &block)
134
+ end
135
+
136
+ def dispatch_with_newrelic
137
+ if ignore_request?
138
+ env['newrelic.ignored'] = true
139
+ return dispatch_without_newrelic
53
140
  end
54
141
 
142
+ name = TransactionNamer.initial_transaction_name(request)
55
143
  perform_action_with_newrelic_trace(:category => :sinatra,
56
- :name => txn_name,
144
+ :name => name,
57
145
  :params => @request.params) do
58
146
  dispatch_and_notice_errors_with_newrelic
59
147
  end
@@ -68,43 +156,20 @@ module NewRelic
68
156
  ::NewRelic::Agent.notice_error(env['sinatra.error']) if had_error
69
157
  end
70
158
 
71
- # Define Request Header accessor for Sinatra
72
- def newrelic_request_headers
73
- request.env
159
+ def ignore_request?
160
+ Ignorer.should_ignore?(self, :routes)
74
161
  end
75
162
 
76
- module NewRelic
77
- extend self
78
-
79
- def http_verb(request)
80
- request.request_method if request.respond_to?(:request_method)
81
- end
82
-
83
- def transaction_name(routes, request)
84
- name = ::NewRelic::Agent::UNKNOWN_METRIC
85
- verb = http_verb(request)
86
-
87
- Array(routes[verb]).each do |pattern, keys, conditions, block|
88
- if route = yield(pattern, keys, conditions)
89
- name = route
90
- # it's important we short circuit here. Otherwise we risk
91
- # applying conditions from lower priority routes which can
92
- # break the action.
93
- break
94
- end
95
- end
96
-
97
- name = name.gsub(%r{^[/^]*(.*?)[/\$\?]*$}, '\1')
98
- if verb
99
- name = verb + ' ' + name
100
- end
163
+ # Overrides ControllerInstrumentation implementation
164
+ def ignore_apdex?
165
+ Ignorer.should_ignore?(self, :apdex)
166
+ end
101
167
 
102
- name
103
- rescue => e
104
- ::NewRelic::Agent.logger.debug("#{e.class} : #{e.message} - Error encountered trying to identify Sinatra transaction name")
105
- ::NewRelic::Agent::UNKNOWN_METRIC
106
- end
168
+ # Overrides ControllerInstrumentation implementation
169
+ def ignore_enduser?
170
+ Ignorer.should_ignore?(self, :enduser)
107
171
  end
172
+
108
173
  end
109
174
  end
110
175
  end
@@ -146,6 +146,12 @@ module NewRelic
146
146
  invoke_remote(:agent_command_results, @agent_id, { command_id.to_s => results })
147
147
  end
148
148
 
149
+ # Send fine-grained analytic data to the collector.
150
+ def analytic_event_data(data)
151
+ data.collect! {|hash| [hash] }
152
+ invoke_remote(:analytic_event_data, @agent_id, data)
153
+ end
154
+
149
155
  # We do not compress if content is smaller than 64kb. There are
150
156
  # problems with bugs in Ruby in some versions that expose us
151
157
  # to a risk of segfaults if we compress aggressively.
@@ -76,6 +76,10 @@ module NewRelic
76
76
  @out.gets("\n\n")
77
77
  end
78
78
 
79
+ def eof?
80
+ !@out.closed? && @out.eof?
81
+ end
82
+
79
83
  def after_fork_in_child
80
84
  @out.close unless @out.closed?
81
85
  write(READY_MARKER)
@@ -123,12 +127,13 @@ module NewRelic
123
127
 
124
128
  if ready = IO.select(pipes_to_listen_to, [], [], @select_timeout)
125
129
  now = Time.now
126
- pipe = ready[0][0]
127
- if pipe == wake.out
128
- pipe.read(1)
129
- else
130
- merge_data_from_pipe(pipe)
130
+
131
+ ready_pipes = ready[0]
132
+ ready_pipes.each do |pipe|
133
+ merge_data_from_pipe(pipe) unless pipe == wake.out
131
134
  end
135
+
136
+ wake.out.read(1) if ready_pipes.include?(wake.out)
132
137
  end
133
138
 
134
139
  break unless should_keep_listening?
@@ -172,9 +177,7 @@ module NewRelic
172
177
  pipe = find_pipe_for_handle(pipe_handle)
173
178
  raw_payload = pipe.read
174
179
 
175
- if raw_payload.nil?
176
- pipe.close
177
- elsif raw_payload && !raw_payload.empty?
180
+ if raw_payload && !raw_payload.empty?
178
181
  payload = unmarshal(raw_payload)
179
182
  if payload == Pipe::READY_MARKER
180
183
  pipe.after_fork_in_parent
@@ -184,6 +187,8 @@ module NewRelic
184
187
  payload[:error_traces]])
185
188
  end
186
189
  end
190
+
191
+ pipe.close if pipe.eof?
187
192
  end
188
193
 
189
194
  def unmarshal(data)