newrelic_rpm 4.5.0.337 → 4.6.0.338

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -0
  3. data/CHANGELOG.md +8 -0
  4. data/lib/new_relic/agent.rb +1 -0
  5. data/lib/new_relic/agent/agent.rb +19 -12
  6. data/lib/new_relic/agent/configuration/default_source.rb +7 -0
  7. data/lib/new_relic/agent/distributed_trace_monitor.rb +29 -0
  8. data/lib/new_relic/agent/distributed_trace_payload.rb +223 -0
  9. data/lib/new_relic/agent/distributed_trace_priority_sampled_buffer.rb +72 -0
  10. data/lib/new_relic/agent/external.rb +137 -0
  11. data/lib/new_relic/agent/http_clients/abstract_request.rb +31 -0
  12. data/lib/new_relic/agent/http_clients/curb_wrappers.rb +3 -1
  13. data/lib/new_relic/agent/http_clients/excon_wrappers.rb +3 -1
  14. data/lib/new_relic/agent/http_clients/http_rb_wrappers.rb +3 -1
  15. data/lib/new_relic/agent/http_clients/httpclient_wrappers.rb +3 -1
  16. data/lib/new_relic/agent/http_clients/net_http_wrappers.rb +3 -1
  17. data/lib/new_relic/agent/http_clients/typhoeus_wrappers.rb +3 -1
  18. data/lib/new_relic/agent/sql_sampler.rb +2 -2
  19. data/lib/new_relic/agent/throughput_monitor.rb +59 -0
  20. data/lib/new_relic/agent/transaction.rb +59 -15
  21. data/lib/new_relic/agent/transaction/abstract_segment.rb +17 -5
  22. data/lib/new_relic/agent/transaction/distributed_tracing.rb +121 -0
  23. data/lib/new_relic/agent/transaction/external_request_segment.rb +183 -19
  24. data/lib/new_relic/agent/transaction/segment.rb +2 -3
  25. data/lib/new_relic/agent/transaction/trace.rb +14 -5
  26. data/lib/new_relic/agent/transaction/trace_builder.rb +58 -0
  27. data/lib/new_relic/agent/transaction/trace_node.rb +34 -32
  28. data/lib/new_relic/agent/transaction/tracing.rb +4 -9
  29. data/lib/new_relic/agent/transaction_error_primitive.rb +18 -0
  30. data/lib/new_relic/agent/transaction_event_aggregator.rb +14 -0
  31. data/lib/new_relic/agent/transaction_event_primitive.rb +14 -0
  32. data/lib/new_relic/agent/transaction_event_recorder.rb +9 -1
  33. data/lib/new_relic/agent/transaction_sampler.rb +12 -66
  34. data/lib/new_relic/agent/transaction_state.rb +1 -3
  35. data/lib/new_relic/supportability_helper.rb +5 -0
  36. data/lib/new_relic/version.rb +1 -1
  37. data/newrelic.yml +1 -1
  38. data/newrelic_rpm.gemspec +1 -1
  39. data/test/agent_helper.rb +11 -3
  40. metadata +10 -4
  41. data/lib/new_relic/agent/transaction_sample_builder.rb +0 -138
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5163342ef18117639611f7ff1658dbd48aaaae2c
4
- data.tar.gz: d2d78f11f66675e6887ea6a9a8ec3606d5e45704
3
+ metadata.gz: 3f0dcf7789c565bfbc24cc8b1c65ec3d3b05d715
4
+ data.tar.gz: 50ba88cad5a895adafc8c4923143b30f0d85f1e1
5
5
  SHA512:
6
- metadata.gz: 3c371c48d1eaddd30865ee2d1fc1f3fef8fc55182c30d35be4d04b858d276132540f9ffb65f23ec5d231afc0be8991545032b2ef3628add899d1a3c473d7e7e6
7
- data.tar.gz: 075fc7e970ac1c0d99ee4152550551cc85f3f764bfdd8ee6643f021710242ab2d47985d4c259f4adbd4544ae74826e2d900b1a9152bb882098f58d36d2e0aacb
6
+ metadata.gz: 98acebde2bc526125b36318ccd71e94dec996adb273894e25b38497ba3e4fe3b62d86613c5dc2d8cef198e0c83084584e8b7b5205002bb79155dbca323f3615c
7
+ data.tar.gz: 8d0f588e0b0c40b4398f2cee2a4d3d30d6f0022a584713c0f068d1546c2d975bc624e93b77c318cb94cbd4f59ecac0611e6f10c7d7fac04e5d15a197854f1d01
data/.yardopts CHANGED
@@ -2,6 +2,7 @@
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/external.rb
5
6
  lib/new_relic/agent/instrumentation/controller_instrumentation.rb
