newrelic_rpm 6.7.0.359 → 6.8.0.360

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +41 -6
  4. data/CHANGELOG.md +76 -0
  5. data/Guardfile +7 -1
  6. data/lib/new_relic/agent.rb +31 -0
  7. data/lib/new_relic/agent/agent.rb +7 -2
  8. data/lib/new_relic/agent/agent_logger.rb +4 -0
  9. data/lib/new_relic/agent/attribute_filter.rb +7 -7
  10. data/lib/new_relic/agent/attributes.rb +152 -0
  11. data/lib/new_relic/agent/autostart.rb +19 -14
  12. data/lib/new_relic/agent/configuration/default_source.rb +72 -5
  13. data/lib/new_relic/agent/configuration/yaml_source.rb +10 -5
  14. data/lib/new_relic/agent/connect/request_builder.rb +3 -11
  15. data/lib/new_relic/agent/datastores/mongo/event_formatter.rb +2 -2
  16. data/lib/new_relic/agent/datastores/mongo/obfuscator.rb +8 -8
  17. data/lib/new_relic/agent/distributed_trace_intrinsics.rb +90 -0
  18. data/lib/new_relic/agent/distributed_trace_metrics.rb +74 -0
  19. data/lib/new_relic/agent/distributed_trace_monitor.rb +2 -12
  20. data/lib/new_relic/agent/distributed_trace_payload.rb +9 -76
  21. data/lib/new_relic/agent/distributed_trace_transport_type.rb +43 -0
  22. data/lib/new_relic/agent/guid_generator.rb +28 -0
  23. data/lib/new_relic/agent/logging.rb +4 -0
  24. data/lib/new_relic/agent/new_relic_service.rb +7 -5
  25. data/lib/new_relic/agent/span_event_aggregator.rb +1 -0
  26. data/lib/new_relic/agent/span_event_primitive.rb +29 -7
  27. data/lib/new_relic/agent/sql_sampler.rb +1 -1
  28. data/lib/new_relic/agent/trace_context.rb +244 -0
  29. data/lib/new_relic/agent/trace_context_payload.rb +134 -0
  30. data/lib/new_relic/agent/trace_context_request_monitor.rb +42 -0
  31. data/lib/new_relic/agent/transaction.rb +26 -18
  32. data/lib/new_relic/agent/transaction/abstract_segment.rb +2 -2
  33. data/lib/new_relic/agent/transaction/distributed_tracing.rb +20 -101
  34. data/lib/new_relic/agent/transaction/external_request_segment.rb +18 -5
  35. data/lib/new_relic/agent/transaction/segment.rb +7 -1
  36. data/lib/new_relic/agent/transaction/trace_context.rb +159 -0
  37. data/lib/new_relic/agent/transaction/trace_node.rb +8 -3
  38. data/lib/new_relic/agent/transaction_error_primitive.rb +4 -11
  39. data/lib/new_relic/agent/transaction_event_primitive.rb +3 -11
  40. data/lib/new_relic/coerce.rb +29 -6
  41. data/lib/new_relic/control/instance_methods.rb +10 -1
  42. data/lib/new_relic/dependency_detection.rb +4 -4
  43. data/lib/new_relic/noticed_error.rb +8 -4
  44. data/lib/new_relic/version.rb +1 -1
  45. data/newrelic_rpm.gemspec +6 -4
  46. data/test/agent_helper.rb +88 -9
  47. data/true +0 -0
  48. metadata +50 -18
  49. data/lib/new_relic/agent/transaction/attributes.rb +0 -154
  50. data/lib/tasks/versions.html.erb +0 -28
  51. data/lib/tasks/versions.postface.html +0 -8
  52. data/lib/tasks/versions.preface.html +0 -9
  53. data/lib/tasks/versions.rake +0 -65
  54. data/lib/tasks/versions.txt.erb +0 -14
@@ -52,8 +52,7 @@ module NewRelic
52
52
 
53
53
  return unless record_metrics?
54
54
 
55
- insert_cross_app_header request
56
- insert_distributed_trace_header request
55
+ insert_context_propagation_headers request
57
56
  rescue => e
