newrelic_rpm 6.6.0.358 → 6.11.0.365

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.travis.yml +81 -5
  4. data/CHANGELOG.md +262 -0
  5. data/Gemfile +6 -2
  6. data/Guardfile +18 -1
  7. data/LICENSE +1 -1
  8. data/Rakefile +2 -0
  9. data/lib/new_relic/agent.rb +89 -7
  10. data/lib/new_relic/agent/agent.rb +115 -58
  11. data/lib/new_relic/agent/agent_logger.rb +4 -0
  12. data/lib/new_relic/agent/attribute_filter.rb +7 -7
  13. data/lib/new_relic/agent/attributes.rb +150 -0
  14. data/lib/new_relic/agent/autostart.rb +19 -14
  15. data/lib/new_relic/agent/configuration/default_source.rb +154 -9
  16. data/lib/new_relic/agent/configuration/event_harvest_config.rb +11 -5
  17. data/lib/new_relic/agent/configuration/manager.rb +0 -8
  18. data/lib/new_relic/agent/configuration/server_source.rb +3 -2
  19. data/lib/new_relic/agent/configuration/yaml_source.rb +11 -6
  20. data/lib/new_relic/agent/connect/request_builder.rb +5 -13
  21. data/lib/new_relic/agent/database.rb +1 -2
  22. data/lib/new_relic/agent/database/obfuscation_helpers.rb +1 -1
  23. data/lib/new_relic/agent/datastores/mongo.rb +1 -1
  24. data/lib/new_relic/agent/datastores/mongo/event_formatter.rb +2 -2
  25. data/lib/new_relic/agent/datastores/mongo/obfuscator.rb +8 -8
  26. data/lib/new_relic/agent/distributed_tracing.rb +155 -6
  27. data/lib/new_relic/agent/{cross_app_payload.rb → distributed_tracing/cross_app_payload.rb} +2 -1
  28. data/lib/new_relic/agent/{cross_app_tracing.rb → distributed_tracing/cross_app_tracing.rb} +60 -45
  29. data/lib/new_relic/agent/distributed_tracing/distributed_trace_intrinsics.rb +80 -0
  30. data/lib/new_relic/agent/distributed_tracing/distributed_trace_metrics.rb +75 -0
  31. data/lib/new_relic/agent/{distributed_trace_payload.rb → distributed_tracing/distributed_trace_payload.rb} +24 -101
  32. data/lib/new_relic/agent/distributed_tracing/distributed_trace_transport_type.rb +39 -0
  33. data/lib/new_relic/agent/distributed_tracing/trace_context.rb +246 -0
  34. data/lib/new_relic/agent/distributed_tracing/trace_context_payload.rb +126 -0
  35. data/lib/new_relic/agent/error_collector.rb +33 -16
  36. data/lib/new_relic/agent/error_event_aggregator.rb +7 -5
  37. data/lib/new_relic/agent/external.rb +7 -7
  38. data/lib/new_relic/agent/guid_generator.rb +28 -0
  39. data/lib/new_relic/agent/hostname.rb +7 -1
  40. data/lib/new_relic/agent/http_clients/abstract.rb +82 -0
  41. data/lib/new_relic/agent/http_clients/curb_wrappers.rb +24 -19
  42. data/lib/new_relic/agent/http_clients/excon_wrappers.rb +28 -13
  43. data/lib/new_relic/agent/http_clients/http_rb_wrappers.rb +17 -21
  44. data/lib/new_relic/agent/http_clients/httpclient_wrappers.rb +10 -11
  45. data/lib/new_relic/agent/http_clients/net_http_wrappers.rb +16 -4
  46. data/lib/new_relic/agent/http_clients/typhoeus_wrappers.rb +4 -6
  47. data/lib/new_relic/agent/http_clients/uri_util.rb +3 -2
  48. data/lib/new_relic/agent/instrumentation/action_cable_subscriber.rb +5 -7
  49. data/lib/new_relic/agent/instrumentation/action_controller_subscriber.rb +4 -0
  50. data/lib/new_relic/agent/instrumentation/action_view_subscriber.rb +11 -2
  51. data/lib/new_relic/agent/instrumentation/active_record.rb +4 -2
  52. data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +7 -2
  53. data/lib/new_relic/agent/instrumentation/active_storage_subscriber.rb +8 -4
  54. data/lib/new_relic/agent/instrumentation/bunny.rb +45 -28
  55. data/lib/new_relic/agent/instrumentation/curb.rb +59 -18
  56. data/lib/new_relic/agent/instrumentation/data_mapper.rb +3 -1
  57. data/lib/new_relic/agent/instrumentation/excon.rb +1 -1
  58. data/lib/new_relic/agent/instrumentation/excon/connection.rb +6 -3
  59. data/lib/new_relic/agent/instrumentation/excon/middleware.rb +2 -1
  60. data/lib/new_relic/agent/instrumentation/grape.rb +5 -10
  61. data/lib/new_relic/agent/instrumentation/http.rb +6 -3
  62. data/lib/new_relic/agent/instrumentation/httpclient.rb +5 -3
  63. data/lib/new_relic/agent/instrumentation/memcache.rb +3 -1
  64. data/lib/new_relic/agent/instrumentation/memcache/dalli.rb +6 -2
  65. data/lib/new_relic/agent/instrumentation/mongo.rb +9 -3
  66. data/lib/new_relic/agent/instrumentation/mongodb_command_subscriber.rb +13 -0
  67. data/lib/new_relic/agent/instrumentation/net.rb +6 -3
  68. data/lib/new_relic/agent/instrumentation/notifications_subscriber.rb +25 -1
  69. data/lib/new_relic/agent/instrumentation/redis.rb +9 -3
  70. data/lib/new_relic/agent/instrumentation/resque.rb +3 -0
  71. data/lib/new_relic/agent/instrumentation/sidekiq.rb +47 -23
  72. data/lib/new_relic/agent/instrumentation/typhoeus.rb +23 -6
  73. data/lib/new_relic/agent/logging.rb +139 -0
  74. data/lib/new_relic/agent/messaging.rb +5 -73
  75. data/lib/new_relic/agent/method_tracer.rb +18 -6
  76. data/lib/new_relic/agent/method_tracer_helpers.rb +2 -2
  77. data/lib/new_relic/agent/monitors.rb +27 -0
  78. data/lib/new_relic/agent/monitors/cross_app_monitor.rb +110 -0
  79. data/lib/new_relic/agent/monitors/distributed_tracing_monitor.rb +27 -0
  80. data/lib/new_relic/agent/{inbound_request_monitor.rb → monitors/inbound_request_monitor.rb} +1 -1
  81. data/lib/new_relic/agent/{synthetics_monitor.rb → monitors/synthetics_monitor.rb} +2 -4
  82. data/lib/new_relic/agent/new_relic_service.rb +7 -6
  83. data/lib/new_relic/agent/noticible_error.rb +22 -0
  84. data/lib/new_relic/agent/span_event_aggregator.rb +1 -0
  85. data/lib/new_relic/agent/span_event_primitive.rb +86 -53
  86. data/lib/new_relic/agent/sql_sampler.rb +3 -3
  87. data/lib/new_relic/agent/supported_versions.rb +2 -2
  88. data/lib/new_relic/agent/system_info.rb +12 -3
  89. data/lib/new_relic/agent/tracer.rb +65 -18
  90. data/lib/new_relic/agent/transaction.rb +84 -79
  91. data/lib/new_relic/agent/transaction/abstract_segment.rb +28 -2
  92. data/lib/new_relic/agent/transaction/distributed_tracer.rb +171 -0
  93. data/lib/new_relic/agent/transaction/distributed_tracing.rb +57 -146
  94. data/lib/new_relic/agent/transaction/external_request_segment.rb +29 -36
  95. data/lib/new_relic/agent/transaction/message_broker_segment.rb +3 -11
  96. data/lib/new_relic/agent/transaction/segment.rb +7 -1
  97. data/lib/new_relic/agent/transaction/trace.rb +2 -4
  98. data/lib/new_relic/agent/transaction/trace_context.rb +168 -0
  99. data/lib/new_relic/agent/transaction/trace_node.rb +10 -8
  100. data/lib/new_relic/agent/transaction_error_primitive.rb +10 -15
  101. data/lib/new_relic/agent/transaction_event_primitive.rb +28 -39
  102. data/lib/new_relic/cli/commands/deployments.rb +1 -1
  103. data/lib/new_relic/cli/commands/install.rb +3 -2
  104. data/lib/new_relic/coerce.rb +31 -6
  105. data/lib/new_relic/constants.rb +38 -0
  106. data/lib/new_relic/control/instance_methods.rb +10 -1
  107. data/lib/new_relic/dependency_detection.rb +4 -4
  108. data/lib/new_relic/environment_report.rb +5 -1
  109. data/lib/new_relic/noticed_error.rb +38 -17
  110. data/lib/new_relic/rack/browser_monitoring.rb +5 -0
  111. data/lib/new_relic/supportability_helper.rb +14 -0
  112. data/lib/new_relic/version.rb +1 -1
  113. data/lib/tasks/multiverse.rb +25 -0
  114. data/lib/tasks/tests.rake +6 -1
  115. data/newrelic_rpm.gemspec +19 -8
  116. data/test/agent_helper.rb +323 -71
  117. metadata +100 -33
  118. data/lib/new_relic/agent/cross_app_monitor.rb +0 -110
  119. data/lib/new_relic/agent/distributed_trace_monitor.rb +0 -40
  120. data/lib/new_relic/agent/http_clients/abstract_request.rb +0 -31
  121. data/lib/new_relic/agent/transaction/attributes.rb +0 -154
  122. data/lib/tasks/versions.html.erb +0 -28
  123. data/lib/tasks/versions.postface.html +0 -8
  124. data/lib/tasks/versions.preface.html +0 -9
  125. data/lib/tasks/versions.rake +0 -65
  126. data/lib/tasks/versions.txt.erb +0 -14
