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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d6f27f55d62839f2426dcc139af19e97f815c70783944d4c67363a7d54a5e208
4
- data.tar.gz: 6543b4fa585ab70291df98c295818ccb74eb4d2ab00a9ac3f5093c7b89656d4d
3
+ metadata.gz: a104aa20426e4da3129e97dfaa651e7232ef804cf91de87b0aa4ac68d00d3fe7
4
+ data.tar.gz: f8ae7ba61e0dc5442212c8d4a8d985d4e9ac353c23e9ff61ebb709ff11bfd28a
5
5
  SHA512:
6
- metadata.gz: 658044904957344ad87805e072168e9f366453733f0b9e42051230c2999be7170bfe5cac64c402e0ced3483e1f3d5ce091622c01d2ecb685e4354b41e6a11a38
7
- data.tar.gz: ec9e153d940103faddd85fca6b00191e9214770aa5c7b5d1318fff41e3ff6d69f9720d2300847571ed1ba92b7d9c468fce5afc8dc6cfa711807405384d6cc94e
6
+ metadata.gz: 58d78970fa151543b165d1ef8b37a9ab7adefabf35ccad2292df5038812a1d5d5524f21cb7822a8d99bc4eabed8ceafc537b6f913b829f2a25ff0cf19a399e3a
7
+ data.tar.gz: 6859b4ba6ceaab1faeac5634ea264e015329f20af436872da764e3f17ac6b22f2ad2cbfc4604eccc883d9f7b1a0ef5c1fb193c9faf7fdbfab107bae3a2109b8d
data/.gitignore CHANGED
@@ -14,6 +14,7 @@ tags
14
14
  *.swp
15
15
  *.swo
16
16
 
17
+ /doc/
17
18
  /log/
18
19
  /lerg/
19
20
  gems/newrelic_rpm.gemspec
@@ -9,6 +9,7 @@ language: ruby
9
9
  sudo: required
10
10
 
11
11
  before_install:
12
+ - sudo apt-get update && sudo apt-get install --only-upgrade openssl && sudo apt-get install --only-upgrade libssl-dev
12
13
  - gem --version
13
14
  - gem update --system
14
15
  - ./test/script/before_install/gemstash_mirror.sh
data/.yardopts CHANGED
@@ -2,6 +2,8 @@
2
2
  --api public
3
3
  lib/new_relic/agent.rb
4
4
  lib/new_relic/agent/method_tracer.rb
5
+ lib/new_relic/agent/distributed_tracing.rb
6
+ lib/new_relic/agent/distributed_trace_payload.rb
5
7
  lib/new_relic/agent/external.rb
6
8
  lib/new_relic/agent/instrumentation/controller_instrumentation.rb
7
9
  lib/new_relic/agent/instrumentation/rack.rb
@@ -19,5 +21,5 @@ lib/new_relic/rack.rb
19
21
  lib/new_relic/agent/transaction/external_request_segment.rb
20
22
  -
21
23
  LICENSE
22
- CHANGELOG
24
+ CHANGELOG.md
23
25
  CONTRIBUTING.md
@@ -1,6 +1,26 @@
1
1
  # New Relic Ruby Agent Release Notes #
2
2
 