58
57
  NewRelic::Agent.logger.error "Error in add_request_headers", e
59
58
  end
@@ -200,9 +199,20 @@ module NewRelic
200
199
  end
201
200
  end
202
201
 
203
- def insert_cross_app_header request
204
- return unless CrossAppTracing.cross_app_enabled?
202
+ def insert_context_propagation_headers request
203
+ return unless transaction
204
+
205
+ if transaction.trace_context_enabled?
206
+ insert_trace_context_headers request
207
+ elsif transaction.nr_distributed_tracing_enabled?
208
+ insert_distributed_trace_header request
209
+ elsif CrossAppTracing.cross_app_enabled?
210
+ insert_cross_app_header request
211
+ end
212
+ end
205
213
 
214
+
215
+ def insert_cross_app_header request
206
216
  transaction.is_cross_app_caller = true
207
217
  txn_guid = transaction.guid
208
218
  trip_id = transaction && transaction.cat_trip_id
@@ -214,11 +224,14 @@ module NewRelic
214
224
  NEWRELIC_TRACE_HEADER = "newrelic".freeze
215
225
 
216
226
  def insert_distributed_trace_header request
217
- return unless Agent.config[:'distributed_tracing.enabled']
218
227
  payload = transaction.create_distributed_trace_payload
219
228
  request[NEWRELIC_TRACE_HEADER] = payload.http_safe if payload
220
229
  end
221
230
 
231
+ def insert_trace_context_headers request
232
+ transaction.insert_trace_context carrier: request
233
+ end
234
+
222
235
  EXTERNAL_ALL = "External/all".freeze
223
236
 
224
237
  def add_unscoped_metrics
@@ -4,6 +4,7 @@
4
4
 
5
5
  require 'new_relic/agent/transaction/abstract_segment'
6
6
  require 'new_relic/agent/span_event_primitive'
7
+ require 'new_relic/agent/attributes'
7
8
 
8
9
  module NewRelic
9
10
  module Agent
@@ -12,13 +13,18 @@ module NewRelic
12
13
  # unscoped_metrics can be nil, a string, or array. we do this to save
13
14
  # object allocations. if allocations weren't important then we would
14
15
  # initialize it as an array that would be empty, have one item, or many items.
15
- attr_reader :unscoped_metrics
16
+ attr_reader :unscoped_metrics, :attributes
16
17
 
17
18
  def initialize name=nil, unscoped_metrics=nil, start_time=nil
18
19
  @unscoped_metrics = unscoped_metrics
20
+ @attributes = Attributes.new(NewRelic::Agent.instance.attribute_filter)
19
21
  super name, start_time
20
22
  end
21
23
 
24
+ def add_custom_attributes(p)
25
+ attributes.merge_custom_attributes(p)
26
+ end
27
+
22
28
  private
23
29
 
24
30
  def record_metrics