@@ -12,7 +12,8 @@ module NewRelic
12
12
  EVENT_HARVEST_CONFIG_KEY_MAPPING = {
13
13
  :analytic_event_data => :'analytics_events.max_samples_stored',
14
14
  :custom_event_data => :'custom_insights_events.max_samples_stored',
15
- :error_event_data => :'error_collector.max_event_samples_stored'
15
+ :error_event_data => :'error_collector.max_event_samples_stored',
16
+ :span_event_data => :'span_events.max_samples_stored'
16
17
  }
17
18
 
18
19
  def from_config(config)
@@ -25,15 +26,20 @@ module NewRelic
25
26
  end
26
27
 
27
28
  def to_config_hash(connect_reply)
28
- config_hash = EVENT_HARVEST_CONFIG_KEY_MAPPING.inject({}) do
29
+ event_harvest_interval = connect_reply['event_harvest_config']['report_period_ms'] / 1000
30
+ config_hash = EVENT_HARVEST_CONFIG_KEY_MAPPING.inject({}) do
29
31
  |event_harvest_config, (connect_payload_key, config_key)|
30
- event_harvest_config[config_key] = connect_reply['event_harvest_config']['harvest_limits'][connect_payload_key.to_s]
32
+ if harvest_limit = connect_reply['event_harvest_config']['harvest_limits'][connect_payload_key.to_s]
33
+ event_harvest_config[config_key] = harvest_limit
34
+ report_period_key = :"event_report_period.#{connect_payload_key}"
35
+ event_harvest_config[report_period_key] = event_harvest_interval
36
+ end
31
37
  event_harvest_config
