newrelic_rpm 4.8.0.341 → 5.0.0.342

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 (33) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +27 -0
  3. data/CHANGELOG.md +39 -0
  4. data/config.dot +0 -3
  5. data/lib/new_relic/agent/{throughput_monitor.rb → adaptive_sampler.rb} +22 -13
  6. data/lib/new_relic/agent/agent.rb +3 -4
  7. data/lib/new_relic/agent/configuration/default_source.rb +22 -17
  8. data/lib/new_relic/agent/configuration/high_security_source.rb +0 -2
  9. data/lib/new_relic/agent/database.rb +5 -0
  10. data/lib/new_relic/agent/database/explain_plan_helpers.rb +11 -0
  11. data/lib/new_relic/agent/distributed_trace_monitor.rb +4 -2
  12. data/lib/new_relic/agent/distributed_trace_payload.rb +88 -119
  13. data/lib/new_relic/agent/external.rb +14 -0
  14. data/lib/new_relic/agent/heap.rb +140 -0
  15. data/lib/new_relic/agent/instrumentation/bunny.rb +5 -1
  16. data/lib/new_relic/agent/instrumentation/rails5/action_cable.rb +5 -1
  17. data/lib/new_relic/agent/messaging.rb +10 -0
  18. data/lib/new_relic/agent/new_relic_service.rb +43 -23
  19. data/lib/new_relic/agent/priority_sampled_buffer.rb +68 -0
  20. data/lib/new_relic/agent/supported_versions.rb +1 -1
  21. data/lib/new_relic/agent/transaction.rb +14 -8
  22. data/lib/new_relic/agent/transaction/distributed_tracing.rb +113 -55
  23. data/lib/new_relic/agent/transaction/external_request_segment.rb +17 -11
  24. data/lib/new_relic/agent/transaction/message_broker_segment.rb +12 -4
  25. data/lib/new_relic/agent/transaction_error_primitive.rb +2 -8
  26. data/lib/new_relic/agent/transaction_event_aggregator.rb +16 -13
  27. data/lib/new_relic/agent/transaction_event_primitive.rb +5 -3
  28. data/lib/new_relic/agent/transaction_event_recorder.rb +3 -11
  29. data/lib/new_relic/recipes/capistrano3.rb +5 -2
  30. data/lib/new_relic/version.rb +2 -2
  31. data/newrelic_rpm.gemspec +3 -2
  32. metadata +38 -9
  33. data/lib/new_relic/agent/distributed_trace_priority_sampled_buffer.rb +0 -72
@@ -14,92 +14,79 @@ module NewRelic
14
14
  !!distributed_trace_payload
15
15
  end
16
16
 
17
- def create_distributed_trace_payload url = nil
17
+ SUPPORTABILITY_CREATE_PAYLOAD_SUCCESS = "Supportability/DistributedTrace/CreatePayload/Success".freeze
18
+ SUPPORTABILITY_CREATE_PAYLOAD_EXCEPTION = "Supportability/DistributedTrace/CreatePayload/Exception".freeze
19
+
20
+ def create_distributed_trace_payload
18
21
  return unless Agent.config[:'distributed_tracing.enabled']
19
- self.order += 1
20
- DistributedTracePayload.for_transaction self, url
22
+ self.distributed_trace_payload_created = true
23
+ payload = DistributedTracePayload.for_transaction self
24
+ NewRelic::Agent.increment_metric SUPPORTABILITY_CREATE_PAYLOAD_SUCCESS
25
+ payload
26
+ rescue => e
27
+ NewRelic::Agent.increment_metric SUPPORTABILITY_CREATE_PAYLOAD_EXCEPTION
28
+ NewRelic::Agent.logger.warn "Failed to create distributed trace payload", e
29
+ nil
21
30
  end
22
31
 
23
- LBRACE = "{".freeze
32
+ SUPPORTABILITY_ACCEPT_PAYLOAD_SUCCESS = "Supportability/DistributedTrace/AcceptPayload/Success".freeze
33
+ SUPPORTABILITY_ACCEPT_PAYLOAD_EXCEPTION = "Supportability/DistributedTrace/AcceptPayload/Exception".freeze
24
34
 
