newrelic_rpm 5.2.0.345 → 5.3.0.346

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +1 -0
  4. data/.yardopts +3 -1
  5. data/CHANGELOG.md +31 -6
  6. data/lib/new_relic/agent/adaptive_sampler.rb +49 -13
  7. data/lib/new_relic/agent/agent.rb +14 -5
  8. data/lib/new_relic/agent/configuration/default_source.rb +54 -2
  9. data/lib/new_relic/agent/configuration/server_source.rb +6 -1
  10. data/lib/new_relic/agent/cross_app_tracing.rb +3 -1
  11. data/lib/new_relic/agent/database.rb +14 -0
  12. data/lib/new_relic/agent/distributed_trace_monitor.rb +14 -4
  13. data/lib/new_relic/agent/distributed_trace_payload.rb +104 -47
  14. data/lib/new_relic/agent/distributed_tracing.rb +67 -0
  15. data/lib/new_relic/agent/error_event_aggregator.rb +1 -1
  16. data/lib/new_relic/agent/event_aggregator.rb +25 -0
  17. data/lib/new_relic/agent/external.rb +7 -14
  18. data/lib/new_relic/agent/messaging.rb +26 -13
  19. data/lib/new_relic/agent/new_relic_service.rb +7 -0
  20. data/lib/new_relic/agent/span_event_aggregator.rb +51 -0
  21. data/lib/new_relic/agent/span_event_primitive.rb +144 -0
  22. data/lib/new_relic/agent/sql_sampler.rb +19 -3
  23. data/lib/new_relic/agent/transaction.rb +21 -17
  24. data/lib/new_relic/agent/transaction/abstract_segment.rb +4 -2
  25. data/lib/new_relic/agent/transaction/datastore_segment.rb +26 -0
  26. data/lib/new_relic/agent/transaction/distributed_tracing.rb +47 -23
  27. data/lib/new_relic/agent/transaction/external_request_segment.rb +11 -2
  28. data/lib/new_relic/agent/transaction/message_broker_segment.rb +2 -2
  29. data/lib/new_relic/agent/transaction/segment.rb +14 -0
  30. data/lib/new_relic/agent/transaction/trace.rb +1 -10
  31. data/lib/new_relic/agent/transaction_event_primitive.rb +0 -2
  32. data/lib/new_relic/version.rb +1 -1
  33. metadata +5 -2
@@ -57,9 +57,7 @@ module NewRelic
57
57
  :process_cpu_start,
58
58
  :http_response_code,
59
59
  :response_content_length,
60
- :response_content_type,
61
- :sampled,
62
- :priority
60
+ :response_content_type
63
61
 
64
62
  attr_reader :guid,
65
63
  :metrics,
@@ -73,6 +71,9 @@ module NewRelic
73
71
  :segments,
74
72
  :end_time
75
73
 
74
+ attr_writer :sampled,
75
+ :priority
76
+
76
77
  # Populated with the trace sample once this transaction is completed.
77
78
  attr_reader :transaction_trace
78
79
 
@@ -283,15 +284,8 @@ module NewRelic
283
284
  @ignore_enduser = options.fetch(:ignore_enduser, false)
284
285
  @ignore_trace = false
285
286
 
286
- if Agent.config[:'distributed_tracing.enabled']
287
- @sampled = NewRelic::Agent.instance.adaptive_sampler.sampled?
288
- else
289
- @sampled = nil
290
- end
291
-
292
- # we will eventually add this behavior into the AdaptiveSampler (ThroughputMontor)
293
- @priority = rand
294
- @priority +=1 if @sampled
287
+ @sampled = nil
288
+ @priority = nil
295
289
 
296
290
  @attributes = Attributes.new(NewRelic::Agent.instance.attribute_filter)
297
291
 
@@ -305,9 +299,21 @@ module NewRelic
305
299
  end
306
300
 
307
301
  def sampled?
302
+ return unless Agent.config[:'distributed_tracing.enabled']
303
+ if @sampled.nil?
304
+ @sampled = NewRelic::Agent.instance.adaptive_sampler.sampled?
305
+ end
308
306
  @sampled
309
307
  end
310
308
 
309
+ def priority
310
+ if @priority.nil?
311
+ @priority = rand.round(6)
312
+ @priority += 1 if sampled?
313
+ end
314
+ @priority
315
+ end
316
+
311
317
  def referer
312
318
  @request_attributes && @request_attributes.referer