32
38
  end
33
- config_hash[:event_report_period] = connect_reply['event_harvest_config']['report_period_ms'] / 1000
39
+ config_hash[:event_report_period] = event_harvest_interval
34
40
  config_hash
35
41
  end
36
42
  end
37
43
  end
38
44
  end
39
- end
45
+ end
@@ -228,14 +228,6 @@ module NewRelic
228
228
  end
229
229
  end
230
230
 
231
- def app_names
232
- case NewRelic::Agent.config[:app_name]
233
- when Array then NewRelic::Agent.config[:app_name]
234
- when String then NewRelic::Agent.config[:app_name].split(';')
235
- else []
236
- end
237
- end
238
-
239
231
  MALFORMED_LABELS_WARNING = "Skipping malformed labels configuration"
240
232
  PARSING_LABELS_FAILURE = "Failure during parsing labels. Ignoring and carrying on with connect."
241
233
 
@@ -21,6 +21,7 @@ module NewRelic
21
21
  "cross_process_id",
22
22
  "data_report_period",
23
23
  "encoding_key",
24
+ "entity_guid",
24
25
  "error_beacon",
25
26
  "js_agent_file",
26
27
  "js_agent_loader",
@@ -69,7 +70,7 @@ module NewRelic
69
70
 
70
71
  def fix_transaction_threshold(merged_settings)