25
- def accept_distributed_trace_payload transport_type, payload
35
+ def accept_distributed_trace_payload payload
26
36
  return unless Agent.config[:'distributed_tracing.enabled']
27
- if distributed_trace_payload
28
- NewRelic::Agent.increment_metric "Supportability/DistributedTracing/AcceptFailure/PayloadAlreadyAccepted"
29
- return false
30
- elsif self.order > 0
31
- NewRelic::Agent.increment_metric "Supportability/DistributedTracing/AcceptFailure/CreateDistributedTracePayload-before-AcceptDistributedTracePayload"
32
- return false
33
- elsif name_frozen?
34
- NewRelic::Agent.increment_metric "Supportability/DistributedTracing/AcceptFailure/BrowserAgentInjected"
35
- return false
36
- end
37
+ return false if check_payload_ignored(payload)
38
+ return false unless payload = decode_payload(payload)
39
+ return false unless check_valid_version(payload)
40
+ return false unless check_trusted_account(payload)
37
41
 
38
- payload = if payload.start_with? LBRACE
39
- DistributedTracePayload.from_json payload
40
- else
41
- DistributedTracePayload.from_http_safe payload
42
- end
43
-
44
- payload.caller_transport_type = transport_type
45
- self.distributed_trace_payload = payload
46
-
47
- self.sampled = payload.sampled unless payload.sampled.nil?
42
+ assign_payload_and_sampling_params(payload)
48
43
 
44
+ NewRelic::Agent.increment_metric SUPPORTABILITY_ACCEPT_PAYLOAD_SUCCESS
49
45
  true
50
46
  rescue => e
51
- NewRelic::Agent.increment_metric "Supportability/DistributedTracing/AcceptFailure/Unknown"
47
+ NewRelic::Agent.increment_metric SUPPORTABILITY_ACCEPT_PAYLOAD_EXCEPTION
52
48
  NewRelic::Agent.logger.warn "Failed to accept distributed trace payload", e
53
49
  false
54
50
  end
55
51
 
56
- def distributed_tracing_trip_id
52
+ def trace_id
57
53
  if distributed_trace_payload
58
- distributed_trace_payload.trip_id
54
+ distributed_trace_payload.trace_id
59
55
  else
60
56
  guid
61
57
  end
62
58
  end
63
59
 
64
- def parent_ids
65
- if distributed_trace_payload &&
66
- distributed_trace_payload.parent_ids &&
67
- distributed_trace_payload.parent_ids.last != guid
68
- inbound_ids = distributed_trace_payload.parent_ids.dup
69
- inbound_ids.push guid
70
- if inbound_ids.size > 3
71
- inbound_ids.shift
72
- end
73
- inbound_ids
74
- else
75
- [guid]
76
- end
60
+ def parent_id
61
+ # The payload comes from our parent transaction, so its ID
62
+ # is our parent ID.
63
+ #
64
+ distributed_trace_payload && distributed_trace_payload.id
77
65
  end
78
66
 
79
- def depth
80
- if distributed_trace_payload
81
- distributed_trace_payload.depth
82
- else
83
- 1
84
- end
67
+ def grandparent_id
68
+ # The payload comes from our parent transaction, so its
69
+ # parent ID is our grandparent ID.
70
+ #
71
+ distributed_trace_payload && distributed_trace_payload.parent_id
85
72
  end
86
73
 
87
- def order
88
- @order ||= 0
74
+ def distributed_trace_payload_created?
75
+ @distributed_trace_payload_created ||= false
89
76
  end
90
77
 
91
- attr_writer :order
78
+ attr_writer :distributed_trace_payload_created
92
79
 
93
- def append_distributed_tracing_info payload
80
+ def append_distributed_trace_info transaction_payload
94
81
  return unless Agent.config[:'distributed_tracing.enabled']
95
82
  if distributed_trace_payload
96
- distributed_trace_payload.assign_intrinsics self, payload
97
- elsif order > 0
98
- DistributedTracePayload.assign_initial_intrinsics self, payload
83
+ distributed_trace_payload.assign_intrinsics self, transaction_payload
84
+ elsif distributed_trace_payload_created?
85
+ DistributedTracePayload.assign_intrinsics_for_first_trace self, transaction_payload
99
86
  end
100
87
  end
101
88
 
