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.
- checksums.yaml +4 -4
- data/.yardopts +2 -0
- data/CHANGELOG.md +8 -0
- data/lib/new_relic/agent.rb +1 -0
- data/lib/new_relic/agent/agent.rb +19 -12
- data/lib/new_relic/agent/configuration/default_source.rb +7 -0
- data/lib/new_relic/agent/distributed_trace_monitor.rb +29 -0
- data/lib/new_relic/agent/distributed_trace_payload.rb +223 -0
- data/lib/new_relic/agent/distributed_trace_priority_sampled_buffer.rb +72 -0
- data/lib/new_relic/agent/external.rb +137 -0
- data/lib/new_relic/agent/http_clients/abstract_request.rb +31 -0
- data/lib/new_relic/agent/http_clients/curb_wrappers.rb +3 -1
- data/lib/new_relic/agent/http_clients/excon_wrappers.rb +3 -1
- data/lib/new_relic/agent/http_clients/http_rb_wrappers.rb +3 -1
- data/lib/new_relic/agent/http_clients/httpclient_wrappers.rb +3 -1
- data/lib/new_relic/agent/http_clients/net_http_wrappers.rb +3 -1
- data/lib/new_relic/agent/http_clients/typhoeus_wrappers.rb +3 -1
- data/lib/new_relic/agent/sql_sampler.rb +2 -2
- data/lib/new_relic/agent/throughput_monitor.rb +59 -0
- data/lib/new_relic/agent/transaction.rb +59 -15
- data/lib/new_relic/agent/transaction/abstract_segment.rb +17 -5
- data/lib/new_relic/agent/transaction/distributed_tracing.rb +121 -0
- data/lib/new_relic/agent/transaction/external_request_segment.rb +183 -19
- data/lib/new_relic/agent/transaction/segment.rb +2 -3
- data/lib/new_relic/agent/transaction/trace.rb +14 -5
- data/lib/new_relic/agent/transaction/trace_builder.rb +58 -0
- data/lib/new_relic/agent/transaction/trace_node.rb +34 -32
- data/lib/new_relic/agent/transaction/tracing.rb +4 -9
- data/lib/new_relic/agent/transaction_error_primitive.rb +18 -0
- data/lib/new_relic/agent/transaction_event_aggregator.rb +14 -0
- data/lib/new_relic/agent/transaction_event_primitive.rb +14 -0
- data/lib/new_relic/agent/transaction_event_recorder.rb +9 -1
- data/lib/new_relic/agent/transaction_sampler.rb +12 -66
- data/lib/new_relic/agent/transaction_state.rb +1 -3
- data/lib/new_relic/supportability_helper.rb +5 -0
- data/lib/new_relic/version.rb +1 -1
- data/newrelic.yml +1 -1
- data/newrelic_rpm.gemspec +1 -1
- data/test/agent_helper.rb +11 -3
- metadata +10 -4
- data/lib/new_relic/agent/transaction_sample_builder.rb +0 -138
@@ -18,6 +18,8 @@ module NewRelic
|
|
18
18
|
super name, start_time
|
19
19
|
end
|
20
20
|
|
21
|
+
private
|
22
|
+
|
21
23
|
def record_metrics
|
22
24
|
if record_scoped_metric?
|
23
25
|
metric_cache.record_scoped_and_unscoped name, duration, exclusive_duration
|
@@ -29,8 +31,6 @@ module NewRelic
|
|
29
31
|
end
|
30
32
|
end
|
31
33
|
|
32
|
-
private
|
33
|
-
|
34
34
|
def append_unscoped_metric metric
|
35
35
|
if @unscoped_metrics
|
36
36
|
if Array === @unscoped_metrics
|
@@ -48,7 +48,6 @@ module NewRelic
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def segment_complete
|
51
|
-
Agent.instance.transaction_sampler.add_node_parameters params if params?
|
52
51
|
end
|
53
52
|
end
|
54
53
|
end
|
@@ -15,10 +15,12 @@ module NewRelic
|
|
15
15
|
:attributes, :node_count, :finished, :threshold,
|
16
16
|
:profile
|
17
17
|
|
18
|
+
ROOT = "ROOT".freeze
|
19
|
+
|
18
20
|
def initialize(start_time)
|
19
21
|
@start_time = start_time
|
20
22
|
@node_count = 0
|
21
|
-
@root_node = NewRelic::Agent::Transaction::TraceNode.new(0.0,
|
23
|
+
@root_node = NewRelic::Agent::Transaction::TraceNode.new(ROOT, 0.0, nil, nil, nil)
|
22
24
|
@prepared = false
|
23
25
|
end
|
24
26
|
|
@@ -27,7 +29,12 @@ module NewRelic
|
|
27
29
|
end
|
28
30
|
|
29
31
|
def count_nodes
|
30
|
-
|
32
|
+
node_count = 0
|
33
|
+
each_node do |node|
|
34
|
+
next if node == root_node
|
35
|
+
node_count +=1
|
36
|
+
end
|
37
|
+
node_count
|
31
38
|
end
|
32
39
|
|
33
40
|
def duration
|
@@ -51,7 +58,7 @@ module NewRelic
|
|
51
58
|
def create_node(time_since_start, metric_name = nil)
|
52
59
|
raise FinishedTraceError.new "Can't create additional node for finished trace." if self.finished
|
53
60
|
self.node_count += 1
|
54
|
-
NewRelic::Agent::Transaction::TraceNode.new(
|
61
|
+
NewRelic::Agent::Transaction::TraceNode.new(metric_name, time_since_start)
|
55
62
|
end
|
56
63
|
|
57
64
|
def each_node(&block)
|
@@ -111,6 +118,8 @@ module NewRelic
|
|
111
118
|
@root_node.each_node_with_nest_tracking(&block)
|
112
119
|
end
|
113
120
|
|
121
|
+
EMPTY_HASH = {}.freeze
|
122
|
+
|
114
123
|
def trace_tree
|
115
124
|
destination = NewRelic::Agent::AttributeFilter::DST_TRANSACTION_TRACER
|
116
125
|
|
@@ -120,8 +129,8 @@ module NewRelic
|
|
120
129
|
|
121
130
|
[
|
122
131
|
NewRelic::Coerce.float(self.start_time),
|
123
|
-
|
124
|
-
|
132
|
+
EMPTY_HASH,
|
133
|
+
EMPTY_HASH,
|
125
134
|
self.root_node.to_array,
|
126
135
|
{
|
127
136
|
'agentAttributes' => agent_attributes,
|
@@ -0,0 +1,58 @@
|
|
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/helper'
|
6
|
+
require 'new_relic/agent/transaction/trace'
|
7
|
+
require 'new_relic/agent/transaction/trace_node'
|
8
|
+
|
9
|
+
module NewRelic
|
10
|
+
module Agent
|
11
|
+
class Transaction
|
12
|
+
module TraceBuilder
|
13
|
+
extend self
|
14
|
+
|
15
|
+
def build_trace transaction
|
16
|
+
trace = Trace.new transaction.start_time
|
17
|
+
trace.root_node.exit_timestamp = transaction.end_time - transaction.start_time
|
18
|
+
copy_attributes transaction, trace
|
19
|
+
first, *rest = transaction.segments
|
20
|
+
relationship_map = rest.group_by { |s| s.parent }
|
21
|
+
trace.root_node.children << process_segments(transaction, first, trace.root_node, relationship_map)
|
22
|
+
trace
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# recursively builds a transaction trace from the flat list of segments
|
28
|
+
def process_segments transaction, segment, parent, relationship_map
|
29
|
+
current = create_trace_node transaction, segment, parent
|
30
|
+
|
31
|
+
if children = relationship_map[segment]
|
32
|
+
current.children = children.map! do |child|
|
33
|
+
process_segments transaction, child, current, relationship_map
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
current
|
38
|
+
end
|
39
|
+
|
40
|
+
def create_trace_node transaction, segment, parent
|
41
|
+
relative_start = segment.start_time - transaction.start_time
|
42
|
+
relative_end = segment.end_time - transaction.start_time
|
43
|
+
TraceNode.new segment.name, relative_start, relative_end, segment.params, parent
|
44
|
+
end
|
45
|
+
|
46
|
+
def copy_attributes transaction, trace
|
47
|
+
trace.transaction_name = transaction.best_name
|
48
|
+
trace.uri = transaction.request_path
|
49
|
+
trace.guid = transaction.guid
|
50
|
+
trace.attributes = transaction.attributes
|
51
|
+
trace.threshold = transaction.threshold
|
52
|
+
trace.xray_session_id = transaction.xray_session_id
|
53
|
+
trace.finished = true
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -9,20 +9,21 @@ module NewRelic
|
|
9
9
|
attr_reader :entry_timestamp
|
10
10
|
# The exit timestamp will be relative except for the outermost sample which will
|
11
11
|
# have a timestamp.
|
12
|
-
|
12
|
+
attr_accessor :exit_timestamp
|
13
|
+
|
13
14
|
attr_reader :parent_node
|
14
15
|
|
15
|
-
attr_accessor :metric_name
|
16
|
+
attr_accessor :metric_name
|
16
17
|
|
17
18
|
UNKNOWN_NODE_NAME = '<unknown>'.freeze
|
18
19
|
|
19
|
-
def initialize(
|
20
|
-
@entry_timestamp =
|
20
|
+
def initialize(metric_name, relative_start, relative_end=nil, params=nil, parent=nil)
|
21
|
+
@entry_timestamp = relative_start
|
21
22
|
@metric_name = metric_name || UNKNOWN_NODE_NAME
|
22
|
-
@exit_timestamp =
|
23
|
-
@
|
24
|
-
@params =
|
25
|
-
@parent_node =
|
23
|
+
@exit_timestamp = relative_end
|
24
|
+
@children = nil
|
25
|
+
@params = params
|
26
|
+
@parent_node = parent
|
26
27
|
end
|
27
28
|
|
28
29
|
# sets the final timestamp on a node to indicate the exit
|
@@ -31,33 +32,31 @@ module NewRelic
|
|
31
32
|
@exit_timestamp = timestamp
|
32
33
|
end
|
33
34
|
|
34
|
-
def add_called_node(s)
|
35
|
-
@called_nodes ||= []
|
36
|
-
@called_nodes << s
|
37
|
-
s.parent_node = self
|
38
|
-
end
|
39
|
-
|
40
35
|
def to_s
|
41
36
|
to_debug_str(0)
|
42
37
|
end
|
43
38
|
|
39
|
+
EMPTY_HASH = {}.freeze
|
40
|
+
EMPTY_ARRAY = [].freeze
|
41
|
+
|
44
42
|
def to_array
|
43
|
+
params = @params ? @params : EMPTY_HASH
|
45
44
|
[ NewRelic::Helper.time_to_millis(@entry_timestamp),
|
46
45
|
NewRelic::Helper.time_to_millis(@exit_timestamp),
|
47
46
|
NewRelic::Coerce.string(@metric_name),
|
48
47
|
params ] +
|
49
|
-
[ (@
|
48
|
+
[ (@children ? @children.map{|s| s.to_array} : EMPTY_ARRAY) ]
|
50
49
|
end
|
51
50
|
|
52
51
|
def path_string
|
53
|
-
"#{metric_name}[#{
|
52
|
+
"#{metric_name}[#{children.collect {|node| node.path_string }.join('')}]"
|
54
53
|
end
|
55
54
|
|
56
55
|
def to_s_compact
|
57
56
|
str = ""
|
58
57
|
str << metric_name
|
59
|
-
if
|
60
|
-
str << "{#{
|
58
|
+
if children.any?
|
59
|
+
str << "{#{children.map { | cs | cs.to_s_compact }.join(",")}}"
|
61
60
|
end
|
62
61
|
str
|
63
62
|
end
|
@@ -71,7 +70,7 @@ module NewRelic
|
|
71
70
|
s << "#{tab} -#{'%-16s' % k}: #{v.to_s[0..80]}\n"
|
72
71
|
end
|
73
72
|
end
|
74
|
-
|
73
|
+
children.each do |cs|
|
75
74
|
s << cs.to_debug_str(depth + 1)
|
76
75
|
end
|
77
76
|
s << tab + "<< "
|
@@ -83,10 +82,12 @@ module NewRelic
|
|
83
82
|
s << " #{metric_name}\n"
|
84
83
|
end
|
85
84
|
|
86
|
-
def
|
87
|
-
@
|
85
|
+
def children
|
86
|
+
@children ||= []
|
88
87
|
end
|
89
88
|
|
89
|
+
attr_writer :children
|
90
|
+
|
90
91
|
# return the total duration of this node
|
91
92
|
def duration
|
92
93
|
(@exit_timestamp - @entry_timestamp).to_f
|
@@ -97,7 +98,7 @@ module NewRelic
|
|
97
98
|
def exclusive_duration
|
98
99
|
d = duration
|
99
100
|
|
100
|
-
|
101
|
+
children.each do |node|
|
101
102
|
d -= node.duration
|
102
103
|
end
|
103
104
|
d
|
@@ -105,10 +106,16 @@ module NewRelic
|
|
105
106
|
|
106
107
|
def count_nodes
|
107
108
|
count = 1
|
108
|
-
|
109
|
+
children.each { | node | count += node.count_nodes }
|
109
110
|
count
|
110
111
|
end
|
111
112
|
|
113
|
+
def params
|
114
|
+
@params ||= {}
|
115
|
+
end
|
116
|
+
|
117
|
+
attr_writer :params
|
118
|
+
|
112
119
|
def []=(key, value)
|
113
120
|
# only create a parameters field if a parameter is set; this will save
|
114
121
|
# bandwidth etc as most nodes have no parameters
|
@@ -124,8 +131,8 @@ module NewRelic
|
|
124
131
|
def each_node(&block)
|
125
132
|
block.call self
|
126
133
|
|
127
|
-
if @
|
128
|
-
@
|
134
|
+
if @children
|
135
|
+
@children.each do |node|
|
129
136
|
node.each_node(&block)
|
130
137
|
end
|
131
138
|
end
|
@@ -137,8 +144,8 @@ module NewRelic
|
|
137
144
|
summary = block.call self
|
138
145
|
summary.current_nest_count += 1 if summary
|
139
146
|
|
140
|
-
if @
|
141
|
-
@
|
147
|
+
if @children
|
148
|
+
@children.each do |node|
|
142
149
|
node.each_node_with_nest_tracking(&block)
|
143
150
|
end
|
144
151
|
end
|
@@ -159,11 +166,6 @@ module NewRelic
|
|
159
166
|
NewRelic::Agent::Database.obfuscate_sql(params[:sql].sql)
|
160
167
|
end
|
161
168
|
|
162
|
-
def called_nodes=(nodes)
|
163
|
-
@called_nodes = nodes
|
164
|
-
end
|
165
|
-
|
166
|
-
protected
|
167
169
|
def parent_node=(s)
|
168
170
|
@parent_node = s
|
169
171
|
end
|
@@ -88,25 +88,20 @@ module NewRelic
|
|
88
88
|
segment.transaction = self
|
89
89
|
segment.parent = current_segment
|
90
90
|
@current_segment = segment
|
91
|
-
if @segments.length <
|
91
|
+
if @segments.length < segment_limit
|
92
92
|
@segments << segment
|
93
|
-
transaction_sampler.notice_push_frame state, segment.start_time if transaction_sampler_enabled?
|
94
93
|
else
|
95
94
|
segment.record_on_finish = true
|
95
|
+
::NewRelic::Agent.logger.debug("Segment limit of #{segment_limit} reached, ceasing collection.")
|
96
96
|
end
|
97
97
|
end
|
98
98
|
|
99
99
|
def segment_complete segment
|
100
100
|
@current_segment = segment.parent
|
101
|
-
if transaction_sampler_enabled? && !segment.record_on_finish?
|
102
|
-
transaction_sampler.notice_pop_frame state, segment.name, segment.end_time
|
103
|
-
end
|
104
101
|
end
|
105
102
|
|
106
|
-
|
107
|
-
|
108
|
-
def transaction_sampler_enabled?
|
109
|
-
Agent.config[:'transaction_tracer.enabled']
|
103
|
+
def segment_limit
|
104
|
+
Agent.config[:'transaction_tracer.limit_segments']
|
110
105
|
end
|
111
106
|
end
|
112
107
|
end
|
@@ -8,6 +8,7 @@
|
|
8
8
|
# the transaction event aggregator and the synthetics container.
|
9
9
|
|
10
10
|
require 'new_relic/agent/payload_metric_mapping'
|
11
|
+
require 'new_relic/agent/distributed_trace_payload'
|
11
12
|
|
12
13
|
module NewRelic
|
13
14
|
module Agent
|
@@ -22,6 +23,7 @@ module NewRelic
|
|
22
23
|
PORT_KEY = 'port'.freeze
|
23
24
|
NAME_KEY = 'transactionName'.freeze
|
24
25
|
DURATION_KEY = 'duration'.freeze
|
26
|
+
SAMPLED_KEY = 'nr.sampled'.freeze
|
25
27
|
GUID_KEY = 'nr.transactionGuid'.freeze
|
26
28
|
REFERRING_TRANSACTION_GUID_KEY = 'nr.referringTransactionGuid'.freeze
|
27
29
|
SYNTHETICS_RESOURCE_ID_KEY = "nr.syntheticsResourceId".freeze
|
@@ -49,8 +51,10 @@ module NewRelic
|
|
49
51
|
if payload
|
50
52
|
attrs[NAME_KEY] = payload[:name]
|
51
53
|
attrs[DURATION_KEY] = payload[:duration]
|
54
|
+
attrs[SAMPLED_KEY] = payload[:'nr.sampled'] if Agent.config[:'distributed_tracing.enabled']
|
52
55
|
append_synthetics payload, attrs
|
53
56
|
append_cat payload, attrs
|
57
|
+
append_distributed_trace_intrinsics payload, attrs
|
54
58
|
PayloadMetricMapping.append_mapped_metrics payload[:metrics], attrs
|
55
59
|
end
|
56
60
|
|
@@ -67,6 +71,20 @@ module NewRelic
|
|
67
71
|
sample[GUID_KEY] = payload[:guid] if payload[:guid]
|
68
72
|
sample[REFERRING_TRANSACTION_GUID_KEY] = payload[:referring_transaction_guid] if payload[:referring_transaction_guid]
|
69
73
|
end
|
74
|
+
|
75
|
+
OTHER_GUID_KEY = "nr.guid".freeze
|
76
|
+
|
77
|
+
def append_distributed_trace_intrinsics payload, sample
|
78
|
+
return unless Agent.config[:'distributed_tracing.enabled']
|
79
|
+
DistributedTracePayload::INTRINSIC_KEYS.each do |key|
|
80
|
+
value = payload[key]
|
81
|
+
sample[key] = value unless value.nil?
|
82
|
+
end
|
83
|
+
# guid has a different name for transaction events
|
84
|
+
if sample.key? OTHER_GUID_KEY
|
85
|
+
sample[GUID_KEY] = sample.delete OTHER_GUID_KEY
|
86
|
+
end
|
87
|
+
end
|
70
88
|
end
|
71
89
|
end
|
72
90
|
end
|
@@ -6,6 +6,7 @@
|
|
6
6
|
require 'newrelic_rpm' unless defined?( NewRelic )
|
7
7
|
require 'new_relic/agent' unless defined?( NewRelic::Agent )
|
8
8
|
require 'new_relic/agent/event_aggregator'
|
9
|
+
require 'new_relic/agent/distributed_trace_priority_sampled_buffer'
|
9
10
|
|
10
11
|
module NewRelic
|
11
12
|
module Agent
|
@@ -14,6 +15,7 @@ module NewRelic
|
|
14
15
|
named :TransactionEventAggregator
|
15
16
|
capacity_key :'analytics_events.max_samples_stored'
|
16
17
|
enabled_key :'analytics_events.enabled'
|
18
|
+
buffer_class DistributedTracePrioritySampledBuffer
|
17
19
|
|
18
20
|
def append event=nil, &blk
|
19
21
|
raise ArgumentError, "Expected argument or block, but received both" if event && blk
|
@@ -25,6 +27,18 @@ module NewRelic
|
|
25
27
|
end
|
26
28
|
end
|
27
29
|
|
30
|
+
# events that are selected to be sampled have priority of other events (ie
|
31
|
+
# the ones passed to append)
|
32
|
+
def append_sampled event=nil, &blk
|
33
|
+
raise ArgumentError, "Expected argument or block, but received both" if event && blk
|
34
|
+
return unless enabled?
|
35
|
+
|
36
|
+
@lock.synchronize do
|
37
|
+
@buffer.append_sampled event, &blk
|
38
|
+
notify_if_full
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
28
42
|
private
|
29
43
|
|
30
44
|
def after_harvest metadata
|
@@ -8,6 +8,7 @@
|
|
8
8
|
# the transaction event aggregator and the synthetics container.
|
9
9
|
|
10
10
|
require 'new_relic/agent/payload_metric_mapping'
|
11
|
+
require 'new_relic/agent/distributed_trace_payload'
|
11
12
|
|
12
13
|
module NewRelic
|
13
14
|
module Agent
|
@@ -24,6 +25,7 @@ module NewRelic
|
|
24
25
|
NAME_KEY = 'name'.freeze
|
25
26
|
DURATION_KEY = 'duration'.freeze
|
26
27
|
ERROR_KEY = 'error'.freeze
|
28
|
+
SAMPLED_KEY = 'nr.sampled'.freeze
|
27
29
|
GUID_KEY = 'nr.guid'.freeze
|
28
30
|
REFERRING_TRANSACTION_GUID_KEY = 'nr.referringTransactionGuid'.freeze
|
29
31
|
CAT_TRIP_ID_KEY = 'nr.tripId'.freeze
|
@@ -35,6 +37,7 @@ module NewRelic
|
|
35
37
|
SYNTHETICS_JOB_ID_KEY = "nr.syntheticsJobId".freeze
|
36
38
|
SYNTHETICS_MONITOR_ID_KEY = "nr.syntheticsMonitorId".freeze
|
37
39
|
|
40
|
+
|
38
41
|
# To avoid allocations when we have empty custom or agent attributes
|
39
42
|
EMPTY_HASH = {}.freeze
|
40
43
|
|
@@ -47,8 +50,11 @@ module NewRelic
|
|
47
50
|
ERROR_KEY => payload[:error]
|
48
51
|
}
|
49
52
|
|
53
|
+
intrinsics[SAMPLED_KEY] = payload[:'nr.sampled'] if Agent.config[:'distributed_tracing.enabled']
|
54
|
+
|
50
55
|
NewRelic::Agent::PayloadMetricMapping.append_mapped_metrics(payload[:metrics], intrinsics)
|
51
56
|
append_optional_attributes(intrinsics, payload)
|
57
|
+
append_distributed_trace_intrinsics(intrinsics, payload)
|
52
58
|
|
53
59
|
attributes = payload[:attributes]
|
54
60
|
|
@@ -78,6 +84,14 @@ module NewRelic
|
|
78
84
|
end
|
79
85
|
end
|
80
86
|
|
87
|
+
def append_distributed_trace_intrinsics(sample, payload)
|
88
|
+
return unless Agent.config[:'distributed_tracing.enabled']
|
89
|
+
DistributedTracePayload::INTRINSIC_KEYS.each do |key|
|
90
|
+
value = payload[key]
|
91
|
+
sample[key] = value unless value.nil?
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
81
95
|
def optionally_append(sample_key, payload_key, sample, payload)
|
82
96
|
if payload.include?(payload_key)
|
83
97
|
sample[sample_key] = string(payload[payload_key])
|