71
72
  # when value is "apdex_f" remove the config and defer to default
72
- if merged_settings['transaction_tracer.transaction_threshold'] =~ /apdex_f/i
73
+ if merged_settings['transaction_tracer.transaction_threshold'].to_s =~ /apdex_f/i
73
74
  merged_settings.delete('transaction_tracer.transaction_threshold')
74
75
  end
75
76
  end
@@ -78,6 +79,7 @@ module NewRelic
78
79
  :'analytics_events.max_samples_stored' => 'Supportability/EventHarvest/AnalyticEventData/HarvestLimit',
79
80
  :'custom_insights_events.max_samples_stored' => 'Supportability/EventHarvest/CustomEventData/HarvestLimit',
80
81
  :'error_collector.max_event_samples_stored'=> 'Supportability/EventHarvest/ErrorEventData/HarvestLimit',
82
+ :'span_events.max_samples_stored'=> 'Supportability/EventHarvest/SpanEventData/HarvestLimit',
81
83
  :event_report_period => 'Supportability/EventHarvest/ReportPeriod'
82
84
  }
83
85
 
@@ -100,7 +102,6 @@ module NewRelic
100
102
  || (event_harvest_config['report_period_ms'] / 1000) <= 0
101
103
  NewRelic::Agent.logger.warn "Invalid event harvest config found " \
102
104
  "in connect response; using default event report period."
103
- NewRelic::Agent.record_metric('Supportability/Agent/Collector/MissingEventHarvestConfig', 1)
104
105
  false
105
106
  else
106
107
  true
@@ -12,6 +12,7 @@ module NewRelic
12
12
  attr_reader :generated_for_user, :license_key
13
13
 
14
14
  def initialize(path, env)
15
+ @path = path
15
16
  config = {}
16
17
  @failures = []
17
18
 
@@ -111,30 +112,34 @@ module NewRelic
111
112
 
112
113
  def substitute_transaction_threshold(config)
113
114
  if config['transaction_tracer'] &&
114
- config['transaction_tracer']['transaction_threshold'] =~ /apdex_f/i
115
+ config['transaction_tracer']['transaction_threshold'].to_s =~ /apdex_f/i
115
116
  # when value is "apdex_f" remove the config and defer to default
116
117
  config['transaction_tracer'].delete('transaction_threshold')
117
118
  end
118
119
  end
119
120
 
120
121
  def booleanify_values(config, *keys)
121
- # auto means defer ro default
122
+ # auto means defer to default
122
123
  keys.each do |option|
123
- if config[option] == 'auto'
124
+ if 'auto' == config[option]
124
125
  config.delete(option)
125
126
  elsif !config[option].nil? && !is_boolean?(config[option])
126
- config[option] = !!(config[option] =~ /yes|on|true/i)
127
+ coerced_value = !!(config[option].to_s =~ /yes|on|true/i)
128
+ if !coerced_value
129
+ log_failure "Unexpected value (#{config[option]}) for '#{option}' in #{@path}"
130
+ end
131
+ config[option] = coerced_value
127
132
  end
128
133
  end
129
134
  end
130
135
 
131
136
  def is_boolean?(value)
132
- value == !!value
137
+ !!value == value
133
138
  end
134
139
 
135
140
  def log_failure(*messages)
136
141
  ::NewRelic::Agent.logger.error(*messages)