@@ -0,0 +1,159 @@
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
+ require 'new_relic/agent/trace_context'
5
+ require 'new_relic/agent/distributed_trace_payload'
6
+ require 'new_relic/agent/distributed_trace_intrinsics'
7
+ require 'new_relic/agent/distributed_trace_metrics'
8
+
9
+ module NewRelic
10
+ module Agent
11
+ class Transaction
12
+ attr_accessor :trace_context_header_data
13
+ attr_reader :trace_state_payload
14
+
15
+ module TraceContext
16
+ EMPTY_STRING = ''.freeze
17
+ SUPPORTABILITY_PREFIX = "Supportability/TraceContext".freeze
18
+ CREATE_PREFIX = "#{SUPPORTABILITY_PREFIX}/Create".freeze
19
+ ACCEPT_PREFIX = "#{SUPPORTABILITY_PREFIX}/Accept".freeze
20
+ TRACESTATE_PREFIX = "#{SUPPORTABILITY_PREFIX}/TraceState".freeze
21
+
22
+ CREATE_SUCCESS_METRIC = "#{CREATE_PREFIX}/Success".freeze
23
+ CREATE_EXCEPTION_METRIC = "#{CREATE_PREFIX}/Exception".freeze
24
+
25
+ ACCEPT_SUCCESS_METRIC = "#{ACCEPT_PREFIX}/Success".freeze
26
+ ACCEPT_EXCEPTION_METRIC = "#{ACCEPT_PREFIX}/Exception".freeze
27
+ IGNORE_MULTIPLE_ACCEPT_METRIC = "#{ACCEPT_PREFIX}/Ignored/Multiple".freeze
28
+ IGNORE_ACCEPT_AFTER_CREATE_METRIC = "#{ACCEPT_PREFIX}/Ignored/CreateBeforeAccept".freeze
29
+
30
+ NO_NR_ENTRY_TRACESTATE_METRIC = "#{TRACESTATE_PREFIX}/NoNrEntry".freeze
31
+ INVALID_TRACESTATE_PAYLOAD_METRIC = "#{TRACESTATE_PREFIX}/InvalidPayload".freeze
32
+
33
+ def insert_trace_context \
34
+ format: NewRelic::Agent::TraceContext::FORMAT_HTTP,
35
+ carrier: nil
36
+
37
+ return unless trace_context_enabled?
38
+ NewRelic::Agent::TraceContext.insert \
39
+ format: format,
40
+ carrier: carrier,
41
+ trace_id: trace_id,
42
+ parent_id: current_segment.guid,
43
+ trace_flags: sampled? ? 0x1 : 0x0,
44
+ trace_state: create_trace_state
45
+ @trace_context_inserted = true
46
+ NewRelic::Agent.increment_metric CREATE_SUCCESS_METRIC
47
+ true
48
+ rescue Exception => e
49
+ NewRelic::Agent.increment_metric CREATE_EXCEPTION_METRIC
50
+ NewRelic::Agent.logger.warn "Failed to create trace context payload", e
51
+ false
52
+ end
53
+
54
+ def create_trace_state
55
+ entry_key = NewRelic::Agent::TraceContext::AccountHelpers.trace_state_entry_key
56
+ payload = create_trace_state_payload
57
+
58
+ if payload
59
+ entry = NewRelic::Agent::TraceContext.create_trace_state_entry \
60
+ entry_key,
61
+ payload.to_s
62
+ else
63
+ entry = EMPTY_STRING
64
+ end
65
+
66
+ trace_context_header_data ? trace_context_header_data.trace_state(entry) : entry
67
+ end
68
+
69
+ def create_trace_state_payload
70
+ unless trace_context_enabled?
71
+ NewRelic::Agent.logger.warn "Not configured to create WC3 trace context payload"
72
+ return
73
+ end
74
+
75
+ if Agent.config[:'span_events.enabled']
76
+ TraceContextPayload.create \
77
+ parent_account_id: Agent.config[:account_id],
78
+ parent_app_id: Agent.config[:primary_application_id],
79
+ transaction_id: guid,
80
+ sampled: sampled?,
81
+ priority: priority,
82
+ id: current_segment.guid
83
+ elsif trace_context_header_data
84
+ trace_context_header_data.trace_state_payload
85
+ end
86
+ end
87
+
88
+ def assign_trace_state_payload
89
+ payload = @trace_context_header_data.trace_state_payload
90
+ unless payload
91
+ NewRelic::Agent.increment_metric NO_NR_ENTRY_TRACESTATE_METRIC
92
+ return false
93
+ end
94
+ unless payload.valid?
95
+ NewRelic::Agent.increment_metric INVALID_TRACESTATE_PAYLOAD_METRIC
96
+ return false
97
+ end
98
+ @trace_state_payload = payload
99
+ end
100
+
101
+ def accept_trace_context trace_context_header_data
102
+ unless trace_context_enabled?
103
+ NewRelic::Agent.logger.warn "Not configured to accept WC3 trace context payload"
104
+ return false
105
+ end
106
+ return false if ignore_trace_context?
107
+
108
+ @trace_context_header_data = trace_context_header_data
109
+ @trace_id = @trace_context_header_data.trace_id
110
+ @parent_span_id = @trace_context_header_data.parent_id
111
+
112
+ return false unless payload = assign_trace_state_payload
113
+
114
+ @parent_transaction_id = payload.transaction_id
115
+
116
+ unless payload.sampled.nil?
117
+ self.sampled = payload.sampled
118
+ self.priority = payload.priority if payload.priority
119
+ end
120
+ NewRelic::Agent.increment_metric ACCEPT_SUCCESS_METRIC
121
+ true
122
+ rescue => e
123
+ NewRelic::Agent.increment_metric ACCEPT_EXCEPTION_METRIC
124
+ NewRelic::Agent.logger.warn "Failed to accept trace context payload", e
125
+ false
126
+ end
127
+
128
+ def append_trace_context_info transaction_payload
129
+ return unless trace_context_enabled?
130
+ DistributedTraceIntrinsics.copy_from_transaction \
131
+ self,
132
+ trace_state_payload,
133
+ transaction_payload
134
+ end
135
+
136
+ def ignore_trace_context?
137
+ if trace_context_header_data
138
+ NewRelic::Agent.increment_metric IGNORE_MULTIPLE_ACCEPT_METRIC
139
+ return true
140
+ elsif trace_context_inserted?
141
+ NewRelic::Agent.increment_metric IGNORE_ACCEPT_AFTER_CREATE_METRIC
142
+ return true
143
+ end
144
+ false
145
+ end
146
+ end
147
+
148
+ def trace_context_inserted?
149
+ @trace_context_inserted ||= false
150
+ end
151
+
152
+ W3C_FORMAT = "w3c".freeze
153
+
154
+ def trace_context_enabled?
155
+ Agent.config[:'distributed_tracing.enabled'] && (Agent.config[:'distributed_tracing.format'] == W3C_FORMAT) && Agent.instance.connected?
156
+ end
157
+ end
158
+ end
159
+ end
@@ -22,12 +22,17 @@ module NewRelic
22
22
  @metric_name = metric_name || UNKNOWN_NODE_NAME