102
- def assign_distributed_tracing_intrinsics
89
+ def assign_distributed_trace_intrinsics
103
90
  return unless Agent.config[:'distributed_tracing.enabled']
104
91
  DistributedTracePayload::INTRINSIC_KEYS.each do |key|
105
92
  next unless value = @payload[key]
@@ -115,7 +102,78 @@ module NewRelic
115
102
  return unless distributed_trace_payload
116
103
  (start_time.to_f * 1000 - distributed_trace_payload.timestamp) / 1000
117
104
  end
105
+
106
+ private
107
+
108
+ SUPPORTABILITY_CREATE_BEFORE_ACCEPT_PAYLOAD = "Supportability/DistributedTrace/AcceptPayload/Ignored/CreateBeforeAccept".freeze
109
+ SUPPORTABILITY_MULTIPLE_ACCEPT_PAYLOAD = "Supportability/DistributedTrace/AcceptPayload/Ignored/Multiple".freeze
110
+ SUPPORTABILITY_PAYLOAD_ACCEPT_IGNORED_NULL = "Supportability/DistributedTrace/AcceptPayload/Ignored/Null".freeze
111
+ SUPPORTABILITY_PAYLOAD_ACCEPT_IGNORED_BROWSER = "Supportability/DistributedTrace/AcceptPayload/Ignored/BrowserAgentInjected".freeze
112
+
113
+ def check_payload_ignored(payload)
114
+ if payload.nil?
115
+ NewRelic::Agent.increment_metric SUPPORTABILITY_PAYLOAD_ACCEPT_IGNORED_NULL
116
+ return true
117
+ elsif distributed_trace_payload
118
+ NewRelic::Agent.increment_metric SUPPORTABILITY_MULTIPLE_ACCEPT_PAYLOAD
119
+ return true
120
+ elsif distributed_trace_payload_created?
121
+ NewRelic::Agent.increment_metric SUPPORTABILITY_CREATE_BEFORE_ACCEPT_PAYLOAD
122
+ return true
123
+ end
124
+ false
125
+ end
126
+
127
+ SUPPORTABILITY_PAYLOAD_ACCEPT_IGNORED_PARSE_EXCEPTION = "Supportability/DistributedTrace/AcceptPayload/ParseException".freeze
128
+ LBRACE = "{".freeze
129
+
130
+ def decode_payload(payload)
131
+ if payload.start_with? LBRACE
132
+ DistributedTracePayload.from_json payload
133
+ else
134
+ DistributedTracePayload.from_http_safe payload
135
+ end
136
+ rescue => e
137
+ NewRelic::Agent.increment_metric SUPPORTABILITY_PAYLOAD_ACCEPT_IGNORED_PARSE_EXCEPTION
138
+ NewRelic::Agent.logger.warn "Error parsing distributed trace payload", e
139
+ nil
140
+ end
141
+
142
+ SUPPORTABILITY_PAYLOAD_ACCEPT_IGNORED_MAJOR_VERSION = "Supportability/DistributedTrace/AcceptPayload/Ignored/MajorVersion".freeze
143
+
144
+ def check_valid_version(payload)
145
+ if DistributedTracePayload.major_version_matches?(payload)
146
+ true
147
+ else
148
+ NewRelic::Agent.increment_metric SUPPORTABILITY_PAYLOAD_ACCEPT_IGNORED_MAJOR_VERSION
149
+ false
150
+ end
151
+ end
152
+
153
+ SUPPORTABILITY_PAYLOAD_ACCEPT_UNTRUSTED_ACCOUNT = "Supportability/DistributedTrace/AcceptPayload/Ignored/UntrustedAccount".freeze
154
+
155
+ def check_trusted_account(payload)
156
+ trusted_account_ids = NewRelic::Agent.config[:trusted_account_ids]
157
+ trusted = trusted_account_ids.include?(payload.parent_account_id.to_i)
158
+
159
+ unless trusted
160
+ NewRelic::Agent.increment_metric SUPPORTABILITY_PAYLOAD_ACCEPT_UNTRUSTED_ACCOUNT
161
+ return false
162
+ end
163
+
164
+ true
165
+ end
166
+
167
+ def assign_payload_and_sampling_params(payload)
168
+ self.distributed_trace_payload = payload
169
+
170
+ unless payload.sampled.nil?
171
+ self.sampled = payload.sampled
172
+ self.priority = payload.priority if payload.priority
173
+ end
174
+ end
118
175
  end