3
- ## v5.2.0 ##
3
+ ## v5.3.0 ##
4
+
5
+ * Distributed Tracing
6
+
7
+ Distributed tracing lets you see the path that a request takes as
8
+ it travels through your distributed system. By showing the
9
+ distributed activity through a unified view, you can troubleshoot
10
+ and understand a complex system better than ever before.
11
+
12
+ Distributed tracing is available with an APM Pro or equivalent
13
+ subscription. To see a complete distributed trace, you need to
14
+ enable the feature on a set of neighboring services. Enabling
15
+ distributed tracing changes the behavior of some New Relic
16
+ features, so carefully consult the
17
+ [transition guide](https://docs.newrelic.com/docs/transition-guide-distributed-tracing)
18
+ before you enable this feature.
19
+
20
+ To enable distributed tracing, set the
21
+ `distributed_tracing.enabled` configuration option to `true`.
22
+
23
+ ## v5.2.0 ##
4
24
 
5
25
  * Use priority sampling for errors and custom events
6
26
 
@@ -14,7 +34,12 @@
14
34
  The agent will now complete the process of wrapping datastore
15
35
  operations even if an error occurs during execution of a callback.
16
36
 
17
- ## v5.1.0 ##
37
+ * Span Events
38
+
39
+ Finished segments whose `sampled` property is `true` will now post
40
+ Span events to Insights.
41
+
42
+ ## v5.1.0 ##
18
43
 
19
44
  * Rails 5.2 support
20
45
 
@@ -68,7 +93,7 @@
68
93
  data to New Relic. This version truncates long traces to 50 frames
69
94
  (split evenly between the top and bottom of the trace).
70
95
 
71
- ## v5.0.0 ##
96
+ ## v5.0.0 ##
72
97
 
73
98
  * SSL connections to New Relic are now mandatory
74
99
 
@@ -107,7 +132,7 @@
107
132
  works correctly with this new behavior. Thanks to Jimmy Zhang for
108
133
  the contribution.
109
134
 
110
- ## v4.8.0 ##
135
+ ## v4.8.0 ##
111
136
 
112
137
  * Initialize New Relic Agent before config initializers
113
138
 
@@ -129,7 +154,7 @@
129
154
  It is now an agent attribute that can be controlled via the attributes config.
130
155
  For more information on agent attributes [see here](https://docs.newrelic.com/docs/agents/manage-apm-agents/agent-data/agent-attributes).
131
156
 
132
- ## 4.7.1 ##
157
+ ## 4.7.1 ##
133
158
 
134
159
  * Bugfix for Manual Browser Instrumentation
135
160
 
@@ -139,7 +164,7 @@
139
164
  instrumentation. Those changes have been reverted. We will revisit this issue
140
165
  in an upcoming release.
141
166
 
142
- ## v4.7.0 ##
167
+ ## v4.7.0 ##
143
168
 
144
169
  * Expected Error API
145
170
 
@@ -6,15 +6,16 @@ module NewRelic
6
6
  module Agent
7
7
  class AdaptiveSampler
8
8
 
9
- def initialize target_samples = 10, interval_duration = 60
9
+ def initialize target_samples = 10, period_duration = 60
10
10
  @target = target_samples
11
11
  @seen = 0
12
12
  @seen_last = 0
13
13
  @sampled_count = 0
14
- @interval_duration = interval_duration
15
- @first_interval = true
16
- @interval_start = Time.now.to_f
14
+ @period_duration = period_duration
15
+ @first_period = true
16
+ @period_start = Time.now.to_f
17
17
  @lock = Mutex.new
18
+ register_config_callbacks
18
19
  end
19
20
 
20
21
  # Called at the beginning of each transaction, increments seen and
@@ -22,13 +23,13 @@ module NewRelic
22
23
  # sampled. This uses the adaptive sampling algorithm.
23
24
  def sampled?
24
25
  @lock.synchronize do
25
- reset_if_interval_expired!
26
- sampled = if @first_interval
26
+ reset_if_period_expired!
27
+ sampled = if @first_period
27
28
  @sampled_count < 10
28
29
  elsif @sampled_count < @target
29
30
  rand(@seen_last) < @target
30
31
  else
31
- rand(@seen) < (@target ** (@target / @sampled_count) - @target ** 0.51)
32
+ rand(@seen) < (@target ** (@target / @sampled_count) - @target ** 0.5)
32
33
  end
33
34
 
34
35
  @sampled_count += 1 if sampled
@@ -51,18 +52,53 @@ module NewRelic
51
52
 
52
53
  private
53
54
 
54
- def reset_if_interval_expired!
55
+ def reset_if_period_expired!
55
56
  now = Time.now.to_f
56
- return unless @interval_start + @interval_duration <= now
57
+ return unless @period_start + @period_duration <= now
57
58
 
58
- elapsed_intervals = Integer((now - @interval_start) / @interval_duration)
59
- @interval_start = @interval_start + elapsed_intervals * @interval_duration
59
+ elapsed_periods = Integer((now - @period_start) / @period_duration)
60
+ @period_start = @period_start + elapsed_periods * @period_duration
60
61
 
61
- @first_interval = false
62
- @seen_last = elapsed_intervals > 1 ? 0 : @seen
62
+ @first_period = false
63
+ @seen_last = elapsed_periods > 1 ? 0 : @seen
63
64
  @seen = 0
64
65
  @sampled_count = 0
65
66
  end
67
+
68
+ def register_config_callbacks
69
+ register_sampling_target_callback
70
+ register_sampling_period_callback
71
+ end
72
+
73
+ def register_sampling_target_callback
74
+ NewRelic::Agent.config.register_callback(:sampling_target) do |target|
75
+ target_changed = false
76
+ @lock.synchronize do
77
+ if @target != target
78
+ @target = target
79
+ target_changed = true
80
+ end
81
+ end
82
+ if target_changed
83
+ NewRelic::Agent.logger.debug "Sampling target set to: #{target}"
84
+ end
85
+ end
86
+ end
87
+
88
+ def register_sampling_period_callback
89
+ NewRelic::Agent.config.register_callback(:sampling_target_period_in_seconds) do |period_duration|
90
+ period_changed = false
91
+ @lock.synchronize do
92
+ if @period_duration != period_duration
93
+ @period_duration = period_duration
94
+ period_changed = true
95
+ end
96
+ end
97
+ if period_changed
98
+ NewRelic::Agent.logger.debug "Sampling period set to: #{period_duration}"
99
+ end
100
+ end
101
+ end
66
102
  end
67
103
  end
68
104
  end
@@ -22,6 +22,7 @@ require 'new_relic/agent/distributed_trace_monitor'
22
22
  require 'new_relic/agent/synthetics_monitor'
23
23
  require 'new_relic/agent/transaction_event_recorder'
24
24
  require 'new_relic/agent/custom_event_aggregator'
25
+ require 'new_relic/agent/span_event_aggregator'
25
26
  require 'new_relic/agent/sampler_collection'
26
27
  require 'new_relic/agent/javascript_instrumentor'
27
28
  require 'new_relic/agent/vm/monotonic_gc_profiler'
@@ -61,14 +62,15 @@ module NewRelic
61
62
  @harvest_samplers = NewRelic::Agent::SamplerCollection.new(@events)
62
63
  @monotonic_gc_profiler = NewRelic::Agent::VM::MonotonicGCProfiler.new
63
64
  @javascript_instrumentor = NewRelic::Agent::JavascriptInstrumentor.new(@events)
64
- @adaptive_sampler = NewRelic::Agent::AdaptiveSampler.new
65
+ @adaptive_sampler = NewRelic::Agent::AdaptiveSampler.new(self.class.config[:sampling_target],
66
+ self.class.config[:sampling_target_period_in_seconds])
65
67
 
66
68
  @harvester = NewRelic::Agent::Harvester.new(@events)
67
69
  @after_fork_lock = Mutex.new
68
70
 
69
71
  @transaction_event_recorder = NewRelic::Agent::TransactionEventRecorder.new
70
-
71
- @custom_event_aggregator = NewRelic::Agent::CustomEventAggregator.new
72
+ @custom_event_aggregator = NewRelic::Agent::CustomEventAggregator.new
73
+ @span_event_aggregator = NewRelic::Agent::SpanEventAggregator.new
72
74
 
73
75
  @connect_state = :pending
74
76
  @connect_attempts = 0
@@ -140,6 +142,7 @@ module NewRelic
140
142
  # GC::Profiler.total_time is not monotonic so we wrap it.
141
143
  attr_reader :monotonic_gc_profiler
142
144
  attr_reader :custom_event_aggregator
145
+ attr_reader :span_event_aggregator
143
146
  attr_reader :transaction_event_recorder
144
147
  attr_reader :attribute_filter
145
148
  attr_reader :adaptive_sampler
@@ -546,6 +549,7 @@ module NewRelic
546
549
  @transaction_sampler.reset!
547
550
  @transaction_event_recorder.drop_buffered_data
548
551
  @custom_event_aggregator.reset!
552
+ @span_event_aggregator.reset!
549
553
  @sql_sampler.reset!
550
554
 
551
555
  if Agent.config[:clear_transaction_state_after_fork]
@@ -1108,8 +1112,9 @@ module NewRelic
1108
1112
 
1109
1113
  def harvest_and_send_analytic_event_data
1110
1114
  harvest_and_send_from_container(transaction_event_aggregator, :analytic_event_data)
1111
- harvest_and_send_from_container(synthetics_event_aggregator, :analytic_event_data)
1112
- harvest_and_send_from_container(@custom_event_aggregator, :custom_event_data)
1115
+ harvest_and_send_from_container(synthetics_event_aggregator, :analytic_event_data)
1116
+ harvest_and_send_from_container(@custom_event_aggregator, :custom_event_data)
1117
+ harvest_and_send_from_container(span_event_aggregator, :span_event_data)
1113
1118
  end
1114
1119
 
1115
1120
  def harvest_and_send_error_event_data
@@ -1138,6 +1143,10 @@ module NewRelic
1138
1143
  transmit_single_data_type(:harvest_and_send_analytic_event_data, "TransactionEvent")
1139
1144
  end
1140
1145
 
1146
+ def transmit_span_event_data
1147
+ transmit_single_data_type(:harvest_and_send_span_event_data, "SpanEvent")
1148
+ end
1149
+
1141
1150
  def transmit_single_data_type(harvest_method, supportability_name)
1142
1151
  now = Time.now
1143
1152
 
@@ -1676,12 +1676,64 @@ module NewRelic
1676
1676
  :allowed_from_server => false,
1677
1677
  :description => 'If <code>true</code>, the agent will clear <code>TransactionState</code> in <code>Agent.drop_buffered_data</code>.'
1678
1678
  },
1679
+ :account_id => {
1680
+ :default => nil,
1681
+ :allow_nil => true,
1682
+ :public => false,
1683
+ :type => String,
1684
+ :allowed_from_server => true,
1685
+ :description => 'The account id associated with this application.'
1686
+ },
1687
+ :primary_application_id => {
1688
+ :default => nil,
1689
+ :allow_nil => true,
1690
+ :public => false,
1691
+ :type => String,
1692
+ :allowed_from_server => true,
1693
+ :description => 'The primary id associated with this application.'
1694
+ },
1679
1695
  :'distributed_tracing.enabled' => {
1680
1696
  :default => false,
1681
- :public => false,
1697
+ :public => true,
1682
1698
  :type => Boolean,
1683
1699
  :allowed_from_server => false,
1684
- :description => 'If <code>true</code> enables experimental distributed tracing feature.'
1700
+ :description => 'Distributed tracing lets you see the path that a request takes through your distributed system. Enabling distributed tracing changes the behavior of some New Relic features, so carefully consult the <a href="https://docs.newrelic.com/docs/transition-guide-distributed-tracing">transition guide</a> before you enable this feature.'
1701
+ },
1702
+ :trusted_account_key => {
1703
+ :default => nil,
1704
+ :allow_nil => true,
1705
+ :public => false,
1706
+ :type => String,
1707
+ :allowed_from_server => true,
1708
+ :description => 'A shared key to validate that a distributed trace payload came from a trusted account.'
1709
+ },
1710
+ :sampling_target => {
1711
+ :default => 10,
1712
+ :public => false,
1713
+ :type => Integer,
1714
+ :allowed_from_server => true,
1715
+ :description => 'The target number of transactions to mark as sampled during a sampled period.'
1716
+ },
1717
+ :sampling_target_period_in_seconds => {
1718
+ :default => 60,
1719
+ :public => false,
1720
+ :type => Integer,
1721
+ :allowed_from_server => true,
1722
+ :description => 'The period during which a target number of transactions should be marked as sampled.'
1723
+ },
1724
+ :'span_events.enabled' => {
1725
+ :default => true,
1726
+ :public => false,
1727
+ :type => Boolean,
1728
+ :allowed_from_server => true,
1729
+ :description => 'If <code>true</code>, enables span event sampling.'
1730
+ },
1731
+ :'span_events.max_samples_stored' => {
1732
+ :default => 1000,
1733
+ :public => false,
1734
+ :type => Integer,
1735
+ :allowed_from_server => true,
1736
+ :description => 'Defines the maximum number of span events reported from a single harvest.'
1685
1737
  }
1686
1738
  }.freeze