23
23
  @exit_timestamp = relative_end
24
24
  @children = nil
25
- @params = params.select do |p|
26
- NewRelic::Agent.instance.attribute_filter.allows_key? p, AttributeFilter::DST_TRANSACTION_SEGMENTS
27
- end if params
25
+ @params = select_allowed_params(params)
28
26
  @parent_node = parent
29
27
  end
30
28
 
29
+ def select_allowed_params params
30
+ return unless params
31
+ params.select do |p|
32
+ NewRelic::Agent.instance.attribute_filter.allows_key? p, AttributeFilter::DST_TRANSACTION_SEGMENTS
33
+ end
34
+ end
35
+
31
36
  # sets the final timestamp on a node to indicate the exit
32
37
  # point of the node
33
38
  def end_trace(timestamp)
@@ -9,6 +9,7 @@
9
9
 
10
10
  require 'new_relic/agent/payload_metric_mapping'
11
11
  require 'new_relic/agent/distributed_trace_payload'
12
+ require 'new_relic/agent/distributed_trace_intrinsics'
12
13
 
13
14
  module NewRelic
14
15
  module Agent
@@ -54,11 +55,11 @@ module NewRelic
54
55
  if payload
55
56
  attrs[NAME_KEY] = payload[:name]
56
57
  attrs[DURATION_KEY] = payload[:duration]
57
- attrs[SAMPLED_KEY] = payload[:'sampled'] if Agent.config[:'distributed_tracing.enabled']
58
- attrs[PRIORITY_KEY] = payload[:'priority']
58
+ attrs[SAMPLED_KEY] = payload[:sampled] if payload.key?(:sampled)
59
+ attrs[PRIORITY_KEY] = payload[:priority]
59
60
  append_synthetics payload, attrs
60
61
  append_cat payload, attrs
61
- append_distributed_trace_intrinsics payload, attrs
62
+ DistributedTraceIntrinsics.copy_to_hash payload, attrs
62
63
  PayloadMetricMapping.append_mapped_metrics payload[:metrics], attrs