137
- @failures << messages
142
+ messages.each { |message| @failures << message }
138
143
  end
139
144
  end
140
145
  end
@@ -11,10 +11,11 @@ module NewRelic
11
11
 
12
12
  class RequestBuilder
13
13
 
14
- def initialize(new_relic_service, config, event_harvest_config)
14
+ def initialize(new_relic_service, config, event_harvest_config, environment_report)
15
15
  @service = new_relic_service
16
16
  @config = config
17
17
  @event_harvest_config = event_harvest_config
18
+ @environment_report = sanitize_environment_report(environment_report)
18
19
  end
19
20
 
20
21
 
@@ -25,16 +26,16 @@ module NewRelic
25
26
  :pid => $$,
26
27
  :host => local_host,
27
28
  :display_host => Agent.config[:'process_host.display_name'],
28
- :app_name => Agent.config.app_names,
29
+ :app_name => Agent.config[:app_name],
29
30
  :language => 'ruby',
30
31
  :labels => Agent.config.parsed_labels,
31
32
  :agent_version => NewRelic::VERSION::STRING,
32
- :environment => sanitize_environment_report(environment_report),
33
+ :environment => @environment_report,
33
34
  :metadata => environment_metadata,
34
35
  :settings => Agent.config.to_collector_hash,
35
36
  :high_security => Agent.config[:high_security],
36
37
  :utilization => UtilizationData.new.to_collector_hash,
37
- :identifier => "ruby:#{local_host}:#{Agent.config.app_names.sort.join(',')}",
38
+ :identifier => "ruby:#{local_host}:#{Agent.config[:app_name].sort.join(',')}",
38
39
  :event_harvest_config => @event_harvest_config
39
40
  }
40
41
  end
@@ -47,15 +48,6 @@ module NewRelic
47
48
  environment_report
48
49
  end
49
50
 
50
- # Checks whether we should send environment info, and if so,
51
- # returns the snapshot from the local environment.
52
- # Generating the EnvironmentReport has the potential to trigger
53
- # require calls in Rails environments, so this method should only
54
- # be called synchronously from on the main thread.
55
- def environment_report
56
- Agent.config[:send_environment_info] ? Array(EnvironmentReport.new) : []
57
- end
58
-
59
51
  def environment_metadata
60
52
  ENV.select {|k, v| k =~ /^NEW_RELIC_METADATA_/}
61
53
  end
@@ -133,10 +133,9 @@ module NewRelic
133
133
  ]
134
134
 
135
135
  SQL_COMMENT_REGEX = Regexp.new('/\*.*?\*/', Regexp::MULTILINE).freeze
136
- EMPTY_STRING = ''.freeze
137
136
 
138
137
  def parse_operation_from_query(sql)
139
- sql = Helper.correctly_encoded(sql).gsub(SQL_COMMENT_REGEX, EMPTY_STRING)
138
+ sql = Helper.correctly_encoded(sql).gsub(SQL_COMMENT_REGEX, NewRelic::EMPTY_STR)
140
139
  if sql =~ /(\w+)/
141
140
  op = $1.downcase
142
141
  return op if KNOWN_OPERATIONS.include?(op)