1687
1739
  end
@@ -10,6 +10,7 @@ module NewRelic
10
10
  # response, but should still be merged in as config settings to the
11
11
  # main agent configuration.
12
12
  TOP_LEVEL_KEYS = [
13
+ "account_id",
13
14
  "apdex_t",
14
15
  "application_id",
15
16
  "beacon",
@@ -24,7 +25,11 @@ module NewRelic
24
25
  "error_beacon",
25
26
  "js_agent_file",
26
27
  "js_agent_loader",
27
- "trusted_account_ids"
28
+ "primary_application_id",
29
+ "sampling_target",
30
+ "sampling_target_period_in_seconds",
31
+ "trusted_account_ids",
32
+ "trusted_account_key"
28
33
  ]
29
34
 
30
35
  def initialize(connect_reply, existing_config={})
@@ -51,7 +51,9 @@ module NewRelic
51
51
  end
52
52
 
53
53
  def cross_application_tracer_enabled?
54
- NewRelic::Agent.config[:"cross_application_tracer.enabled"] || NewRelic::Agent.config[:cross_application_tracing]
54
+ !NewRelic::Agent.config[:"distributed_tracing.enabled"] &&
55
+ (NewRelic::Agent.config[:"cross_application_tracer.enabled"] ||
56
+ NewRelic::Agent.config[:cross_application_tracing])
55
57
  end