119
176
  end
120
177
  end
121
178
  end
179
+
@@ -50,14 +50,9 @@ module NewRelic
50
50
  synthetics_header = transaction && transaction.raw_synthetics_header
51
51
  insert_synthetics_header request, synthetics_header if synthetics_header
52
52
 
53
- return unless record_metrics? && CrossAppTracing.cross_app_enabled?
53
+ return unless record_metrics?
54
54
 
55
- transaction_state.is_cross_app_caller = true
56
- txn_guid = transaction_state.request_guid
57
- trip_id = transaction && transaction.cat_trip_id
58
- path_hash = transaction && transaction.cat_path_hash
59
-
60
- CrossAppTracing.insert_request_headers request, txn_guid, trip_id, path_hash
55
+ insert_cross_app_header request
61
56
  insert_distributed_trace_header request
62
57
  rescue => e
63
58
  NewRelic::Agent.logger.error "Error in add_request_headers", e
@@ -206,11 +201,22 @@ module NewRelic
206
201
  end
207
202
  end
208
203
 
204
+ def insert_cross_app_header request
205
+ return unless CrossAppTracing.cross_app_enabled?
206
+
207
+ transaction_state.is_cross_app_caller = true
208
+ txn_guid = transaction_state.request_guid
209
+ trip_id = transaction && transaction.cat_trip_id
210
+ path_hash = transaction && transaction.cat_path_hash
211
+
212
+ CrossAppTracing.insert_request_headers request, txn_guid, trip_id, path_hash
213
+ end
214
+
209
215
  X_NEWRELIC_TRACE_HEADER = "X-NewRelic-Trace".freeze
210
216
 
211
217
  def insert_distributed_trace_header request
212
218
  return unless Agent.config[:'distributed_tracing.enabled']
213
- payload = transaction.create_distributed_trace_payload uri
219
+ payload = transaction.create_distributed_trace_payload
214
220
  request[X_NEWRELIC_TRACE_HEADER] = payload.http_safe
215
221
  end
216
222
 
@@ -261,7 +267,7 @@ module NewRelic
261
267
  def add_caller_by_duration_metrics
262
268
  prefix = if transaction.distributed_trace?
263
269
  payload = transaction.distributed_trace_payload
264
- "DurationByCaller/#{payload.caller_type}/#{payload.caller_account_id}/#{payload.caller_app_id}/transport"
270
+ "DurationByCaller/#{payload.parent_type}/#{payload.parent_account_id}/#{payload.parent_app_id}/transport"
265
271
  else
266
272
  DURATION_BY_CALLER_UNKOWN_PREFIX
267
273
  end
@@ -273,7 +279,7 @@ module NewRelic
273
279
  def record_transport_duration_metrics
274
280
  return unless transaction.distributed_trace?
275
281
  payload = transaction.distributed_trace_payload
276
- prefix = "TransportDuration/#{payload.caller_type}/#{payload.caller_account_id}/#{payload.caller_app_id}/transport"
282
+ prefix = "TransportDuration/#{payload.parent_type}/#{payload.parent_account_id}/#{payload.parent_app_id}/transport"
277
283
  metric_cache.record_unscoped "#{prefix}/#{ALL_SUFFIX}", transaction.transport_duration
278
284
  metric_cache.record_unscoped "#{prefix}/#{transaction_type_suffix}", transaction.transport_duration
279
285
  end
@@ -284,7 +290,7 @@ module NewRelic
284
290
  return unless transaction.exceptions.size > 0
285
291
  prefix = if transaction.distributed_trace?
286
292
  payload = transaction.distributed_trace_payload
287
- "ErrorsByCaller/#{payload.caller_type}/#{payload.caller_account_id}/#{payload.caller_app_id}/transport"
293
+ "ErrorsByCaller/#{payload.parent_type}/#{payload.parent_account_id}/#{payload.parent_app_id}/transport"
288
294
  else
289
295
  ERRORS_BY_CALLER_UNKOWN_PREFIX
290
296
  end