313
319
  end
@@ -602,7 +608,7 @@ module NewRelic
602
608
  end
603
609
 
604
610
  def assign_intrinsics(state)
605
- attributes.add_intrinsic_attribute :'sampled', sampled?
611
+ attributes.add_intrinsic_attribute(:priority, priority)
606
612
 
607
613
  if gc_time = calculate_gc_time
608
614
  attributes.add_intrinsic_attribute(:gc_time, gc_time)
@@ -618,7 +624,7 @@ module NewRelic
618
624
  attributes.add_intrinsic_attribute(:synthetics_monitor_id, synthetics_monitor_id)
619
625
  end
620
626
 
621
- if distributed_trace_payload || distributed_trace_payload_created?
627
+ if Agent.config[:'distributed_tracing.enabled']
622
628
  assign_distributed_trace_intrinsics
623
629
  elsif state.is_cross_app?
624
630
  attributes.add_intrinsic_attribute(:trip_id, cat_trip_id)
@@ -655,11 +661,9 @@ module NewRelic
655
661
  :metrics => @metrics,
656
662
  :attributes => @attributes,
657
663
  :error => false,
658
- :priority => @priority
664
+ :priority => priority
659
665
  }
660
666
 
661
- @payload[:'sampled'] = sampled? if Agent.config[:'distributed_tracing.enabled']
662
-
663
667
  append_cat_info(state, duration, @payload)
664
668
  append_distributed_trace_info(@payload)
665
669
  append_apdex_perf_zone(duration, @payload)
@@ -3,6 +3,7 @@
3
3
  # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
4
 
5
5
  require 'new_relic/agent/range_extensions'
6
+ require 'securerandom'
6
7
 
7
8
  module NewRelic
8
9
  module Agent
@@ -16,16 +17,17 @@ module NewRelic
16
17
  # a segments children time. The reason for this is that computing
17
18
  # exclusive duration using time ranges is expensive and it's only
18
19
  # necessary if a segment's children run concurrently, or a segment ends
19
- # after it's parent. We will use the optimized exclusive duration
20
+ # after its parent. We will use the optimized exclusive duration
20
21
  # calculation in all other cases.
21
22
  #
22
- attr_reader :start_time, :end_time, :duration, :exclusive_duration
23
+ attr_reader :start_time, :end_time, :duration, :exclusive_duration, :guid
23
24
  attr_accessor :name, :parent, :children_time, :transaction
24
25
  attr_writer :record_metrics, :record_scoped_metric, :record_on_finish
25
26
 
26
27
  def initialize name=nil, start_time=nil
27
28
  @name = name
28
29
  @transaction = nil
30
+ @guid = SecureRandom.hex(8)
29
31
  @parent = nil
30
32
  @params = nil
31
33
  @start_time = start_time if start_time
@@ -67,6 +67,23 @@ module NewRelic
67
67
  @sql_statement = Database::Statement.new sql, config, explainer, binds, name, host, port_path_or_id, database_name
68
68
  end
69
69
 
70
+ # Method for simplifying attaching non-SQL data statements to a
71
+ # transaction. For instance, Mongo or CQL queries, Memcached or Redis
72
+ # keys would all be appropriate data to attach as statements.
73
+ #
74
+ # Data passed to this method is NOT obfuscated by New Relic, so please
75
+ # ensure that user information is obfuscated if the agent setting
76
+ # `transaction_tracer.record_sql` is set to `obfuscated`
77
+ #
78
+ # @param [String] nosql_statement text of the statement to capture.
79
+ #
80
+ # @note THERE ARE SECURITY CONCERNS WHEN CAPTURING STATEMENTS!
81
+ # This method will properly ignore statements when the user has turned
82
+ # off capturing queries, but it is not able to obfuscate arbitrary data!
83
+ # To prevent exposing user information embedded in captured queries,
84
+ # please ensure all data passed to this method is safe to transmit to
85
+ # New Relic.
86
+
70
87
  def notice_nosql_statement nosql_statement
71
88
  return unless record_sql?
72
89
  @nosql_statement = Database.truncate_query(nosql_statement)
@@ -120,6 +137,15 @@ module NewRelic
120
137
  def record_sql?
121
138
  transaction_state.is_sql_recorded?
122
139
  end