56
58
 
57
59
  def obfuscator
@@ -195,6 +195,20 @@ module NewRelic
195
195
  @host = host
196
196
  @port_path_or_id = port_path_or_id
197
197
  @database_name = database_name
198
+ @safe_sql = nil
199
+ end
200
+
201
+ # Returns an sql statement that will be in the form most permissable by
202
+ # the config. The format will be safe for transmission to New Relic.
203
+ def safe_sql
204
+ @safe_sql ||= case Database.record_sql_method
205
+ when :obfuscated
206
+ Database.obfuscate_sql(sql)
207
+ when :raw
208
+ sql.to_s
209
+ else
210
+ nil
211
+ end
198
212
  end
199
213
 
200
214
  # This takes a connection config hash from ActiveRecord or Sequel and
@@ -8,14 +8,13 @@ require 'new_relic/agent/cross_app_tracing'
8
8
  module NewRelic
9
9
  module Agent
10
10
  class DistributedTraceMonitor < InboundRequestMonitor
11
- NEWRELIC_TRACE_KEY = 'HTTP_X_NEWRELIC_TRACE'.freeze
12
- HTTP_TRANSPORT_TYPE = 'HTTP'.freeze
13
-
14
11
  def on_finished_configuring(events)
15
12
  return unless NewRelic::Agent.config[:'distributed_tracing.enabled']