@@ -83,21 +83,29 @@ module NewRelic
83
83
  if destination_type == :temporary_queue || destination_type == :temporary_topic
84
84
  @name << TEMP
85
85
  else
86
- @name << NAMED << destination_name
86
+ @name << NAMED << destination_name.to_s
87
87
  end
88
88
 
89
89
  @name
90
90
  end
91
91
 
92
+ NEWRELIC_TRACE_KEY = "NewRelicTrace".freeze
93
+
94
+ def insert_distributed_trace_header
95
+ return unless Agent.config[:'distributed_tracing.enabled']
96
+ payload = transaction.create_distributed_trace_payload
97
+ headers[NEWRELIC_TRACE_KEY] = payload.http_safe
98
+ end
99
+
92
100
  def transaction= t
93
101
  super
94
- if headers && transaction && action == :produce && record_metrics? && CrossAppTracing.cross_app_enabled?
95
- transaction.add_message_cat_headers headers
102
+ if headers && transaction && action == :produce && record_metrics?
103
+ insert_distributed_trace_header
104
+ transaction.add_message_cat_headers headers if CrossAppTracing.cross_app_enabled?
96
105
  end
97
106
  rescue => e
98
107
  NewRelic::Agent.logger.error "Error during message header processing", e
99
108
  end
100
-
101
109
  end
102
110
  end
103
111
  end
@@ -24,7 +24,7 @@ module NewRelic
24
24
  PORT_KEY = 'port'.freeze
25
25
  NAME_KEY = 'transactionName'.freeze
26
26
  DURATION_KEY = 'duration'.freeze
27
- SAMPLED_KEY = 'nr.sampled'.freeze
27
+ SAMPLED_KEY = 'sampled'.freeze
28
28
  GUID_KEY = 'nr.transactionGuid'.freeze
29
29
  REFERRING_TRANSACTION_GUID_KEY = 'nr.referringTransactionGuid'.freeze
30
30
  SYNTHETICS_RESOURCE_ID_KEY = "nr.syntheticsResourceId".freeze
@@ -53,7 +53,7 @@ module NewRelic
53
53
  if payload
54
54
  attrs[NAME_KEY] = payload[:name]
55
55
  attrs[DURATION_KEY] = payload[:duration]
56
- attrs[SAMPLED_KEY] = payload[:'nr.sampled'] if Agent.config[:'distributed_tracing.enabled']
56
+ attrs[SAMPLED_KEY] = payload[:'sampled'] if Agent.config[:'distributed_tracing.enabled']
57
57
  append_synthetics payload, attrs
58
58
  append_cat payload, attrs
59
59
  append_distributed_trace_intrinsics payload, attrs
@@ -74,18 +74,12 @@ module NewRelic
74
74
  sample[REFERRING_TRANSACTION_GUID_KEY] = payload[:referring_transaction_guid] if payload[:referring_transaction_guid]
75
75
  end
76
76
 
77
- OTHER_GUID_KEY = "nr.guid".freeze
78
-
79
77
  def append_distributed_trace_intrinsics payload, sample
80
78
  return unless Agent.config[:'distributed_tracing.enabled']
81
79
  DistributedTracePayload::INTRINSIC_KEYS.each do |key|
82
80
  value = payload[key]
83
81
  sample[key] = value unless value.nil?
84
82
  end
85
- # guid has a different name for transaction events
86
- if sample.key? OTHER_GUID_KEY
87
- sample[GUID_KEY] = sample.delete OTHER_GUID_KEY
88
- end
89
83
  end
90
84
  end
91
85
  end
@@ -6,7 +6,7 @@
6
6
  require 'newrelic_rpm' unless defined?( NewRelic )
7
7
  require 'new_relic/agent' unless defined?( NewRelic::Agent )
8
8
  require 'new_relic/agent/event_aggregator'
9
- require 'new_relic/agent/distributed_trace_priority_sampled_buffer'
9
+ require 'new_relic/agent/priority_sampled_buffer'
10
10
 
11
11
  module NewRelic
12
12
  module Agent
@@ -15,27 +15,30 @@ module NewRelic
15
15
  named :TransactionEventAggregator
16
16
  capacity_key :'analytics_events.max_samples_stored'
17
17
  enabled_key :'analytics_events.enabled'