140
+
141
+ def record_span_event
142
+ aggregator = ::NewRelic::Agent.agent.span_event_aggregator
143
+ priority = transaction.priority
144
+
145
+ aggregator.record(priority: priority) do
146
+ SpanEventPrimitive.for_datastore_segment(self)
147
+ end
148
+ end
123
149
  end
124
150
  end
125
151
  end
@@ -35,7 +35,9 @@ module NewRelic
35
35
  def accept_distributed_trace_payload payload
36
36
  return unless Agent.config[:'distributed_tracing.enabled']
37
37
  return false if check_payload_ignored(payload)
38
+ return false unless check_payload_present(payload)
38
39
  return false unless payload = decode_payload(payload)
40
+ return false unless check_required_fields_present(payload)
39
41
  return false unless check_valid_version(payload)
40
42
  return false unless check_trusted_account(payload)
41
43
 
@@ -61,14 +63,7 @@ module NewRelic
61
63
  # The payload comes from our parent transaction, so its ID
62
64
  # is our parent ID.
63
65
  #
64
- distributed_trace_payload && distributed_trace_payload.id
65
- end
66
-
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
66
+ distributed_trace_payload && distributed_trace_payload.transaction_id
72
67
  end
73
68
 
74
69
  def distributed_trace_payload_created?
@@ -81,16 +76,16 @@ module NewRelic
81
76
  return unless Agent.config[:'distributed_tracing.enabled']
82
77
  if distributed_trace_payload
83
78
  distributed_trace_payload.assign_intrinsics self, transaction_payload
84
- elsif distributed_trace_payload_created?
85
- DistributedTracePayload.assign_intrinsics_for_first_trace self, transaction_payload
79
+ else
80
+ DistributedTracePayload.assign_initial_intrinsics self, transaction_payload
86
81
  end
87
82
  end
88
83
 
89
84
  def assign_distributed_trace_intrinsics
90
85
  return unless Agent.config[:'distributed_tracing.enabled']
91
86
  DistributedTracePayload::INTRINSIC_KEYS.each do |key|
92
- next unless value = @payload[key]
93
- attributes.add_intrinsic_attribute key, value
87
+ next unless @payload.key? key
88
+ attributes.add_intrinsic_attribute key, @payload[key]
94
89
  end
95
90
  nil
96
91
  end
@@ -100,7 +95,8 @@ module NewRelic
100
95
  # for metrics and intrinsics.
101
96
  def transport_duration
102
97
  return unless distributed_trace_payload
103
- (start_time.to_f * 1000 - distributed_trace_payload.timestamp) / 1000
98
+ duration = (start_time.to_f * 1000 - distributed_trace_payload.timestamp) / 1000
99
+ duration < 0 ? 0 : duration
104
100
  end
105
101
 
106
102
  private
@@ -111,10 +107,7 @@ module NewRelic
111
107
  SUPPORTABILITY_PAYLOAD_ACCEPT_IGNORED_BROWSER = "Supportability/DistributedTrace/AcceptPayload/Ignored/BrowserAgentInjected".freeze
112
108
 
113
109
  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
110
+ if distributed_trace_payload
118
111
  NewRelic::Agent.increment_metric SUPPORTABILITY_MULTIPLE_ACCEPT_PAYLOAD
119
112
  return true
120
113
  elsif distributed_trace_payload_created?
@@ -124,21 +117,55 @@ module NewRelic
124
117
  false
125
118
  end
126
119
 
120
+ NULL_PAYLOAD = 'null'.freeze
121
+
122
+ def check_payload_present(payload)
123
+ # We might be passed a Ruby `nil` object _or_ the JSON "null"
124
+ if payload.nil? || payload == NULL_PAYLOAD
125
+ NewRelic::Agent.increment_metric SUPPORTABILITY_PAYLOAD_ACCEPT_IGNORED_NULL
126
+ return nil
127
+ end
128
+
129
+ payload
130
+ end
131
+
127
132
  SUPPORTABILITY_PAYLOAD_ACCEPT_IGNORED_PARSE_EXCEPTION = "Supportability/DistributedTrace/AcceptPayload/ParseException".freeze
128
133
  LBRACE = "{".freeze
129
134
 
130
135
  def decode_payload(payload)
131
- if payload.start_with? LBRACE
136
+ decoded = if payload.start_with? LBRACE
132
137
  DistributedTracePayload.from_json payload
133
138
  else
134
139
  DistributedTracePayload.from_http_safe payload
135
140
  end