16
13
  events.subscribe(:before_call, &method(:on_before_call))
17
14
  end
18
15
 
16
+ NEWRELIC_TRACE_KEY = 'HTTP_NEWRELIC'
17
+
19
18
  def on_before_call(request)
20
19
  return unless NewRelic::Agent.config[:'distributed_tracing.enabled']
21
20
  return unless payload = request[NEWRELIC_TRACE_KEY]
@@ -23,9 +22,20 @@ module NewRelic
23
22
  state = NewRelic::Agent::TransactionState.tl_get
24
23
  txn = state.current_transaction
25
24
  if txn.accept_distributed_trace_payload payload
26
- txn.distributed_trace_payload.caller_transport_type = HTTP_TRANSPORT_TYPE
25
+ txn.distributed_trace_payload.caller_transport_type = transport_type(request)
27
26
  end
28
27
  end
28
+
29
+ URL_SCHEMES = {
30
+ 'http' => 'HTTP'.freeze,
31
+ 'https' => 'HTTPS'.freeze
32
+ }
33
+
34
+ RACK_URL_SCHEME = 'rack.url_scheme'.freeze
35
+
36
+ def transport_type(request)
37
+ URL_SCHEMES[request[RACK_URL_SCHEME]]
38
+ end
29
39
  end
30
40
  end
31
41
  end
@@ -3,9 +3,16 @@
3
3
  # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
4
  require 'json'
5
5
  require 'base64'
6
+ require 'set'
6
7
 
7
8
  module NewRelic