63
64
  end
64
65
 
@@ -75,14 +76,6 @@ module NewRelic
75
76
  sample[GUID_KEY] = payload[:guid] if payload[:guid]
76
77
  sample[REFERRING_TRANSACTION_GUID_KEY] = payload[:referring_transaction_guid] if payload[:referring_transaction_guid]
77
78
  end
78
-
79
- def append_distributed_trace_intrinsics payload, sample
80
- return unless Agent.config[:'distributed_tracing.enabled']
81
- DistributedTracePayload::INTRINSIC_KEYS.each do |key|
82
- value = payload[key]
83
- sample[key] = value unless value.nil?
84
- end
85
- end
86
79
  end
87
80
  end
88
81
  end
@@ -8,7 +8,7 @@
8
8
  # the transaction event aggregator and the synthetics container.
9
9
 
10
10
  require 'new_relic/agent/payload_metric_mapping'
11
- require 'new_relic/agent/distributed_trace_payload'
11
+ require 'new_relic/agent/distributed_trace_intrinsics'
12
12
 
13
13
  module NewRelic
14
14
  module Agent
@@ -51,11 +51,11 @@ module NewRelic
51
51
  PRIORITY_KEY => payload[:priority]
52
52
  }
53
53
 
54
- intrinsics[SAMPLED_KEY] = payload[:'sampled'] if Agent.config[:'distributed_tracing.enabled']
54
+ intrinsics[SAMPLED_KEY] = payload[:sampled] if payload.key?(:sampled)
55
55
 
56
56
  NewRelic::Agent::PayloadMetricMapping.append_mapped_metrics(payload[:metrics], intrinsics)
57
57
  append_optional_attributes(intrinsics, payload)
58
- append_distributed_trace_intrinsics(intrinsics, payload)
58
+ DistributedTraceIntrinsics.copy_to_hash payload, intrinsics
59
59
 
60
60
  attributes = payload[:attributes]
61
61
 
@@ -84,14 +84,6 @@ module NewRelic
84
84
  end
85
85
  end
86
86
 
87
- def append_distributed_trace_intrinsics(sample, payload)
88
- return unless Agent.config[:'distributed_tracing.enabled']
89
- DistributedTracePayload::INTRINSIC_KEYS.each do |key|
90
- value = payload[key]
91
- sample[key] = value unless value.nil?
92
- end
93
- end
94
-
95
87
  def optionally_append(sample_key, payload_key, sample, payload)
96
88
  if payload.include?(payload_key)
97
89
  sample[sample_key] = string(payload[payload_key])
@@ -3,15 +3,16 @@
3
3
  # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
4
 
5
5
  module NewRelic
6
- # We really don't want to send bad values to the collector, and it doesn't
7
- # accept types like Rational that have occasionally slipped into our data.
8
- #
9
- # These methods are intended to safely coerce things into the form we want,
10
- # to provide documentation of expected types on to_collector_array methods,
11
- # and to log failures if totally invalid data gets into outgoing data
12
6
  module Coerce
13
7
  module_function
14
8
 
9
+ # We really don't want to send bad values to the collector, and it doesn't
10
+ # accept types like Rational that have occasionally slipped into our data.
11
+ #
12
+ # These non-bang methods are intended to safely coerce things into the form we want,
13
+ # to provide documentation of expected types on to_collector_array methods,
14
+ # and to log failures if totally invalid data gets into outgoing data
15
+
15
16
  def int(value, context=nil)
16
17
  Integer(value)
17
18
  rescue => error
@@ -61,6 +62,28 @@ module NewRelic
61
62
  end
62
63
  end
63
64
 
65
+ def int! value
66
+ return nil unless value_or_nil(value)
67
+ Integer(value)
68
+ end
69
+
70
+ # Use when you plan to perform a boolean check using the integer 1
71
+ # for true and the integer 0 for false
72
+ # String values will be converted to 0
73
+ def boolean_int! value
74
+ value.to_i
75
+ end
76
+
77
+ def float! value
78
+ return nil unless value_or_nil(value)
79
+ value.to_f
80
+ end
81
+
82
+ def value_or_nil value
83
+ return nil if value.nil? || value.empty?
84
+ value
85
+ end
86
+
64
87
  def log_failure(value, type, context, error)
