newrelic_rpm 10.9.0 → 10.9.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fbb51c8f4559d8bb50f88a7e3fcd47d63de49fbe5ec974e9c4ec48b277e28049
4
- data.tar.gz: 129662fccdead351c98519c957172412b20a917e79350960875b53a5ff2d4dcd
3
+ metadata.gz: 76701fc98dcc89355b941dcf726ee2864d9a2badad1519d783d22e033532aa73
4
+ data.tar.gz: 7bfb863d02d054cac5e396b220b0d88aed86bc386f9fab2cb7ce4901f75aa4cf
5
5
  SHA512:
6
- metadata.gz: 630af5f3ffd009f852384cae072cb42d6f0b293c5ca4b13d096d442bbc2f51ab52d12af348e72bdbccfee60549a45ad4e449e45c0ee401aabc8efb58342e61ad
7
- data.tar.gz: 429d5e818a9ec3ece5838b30882fc9ae56dc717916ce423c1bde6e928f4bc672f3eaeb77f26ea608206c203f0db03bec52bc8d9b406822e4646ad0f807a781f3
6
+ metadata.gz: feec753d9d9e92e15a1fe7fa6903af4742aab5714bfc30c9a1100bc4278c614d9a62b0b57119930d9015deda23780ec264f6f5e775f846ea24f6f5f741119ffd
7
+ data.tar.gz: 85cfbf5ae32b4778a3ce743d030ba4995b1da13e9cc8ebaa4c7fe94204be2b3a8e84055ea52b5993e0501976c1a25657fd4626c4192d5bbc794a3e2c1af2473e
data/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # New Relic Ruby Agent Release Notes
2
2
 
3
+ ## v10.9.1
4
+
5
+ - **Bugfix: Action Controller instrumentation no longer errors when it can't identify the controller class**
6
+
7
+ When the agent could not identify a request's controller class, it logged `TypeError: no implicit conversion of nil into String` and then `NoMethodError: undefined method 'finish' for nil`, and recorded no data for that request. These transactions are now named `Controller/(unknown)/<action>` and recorded normally. [PR#3691](https://github.com/newrelic/newrelic-ruby-agent/pull/3691)
8
+
9
+ - **Bugfix: Prevent `Parallel` workers from hanging when reporting large payloads**
10
+
11
+ When `parallel` instrumentation was enabled, `Parallel.each`/`Parallel.map` with `in_processes:` could hang forever. Each worker inherited the pipe write ends the agent registered for its earlier siblings, so those pipes couldn't reach end-of-file, and the agent's pipe listener thread blocked waiting on one of them. Any worker whose data exceeded the operating system pipe buffer then blocked on exit. Now, the agent closes each pipe's write end in the parent right after forking, and the listener no longer blocks on a single pipe while others still have data waiting. Thank you to [@yayamochi](https://github.com/yayamochi) for reporting this bug. [Issue#3680](https://github.com/newrelic/newrelic-ruby-agent/issues/3680) [PR#3688](https://github.com/newrelic/newrelic-ruby-agent/pull/3688)
12
+
13
+ - **Bugfix: gRPC calls no longer fail on requests from Synthetics monitors**
14
+
15
+ When a request from a Synthetics monitor made a gRPC call, the agent added `X-NewRelic-Synthetics` to the call's metadata. gRPC only allows lowercase metadata keys, so the call raised `ArgumentError: 'X-NewRelic-Synthetics' is an invalid header key`. The agent now sends the synthetics headers in lowercase. gRPC server transactions also now read the synthetics headers from incoming metadata, so a gRPC service called during a Synthetics check records its trace and Synthetics attributes. [PR#3693](https://github.com/newrelic/newrelic-ruby-agent/pull/3693)
16
+
3
17
  ## v10.9.0
4
18
 
5
19
  - **Feature: Continuous Profiling (preview)**
@@ -33,10 +33,10 @@ module NewRelic
33
33
  && !should_ignore(payload, controller_class(payload))
34
34
 
35
35
  if exception = exception_object(payload)