8
9
  module Agent
10
+ #
11
+ # This class contains properties related to distributed traces.
12
+ # To obtain an instance, call
13
+ # {DistributedTracing#create_distributed_trace_payload}
14
+ #
15
+ # @api public
9
16
  class DistributedTracePayload
10
17
  VERSION =[0, 1].freeze
11
18
  PARENT_TYPE = "App".freeze
@@ -17,10 +24,11 @@ module NewRelic
17
24
  PARENT_TYPE_KEY = 'ty'.freeze
18
25
  PARENT_ACCOUNT_ID_KEY = 'ac'.freeze
19
26
  PARENT_APP_KEY = 'ap'.freeze
27
+ TRUSTED_ACCOUNT_KEY = 'tk'.freeze
20
28
  ID_KEY = 'id'.freeze
29
+ TX_KEY = 'tx'.freeze
21
30
  TRACE_ID_KEY = 'tr'.freeze
22
31
  SAMPLED_KEY = 'sa'.freeze
23
- PARENT_ID_KEY = 'pa'.freeze
24
32
  TIMESTAMP_KEY = 'ti'.freeze
25
33
  PRIORITY_KEY = 'pr'.freeze
26
34
 
@@ -32,9 +40,9 @@ module NewRelic
32
40
  PARENT_TRANSPORT_DURATION_INTRINSIC_KEY = "parent.transportDuration".freeze
33
41
  GUID_INTRINSIC_KEY = "guid".freeze
34
42
  TRACE_ID_INTRINSIC_KEY = "traceId".freeze
35
- TRIP_ID_INTRINSIC_KEY = "nr.tripId".freeze
36
43
  PARENT_ID_INTRINSIC_KEY = "parentId".freeze
37
- GRANDPARENT_ID_INTRINSIC_KEY = "grandparentId".freeze
44
+ PARENT_SPAN_ID_INTRINSIC_KEY = "parentSpanId".freeze
45
+ SAMPLED_INTRINSIC_KEY = "sampled".freeze
38
46
  COMMA = ",".freeze
39
47
 
40
48
  INTRINSIC_KEYS = [
@@ -45,58 +53,54 @@ module NewRelic
45
53
  PARENT_TRANSPORT_DURATION_INTRINSIC_KEY,
46
54
  GUID_INTRINSIC_KEY,
47
55
  TRACE_ID_INTRINSIC_KEY,
48
- TRIP_ID_INTRINSIC_KEY,
49
56
  PARENT_ID_INTRINSIC_KEY,
50
- GRANDPARENT_ID_INTRINSIC_KEY
57
+ PARENT_SPAN_ID_INTRINSIC_KEY,
58
+ SAMPLED_INTRINSIC_KEY
51
59
  ].freeze
52
60
 
53
61
  # Intrinsic Values
54
- PARENT_TRANSPORT_TYPE_UNKNOWN = 'unknown'.freeze
62
+ PARENT_TRANSPORT_TYPE_UNKNOWN = 'Unknown'.freeze
55
63
 
56
64
  class << self
65
+
57
66
  def for_transaction transaction
58
- payload = new
59
- return payload unless connected?
67
+ return nil unless connected?
60
68
 
69
+ payload = new
61
70
  payload.version = VERSION
62
71
  payload.parent_type = PARENT_TYPE
72
+ payload.parent_account_id = Agent.config[:account_id]
73
+ payload.parent_app_id = Agent.config[:primary_application_id]
63
74
 
64
- # We should not rely on the xp_id being formulated this way, but we have
65
- # seen nil account ids coming down in staging for some accounts
66
- account_id, fallback_app_id = Agent.config[:cross_process_id].split(POUND)
67
- payload.parent_account_id = account_id
68
-
69
- payload.parent_app_id = if Agent.config[:application_id].empty?
70
- fallback_app_id
71
- else
72
- Agent.config[:application_id]
73
- end
75
+ assign_trusted_account_key(payload, payload.parent_account_id)
74
76
 
77
+ payload.id = current_segment_id(transaction)
78
+ payload.transaction_id = transaction.guid
75
79
  payload.timestamp = (Time.now.to_f * 1000).round