@@ -11,7 +11,7 @@ module NewRelic
11
11
  :double_quotes => /"(?:[^"]|"")*?(?:\\".*|"(?!"))/,
12
12
  :dollar_quotes => /(\$(?!\d)[^$]*?\$).*?(?:\1|$)/,
13
13
  :uuids => /\{?(?:[0-9a-fA-F]\-*){32}\}?/,
14
- :numeric_literals => /\b-?(?:[0-9]+\.)?[0-9]+([eE][+-]?[0-9]+)?\b/,
14
+ :numeric_literals => /-?\b(?:[0-9]+\.)?[0-9]+([eE][+-]?[0-9]+)?\b/,
15
15
  :boolean_literals => /\b(?:true|false|null)\b/i,
16
16
  :hexadecimal_literals => /0x[0-9a-fA-F]+/,
17
17
  :comments => /(?:#|--).*?(?=\r|\n|$)/i,
@@ -12,7 +12,7 @@ module NewRelic
12
12
  end
13
13
 
14
14
  def self.is_monitoring_enabled?
15
- defined?(::Mongo::Monitoring)
15
+ defined?(::Mongo::Monitoring) # @since 2.1.0
16
16
  end
17
17
 
18
18
  def self.is_unsupported_2x?
@@ -13,7 +13,7 @@ module NewRelic
13
13
  OBFUSCATE_KEYS = [ 'filter', 'query', 'pipeline' ].freeze
14
14
 
15
15
  # Keys that will get completely removed from the statement.
16
- BLACKLISTED_KEYS = [ 'deletes', 'documents', 'updates' ].freeze
16
+ DENYLISTED_KEYS = [ 'deletes', 'documents', 'updates' ].freeze
17
17
 
18
18
  def self.format(command_name, database_name, command)
19
19
  return nil unless NewRelic::Agent.config[:'mongo.capture_queries']
@@ -25,7 +25,7 @@ module NewRelic
25
25
  }
26
26
 
27
27
  command.each do |key, value|
28
- next if BLACKLISTED_KEYS.include?(key)
28
+ next if DENYLISTED_KEYS.include?(key)
29
29
  if OBFUSCATE_KEYS.include?(key)
30
30
  obfuscated = obfuscate(value)
31
31
  result[key] = obfuscated if obfuscated
@@ -8,31 +8,31 @@ module NewRelic
8
8
  module Mongo
9
9
  module Obfuscator
10
10
 
11
- WHITELIST = [:operation].freeze
11
+ ALLOWLIST = [:operation].freeze
12
12
 
13
- def self.obfuscate_statement(source, whitelist = WHITELIST)
13
+ def self.obfuscate_statement(source, allowlist = ALLOWLIST)
14
14
  if source.is_a? Hash
15
15
  obfuscated = {}
16
16
  source.each do |key, value|
17
- if whitelist.include?(key)
17
+ if allowlist.include?(key)
18
18
  obfuscated[key] = value
19
19
  else
20
- obfuscated[key] = obfuscate_value(value, whitelist)
20
+ obfuscated[key] = obfuscate_value(value, allowlist)
21
21
  end
22
22
  end
23
23
  obfuscated
24
24
  else
25
- obfuscate_value(source, whitelist)
25
+ obfuscate_value(source, allowlist)
26
26
  end
27
27
  end
28
28
 
29
29
  QUESTION_MARK = '?'.freeze
30
30
 
31
- def self.obfuscate_value(value, whitelist = WHITELIST)
31
+ def self.obfuscate_value(value, allowlist = ALLOWLIST)
32
32
  if value.is_a?(Hash)
33
- obfuscate_statement(value, whitelist)
33
+ obfuscate_statement(value, allowlist)
34
34
  elsif value.is_a?(Array)
35
- value.map {|v| obfuscate_value(v, whitelist)}
35
+ value.map {|v| obfuscate_value(v, allowlist)}
36
36
  else
37
37
  QUESTION_MARK
38
38
  end
@@ -1,8 +1,15 @@
1
1
  # encoding: utf-8
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
+ # frozen_string_literal: true
4
5
 
5
- require 'new_relic/agent/distributed_trace_payload'
6
+ require_relative 'distributed_tracing/cross_app_payload'
7
+ require_relative 'distributed_tracing/cross_app_tracing'
8
+
9
+ require_relative 'distributed_tracing/distributed_trace_transport_type'
10
+ require_relative 'distributed_tracing/distributed_trace_payload'
11
+
12
+ require_relative 'distributed_tracing/trace_context'
6
13
 
7
14
  module NewRelic
8
15
  module Agent
@@ -14,8 +21,9 @@ module NewRelic
14
21
  #
15
22
  # @api public
16
23
  module DistributedTracing
24
+ extend NewRelic::SupportabilityHelper
17
25
  extend self
18
-
26
+
19
27
  # Create a payload object containing the current transaction's
20
28
  # tracing properties (e.g., duration, priority). You can use
21
29
  # this object to generate headers to inject into a network
@@ -27,10 +35,19 @@ module NewRelic
27
35
  # could not create the payload
28
36
  #
29
37
  # @api public
38
+ #
39
+ # @deprecated See {#create_distributed_trace_headers} instead.
40
+ #
30
41
  def create_distributed_trace_payload
31
- if transaction = Transaction.tl_current
32
- transaction.create_distributed_trace_payload
42
+ Deprecator.deprecate :create_distributed_trace_payload, :create_distributed_trace_headers
43
+
44
+ unless Agent.config[:'distributed_tracing.enabled']
45
+ NewRelic::Agent.logger.warn "Not configured to create New Relic distributed trace payload"
46
+ return nil
33
47
  end
48
+
49
+ return unless transaction = Transaction.tl_current
50
+ transaction.distributed_tracer.create_distributed_trace_payload
34
51
  rescue => e
35
52
  NewRelic::Agent.logger.error 'error during create_distributed_trace_payload', e
36
53
  nil
@@ -53,15 +70,147 @@ module NewRelic
53
70
  # @return nil
54
71
  #
55
72
  # @api public
73
+ #
74
+ # @deprecated See {#accept_distributed_trace_headers} instead
75
+ #
56
76
  def accept_distributed_trace_payload payload
57
- if transaction = Transaction.tl_current
58
- transaction.accept_distributed_trace_payload(payload)
77
+ Deprecator.deprecate :accept_distributed_trace_payload, :accept_distributed_trace_headers
78
+
79
+ unless Agent.config[:'distributed_tracing.enabled']
80
+ NewRelic::Agent.logger.warn "Not configured to accept New Relic distributed trace payload"
81
+ return nil
59
82
  end
83
+
84
+ return unless transaction = Transaction.tl_current
85
+ transaction.distributed_tracer.accept_distributed_trace_payload(payload)
60
86
  nil
61
87
  rescue => e
62
88
  NewRelic::Agent.logger.error 'error during accept_distributed_trace_payload', e
63
89
  nil
64
90
  end
91
+
92
+
93
+ # Adds the Distributed Trace headers so that the downstream service can participate in a
94
+ # distributed trace. This method should be called every time an outbound call is made
95
+ # since the header payload contains a timestamp.
96
+ #
97
+ # Distributed Tracing must be enabled to use this method.
98
+ #
99
+ # +insert_distributed_trace_headers+ always inserts W3C trace context headers and inserts
100
+ # New Relic distributed tracing header by default. New Relic headers may be suppressed by
101
+ # setting +exclude_new_relic_header+ to +true+ in your configuration file.
102
+ #
103
+ # @param headers [Hash] Is a Hash to which the distributed trace headers
104
+ # will be inserted.
105
+ #
106
+ # @return {Transaction} The transaction the headers were inserted from,
107
+ # or +nil+ if headers were not inserted.
108
+ #
109
+ # @api public
110
+ #
111
+ def insert_distributed_trace_headers headers={}
112
+ record_api_supportability_metric(:insert_distributed_trace_headers)
113
+
114
+ unless Agent.config[:'distributed_tracing.enabled']
115
+ NewRelic::Agent.logger.warn "Not configured to insert distributed trace headers"
116
+ return nil
117
+ end
118
+
119
+ return unless valid_api_argument_class? headers, "headers", Hash
120
+
121
+ return unless transaction = Transaction.tl_current
122
+
123
+ transaction.distributed_tracer.insert_headers headers
124
+ transaction
125
+ rescue => e
126
+ NewRelic::Agent.logger.error 'error during insert_distributed_trace_headers', e
127
+ nil
128
+ end
129
+
130
+ # Accepts distributed tracing headers from any source that has been packaged
131
+ # as a Ruby Hash, thereby allowing the user to manually inject distributed
132
+ # tracing headers. It is optimized to process +HTTP_TRACEPARENT+, +HTTP_TRACESTATE+,
133
+ # and +HTTP_NEWRELIC+ as the given Hash keys. which is the most common scenario
134
+ # from Rack middleware in most Ruby applications. However, the Hash keys are
135
+ # case-insensitive and the "HTTP_" prefixes may also be omitted.
136
+ #
137
+ # Calling this method is not necessary in a typical HTTP trace as
138
+ # distributed tracing is already handled by the agent.
139
+ #
140
+ # When used, invoke this method as early as possible in a transaction's life-cycle
141
+ # as calling after the headers are already created will have no effect.
142
+ #
143
+ # This method accepts both W3C trace context and New Relic distributed tracing headers.
144
+ # When both are present, only the W3C headers are utilized. When W3C trace context
145
+ # headers are present, New Relic headers are ignored regardless if W3C trace context
146
+ # headers are valid and parsable.
147
+ #
148
+ # @param headers [Hash] Incoming distributed trace headers as a Ruby
149
+ # Hash object. Hash keys are expected to be one of
150
+ # +TRACEPARENT+, +TRACESTATE+, +NEWRELIC+ and are
151
+ # case-insensitive, with or without "HTTP_" prefixes.
152
+ #
153
+ # either as a JSON string or as a
154
+ # header-friendly string returned from
155
+ # {DistributedTracePayload#http_safe}
156
+ #
157
+ # @param transport_Type [String] May be one of: +HTTP+, +HTTPS+, +Kafka+, +JMS+,
158
+ # +IronMQ+, +AMQP+, +Queue+, +Other+. Values are
159
+ # case sensitive. All other values result in +Unknown+
160
+ #
161
+ # @return {Transaction} if successful, +nil+ otherwise
162
+ #
163
+ # @api public
164
+ #
165
+ def accept_distributed_trace_headers headers, transport_type = NewRelic::HTTP
166
+ record_api_supportability_metric(:accept_distributed_trace_headers)
167
+
168
+ unless Agent.config[:'distributed_tracing.enabled']
169
+ NewRelic::Agent.logger.warn "Not configured to accept distributed trace headers"
170
+ return nil
171
+ end
172
+
173
+ return unless valid_api_argument_class? headers, "headers", Hash
174
+ return unless valid_api_argument_class? transport_type, "transport_type", String
175
+
176
+ return unless transaction = Transaction.tl_current
177
+
178
+ # assume we have Rack conforming keys when transport_type is HTTP(S)
179
+ # otherwise, fish for key/value pairs regardless of prefix and case-sensitivity.
180
+ hdr = if transport_type.start_with? NewRelic::HTTP
181
+ headers
182
+ else
183
+ # start with the most common case first
184
+ hdr = {
185
+ NewRelic::HTTP_TRACEPARENT_KEY => headers[NewRelic::TRACEPARENT_KEY],
186
+ NewRelic::HTTP_TRACESTATE_KEY => headers[NewRelic::TRACESTATE_KEY],
187
+ NewRelic::HTTP_NEWRELIC_KEY => headers[NewRelic::NEWRELIC_KEY]
188
+ }
189
+
190
+ # when not found, search for any casing for trace context headers, ignoring potential prefixes
191
+ hdr[NewRelic::HTTP_TRACEPARENT_KEY] ||= variant_key_value headers, NewRelic::TRACEPARENT_KEY
192
+ hdr[NewRelic::HTTP_TRACESTATE_KEY] ||= variant_key_value headers, NewRelic::TRACESTATE_KEY
193
+ hdr[NewRelic::HTTP_NEWRELIC_KEY] ||= variant_key_value headers, NewRelic::CANDIDATE_NEWRELIC_KEYS
194
+ hdr
195
+ end
196
+
197
+ transaction.distributed_tracer.accept_incoming_request hdr, transport_type
198
+ transaction
199
+ rescue => e
200
+ NewRelic::Agent.logger.error 'error during accept_distributed_trace_headers', e
201
+ nil
202
+ end
203
+
204
+ private
205
+
206
+ def has_variant_key? key, variants
207
+ key.to_s.downcase.end_with?(*Array(variants))
208
+ end
209
+
210
+ def variant_key_value headers, variants
211
+ (headers.detect{|k, v| has_variant_key?(k, variants)} || NewRelic::EMPTY_ARRAY)[1]
212
+ end
213
+
65
214
  end
66
215
  end
67
216
  end