newrelic_rpm 4.8.0.341 → 5.0.0.342
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +27 -0
- data/CHANGELOG.md +39 -0
- data/config.dot +0 -3
- data/lib/new_relic/agent/{throughput_monitor.rb → adaptive_sampler.rb} +22 -13
- data/lib/new_relic/agent/agent.rb +3 -4
- data/lib/new_relic/agent/configuration/default_source.rb +22 -17
- data/lib/new_relic/agent/configuration/high_security_source.rb +0 -2
- data/lib/new_relic/agent/database.rb +5 -0
- data/lib/new_relic/agent/database/explain_plan_helpers.rb +11 -0
- data/lib/new_relic/agent/distributed_trace_monitor.rb +4 -2
- data/lib/new_relic/agent/distributed_trace_payload.rb +88 -119
- data/lib/new_relic/agent/external.rb +14 -0
- data/lib/new_relic/agent/heap.rb +140 -0
- data/lib/new_relic/agent/instrumentation/bunny.rb +5 -1
- data/lib/new_relic/agent/instrumentation/rails5/action_cable.rb +5 -1
- data/lib/new_relic/agent/messaging.rb +10 -0
- data/lib/new_relic/agent/new_relic_service.rb +43 -23
- data/lib/new_relic/agent/priority_sampled_buffer.rb +68 -0
- data/lib/new_relic/agent/supported_versions.rb +1 -1
- data/lib/new_relic/agent/transaction.rb +14 -8
- data/lib/new_relic/agent/transaction/distributed_tracing.rb +113 -55
- data/lib/new_relic/agent/transaction/external_request_segment.rb +17 -11
- data/lib/new_relic/agent/transaction/message_broker_segment.rb +12 -4
- data/lib/new_relic/agent/transaction_error_primitive.rb +2 -8
- data/lib/new_relic/agent/transaction_event_aggregator.rb +16 -13
- data/lib/new_relic/agent/transaction_event_primitive.rb +5 -3
- data/lib/new_relic/agent/transaction_event_recorder.rb +3 -11
- data/lib/new_relic/recipes/capistrano3.rb +5 -2
- data/lib/new_relic/version.rb +2 -2
- data/newrelic_rpm.gemspec +3 -2
- metadata +38 -9
- data/lib/new_relic/agent/distributed_trace_priority_sampled_buffer.rb +0 -72
@@ -53,6 +53,15 @@ module NewRelic
|
|
53
53
|
#
|
54
54
|
def process_request_metadata request_metadata
|
55
55
|
NewRelic::Agent.record_api_supportability_metric(:process_request_metadata)
|
56
|
+
|
57
|
+
if NewRelic::Agent.config[:'distributed_tracing.enabled']
|
58
|
+
NewRelic::Agent.logger.log_once(
|
59
|
+
:warn,
|
60
|
+
:process_request_metadata_noop,
|
61
|
+
'Skipping process_request_metadata because distributed tracing is enabled')
|
62
|
+
return
|
63
|
+
end
|
64
|
+
|
56
65
|
return unless CrossAppTracing.cross_app_enabled?
|
57
66
|
|
58
67
|
state = NewRelic::Agent::TransactionState.tl_get
|
@@ -100,6 +109,11 @@ module NewRelic
|
|
100
109
|
NewRelic::Agent.record_api_supportability_metric(:get_response_metadata)
|
101
110
|
return unless CrossAppTracing.cross_app_enabled?
|
102
111
|
|
112
|
+
if NewRelic::Agent.config[:'distributed_tracing.enabled']
|
113
|
+
::NewRelic::Agent.logger.warn('Skipping get_response_metadata because distributed tracing is enabled')
|
114
|
+
return
|
115
|
+
end
|
116
|
+
|
103
117
|
state = NewRelic::Agent::TransactionState.tl_get
|
104
118
|
if transaction = state.current_transaction and state.client_cross_app_id
|
105
119
|
|
@@ -0,0 +1,140 @@
|
|
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
|
+
module NewRelic
|
6
|
+
module Agent
|
7
|
+
# This class implements a min Heap. The first element is always the one with the
|
8
|
+
# lowest priority. It is a tree structure that is represented as an array. The
|
9
|
+
# relationship between between nodes in the tree and indices in the array are as
|
10
|
+
# follows:
|
11
|
+
#
|
12
|
+
# parent_index = (child_index - 1) / 2
|
13
|
+
# left_child_index = parent_index * 2 + 1
|
14
|
+
# right_child_index = parent_index * 2 + 2
|
15
|
+
#
|
16
|
+
# the root node is at index 0
|
17
|
+
# a node is a leaf node when its index >= length / 2
|
18
|
+
#
|
19
|
+
|
20
|
+
class Heap
|
21
|
+
|
22
|
+
# @param [Array] items an optional array of items to intialize the heap
|
23
|
+
#
|
24
|
+
# @param [Callable] priority_fn an optional priority function used to
|
25
|
+
# to compute the priority for an item. If it's not supplied priority
|
26
|
+
# will be computed using Comparable.
|
27
|
+
def initialize(items = nil, &priority_fn)
|
28
|
+
@items = []
|
29
|
+
@priority_fn = priority_fn || ->(x) { x }
|
30
|
+
items.each{ |item| push(item) } if items
|
31
|
+
end
|
32
|
+
|
33
|
+
def [](index)
|
34
|
+
@items[index]
|
35
|
+
end
|
36
|
+
|
37
|
+
def []=(index, value)
|
38
|
+
@items[index] = value
|
39
|
+
end
|
40
|
+
|
41
|
+
def fix(index)
|
42
|
+
parent_index = parent_index_for(index)
|
43
|
+
|
44
|
+
if in_range?(parent_index) && priority(parent_index) > priority(index)
|
45
|
+
heapify_up(index)
|
46
|
+
else
|
47
|
+
child_index = left_child_index_for(index)
|
48
|
+
|
49
|
+
return unless in_range?(child_index)
|
50
|
+
|
51
|
+
if right_sibling_smaller?(child_index)
|
52
|
+
child_index += 1
|
53
|
+
end
|
54
|
+
|
55
|
+
if priority(child_index) < priority(index)
|
56
|
+
heapify_down(index)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def push(item)
|
62
|
+
@items << item
|
63
|
+
heapify_up(size - 1)
|
64
|
+
end
|
65
|
+
|
66
|
+
alias_method :<<, :push
|
67
|
+
|
68
|
+
def pop
|
69
|
+
swap(0, size - 1)
|
70
|
+
item = @items.pop
|
71
|
+
heapify_down(0)
|
72
|
+
item
|
73
|
+
end
|
74
|
+
|
75
|
+
def size
|
76
|
+
@items.size
|
77
|
+
end
|
78
|
+
|
79
|
+
def empty?
|
80
|
+
@items.empty?
|
81
|
+
end
|
82
|
+
|
83
|
+
def to_a
|
84
|
+
@items
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def priority(index)
|
90
|
+
@priority_fn.call(@items[index])
|
91
|
+
end
|
92
|
+
|
93
|
+
def parent_index_for child_index
|
94
|
+
(child_index - 1) / 2
|
95
|
+
end
|
96
|
+
|
97
|
+
def left_child_index_for parent_index
|
98
|
+
2 * parent_index + 1
|
99
|
+
end
|
100
|
+
|
101
|
+
def right_sibling_smaller?(lchild_index)
|
102
|
+
in_range?(lchild_index + 1) && priority(lchild_index) > priority(lchild_index + 1)
|
103
|
+
end
|
104
|
+
|
105
|
+
def in_range?(index)
|
106
|
+
index >= 0 && index < size
|
107
|
+
end
|
108
|
+
|
109
|
+
def heapify_up(child_index)
|
110
|
+
return if child_index == 0
|
111
|
+
|
112
|
+
parent_index = parent_index_for(child_index)
|
113
|
+
|
114
|
+
if priority(child_index) < priority(parent_index)
|
115
|
+
swap(child_index, parent_index)
|
116
|
+
heapify_up(parent_index)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def heapify_down(parent_index)
|
121
|
+
child_index = left_child_index_for(parent_index)
|
122
|
+
return unless in_range?(child_index)
|
123
|
+
|
124
|
+
if right_sibling_smaller?(child_index)
|
125
|
+
child_index += 1
|
126
|
+
end
|
127
|
+
|
128
|
+
if priority(child_index) < priority(parent_index)
|
129
|
+
swap(parent_index, child_index)
|
130
|
+
heapify_down(child_index)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def swap(i, j)
|
135
|
+
@items[i], @items[j] = @items[j], @items[i]
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
end
|
@@ -24,7 +24,11 @@ DependencyDetection.defer do
|
|
24
24
|
def publish payload, opts = {}
|
25
25
|
begin
|
26
26
|
destination = NewRelic::Agent::Instrumentation::Bunny.exchange_name(name)
|
27
|
-
|
27
|
+
|
28
|
+
tracing_enabled =
|
29
|
+
NewRelic::Agent::CrossAppTracing.cross_app_enabled? ||
|
30
|
+
NewRelic::Agent.config[:'distributed_tracing.enabled']
|
31
|
+
opts[:headers] ||= {} if tracing_enabled
|
28
32
|
|
29
33
|
segment = NewRelic::Agent::Messaging.start_amqp_publish_segment(
|
30
34
|
library: NewRelic::Agent::Instrumentation::Bunny::LIBRARY,
|
@@ -27,6 +27,10 @@ DependencyDetection.defer do
|
|
27
27
|
ActiveSupport::Notifications.subscribe(/(perform_action|transmit)\.action_cable/,
|
28
28
|
NewRelic::Agent::Instrumentation::ActionCableSubscriber.new)
|
29
29
|
|
30
|
-
|
30
|
+
ActiveSupport.on_load(:action_cable) do
|
31
|
+
::NewRelic::Agent::PrependSupportability.record_metrics_for(
|
32
|
+
::ActionCable::Engine,
|
33
|
+
::ActionCable::RemoteConnections)
|
34
|
+
end
|
31
35
|
end
|
32
36
|
end
|
@@ -364,7 +364,17 @@ module NewRelic
|
|
364
364
|
transaction_name
|
365
365
|
end
|
366
366
|
|
367
|
+
NEWRELIC_TRACE_KEY = "NewRelicTrace".freeze
|
368
|
+
RABBITMQ_TRANSPORT_TYPE = "RabbitMQ".freeze
|
369
|
+
|
367
370
|
def consume_message_headers headers, transaction, state
|
371
|
+
if Agent.config[:'distributed_tracing.enabled']
|
372
|
+
payload = headers[NEWRELIC_TRACE_KEY]
|
373
|
+
if transaction.accept_distributed_trace_payload payload
|
374
|
+
transaction.distributed_trace_payload.caller_transport_type = RABBITMQ_TRANSPORT_TYPE
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
368
378
|
if CrossAppTracing.cross_app_enabled? && CrossAppTracing.message_has_crossapp_request_header?(headers)
|
369
379
|
decode_id headers[CrossAppTracing::NR_MESSAGE_BROKER_ID_HEADER], state
|
370
380
|
decode_txn_info headers[CrossAppTracing::NR_MESSAGE_BROKER_TXN_HEADER], state
|
@@ -15,7 +15,8 @@ module NewRelic
|
|
15
15
|
# Specifies the version of the agent's communication protocol with
|
16
16
|
# the NewRelic hosted site.
|
17
17
|
|
18
|
-
PROTOCOL_VERSION =
|
18
|
+
PROTOCOL_VERSION = 15
|
19
|
+
|
19
20
|
# 1f147a42: v10 (tag 3.5.3.17)
|
20
21
|
# cf0d1ff1: v9 (tag 3.5.0)
|
21
22
|
# 14105: v8 (tag 2.10.3)
|
@@ -30,8 +31,8 @@ module NewRelic
|
|
30
31
|
# underlying TCP connection may be in a bad state.
|
31
32
|
CONNECTION_ERRORS = [Timeout::Error, EOFError, SystemCallError, SocketError].freeze
|
32
33
|
|
33
|
-
attr_accessor :request_timeout
|
34
|
-
attr_reader :collector, :marshaller
|
34
|
+
attr_accessor :request_timeout
|
35
|
+
attr_reader :collector, :marshaller, :agent_id
|
35
36
|
|
36
37
|
def initialize(license_key=nil, collector=control.server)
|
37
38
|
@license_key = license_key
|
@@ -41,18 +42,12 @@ module NewRelic
|
|
41
42
|
@in_session = nil
|
42
43
|
@agent_id = nil
|
43
44
|
@shared_tcp_connection = nil
|
45
|
+
reset_remote_method_uris
|
44
46
|
|
45
47
|
@audit_logger = ::NewRelic::Agent::AuditLogger.new
|
46
48
|
Agent.config.register_callback(:'audit_log.enabled') do |enabled|
|
47
49
|
@audit_logger.enabled = enabled
|
48
50
|
end
|
49
|
-
Agent.config.register_callback(:ssl) do |ssl|
|
50
|
-
if !ssl
|
51
|
-
::NewRelic::Agent.logger.warn("Agent is configured not to use SSL when communicating with New Relic's servers")
|
52
|
-
else
|
53
|
-
::NewRelic::Agent.logger.debug("Agent is configured to use SSL")
|
54
|
-
end
|
55
|
-
end
|
56
51
|
|
57
52
|
Agent.config.register_callback(:marshaller) do |marshaller|
|
58
53
|
if marshaller != 'json'
|
@@ -63,17 +58,26 @@ module NewRelic
|
|
63
58
|
end
|
64
59
|
end
|
65
60
|
|
61
|
+
def agent_id=(id)
|
62
|
+
# Remote URIs have the agent run ID in them, so we need to
|
63
|
+
# clear out our cached values whenever the run ID changes.
|
64
|
+
#
|
65
|
+
reset_remote_method_uris
|
66
|
+
|
67
|
+
@agent_id = id
|
68
|
+
end
|
69
|
+
|
66
70
|
def connect(settings={})
|
67
|
-
if host =
|
71
|
+
if host = preconnect
|
68
72
|
@collector = NewRelic::Control.instance.server_from_host(host)
|
69
73
|
end
|
70
74
|
response = invoke_remote(:connect, [settings])
|
71
|
-
|
75
|
+
self.agent_id = response['agent_run_id']
|
72
76
|
response
|
73
77
|
end
|
74
78
|
|
75
|
-
def
|
76
|
-
invoke_remote(:
|
79
|
+
def preconnect
|
80
|
+
invoke_remote(:preconnect)
|
77
81
|
end
|
78
82
|
|
79
83
|
def shutdown(time)
|
@@ -261,8 +265,7 @@ module NewRelic
|
|
261
265
|
conn.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
262
266
|
conn.cert_store = ssl_cert_store
|
263
267
|
rescue StandardError, LoadError
|
264
|
-
msg = "
|
265
|
-
msg << "Either disable SSL in the agent configuration, or install SSL support."
|
268
|
+
msg = "SSL is not available in the environment; please install SSL support."
|
266
269
|
raise UnrecoverableAgentException.new(msg)
|
267
270
|
end
|
268
271
|
|
@@ -296,7 +299,7 @@ module NewRelic
|
|
296
299
|
conn = Net::HTTP.new(@collector.name, @collector.port)
|
297
300
|
end
|
298
301
|
|
299
|
-
setup_connection_for_ssl(conn)
|
302
|
+
setup_connection_for_ssl(conn)
|
300
303
|
setup_connection_timeouts(conn)
|
301
304
|
|
302
305
|
::NewRelic::Agent.logger.debug("Created net/http handle to #{conn.address}:#{conn.port}")
|
@@ -335,11 +338,28 @@ module NewRelic
|
|
335
338
|
NewRelic::Control.instance
|
336
339
|
end
|
337
340
|
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
341
|
+
def remote_method_uri(method)
|
342
|
+
@remote_method_uris[method]
|
343
|
+
end
|
344
|
+
|
345
|
+
def reset_remote_method_uris
|
346
|
+
@remote_method_uris = Hash.new do |hash, remote_method|
|
347
|
+
hash[remote_method] = generate_remote_method_uri(remote_method)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
def generate_remote_method_uri(method)
|
352
|
+
params = {
|
353
|
+
'protocol_version' => PROTOCOL_VERSION,
|
354
|
+
'license_key' => license_key,
|
355
|
+
'run_id' => @agent_id,
|
356
|
+
'method' => method,
|
357
|
+
'marshal_format' => 'json', # Other formats are explicitly
|
358
|
+
# ruled out; see the initializer
|
359
|
+
}
|
360
|
+
|
361
|
+
uri = "/agent_listener/invoke_raw_method?"
|
362
|
+
uri << params.map do |k,v|
|
343
363
|
next unless v
|
344
364
|
"#{k}=#{v}"
|
345
365
|
end.compact.join('&')
|
@@ -368,7 +388,7 @@ module NewRelic
|
|
368
388
|
data, encoding = compress_request_if_needed(data)
|
369
389
|
size = data.size
|
370
390
|
|
371
|
-
uri = remote_method_uri(method
|
391
|
+
uri = remote_method_uri(method)
|
372
392
|
full_uri = "#{@collector}#{uri}"
|
373
393
|
|
374
394
|
@audit_logger.log_request(full_uri, payload, @marshaller)
|
@@ -0,0 +1,68 @@
|
|
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/heap'
|
6
|
+
|
7
|
+
module NewRelic
|
8
|
+
module Agent
|
9
|
+
class PrioritySampledBuffer < SampledBuffer
|
10
|
+
PRIORITY_KEY = "priority".freeze
|
11
|
+
|
12
|
+
attr_reader :seen_lifetime, :captured_lifetime
|
13
|
+
|
14
|
+
def initialize(capacity)
|
15
|
+
super
|
16
|
+
@captured_lifetime = 0
|
17
|
+
@seen_lifetime = 0
|
18
|
+
end
|
19
|
+
|
20
|
+
# expects priority and a block, or an event as a hash with a `priority` key.
|
21
|
+
def append(priority: nil, event: nil, &blk)
|
22
|
+
increment_seen
|
23
|
+
|
24
|
+
if @seen == @capacity
|
25
|
+
@items = Heap.new(@items) { |x| priority_for(x) }
|
26
|
+
end
|
27
|
+
|
28
|
+
if full?
|
29
|
+
priority ||= priority_for(event)
|
30
|
+
if priority_for(@items[0]) < priority
|
31
|
+
@items[0] = event || blk.call
|
32
|
+
@items.fix(0)
|
33
|
+
end
|
34
|
+
else
|
35
|
+
@items << (event || blk.call)
|
36
|
+
@captured_lifetime += 1
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
alias_method :append_event, :append
|
41
|
+
|
42
|
+
def capacity=(new_capacity)
|
43
|
+
@capacity = new_capacity
|
44
|
+
old_items = @items.to_a
|
45
|
+
old_seen = @seen
|
46
|
+
reset!
|
47
|
+
old_items.each { |i| append(event: i) }
|
48
|
+
@seen = old_seen
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_a
|
52
|
+
@items.to_a.dup
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def increment_seen
|
58
|
+
@seen += 1
|
59
|
+
@seen_lifetime += 1
|
60
|
+
end
|
61
|
+
|
62
|
+
def priority_for(event)
|
63
|
+
event[0][PRIORITY_KEY]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
@@ -11,7 +11,7 @@ module NewRelic
|
|
11
11
|
{
|
12
12
|
:type => :ruby,
|
13
13
|
:name => "MRI",
|
14
|
-
:supported => ["2.0.0", "~>2.1.0", "~>2.2.0", "~>2.3.0", "~>2.4.0"],
|
14
|
+
:supported => ["2.0.0", "~>2.1.0", "~>2.2.0", "~>2.3.0", "~>2.4.0", "~>2.5.0"],
|
15
15
|
:deprecated => ["1.8.6", "1.8.7", "1.9.2", "1.9.3"],
|
16
16
|
:url => "https://www.ruby-lang.org",
|
17
17
|
:feed => "https://www.ruby-lang.org/en/feeds/news.rss",
|
@@ -58,7 +58,8 @@ module NewRelic
|
|
58
58
|
:http_response_code,
|
59
59
|
:response_content_length,
|
60
60
|
:response_content_type,
|
61
|
-
:sampled
|
61
|
+
:sampled,
|
62
|
+
:priority
|
62
63
|
|
63
64
|
attr_reader :guid,
|
64
65
|
:metrics,
|
@@ -283,11 +284,15 @@ module NewRelic
|
|
283
284
|
@ignore_trace = false
|
284
285
|
|
285
286
|
if Agent.config[:'distributed_tracing.enabled']
|
286
|
-
@sampled = NewRelic::Agent.instance.
|
287
|
+
@sampled = NewRelic::Agent.instance.adaptive_sampler.sampled?
|
287
288
|
else
|
288
289
|
@sampled = nil
|
289
290
|
end
|
290
291
|
|
292
|
+
# we will eventually add this behavior into the AdaptiveSampler (ThroughputMontor)
|
293
|
+
@priority = rand
|
294
|
+
@priority +=1 if @sampled
|
295
|
+
|
291
296
|
@attributes = Attributes.new(NewRelic::Agent.instance.attribute_filter)
|
292
297
|
|
293
298
|
merge_request_parameters(@filtered_params)
|
@@ -596,7 +601,7 @@ module NewRelic
|
|
596
601
|
end
|
597
602
|
|
598
603
|
def assign_intrinsics(state)
|
599
|
-
attributes.add_intrinsic_attribute :'
|
604
|
+
attributes.add_intrinsic_attribute :'sampled', sampled?
|
600
605
|
|
601
606
|
if gc_time = calculate_gc_time
|
602
607
|
attributes.add_intrinsic_attribute(:gc_time, gc_time)
|
@@ -612,8 +617,8 @@ module NewRelic
|
|
612
617
|
attributes.add_intrinsic_attribute(:synthetics_monitor_id, synthetics_monitor_id)
|
613
618
|
end
|
614
619
|
|
615
|
-
if distributed_trace_payload ||
|
616
|
-
|
620
|
+
if distributed_trace_payload || distributed_trace_payload_created?
|
621
|
+
assign_distributed_trace_intrinsics
|
617
622
|
elsif state.is_cross_app?
|
618
623
|
attributes.add_intrinsic_attribute(:trip_id, cat_trip_id)
|
619
624
|
attributes.add_intrinsic_attribute(:path_hash, cat_path_hash)
|
@@ -648,13 +653,14 @@ module NewRelic
|
|
648
653
|
:duration => duration,
|
649
654
|
:metrics => @metrics,
|
650
655
|
:attributes => @attributes,
|
651
|
-
:error => false
|
656
|
+
:error => false,
|
657
|
+
:priority => @priority
|
652
658
|
}
|
653
659
|
|
654
|
-
@payload[:'
|
660
|
+
@payload[:'sampled'] = sampled? if Agent.config[:'distributed_tracing.enabled']
|
655
661
|
|
656
662
|
append_cat_info(state, duration, @payload)
|
657
|
-
|
663
|
+
append_distributed_trace_info(@payload)
|
658
664
|
append_apdex_perf_zone(duration, @payload)
|
659
665
|
append_synthetics_to(state, @payload)
|
660
666
|
append_referring_transaction_guid_to(state, @payload)
|