76
- payload.id = transaction.guid
77
80
  payload.trace_id = transaction.trace_id
78
81
  payload.sampled = transaction.sampled?
79
82
  payload.priority = transaction.priority
80
- payload.parent_id = transaction.parent_id
81
83
 
82
84
  payload
83
85
  end
84
86
 
85
87
  def from_json serialized_payload
86
88
  raw_payload = JSON.parse serialized_payload
89
+ return raw_payload if raw_payload.nil?
87
90
  payload_data = raw_payload[DATA_KEY]
88
91
 
89
92
  payload = new
90
- payload.version = raw_payload[VERSION_KEY]
91
- payload.parent_type = payload_data[PARENT_TYPE_KEY]
92
- payload.parent_account_id = payload_data[PARENT_ACCOUNT_ID_KEY]
93
- payload.parent_app_id = payload_data[PARENT_APP_KEY]
94
- payload.timestamp = payload_data[TIMESTAMP_KEY]
95
- payload.id = payload_data[ID_KEY]
96
- payload.trace_id = payload_data[TRACE_ID_KEY]
97
- payload.sampled = payload_data[SAMPLED_KEY]
98
- payload.priority = payload_data[PRIORITY_KEY]
99
- payload.parent_id = payload_data[PARENT_ID_KEY]
93
+ payload.version = raw_payload[VERSION_KEY]
94
+ payload.parent_type = payload_data[PARENT_TYPE_KEY]
95
+ payload.parent_account_id = payload_data[PARENT_ACCOUNT_ID_KEY]
96
+ payload.parent_app_id = payload_data[PARENT_APP_KEY]
97
+ payload.trusted_account_key = payload_data[TRUSTED_ACCOUNT_KEY]
98
+ payload.timestamp = payload_data[TIMESTAMP_KEY]
99
+ payload.id = payload_data[ID_KEY]
100
+ payload.transaction_id = payload_data[TX_KEY]
101
+ payload.trace_id = payload_data[TRACE_ID_KEY]
102
+ payload.sampled = payload_data[SAMPLED_KEY]
103
+ payload.priority = payload_data[PRIORITY_KEY]
100
104
 
101
105
  payload
102
106
  end
@@ -106,11 +110,10 @@ module NewRelic
106
110
  from_json decoded_payload
107
111
  end
108
112
 
109
- # Assigns intrinsics for the first distributed trace in a trip
110
- def assign_intrinsics_for_first_trace transaction, transaction_payload
113
+ def assign_initial_intrinsics transaction, transaction_payload
111
114
  transaction_payload[GUID_INTRINSIC_KEY] = transaction.guid
112
115
  transaction_payload[TRACE_ID_INTRINSIC_KEY] = transaction.trace_id
113
- transaction_payload[TRIP_ID_INTRINSIC_KEY] = transaction.trace_id
116
+ transaction_payload[SAMPLED_INTRINSIC_KEY] = transaction.sampled?
114
117
  end
115
118
 
116
119
  def major_version_matches?(payload)
@@ -119,27 +122,48 @@ module NewRelic
119
122
 
120
123
  private
121
124
 
122
- # We use the presence of the cross_process_id in the config to tell if we
123
- # have connected yet.
125
+ # We use the presence of the account_id and primary_application in the
126
+ # config to tell if we have connected yet.
124
127
  def connected?
125
- !!Agent.config[:'cross_process_id']
128
+ Agent.config[:account_id] && Agent.config[:primary_application_id]
129
+ end
130
+
131
+ def assign_trusted_account_key payload, account_id
132
+ trusted_account_key = Agent.config[:trusted_account_key]
133
+
134
+ if account_id != trusted_account_key
135
+ payload.trusted_account_key = trusted_account_key
136
+ end
137
+ end
138
+
139
+ def current_segment_id(transaction)
140
+ if Agent.config[:'span_events.enabled'] && transaction.sampled? &&
141
+ transaction.current_segment
142
+ transaction.current_segment.guid
143
+ end
126
144
  end
127
145
  end
128
146
 
129
147
  attr_accessor :version,
130
148
  :parent_type,
131
- :caller_transport_type,
132
149
  :parent_account_id,
133
150
  :parent_app_id,