18
- buffer_class DistributedTracePrioritySampledBuffer
18
+ buffer_class PrioritySampledBuffer
19
+
20
+ def append priority: nil, event:nil, &blk
21
+ unless(event || priority && blk)
22
+ raise ArgumentError, "Expected priority and block, or event"
23
+ end
19
24
 
20
- def append event=nil, &blk
21
- raise ArgumentError, "Expected argument or block, but received both" if event && blk
22
25
  return unless enabled?
23
26
 
24
27
  @lock.synchronize do
25
- @buffer.append event, &blk
28
+ @buffer.append priority: priority, event: event, &blk
26
29
  notify_if_full
27
30
  end
28
31
  end
29
32
 
30
- # events that are selected to be sampled have priority of other events (ie
31
- # the ones passed to append)
32
- def append_sampled event=nil, &blk
33
- raise ArgumentError, "Expected argument or block, but received both" if event && blk
34
- return unless enabled?
35
-
33
+ def merge! payload, adjust_count = true
36
34
  @lock.synchronize do
37
- @buffer.append_sampled event, &blk
38
- notify_if_full
35
+ _, samples = payload
36
+
37
+ if adjust_count
38
+ @buffer.decrement_lifetime_counts_by samples.count
39
+ end
40
+
41
+ samples.each { |s| @buffer.append event: s }
39
42
  end
40
43
  end
41
44
 
@@ -25,7 +25,8 @@ module NewRelic
25
25
  NAME_KEY = 'name'.freeze
26
26
  DURATION_KEY = 'duration'.freeze
27
27
  ERROR_KEY = 'error'.freeze
28
- SAMPLED_KEY = 'nr.sampled'.freeze
28
+ SAMPLED_KEY = 'sampled'.freeze
29
+ PRIORITY_KEY = 'priority'.freeze
29
30
  GUID_KEY = 'nr.guid'.freeze
30
31
  REFERRING_TRANSACTION_GUID_KEY = 'nr.referringTransactionGuid'.freeze
31
32
  CAT_TRIP_ID_KEY = 'nr.tripId'.freeze
@@ -47,10 +48,11 @@ module NewRelic
47
48
  NAME_KEY => string(payload[:name]),
48
49
  DURATION_KEY => float(payload[:duration]),
49
50
  TYPE_KEY => SAMPLE_TYPE,
50
- ERROR_KEY => payload[:error]
51
+ ERROR_KEY => payload[:error],
52
+ PRIORITY_KEY => payload[:priority]
51
53
  }
52
54
 
53
- intrinsics[SAMPLED_KEY] = payload[:'nr.sampled'] if Agent.config[:'distributed_tracing.enabled']
55
+ intrinsics[SAMPLED_KEY] = payload[:'sampled'] if Agent.config[:'distributed_tracing.enabled']
54
56
 
55
57
  NewRelic::Agent::PayloadMetricMapping.append_mapped_metrics(payload[:metrics], intrinsics)
56
58
  append_optional_attributes(intrinsics, payload)
@@ -22,14 +22,12 @@ module NewRelic
22
22
  def record payload
23
23
  return unless NewRelic::Agent.config[:'analytics_events.enabled']
24
24
 
25
- if sampled_event? payload
26
- transaction_event_aggregator.append_sampled { create_event(payload) }
27
- elsif synthetics_event? payload
25
+ if synthetics_event? payload
28
26
  event = create_event payload
29
27
  _, rejected = synthetics_event_aggregator.append_or_reject event
30
- transaction_event_aggregator.append event if rejected
28
+ transaction_event_aggregator.append event: event if rejected
31
29
  else
32
- transaction_event_aggregator.append { create_event(payload) }
30
+ transaction_event_aggregator.append(priority: payload[:priority]) { create_event(payload) }
33
31
  end
34
32
  end
35
33
 
@@ -41,12 +39,6 @@ module NewRelic
41
39
  payload.key? :synthetics_resource_id
42
40
  end
43
41
 
44
- SAMPLED_KEY = 'nr.sampled'
45
-
46
- def sampled_event? payload
47
- !!payload[SAMPLED_KEY]
48
- end
49
-
50
42
  def drop_buffered_data
51
43
  transaction_event_aggregator.reset!
52
44
  synthetics_event_aggregator.reset!