36
- finishable.notice_error(exception)
36
+ finishable&.notice_error(exception)
37
37
  end
38
38
 
39
- finishable.finish
39
+ finishable&.finish
40
40
  else
41
41
  Agent.instance.pop_trace_execution_flag
42
42
  end
@@ -75,6 +75,9 @@ module NewRelic
75
75
  def format_metric_name(metric_action, controller)
76
76
  controller_class = controller.is_a?(Class) ? controller : Object.const_get(controller)
77
77
  "Controller/#{controller_class.controller_path}/#{metric_action}"
78
+ rescue StandardError => e
79
+ NewRelic::Agent.logger.debug("#{e.class} : #{e.message} - Error encountered trying to identify Rails controller name")
80
+ "Controller/#{NewRelic::Agent::UNKNOWN_METRIC}/#{metric_action}"
78
81
  end
79
82
 
80
83
  def controller_class(payload)
@@ -19,8 +19,9 @@ module NewRelic
19
19
  @host
20
20
  end
21
21
 
22
+ # gRPC raises ArgumentError on non-lowercase metadata keys.
22
23
  def []=(key, value)
23
- @newrelic_metadata[key] = value
24
+ @newrelic_metadata[key.to_s.downcase] = value
24
25
  end
25
26
  end
26
27
  end
@@ -14,6 +14,9 @@ module NewRelic
14
14
  INSTRUMENTATION_NAME = 'gRPC_Server'
15
15
 
16
16
  DT_KEYS = [NewRelic::NEWRELIC_KEY, NewRelic::TRACEPARENT_KEY, NewRelic::TRACESTATE_KEY].freeze
17
+ SYNTHETICS_KEY = 'x-newrelic-synthetics'
18
+ SYNTHETICS_INFO_KEY = 'x-newrelic-synthetics-info'
19
+ NEWRELIC_KEYS = (DT_KEYS + [SYNTHETICS_KEY, SYNTHETICS_INFO_KEY]).freeze
17
20
  INSTANCE_VAR_HOST = :@host_nr
18
21
  INSTANCE_VAR_PORT = :@port_nr
19
22
  INSTANCE_VAR_METHOD = :@method_nr
@@ -33,6 +36,7 @@ module NewRelic
33
36
  trace_options)
34
37
  add_attributes(txn, metadata, streamer_type)
35
38
  process_distributed_tracing_headers(metadata)
39
+ process_synthetics_headers(metadata)
36
40
 
37
41
  begin
38
42
  yield
@@ -75,6 +79,14 @@ module NewRelic
75
79
  ::NewRelic::Agent::DistributedTracing::accept_distributed_trace_headers(metadata, 'Other')
76
80
  end
77
81
 
82
+ def process_synthetics_headers(metadata)
83
+ return unless metadata && !metadata.empty?
84
+
85
+ ::NewRelic::Agent.agent.monitors.synthetics_monitor.accept_headers(
86
+ metadata[SYNTHETICS_KEY], metadata[SYNTHETICS_INFO_KEY]
87
+ )
88
+ end
89
+
78
90
  def host_and_port_from_host_string(host_string)
79
91
  return unless host_string
80
92
 
@@ -101,7 +113,7 @@ module NewRelic
101
113
  end
102
114
 
103
115
  def grpc_headers(metadata)
104
- metadata.reject { |k, v| DT_KEYS.include?(k) }
116
+ metadata.reject { |k, v| NEWRELIC_KEYS.include?(k) }
105
117
  end
106
118
 
107
119
  def grpc_params(metadata, streamer_type)
@@ -22,9 +22,11 @@ module NewRelic::Agent::Instrumentation
22
22
  channel_id = Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond)
23
23
  NewRelic::Agent.register_report_channel(channel_id)
24
24
 
25
- worker_without_newrelic(job_factory, options) do |*args|
25
+ worker = worker_without_newrelic(job_factory, options) do |*args|
26
26
  worker_with_tracing(channel_id) { yield(*args) }
27
27
  end