151
+ :trusted_account_key,
134
152
  :id,
153
+ :transaction_id,
135
154
  :trace_id,
136
155
  :sampled,
137
156
  :priority,
138
- :parent_id,
139
157
  :timestamp
140
158
 
141
159
  alias_method :sampled?, :sampled
142
160
 
161
+ attr_reader :caller_transport_type
162
+
163
+ def caller_transport_type=(type)
164
+ @caller_transport_type = valid_transport_type_for(type)
165
+ end
166
+
143
167
  def initialize
144
168
  @caller_transport_type = PARENT_TRANSPORT_TYPE_UNKNOWN
145
169
  end
@@ -153,25 +177,39 @@ module NewRelic
153
177
  PARENT_TYPE_KEY => parent_type,
154
178
  PARENT_ACCOUNT_ID_KEY => parent_account_id,
155
179
  PARENT_APP_KEY => parent_app_id,
156
- ID_KEY => id,
180
+ TX_KEY => transaction_id,
157
181
  TRACE_ID_KEY => trace_id,
158
182
  SAMPLED_KEY => sampled,
159
183
  PRIORITY_KEY => priority,
160
- PARENT_ID_KEY => parent_id,
161
- # GRANDPARENT_ID_KEY does not go into the outbound JSON payload;
162
- # the callee will take our parent ID as its grandparent ID
163
- TIMESTAMP_KEY => timestamp,
184
+ TIMESTAMP_KEY => timestamp,
164
185
  }
165
186
 
187
+ result[DATA_KEY][ID_KEY] = id if id
188
+ result[DATA_KEY][TRUSTED_ACCOUNT_KEY] = trusted_account_key if trusted_account_key
189
+
166
190
  JSON.dump(result)
167
191
  end
168
192
 
169
- alias_method :text, :to_json
170
-
193
+ # Encode this payload as a string suitable for passing via an
194
+ # HTTP header.
195
+ #
196
+ # @return [String] Payload translated to JSON and encoded for
197
+ # inclusion in headers
198
+ #
199
+ # @api public
171
200
  def http_safe
172
201
  Base64.strict_encode64 to_json
173
202
  end
174
203
 
204
+ # Represent this payload as a raw JSON string.
205
+ #
206
+ # @return [String] Payload translated to JSON
207
+ #
208
+ # @api public
209
+ def text
210
+ to_json
211
+ end
212
+
175
213
  def assign_intrinsics transaction, transaction_payload
176
214
  transaction_payload[PARENT_TYPE_INTRINSIC_KEY] = parent_type
177
215
  transaction_payload[PARENT_APP_INTRINSIC_KEY] = parent_app_id
@@ -180,9 +218,28 @@ module NewRelic
180
218
  transaction_payload[PARENT_TRANSPORT_DURATION_INTRINSIC_KEY] = transaction.transport_duration
181
219
  transaction_payload[GUID_INTRINSIC_KEY] = transaction.guid
182
220
  transaction_payload[TRACE_ID_INTRINSIC_KEY] = trace_id
183
- transaction_payload[TRIP_ID_INTRINSIC_KEY] = trace_id
184
221
  transaction_payload[PARENT_ID_INTRINSIC_KEY] = transaction.parent_id if transaction.parent_id
185
- transaction_payload[GRANDPARENT_ID_INTRINSIC_KEY] = transaction.grandparent_id if transaction.grandparent_id
222
+ transaction_payload[PARENT_SPAN_ID_INTRINSIC_KEY] = id if id
223
+ transaction_payload[SAMPLED_INTRINSIC_KEY] = transaction.sampled?
224
+ end
225
+
226
+ private
227
+
228
+ ALLOWABLE_TRANSPORT_TYPES = Set.new(%w[
229
+ Unknown
230
+ HTTP
231
+ HTTPS
232
+ Kafka
233
+ JMS
234
+ IronMQ
235
+ AMQP
236
+ Queue
237
+ Other
238
+ ]).freeze
239
+
240
+ def valid_transport_type_for(value)
241
+ return value if ALLOWABLE_TRANSPORT_TYPES.include?(value)
242
+ PARENT_TRANSPORT_TYPE_UNKNOWN
186
243
  end
187
244
  end
188
245
  end