65
88
  msg = "Unable to convert '#{value}' to #{type}"
66
89
  msg += " in context '#{context}'" if context
@@ -101,7 +101,13 @@ module NewRelic
101
101
  Agent.config.replace_or_add_config(manual)
102
102
 
103
103
  config_file_path = @config_file_override || Agent.config[:config_path]
104
- Agent.config.replace_or_add_config(Agent::Configuration::YamlSource.new(config_file_path, env))
104
+ yaml_source = Agent::Configuration::YamlSource.new(config_file_path, env)
105
+ if yaml_source.failed?
106
+ yaml_source.failures.each do |msg|
107
+ stdout.puts Agent::AgentLogger.format_fatal_error(msg)
108
+ end
109
+ end
110
+ Agent.config.replace_or_add_config(yaml_source)
105
111
 
106
112
  if security_settings_valid? && Agent.config[:high_security]
107
113
  Agent.logger.info("Installing high security configuration based on local configuration")
@@ -172,6 +178,9 @@ module NewRelic
172
178
  '.'
173
179
  end
174
180
 
181
+ def stdout
182
+ STDOUT
183
+ end
175
184
  end
176
185
  include InstanceMethods
177
186
  end
@@ -93,8 +93,8 @@ module DependencyDetection
93
93
  end
94
94
  end
95
95
 
96
- def depends_on
97
- @dependencies << Proc.new
96
+ def depends_on &block
97
+ @dependencies << block if block_given?
98
98
  end
99
99
 
100
100
  def allowed_by_config?
@@ -114,8 +114,8 @@ module DependencyDetection
114
114
  self.name = new_name
115
115
  end
116
116
 
117
- def executes
118
- @executes << Proc.new
117
+ def executes &block
118
+ @executes << block if block_given?
119
119
  end
120
120
  end
121
121
  end
@@ -39,7 +39,7 @@ class NewRelic::NoticedError
39
39
 
40
40
  # replace error message if enabled
41
41
  if NewRelic::Agent.config[:'strip_exception_messages.enabled'] &&
42
- !self.class.passes_message_whitelist(exception.class)
42
+ !self.class.passes_message_allowlist(exception.class)
43
43
  @message = STRIPPED_EXCEPTION_REPLACEMENT_MESSAGE
44
44
  end
45
45
 
@@ -57,8 +57,12 @@ class NewRelic::NoticedError
57
57
  end
58
58
  end
59
59
 
60
- def self.passes_message_whitelist(exception_class)
61
- NewRelic::Agent.config[:'strip_exception_messages.whitelist'].any? do |klass|
60
+ def self.passes_message_allowlist(exception_class)
61
+ # For backwards compatibility until we remove :'strip_exception_messages.whitelist' config option
62
+
63
+ allowed = NewRelic::Agent.config[:'strip_exception_messages.allowed_classes'].concat(NewRelic::Agent.config[:'strip_exception_messages.whitelist'])
64
+
65
+ allowed.any? do |klass|
62
66
  exception_class <= klass
63
67
  end
64
68
  end
@@ -87,7 +91,7 @@ class NewRelic::NoticedError
87
91
  def processed_attributes
88
92
  @processed_attributes ||= begin
89
93
  attributes = base_parameters
90
- merged_attributes = NewRelic::Agent::Transaction::Attributes.new(NewRelic::Agent.instance.attribute_filter)
94
+ merged_attributes = NewRelic::Agent::Attributes.new(NewRelic::Agent.instance.attribute_filter)
91
95
  append_attributes(attributes, USER_ATTRIBUTES, merged_custom_attributes(merged_attributes))
92
96
  append_attributes(attributes, AGENT_ATTRIBUTES, build_agent_attributes(merged_attributes))
93
97
  append_attributes(attributes, INTRINSIC_ATTRIBUTES, build_intrinsic_attributes)