141
+
142
+ return nil unless check_payload_present(decoded)
143
+
144
+ decoded
136
145
  rescue => e
137
146
  NewRelic::Agent.increment_metric SUPPORTABILITY_PAYLOAD_ACCEPT_IGNORED_PARSE_EXCEPTION
138
147
  NewRelic::Agent.logger.warn "Error parsing distributed trace payload", e
139
148
  nil
140
149
  end
141
150
 
151
+ def check_required_fields_present(payload)
152
+ if \
153
+ !payload.version.nil? &&
154
+ !payload.parent_account_id.nil? &&
155
+ !payload.parent_app_id.nil? &&
156
+ !payload.parent_type.nil? &&
157
+ (!payload.transaction_id.nil? || !payload.id.nil?) &&
158
+ !payload.trace_id.nil? &&
159
+ !payload.timestamp.nil? &&
160
+ !payload.parent_account_id.nil?
161
+
162
+ true
163
+ else
164
+ NewRelic::Agent.increment_metric SUPPORTABILITY_PAYLOAD_ACCEPT_IGNORED_PARSE_EXCEPTION
165
+ false
166
+ end
167
+ end
168
+
142
169
  SUPPORTABILITY_PAYLOAD_ACCEPT_IGNORED_MAJOR_VERSION = "Supportability/DistributedTrace/AcceptPayload/Ignored/MajorVersion".freeze
143
170
 
144
171
  def check_valid_version(payload)
@@ -153,14 +180,11 @@ module NewRelic
153
180
  SUPPORTABILITY_PAYLOAD_ACCEPT_UNTRUSTED_ACCOUNT = "Supportability/DistributedTrace/AcceptPayload/Ignored/UntrustedAccount".freeze
154
181
 
155
182
  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
183
+ compare_key = payload.trusted_account_key || payload.parent_account_id
184
+ unless compare_key == NewRelic::Agent.config[:trusted_account_key]
160
185
  NewRelic::Agent.increment_metric SUPPORTABILITY_PAYLOAD_ACCEPT_UNTRUSTED_ACCOUNT
161
186
  return false
162
187
  end
163
-
164
188
  true
165
189
  end
166
190
 
@@ -211,12 +211,12 @@ module NewRelic
211
211
  CrossAppTracing.insert_request_headers request, txn_guid, trip_id, path_hash
212
212
  end
213
213
 
214
- X_NEWRELIC_TRACE_HEADER = "X-NewRelic-Trace".freeze
214
+ NEWRELIC_TRACE_HEADER = "newrelic".freeze
215
215
 
216
216
  def insert_distributed_trace_header request
217
217
  return unless Agent.config[:'distributed_tracing.enabled']
218
218
  payload = transaction.create_distributed_trace_payload
219
- request[X_NEWRELIC_TRACE_HEADER] = payload.http_safe
219
+ request[NEWRELIC_TRACE_HEADER] = payload.http_safe if payload
220
220
  end
221
221
 
222
222
  EXTERNAL_ALL = "External/all".freeze
@@ -254,6 +254,15 @@ module NewRelic
254
254
  def obfuscator
255
255
  CrossAppTracing.obfuscator
256
256
  end
257
+
258
+ def record_span_event
259
+ aggregator = ::NewRelic::Agent.agent.span_event_aggregator
260
+ priority = transaction.priority
261
+
262
+ aggregator.record(priority: priority) do
263
+ SpanEventPrimitive.for_external_request_segment(self)
264
+ end
265
+ end
257
266
  end
258
267
  end
259
268
  end
@@ -89,12 +89,12 @@ module NewRelic
89
89
  @name
90
90
  end
91
91
 
92
- NEWRELIC_TRACE_KEY = "NewRelicTrace".freeze
92
+ NEWRELIC_TRACE_KEY = "newrelic".freeze
93
93
 
94
94
  def insert_distributed_trace_header
95
95
  return unless Agent.config[:'distributed_tracing.enabled']
96
96
  payload = transaction.create_distributed_trace_payload
97
- headers[NEWRELIC_TRACE_KEY] = payload.http_safe
97
+ headers[NEWRELIC_TRACE_KEY] = payload.http_safe if payload
98
98
  end
99
99
 
100
100
  def transaction= t
@@ -3,6 +3,7 @@
3
3
  # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
4
 
5
5
  require 'new_relic/agent/transaction/abstract_segment'
6
+ require 'new_relic/agent/span_event_primitive'
6
7
 