6
7
  lib/new_relic/agent/instrumentation/rack.rb
7
8
  lib/new_relic/agent/instrumentation/metric_frame.rb
@@ -15,6 +16,7 @@ lib/new_relic/rack/agent_hooks.rb
15
16
  lib/new_relic/rack/browser_monitoring.rb
16
17
  lib/new_relic/rack/error_collector.rb
17
18
  lib/new_relic/rack.rb
19
+ lib/new_relic/agent/transaction/external_request_segment.rb
18
20
  -
19
21
  LICENSE
20
22
  CHANGELOG
@@ -1,5 +1,13 @@
1
1
  # New Relic Ruby Agent Release Notes #
2
2
 
3
+ ## v4.6.0 ##
4
+
5
+ * Public API for External Requests
6
+
7
+ The agent now has public API for instrumenting external requests and linking
8
+ up transactions via cross application tracing. See the [API Guide](https://docs.newrelic.com/docs/agents/ruby-agent/customization/ruby-agent-api-guide#externals)
9
+ for more details this new functionality.
10
+
3
11
  ## v4.5.0 ##
4
12
 
5
13
  * Send synthetics headers even when CAT disabled
@@ -54,6 +54,7 @@ module NewRelic
54
54
  require 'new_relic/agent/rules_engine'
55
55
  require 'new_relic/agent/http_clients/uri_util'
56
56
  require 'new_relic/agent/system_info'
57
+ require 'new_relic/agent/external'
57
58
 
58
59
  require 'new_relic/agent/instrumentation/controller_instrumentation'
59
60
 
@@ -19,6 +19,7 @@ require 'new_relic/agent/database'
19
19
  require 'new_relic/agent/commands/agent_command_router'
20
20
  require 'new_relic/agent/event_listener'
21
21
  require 'new_relic/agent/cross_app_monitor'
22
+ require 'new_relic/agent/distributed_trace_monitor'
22
23
  require 'new_relic/agent/synthetics_monitor'
23
24
  require 'new_relic/agent/synthetics_event_buffer'
24
25
  require 'new_relic/agent/transaction_event_recorder'
@@ -29,6 +30,7 @@ require 'new_relic/agent/vm/monotonic_gc_profiler'
29
30
  require 'new_relic/agent/utilization_data'
30
31
  require 'new_relic/environment_report'
31
32
  require 'new_relic/agent/attribute_filter'
33
+ require 'new_relic/agent/throughput_monitor'
32
34
 
33
35
  module NewRelic
34
36
  module Agent
@@ -48,18 +50,20 @@ module NewRelic
48
50
 
49
51
  @service = NewRelicService.new
50
52
 
51
- @events = NewRelic::Agent::EventListener.new
52
- @stats_engine = NewRelic::Agent::StatsEngine.new
53
- @transaction_sampler = NewRelic::Agent::TransactionSampler.new
54
- @sql_sampler = NewRelic::Agent::SqlSampler.new
55
- @agent_command_router = NewRelic::Agent::Commands::AgentCommandRouter.new(@events)
56
- @cross_app_monitor = NewRelic::Agent::CrossAppMonitor.new(@events)
57
- @synthetics_monitor = NewRelic::Agent::SyntheticsMonitor.new(@events)
58
- @error_collector = NewRelic::Agent::ErrorCollector.new
59
- @transaction_rules = NewRelic::Agent::RulesEngine.new
60
- @harvest_samplers = NewRelic::Agent::SamplerCollection.new(@events)
61
- @monotonic_gc_profiler = NewRelic::Agent::VM::MonotonicGCProfiler.new
62
- @javascript_instrumentor = NewRelic::Agent::JavascriptInstrumentor.new(@events)
53
+ @events = NewRelic::Agent::EventListener.new
54
+ @stats_engine = NewRelic::Agent::StatsEngine.new
55
+ @transaction_sampler = NewRelic::Agent::TransactionSampler.new
56
+ @sql_sampler = NewRelic::Agent::SqlSampler.new
57
+ @agent_command_router = NewRelic::Agent::Commands::AgentCommandRouter.new(@events)
58
+ @cross_app_monitor = NewRelic::Agent::CrossAppMonitor.new(@events)
59
+ @distributed_trace_monitor = NewRelic::Agent::DistributedTraceMonitor.new(@events)
60
+ @synthetics_monitor = NewRelic::Agent::SyntheticsMonitor.new(@events)
61
+ @error_collector = NewRelic::Agent::ErrorCollector.new
62
+ @transaction_rules = NewRelic::Agent::RulesEngine.new
63
+ @harvest_samplers = NewRelic::Agent::SamplerCollection.new(@events)
64
+ @monotonic_gc_profiler = NewRelic::Agent::VM::MonotonicGCProfiler.new
65
+ @javascript_instrumentor = NewRelic::Agent::JavascriptInstrumentor.new(@events)
66
+ @throughput_monitor = NewRelic::Agent::ThroughputMonitor.new
63
67
 
64
68
  @harvester = NewRelic::Agent::Harvester.new(@events)
65
69
  @after_fork_lock = Mutex.new
@@ -140,6 +144,7 @@ module NewRelic
140
144
  attr_reader :custom_event_aggregator
141
145
  attr_reader :transaction_event_recorder
142
146
  attr_reader :attribute_filter
147
+ attr_reader :throughput_monitor
143
148
 
144
149
  def transaction_event_aggregator
145
150
  @transaction_event_recorder.transaction_event_aggregator
@@ -543,6 +548,7 @@ module NewRelic
543
548
  @transaction_event_recorder.drop_buffered_data
544
549
  @custom_event_aggregator.reset!
545
550
  @sql_sampler.reset!
551
+
546
552
  if Agent.config[:clear_transaction_state_after_fork]
547
553
  TransactionState.tl_clear
548
554
  end
@@ -1148,6 +1154,7 @@ module NewRelic
1148
1154
  harvest_and_send_for_agent_commands
1149
1155
  end
1150
1156
  ensure
1157
+ throughput_monitor.reset!
1151
1158
  NewRelic::Agent::Database.close_connections
1152
1159
  duration = (Time.now - now).to_f
1153
1160
  NewRelic::Agent.record_metric('Supportability/Harvest', duration)
@@ -1639,6 +1639,13 @@ module NewRelic
1639
1639
  :type => Boolean,
1640
1640
  :allowed_from_server => false,
1641
1641
  :description => 'If <code>true</code>, the agent will clear <code>TransactionState</code> in <code>Agent.drop_buffered_data</code>.'
1642
+ },
1643
+ :'distributed_tracing.enabled' => {
1644
+ :default => false,
1645
+ :public => false,
1646
+ :type => Boolean,
1647
+ :allowed_from_server => false,
1648
+ :description => 'If <code>true</code> enables experimental distributed tracing feature.'
1642
1649
  }