28
+ close_report_channel_write_end(channel_id)
29
+ worker
28
30
  end
29
31
  end
30
32
  end
@@ -17,6 +17,12 @@ module NewRelic::Agent::Instrumentation
17
17
  yield
18
18
  end
19
19
 
20
+ # Runs in the parent right after the fork. Parallel forks every worker back-to-back,
21
+ # so waiting for the child's READY marker would let later siblings inherit this write end.
22
+ def close_report_channel_write_end(channel_id)
23
+ NewRelic::Agent::PipeChannelManager.channels[channel_id]&.after_fork_in_parent
24
+ end
25
+
20
26
  def setup_for_txn_metric_merge_at_exit
21
27
  # Clear out any existing transaction metrics to prevent duplicates
22
28
  # when merging metrics back in at the end of the forked process
@@ -17,9 +17,11 @@ module NewRelic::Agent::Instrumentation
17
17
  channel_id = Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond)
18
18
  NewRelic::Agent.register_report_channel(channel_id)
19
19
 
20
- super do |*args|
20
+ worker = super do |*args|
21
21
  worker_with_tracing(channel_id) { yield(*args) }
22
22
  end
23
+ close_report_channel_write_end(channel_id)
24
+ worker
23
25
  end
24
26
  end
25
27
  end
@@ -17,9 +17,11 @@ module NewRelic
17
17
  end
18
18
 
19
19
  def on_before_call(request) # THREAD_LOCAL_ACCESS
20
- encoded_header = request[SYNTHETICS_HEADER_KEY]
21
- info_header = request[SYNTHETICS_INFO_HEADER_KEY]
22
- return unless encoded_header
20
+ accept_headers(request[SYNTHETICS_HEADER_KEY], request[SYNTHETICS_INFO_HEADER_KEY])
21
+ end
22
+
23
+ def accept_headers(encoded_header, info_header)
24
+ return unless encoded_header && (txn = Tracer.current_transaction)
23
25
 
24
26
  incoming_payload = deserialize_header(encoded_header, SYNTHETICS_HEADER_KEY)
25
27
 
@@ -28,11 +30,12 @@ module NewRelic
28
30
  SyntheticsMonitor.is_supported_version?(incoming_payload) &&
29
31
  SyntheticsMonitor.is_trusted?(incoming_payload)
30
32
 
31
- txn = Tracer.current_transaction
32
33
  txn.raw_synthetics_header = encoded_header
33
34
  txn.raw_synthetics_info_header = info_header
34
35
  txn.synthetics_payload = incoming_payload
35
36
  txn.synthetics_info_payload = load_json(info_header, SYNTHETICS_INFO_HEADER_KEY)
37
+ rescue => e
38
+ NewRelic::Agent.logger.debug('Failure accepting synthetics headers', e)
36
39
  end
37
40
 
38
41
  def load_json(header, key)
@@ -237,6 +237,9 @@ module NewRelic
237
237
 
238
238
  def merge_data_from_pipe(pipe_handle)
239
239
  pipe = find_pipe_for_handle(pipe_handle)
240
+
241
+ return pipe.close if pipe.eof?
242
+
240
243
  raw_payload = pipe.read
241
244
  if raw_payload && !raw_payload.empty?
242
245
  if raw_payload == Pipe::READY_MARKER
@@ -249,8 +252,6 @@ module NewRelic
249
252
  end
250
253
  end
251
254
  end
252
-
253
- pipe.close if pipe.eof?
254
255
  end
255
256
 
256
257
  def unmarshal(data)
@@ -7,7 +7,7 @@ module NewRelic
7
7
  module VERSION # :nodoc:
8
8
  MAJOR = 10
9
9
  MINOR = 9
10
- TINY = 0
10
+ TINY = 1
11
11
 
12
12
  STRING = "#{MAJOR}.#{MINOR}.#{TINY}"
13
13
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: newrelic_rpm
3
3
  version: !ruby/object:Gem::Version
4
- version: 10.9.0
4
+ version: 10.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tanna McClure