7
8
  module NewRelic
8
9
  module Agent
@@ -46,6 +47,19 @@ module NewRelic
46
47
  @unscoped_metrics = metric
47
48
  end
48
49
  end
50
+
51
+ def segment_complete
52
+ record_span_event if transaction.sampled?
53
+ end
54
+
55
+ def record_span_event
56
+ aggregator = ::NewRelic::Agent.agent.span_event_aggregator
57
+ priority = transaction.priority
58
+
59
+ aggregator.record(priority: priority) do
60
+ SpanEventPrimitive.for_segment(self)
61
+ end
62
+ end
49
63
  end
50
64
  end
51
65
  end
@@ -90,18 +90,9 @@ module NewRelic
90
90
  end
91
91
 
92
92
  def prepare_sql_for_transmission!
93
- strategy = NewRelic::Agent::Database.record_sql_method
94
93
  each_node do |node|
95
94
  next unless node[:sql]
96
-
97
- case strategy
98
- when :obfuscated
99
- node[:sql] = NewRelic::Agent::Database.obfuscate_sql(node[:sql])
100
- when :raw
101
- node[:sql] = node[:sql].sql.to_s
102
- else
103
- node[:sql] = nil
104
- end
95
+ node[:sql] = node[:sql].safe_sql
105
96
  end
106
97
  end
107
98
 
@@ -29,7 +29,6 @@ module NewRelic
29
29
  PRIORITY_KEY = 'priority'.freeze
30
30
  GUID_KEY = 'nr.guid'.freeze
31
31
  REFERRING_TRANSACTION_GUID_KEY = 'nr.referringTransactionGuid'.freeze
32
- CAT_TRIP_ID_KEY = 'nr.tripId'.freeze
33
32
  CAT_PATH_HASH_KEY = 'nr.pathHash'.freeze
34
33
  CAT_REFERRING_PATH_HASH_KEY = 'nr.referringPathHash'.freeze
35
34
  CAT_ALTERNATE_PATH_HASHES_KEY = 'nr.alternatePathHashes'.freeze
@@ -68,7 +67,6 @@ module NewRelic
68
67
  def append_optional_attributes(sample, payload)
69
68
  optionally_append(GUID_KEY, :guid, sample, payload)
70
69
  optionally_append(REFERRING_TRANSACTION_GUID_KEY, :referring_transaction_guid, sample, payload)
71
- optionally_append(CAT_TRIP_ID_KEY, :cat_trip_id, sample, payload)
72
70
  optionally_append(CAT_PATH_HASH_KEY, :cat_path_hash, sample, payload)
73
71
  optionally_append(CAT_REFERRING_PATH_HASH_KEY, :cat_referring_path_hash, sample, payload)
74
72
  optionally_append(APDEX_PERF_ZONE_KEY, :apdex_perf_zone, sample, payload)
@@ -11,7 +11,7 @@ module NewRelic
11
11
  end
12
12
 
13
13
  MAJOR = 5
14
- MINOR = 2
14
+ MINOR = 3
15
15
  TINY = 0
16
16
 
17
17
  begin
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: 5.2.0.345
4
+ version: 5.3.0.346
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Wear
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2018-05-23 00:00:00.000000000 Z
14
+ date: 2018-07-26 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: rake
@@ -239,6 +239,7 @@ files:
239
239
  - lib/new_relic/agent/deprecator.rb
240
240
  - lib/new_relic/agent/distributed_trace_monitor.rb
241
241
  - lib/new_relic/agent/distributed_trace_payload.rb
242
+ - lib/new_relic/agent/distributed_tracing.rb
242
243
  - lib/new_relic/agent/encoding_normalizer.rb
243
244
  - lib/new_relic/agent/error_collector.rb
244
245
  - lib/new_relic/agent/error_event_aggregator.rb
@@ -352,6 +353,8 @@ files:
352
353
  - lib/new_relic/agent/samplers/memory_sampler.rb
353
354
  - lib/new_relic/agent/samplers/object_sampler.rb
354
355
  - lib/new_relic/agent/samplers/vm_sampler.rb
356
+ - lib/new_relic/agent/span_event_aggregator.rb
357
+ - lib/new_relic/agent/span_event_primitive.rb
355
358
  - lib/new_relic/agent/sql_sampler.rb
356
359
  - lib/new_relic/agent/stats.rb
357
360
  - lib/new_relic/agent/stats_engine.rb