1643
1650
  }.freeze
1644
1651
  end
@@ -0,0 +1,29 @@
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
+
5
+ require 'new_relic/agent/inbound_request_monitor'
6
+ require 'new_relic/agent/cross_app_tracing'
7
+
8
+ module NewRelic
9
+ module Agent
10
+ class DistributedTraceMonitor < InboundRequestMonitor
11
+ NEWRELIC_TRACE_KEY = 'HTTP_X_NEWRELIC_TRACE'.freeze
12
+ HTTP_TRANSPORT_TYPE = 'HTTP'.freeze
13
+
14
+ def on_finished_configuring(events)
15
+ return unless NewRelic::Agent.config[:'distributed_tracing.enabled']
16
+ events.subscribe(:before_call, &method(:on_before_call))
17
+ end
18
+
19
+ def on_before_call(request)
20
+ return unless CrossAppTracing.cross_app_enabled?
21
+ return unless payload = request[NEWRELIC_TRACE_KEY]
22
+
23
+ state = NewRelic::Agent::TransactionState.tl_get
24
+ txn = state.current_transaction
25
+ txn.accept_distributed_trace_payload HTTP_TRANSPORT_TYPE, payload
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,223 @@
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 'json'
5
+ require 'base64'
6
+
7
+ module NewRelic
8
+ module Agent
9
+ class DistributedTracePayload
10
+ VERSION =[0, 0].freeze
11
+ CALLER_TYPE = "App".freeze
12
+ POUND = '#'.freeze
13
+
14
+ # Key names for serialization
15
+ VERSION_KEY = 'v'.freeze
16
+ DATA_KEY = 'd'.freeze
17
+ CALLER_TYPE_KEY = 'ty'.freeze
18
+ CALLER_ACCOUNT_KEY = 'ac'.freeze
19
+ CALLER_APP_KEY = 'ap'.freeze
20
+ ID_KEY = 'id'.freeze
21
+ TRIP_ID_KEY = 'tr'.freeze
22
+ SAMPLED_KEY = 'sa'.freeze
23
+ PARENT_IDS_KEY = 'pa'.freeze
24
+ DEPTH_KEY = 'de'.freeze
25
+ ORDER_KEY = 'or'.freeze
26
+ TIMESTAMP_KEY = 'ti'.freeze
27
+ HOST_KEY = 'ho'.freeze
28
+ SYNTHETICS_KEY = 'sy'.freeze
29
+ SYNTHETICS_RESOURCE_KEY = 'r'.freeze
30
+ SYNTHETICS_JOB_KEY = 'j'.freeze
31
+ SYNTHETICS_MONITOR_KEY = 'm'.freeze
32
+
33
+ # Intrinsic Keys
34
+ CALLER_TYPE_INTRINSIC_KEY = "caller.type".freeze
35
+ CALLER_APP_INTRINSIC_KEY = "caller.app".freeze
36
+ CALLER_ACCOUNT_ID_INTRINSIC_KEY = "caller.account".freeze
37
+ CALLER_TRANSPORT_TYPE_INTRINSIC_KEY = "caller.transportType".freeze
38
+ CALLER_TRANSPORT_DURATION_INTRINSIC_KEY = "caller.transportDuration".freeze
39
+ CALLER_HOST_INTRINSIC_KEY = "caller.host".freeze
40
+ DEPTH_INTRINSIC_KEY = "nr.depth".freeze
41
+ ORDER_INTRINSIC_KEY = "nr.order".freeze
42
+ GUID_INTRINSIC_KEY = "nr.guid".freeze
43
+ REFERRING_TRANSACTION_GUID_INTRINSIC_KEY = "nr.referringTransactionGuid".freeze
44
+ TRIP_ID_INTRINSIC_KEY = "nr.tripId".freeze
45
+ PARENT_IDS_INTRINSIC_KEY = "nr.parentIds".freeze
46
+ COMMA = ",".freeze
47
+
48
+ INTRINSIC_KEYS = [
49
+ CALLER_TYPE_INTRINSIC_KEY,
50
+ CALLER_APP_INTRINSIC_KEY,
51
+ CALLER_ACCOUNT_ID_INTRINSIC_KEY,
52
+ CALLER_TRANSPORT_TYPE_INTRINSIC_KEY,
53
+ CALLER_TRANSPORT_DURATION_INTRINSIC_KEY,
54
+ CALLER_HOST_INTRINSIC_KEY,
55
+ DEPTH_INTRINSIC_KEY,
56
+ ORDER_INTRINSIC_KEY,
57
+ GUID_INTRINSIC_KEY,
58
+ REFERRING_TRANSACTION_GUID_INTRINSIC_KEY,
59
+ TRIP_ID_INTRINSIC_KEY,
60
+ PARENT_IDS_INTRINSIC_KEY
61
+ ].freeze
62
+
63
+ class << self
64
+ def for_transaction transaction, uri=nil
65
+ payload = new
66
+ return payload unless connected?
67
+
68
+ payload.version = VERSION
69
+ payload.caller_type = CALLER_TYPE
70
+
71
+ # We should not rely on the xp_id being formulated this way, but we have
72
+ # seen nil account ids coming down in staging for some accounts
73
+ account_id, fallback_app_id = Agent.config[:cross_process_id].split(POUND)
74
+ payload.caller_account_id = account_id
75
+
76
+ payload.caller_app_id = if Agent.config[:application_id].empty?
77
+ fallback_app_id
78
+ else
79
+ Agent.config[:application_id]
80
+ end
81
+
82
+ payload.timestamp = (Time.now.to_f * 1000).round
83
+ payload.id = transaction.guid
84
+ payload.trip_id = transaction.distributed_tracing_trip_id
85
+ payload.sampled = transaction.sampled?
86
+ payload.parent_ids = transaction.parent_ids
87
+ payload.depth = transaction.depth + 1
88
+ payload.order = transaction.order
89
+ payload.host = uri.host if uri
90
+
91
+ if transaction.synthetics_payload
92
+ payload.synthetics_resource = transaction.synthetics_payload[2]
93
+ payload.synthetics_job = transaction.synthetics_payload[3]
94
+ payload.synthetics_monitor = transaction.synthetics_payload[4]
95
+ end
96
+
97
+ payload
98
+ end
99
+
100
+ def from_json serialized_payload
101
+ raw_payload = JSON.parse serialized_payload
102
+ payload_data = raw_payload[DATA_KEY]
103
+
104
+ payload = new
105
+ payload.version = raw_payload[VERSION_KEY]
106
+ payload.caller_type = payload_data[CALLER_TYPE_KEY]
107
+ payload.caller_account_id = payload_data[CALLER_ACCOUNT_KEY]
108
+ payload.caller_app_id = payload_data[CALLER_APP_KEY]
109
+ payload.timestamp = payload_data[TIMESTAMP_KEY]
110
+ payload.id = payload_data[ID_KEY]
111
+ payload.trip_id = payload_data[TRIP_ID_KEY]
112
+ payload.sampled = payload_data[SAMPLED_KEY]
113
+ payload.parent_ids = payload_data[PARENT_IDS_KEY]
114
+ payload.depth = payload_data[DEPTH_KEY]
115
+ payload.order = payload_data[ORDER_KEY]
116
+ payload.host = payload_data[HOST_KEY]
117
+
118
+ if payload_synthetics = payload_data[SYNTHETICS_KEY]
119
+ payload.synthetics_resource = payload_synthetics[SYNTHETICS_RESOURCE_KEY]
120
+ payload.synthetics_job = payload_synthetics[SYNTHETICS_JOB_KEY]
121
+ payload.synthetics_monitor = payload_synthetics[SYNTHETICS_MONITOR_KEY]
122
+ end
123
+
124
+ payload
125
+ end
126
+
127
+ def from_http_safe http_safe_payload
128
+ decoded_payload = Base64.strict_decode64 http_safe_payload
129
+ from_json decoded_payload
130
+ end
131
+
132
+ #assigns intrinsics for the first distributed trace in a trip
133
+ def assign_initial_intrinsics transaction, payload
134
+ payload[TRIP_ID_INTRINSIC_KEY] = transaction.distributed_tracing_trip_id
135
+ payload[DEPTH_INTRINSIC_KEY] = transaction.depth
136
+ payload[PARENT_IDS_INTRINSIC_KEY] = transaction.parent_ids
137
+ end
138
+
139
+ private
140
+
141
+ # We use the presence of the cross_process_id in the config to tell if we
142
+ # have connected yet.
143
+ def connected?
144
+ !!Agent.config[:'cross_process_id']
145
+ end
146
+ end
147
+
148
+ attr_accessor :version,
149
+ :caller_type,
150
+ :caller_transport_type,
151
+ :caller_account_id,
152
+ :caller_app_id,
153
+ :id,
154
+ :trip_id,
155
+ :sampled,
156
+ :parent_ids,
157
+ :synthetics_resource,
158
+ :synthetics_job,
159
+ :synthetics_monitor,
160
+ :order,
161
+ :depth,
162
+ :timestamp,
163
+ :host
164
+
165
+ alias_method :sampled?, :sampled
166
+
167
+ def synthetics?
168
+ !!(synthetics_resource || synthetics_job || synthetics_monitor)
169
+ end
170
+
171
+ def to_json
172
+ result = {
173
+ VERSION_KEY => version
174
+ }
175
+
176
+ result[DATA_KEY] = {
177
+ CALLER_TYPE_KEY => caller_type,
178
+ CALLER_ACCOUNT_KEY => caller_account_id,
179
+ CALLER_APP_KEY => caller_app_id,
180
+ ID_KEY => id,
181
+ TRIP_ID_KEY => trip_id,
182
+ SAMPLED_KEY => sampled,
183
+ PARENT_IDS_KEY => parent_ids,
184
+ DEPTH_KEY => depth,
185
+ ORDER_KEY => order,
186
+ HOST_KEY => host,
187
+ TIMESTAMP_KEY => timestamp,
188
+ }
189
+
190
+ if synthetics?
191
+ result[DATA_KEY][SYNTHETICS_KEY] = {
192
+ SYNTHETICS_RESOURCE_KEY => synthetics_resource,
193
+ SYNTHETICS_JOB_KEY => synthetics_job,
194
+ SYNTHETICS_MONITOR_KEY => synthetics_monitor
195
+ }
196
+ end
197
+
198
+ JSON.dump(result)
199
+ end
200
+
201
+ alias_method :text, :to_json
202
+
203
+ def http_safe
204
+ Base64.strict_encode64 to_json
205
+ end
206
+
207
+ def assign_intrinsics transaction, payload
208
+ payload[CALLER_TYPE_INTRINSIC_KEY] = caller_type
209
+ payload[CALLER_APP_INTRINSIC_KEY] = caller_app_id
210
+ payload[CALLER_ACCOUNT_ID_INTRINSIC_KEY] = caller_account_id
211
+ payload[CALLER_TRANSPORT_TYPE_INTRINSIC_KEY] = caller_transport_type
212
+ payload[CALLER_TRANSPORT_DURATION_INTRINSIC_KEY] = transaction.transport_duration
213
+ payload[CALLER_HOST_INTRINSIC_KEY] = host
214
+ payload[DEPTH_INTRINSIC_KEY] = depth
215
+ payload[ORDER_INTRINSIC_KEY] = order
216
+ payload[GUID_INTRINSIC_KEY] = transaction.guid
217
+ payload[REFERRING_TRANSACTION_GUID_INTRINSIC_KEY] = id
218
+ payload[TRIP_ID_INTRINSIC_KEY] = trip_id
219
+ payload[PARENT_IDS_INTRINSIC_KEY] = parent_ids.join COMMA if parent_ids
220
+ end
221
+ end
222
+ end
223
+ end
@@ -0,0 +1,72 @@
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
+
5
+ require 'new_relic/agent/event_buffer'
6
+ require 'set'
7
+
8
+ module NewRelic
9
+ module Agent
10
+ class DistributedTracePrioritySampledBuffer < SampledBuffer
11
+ attr_reader :seen_lifetime, :captured_lifetime
12
+
13
+ def initialize(capacity)
14
+ @low_priority_indices = []
15
+ @high_priority_indices = Set.new
16
+ super
17
+ end
18
+
19
+ def append_sampled(x = nil, &blk)
20
+ raise ArgumentError, "Expected argument or block, but received both" if x && blk
21
+
22
+ @seen += 1
23
+ @seen_lifetime += 1
24
+ if @items.size < @capacity
25
+ x = blk.call if block_given?
26
+ insert_high_priority x
27
+ @captured_lifetime += 1
28
+ return x
29
+ elsif !@low_priority_indices.empty? # overwite random low priority sample
30
+ m = rand(@low_priority_indices.size)
31
+ insert_high_priority x, @low_priority_indices.delete_at(m)
32
+ return x
33
+ else
34
+ NewRelic::Agent.increment_metric "Supportability/DistributedTracing/SampledBufferFailure/BufferFull"
35
+ return nil
36
+ end
37
+ end
38
+
39
+ def append_event(x = nil, &blk)
40
+ raise ArgumentError, "Expected argument or block, but received both" if x && blk
41
+
42
+ if @items.size < @capacity
43
+ x = blk.call if block_given?
44
+ insert_low_priority x
45
+ @captured_lifetime += 1
46
+ return x
47
+ else
48
+ m = rand(@seen) # [0, @seen)
49
+ if m < @capacity && !@high_priority_indices.include?(m)
50
+ x = blk.call if block_given?
51
+ insert_low_priority x, m
52
+ return x
53
+ else
54
+ # discard current sample
55
+ return nil
56
+ end
57
+ end
58
+ end
59
+
60
+ def insert_low_priority x, index = @items.size
61
+ @items[index] = x
62
+ @low_priority_indices << index
63
+ end
64
+
65
+ def insert_high_priority x, index = @items.size
66
+ @items[index] = x
67
+ @high_priority_indices << index
68
+ end
69
+ end
70
+ end
71
+ end
72
+