newrelic-infinite_tracing 8.7.0 → 8.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/Rakefile +6 -1
- data/lib/infinite_tracing/agent_integrations/agent.rb +16 -2
- data/lib/infinite_tracing/agent_integrations/datastore_segment.rb +1 -1
- data/lib/infinite_tracing/agent_integrations/external_request_segment.rb +1 -1
- data/lib/infinite_tracing/agent_integrations/segment.rb +1 -1
- data/lib/infinite_tracing/agent_integrations.rb +2 -2
- data/lib/infinite_tracing/channel.rb +5 -8
- data/lib/infinite_tracing/client.rb +27 -27
- data/lib/infinite_tracing/config.rb +3 -3
- data/lib/infinite_tracing/connection.rb +15 -15
- data/lib/infinite_tracing/record_status_handler.rb +7 -7
- data/lib/infinite_tracing/streaming_buffer.rb +17 -17
- data/lib/infinite_tracing/suspended_streaming_buffer.rb +4 -4
- data/lib/infinite_tracing/transformer.rb +4 -5
- data/lib/infinite_tracing/worker.rb +7 -7
- data/lib/infinite_tracing.rb +2 -2
- data/lib/new_relic/infinite_tracing.rb +2 -2
- data/newrelic-infinite_tracing.gemspec +6 -7
- data/tasks/all.rb +1 -0
- data/tasks/proto.rake +11 -10
- metadata +10 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 82175bbdb36620845384d5a1d9ed84eafe35e4e0b822b92760dd96b30ab5064a
|
4
|
+
data.tar.gz: 8478c0cf1d539a3d618989d0dd436bcf8d5f3f81360c2b1bd005fc37ddefd057
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8cd2e71a2508bac59ac35fd8eacc1a8176e44351299808a883b6bd0a6cadca7ffc4c2741005e90647f5d03b197dd40d08ecc97a0468fc1f85744adccc944bdeb
|
7
|
+
data.tar.gz: 9bf7c047221d6d6f3eeabe1ea4381906dbb0dc511dd22638875d6b7d923b80373fcfbaf2afc0516e77bc983773afc08b4616e2c0059ce8990c9671518580d6e7
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# New Relic Infinite Tracing for Ruby Agent Release Notes #
|
2
2
|
|
3
|
+
## v8.9.0
|
4
|
+
|
5
|
+
* **Bugfix: Infinite Tracing hung on connection restart**
|
6
|
+
|
7
|
+
Previously, when using infinite tracing, the agent would intermittently encounter a deadlock when attempting to restart the infinite tracing connection. This bug would prevent the agent from sending all data types, including non-infinite-tracing-related data. This change reworks how we restart infinite tracing to prevent potential deadlocks.
|
8
|
+
|
3
9
|
## v7.0.0
|
4
10
|
* Bugfix: Fixes an intermittent bug where the agent was unable to start when infinite tracing was enabled.
|
5
11
|
|
data/Rakefile
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# This file is distributed under New Relic's license terms.
|
3
|
+
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
4
|
+
# frozen_string_literal: true
|
5
|
+
|
1
6
|
require 'rubygems'
|
2
7
|
require 'rake/testtask'
|
3
8
|
require "#{File.dirname(__FILE__)}/tasks/all.rb"
|
@@ -12,7 +17,7 @@ task :console do
|
|
12
17
|
end
|
13
18
|
|
14
19
|
Rake::TestTask.new do |t|
|
15
|
-
ROOT = File.join
|
20
|
+
ROOT = File.join(File.dirname(__FILE__))
|
16
21
|
$LOAD_PATH << ROOT
|
17
22
|
|
18
23
|
file_pattern = "#{ROOT}/**/*_test.rb"
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# frozen_string_literal: true
|
5
5
|
|
6
6
|
module NewRelic::Agent
|
7
|
-
NewRelic::Agent.logger.debug
|
7
|
+
NewRelic::Agent.logger.debug("Installing Infinite Tracer in Agent")
|
8
8
|
|
9
9
|
Agent.class_eval do
|
10
10
|
def new_infinite_tracer
|
@@ -12,13 +12,27 @@ module NewRelic::Agent
|
|
12
12
|
# entire start up process for the Agent.
|
13
13
|
InfiniteTracing::Client.new.tap do |client|
|
14
14
|
@infinite_tracer_thread = InfiniteTracing::Worker.new(:infinite_tracer) do
|
15
|
-
NewRelic::Agent.logger.debug
|
15
|
+
NewRelic::Agent.logger.debug("Opening Infinite Tracer Stream with gRPC server")
|
16
16
|
client.start_streaming
|
17
17
|
end
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
+
# Handles the case where the server tells us to restart -
|
22
|
+
# this clears the data, clears connection attempts, and
|
23
|
+
# waits a while to reconnect.
|
24
|
+
def handle_force_restart(error)
|
25
|
+
::NewRelic::Agent.logger.debug(error.message)
|
26
|
+
drop_buffered_data
|
27
|
+
@service.force_restart if @service
|
28
|
+
@connect_state = :pending
|
29
|
+
close_infinite_tracer
|
30
|
+
sleep(30)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Whenever we reconnect, close and restart
|
21
34
|
def close_infinite_tracer
|
35
|
+
NewRelic::Agent.logger.debug("Closing infinite tracer threads")
|
22
36
|
return unless @infinite_tracer_thread
|
23
37
|
@infinite_tracer_thread.join
|
24
38
|
@infinite_tracer_thread.stop
|
@@ -12,7 +12,7 @@ module NewRelic
|
|
12
12
|
return if transaction.ignore?
|
13
13
|
|
14
14
|
tracer = ::NewRelic::Agent.agent.infinite_tracer
|
15
|
-
tracer << Proc.new { SpanEventPrimitive.for_datastore_segment
|
15
|
+
tracer << Proc.new { SpanEventPrimitive.for_datastore_segment(self) }
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
@@ -12,7 +12,7 @@ module NewRelic
|
|
12
12
|
return if transaction.ignore?
|
13
13
|
|
14
14
|
tracer = ::NewRelic::Agent.agent.infinite_tracer
|
15
|
-
tracer << Proc.new { SpanEventPrimitive.for_external_request_segment
|
15
|
+
tracer << Proc.new { SpanEventPrimitive.for_external_request_segment(self) }
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
@@ -6,7 +6,7 @@
|
|
6
6
|
module NewRelic::Agent
|
7
7
|
module InfiniteTracing
|
8
8
|
if Config.enabled? || Config.test_framework?
|
9
|
-
NewRelic::Agent.logger.debug
|
9
|
+
NewRelic::Agent.logger.debug("Integrating Infinite Tracer with Agent")
|
10
10
|
|
11
11
|
require_relative 'agent_integrations/agent'
|
12
12
|
require_relative 'agent_integrations/segment'
|
@@ -14,7 +14,7 @@ module NewRelic::Agent
|
|
14
14
|
require_relative 'agent_integrations/external_request_segment'
|
15
15
|
|
16
16
|
else
|
17
|
-
NewRelic::Agent.logger.debug
|
17
|
+
NewRelic::Agent.logger.debug("Skipped Integrating Infinite Tracer with Agent")
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
@@ -7,12 +7,13 @@ module NewRelic::Agent
|
|
7
7
|
module InfiniteTracing
|
8
8
|
class Channel
|
9
9
|
def stub
|
10
|
-
NewRelic::Agent.logger.debug
|
10
|
+
NewRelic::Agent.logger.debug("Infinite Tracer Opening Channel to #{host_and_port}")
|
11
11
|
|
12
|
-
Com::Newrelic::Trace::V1::IngestService::Stub.new \
|
12
|
+
Com::Newrelic::Trace::V1::IngestService::Stub.new( \
|
13
13
|
host_and_port,
|
14
14
|
credentials,
|
15
15
|
channel_override: channel
|
16
|
+
)
|
16
17
|
end
|
17
18
|
|
18
19
|
def channel
|
@@ -20,12 +21,8 @@ module NewRelic::Agent
|
|
20
21
|
end
|
21
22
|
|
22
23
|
def credentials
|
23
|
-
|
24
|
-
|
25
|
-
else
|
26
|
-
# Uses system configured certificates by default
|
27
|
-
GRPC::Core::ChannelCredentials.new
|
28
|
-
end
|
24
|
+
# Uses system configured certificates by default
|
25
|
+
GRPC::Core::ChannelCredentials.new
|
29
26
|
end
|
30
27
|
|
31
28
|
def host_and_port
|
@@ -22,15 +22,15 @@ module NewRelic::Agent
|
|
22
22
|
@lock = Mutex.new
|
23
23
|
end
|
24
24
|
|
25
|
-
def <<
|
25
|
+
def <<(segment)
|
26
26
|
buffer << segment
|
27
27
|
end
|
28
28
|
|
29
29
|
# Transfers spans in streaming buffer from previous
|
30
30
|
# client (if any) and returns self (so we chain the call)
|
31
|
-
def transfer
|
31
|
+
def transfer(previous_client)
|
32
32
|
return self unless previous_client
|
33
|
-
previous_client.buffer.transfer
|
33
|
+
previous_client.buffer.transfer(buffer)
|
34
34
|
self
|
35
35
|
end
|
36
36
|
|
@@ -38,7 +38,7 @@ module NewRelic::Agent
|
|
38
38
|
# client is currently suspended.
|
39
39
|
def new_streaming_buffer
|
40
40
|
buffer_class = suspended? ? SuspendedStreamingBuffer : StreamingBuffer
|
41
|
-
buffer_class.new
|
41
|
+
buffer_class.new(Config.span_events_queue_size)
|
42
42
|
end
|
43
43
|
|
44
44
|
def buffer
|
@@ -50,30 +50,30 @@ module NewRelic::Agent
|
|
50
50
|
end
|
51
51
|
|
52
52
|
# Turns camelcase base class name into upper snake case version of the name.
|
53
|
-
def formatted_class_name
|
53
|
+
def formatted_class_name(class_name)
|
54
54
|
class_name = class_name.split(":")[-1]
|
55
|
-
|
55
|
+
(class_name.gsub!(/(.)([A-Z])/, '\1_\2') || class_name).upcase
|
56
56
|
end
|
57
57
|
|
58
58
|
# Literal codes are all mapped to unique class names, so we can deduce the
|
59
59
|
# name of the error to report in the metric from the error's class name.
|
60
|
-
def grpc_error_metric_name
|
60
|
+
def grpc_error_metric_name(error)
|
61
61
|
GRPC_ERROR_NAME_METRIC % formatted_class_name(error.class.name)
|
62
62
|
end
|
63
63
|
|
64
64
|
# Reports AND logs general response metric along with a more specific error metric
|
65
|
-
def record_error_metrics_and_log
|
66
|
-
NewRelic::Agent.record_metric
|
67
|
-
if error.is_a?
|
68
|
-
NewRelic::Agent.record_metric
|
65
|
+
def record_error_metrics_and_log(error)
|
66
|
+
NewRelic::Agent.record_metric(RESPONSE_ERROR_METRIC, 0.0)
|
67
|
+
if error.is_a?(GRPC::BadStatus)
|
68
|
+
NewRelic::Agent.record_metric(grpc_error_metric_name(error), 0.0)
|
69
69
|
else
|
70
|
-
NewRelic::Agent.record_metric
|
70
|
+
NewRelic::Agent.record_metric(GRPC_OTHER_ERROR_METRIC, 0.0)
|
71
71
|
end
|
72
|
-
NewRelic::Agent.logger.warn
|
72
|
+
NewRelic::Agent.logger.warn("gRPC response error received.", error)
|
73
73
|
end
|
74
74
|
|
75
|
-
def handle_error
|
76
|
-
record_error_metrics_and_log
|
75
|
+
def handle_error(error)
|
76
|
+
record_error_metrics_and_log(error)
|
77
77
|
|
78
78
|
case error
|
79
79
|
when GRPC::Unavailable then restart
|
@@ -81,7 +81,7 @@ module NewRelic::Agent
|
|
81
81
|
when GRPC::Unimplemented then suspend
|
82
82
|
else
|
83
83
|
# Set exponential backoff to false so we'll reconnect at periodic (15 second) intervals instead
|
84
|
-
start_streaming
|
84
|
+
start_streaming(false)
|
85
85
|
end
|
86
86
|
end
|
87
87
|
|
@@ -95,8 +95,8 @@ module NewRelic::Agent
|
|
95
95
|
# server and re-establish the gRPC bi-directional stream. Useful for the server
|
96
96
|
# to initiate a load-balancing scheme.
|
97
97
|
def handle_close
|
98
|
-
NewRelic::Agent.logger.debug
|
99
|
-
"Restarting the stream."
|
98
|
+
NewRelic::Agent.logger.debug("The gRPC Trace Observer closed the stream with OK response. " \
|
99
|
+
"Restarting the stream.")
|
100
100
|
start_streaming
|
101
101
|
end
|
102
102
|
|
@@ -108,8 +108,8 @@ module NewRelic::Agent
|
|
108
108
|
@lock.synchronize do
|
109
109
|
@suspended = true
|
110
110
|
@buffer = new_streaming_buffer
|
111
|
-
NewRelic::Agent.logger.warn
|
112
|
-
"No more span events will be sent during this session."
|
111
|
+
NewRelic::Agent.logger.warn("The Trace Observer host signaled to suspend streaming span events. " \
|
112
|
+
"No more span events will be sent during this session.")
|
113
113
|
end
|
114
114
|
end
|
115
115
|
|
@@ -123,7 +123,7 @@ module NewRelic::Agent
|
|
123
123
|
@lock.synchronize do
|
124
124
|
old_buffer = @buffer
|
125
125
|
@buffer = new_streaming_buffer
|
126
|
-
old_buffer.transfer
|
126
|
+
old_buffer.transfer(@buffer)
|
127
127
|
end
|
128
128
|
end
|
129
129
|
|
@@ -141,18 +141,18 @@ module NewRelic::Agent
|
|
141
141
|
end
|
142
142
|
end
|
143
143
|
|
144
|
-
def start_streaming
|
144
|
+
def start_streaming(exponential_backoff = true)
|
145
145
|
return if suspended?
|
146
146
|
Connection.instance.wait_for_agent_connect
|
147
|
-
@lock.synchronize { @response_handler = record_spans
|
147
|
+
@lock.synchronize { @response_handler = record_spans(exponential_backoff) }
|
148
148
|
end
|
149
149
|
|
150
|
-
def record_spans
|
151
|
-
RecordStatusHandler.new
|
150
|
+
def record_spans(exponential_backoff)
|
151
|
+
RecordStatusHandler.new(self, Connection.record_spans(self, buffer.enumerator, exponential_backoff))
|
152
152
|
end
|
153
153
|
|
154
|
-
def record_span_batches
|
155
|
-
RecordStatusHandler.new
|
154
|
+
def record_span_batches(exponential_backoff)
|
155
|
+
RecordStatusHandler.new(self, Connection.record_span_batches(self, buffer.batch_enumerator, exponential_backoff))
|
156
156
|
end
|
157
157
|
end
|
158
158
|
end
|
@@ -48,12 +48,12 @@ module NewRelic::Agent
|
|
48
48
|
end
|
49
49
|
|
50
50
|
# removes the scheme and port from a host entry.
|
51
|
-
def without_scheme_or_port
|
51
|
+
def without_scheme_or_port(url)
|
52
52
|
url.gsub(%r{^https?://|:\d+$}, '')
|
53
53
|
end
|
54
54
|
|
55
55
|
def trace_observer_host
|
56
|
-
without_scheme_or_port
|
56
|
+
without_scheme_or_port(NewRelic::Agent.config[:'infinite_tracing.trace_observer.host'])
|
57
57
|
end
|
58
58
|
|
59
59
|
# If the port is declared on the host entry, it overrides the port entry because otherwise
|
@@ -85,7 +85,7 @@ module NewRelic::Agent
|
|
85
85
|
if trace_observer_configured?
|
86
86
|
URI("#{trace_observer_scheme}://#{trace_observer_host_and_port}")
|
87
87
|
else
|
88
|
-
NewRelic::Agent.logger.error
|
88
|
+
NewRelic::Agent.logger.error(TRACE_OBSERVER_NOT_CONFIGURED_ERROR)
|
89
89
|
raise TRACE_OBSERVER_NOT_CONFIGURED_ERROR
|
90
90
|
end
|
91
91
|
end
|
@@ -25,9 +25,10 @@ module NewRelic::Agent
|
|
25
25
|
begin
|
26
26
|
Connection.instance.notify_agent_started
|
27
27
|
rescue => error
|
28
|
-
NewRelic::Agent.logger.error \
|
28
|
+
NewRelic::Agent.logger.error( \
|
29
29
|
"Error during notify :server_source_configuration_added event",
|
30
30
|
error
|
31
|
+
)
|
31
32
|
end
|
32
33
|
end
|
33
34
|
|
@@ -43,15 +44,15 @@ module NewRelic::Agent
|
|
43
44
|
# RPC calls will pass the calling client instance in. We track this
|
44
45
|
# so we're able to signal the client to restart when connectivity to the
|
45
46
|
# server is disrupted.
|
46
|
-
def record_spans
|
47
|
-
instance.record_spans
|
47
|
+
def record_spans(client, enumerator, exponential_backoff)
|
48
|
+
instance.record_spans(client, enumerator, exponential_backoff)
|
48
49
|
end
|
49
50
|
|
50
51
|
# RPC calls will pass the calling client instance in. We track this
|
51
52
|
# so we're able to signal the client to restart when connectivity to the
|
52
53
|
# server is disrupted.
|
53
|
-
def record_span_batches
|
54
|
-
instance.record_span_batch
|
54
|
+
def record_span_batches(client, enumerator, exponential_backoff)
|
55
|
+
instance.record_span_batch(client, enumerator, exponential_backoff)
|
55
56
|
end
|
56
57
|
|
57
58
|
def metadata
|
@@ -61,17 +62,17 @@ module NewRelic::Agent
|
|
61
62
|
|
62
63
|
# We attempt to connect and record spans with reconnection backoff in order to deal with
|
63
64
|
# unavailable errors coming from the stub being created and record_span call
|
64
|
-
def record_spans
|
65
|
+
def record_spans(client, enumerator, exponential_backoff)
|
65
66
|
@active_clients[client] = client
|
66
|
-
with_reconnection_backoff(exponential_backoff) { rpc.record_span
|
67
|
+
with_reconnection_backoff(exponential_backoff) { rpc.record_span(enumerator, metadata: metadata) }
|
67
68
|
end
|
68
69
|
|
69
70
|
# RPC calls will pass the calling client instance in. We track this
|
70
71
|
# so we're able to signal the client to restart when connectivity to the
|
71
72
|
# server is disrupted.
|
72
|
-
def record_span_batches
|
73
|
+
def record_span_batches(client, enumerator, exponential_backoff)
|
73
74
|
@active_clients[client] = client
|
74
|
-
with_reconnection_backoff(exponential_backoff) { rpc.record_span_batch
|
75
|
+
with_reconnection_backoff(exponential_backoff) { rpc.record_span_batch(enumerator, metadata: metadata) }
|
75
76
|
end
|
76
77
|
|
77
78
|
# Acquires the new channel stub for the RPC calls.
|
@@ -114,7 +115,6 @@ module NewRelic::Agent
|
|
114
115
|
@agent_connected = true
|
115
116
|
@agent_started.signal
|
116
117
|
end
|
117
|
-
@active_clients.each_value(&:restart)
|
118
118
|
end
|
119
119
|
|
120
120
|
private
|
@@ -148,21 +148,21 @@ module NewRelic::Agent
|
|
148
148
|
end
|
149
149
|
|
150
150
|
# Continues retrying the connection at backoff intervals until a successful connection is made
|
151
|
-
def with_reconnection_backoff
|
151
|
+
def with_reconnection_backoff(exponential_backoff = true, &block)
|
152
152
|
@connection_attempts = 0
|
153
153
|
begin
|
154
154
|
yield
|
155
155
|
rescue => exception
|
156
156
|
retry_connection_period = retry_connection_period(exponential_backoff)
|
157
|
-
::NewRelic::Agent.logger.error
|
158
|
-
::NewRelic::Agent.logger.info
|
159
|
-
sleep
|
157
|
+
::NewRelic::Agent.logger.error("Error establishing connection with infinite tracing service:", exception)
|
158
|
+
::NewRelic::Agent.logger.info("Will re-attempt infinte tracing connection in #{retry_connection_period} seconds")
|
159
|
+
sleep(retry_connection_period)
|
160
160
|
note_connect_failure
|
161
161
|
retry
|
162
162
|
end
|
163
163
|
end
|
164
164
|
|
165
|
-
def retry_connection_period
|
165
|
+
def retry_connection_period(exponential_backoff = true)
|
166
166
|
if exponential_backoff
|
167
167
|
NewRelic::CONNECT_RETRY_PERIODS[@connection_attempts] || NewRelic::MAX_RETRY_PERIOD
|
168
168
|
else
|
@@ -6,7 +6,7 @@
|
|
6
6
|
module NewRelic::Agent
|
7
7
|
module InfiniteTracing
|
8
8
|
class RecordStatusHandler
|
9
|
-
def initialize
|
9
|
+
def initialize(client, enumerator)
|
10
10
|
@client = client
|
11
11
|
@enumerator = enumerator
|
12
12
|
@messages_seen = nil
|
@@ -19,29 +19,29 @@ module NewRelic::Agent
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def start_handler
|
22
|
-
Worker.new
|
22
|
+
Worker.new(self.class.name) do
|
23
23
|
begin
|
24
24
|
@enumerator.each do |response|
|
25
25
|
break if response.nil? || response.is_a?(Exception)
|
26
26
|
@lock.synchronize do
|
27
27
|
@messages_seen = response
|
28
|
-
NewRelic::Agent.logger.debug
|
28
|
+
NewRelic::Agent.logger.debug("gRPC Infinite Tracer Observer saw #{messages_seen} messages")
|
29
29
|
end
|
30
30
|
end
|
31
|
-
NewRelic::Agent.logger.debug
|
31
|
+
NewRelic::Agent.logger.debug("gRPC Infinite Tracer Observer closed the stream")
|
32
32
|
@client.handle_close
|
33
33
|
rescue => error
|
34
|
-
@client.handle_error
|
34
|
+
@client.handle_error(error)
|
35
35
|
end
|
36
36
|
end
|
37
37
|
rescue => error
|
38
|
-
NewRelic::Agent.logger.error
|
38
|
+
NewRelic::Agent.logger.error("gRPC Worker Error", error)
|
39
39
|
end
|
40
40
|
|
41
41
|
def stop
|
42
42
|
return if @worker.nil?
|
43
43
|
@lock.synchronize do
|
44
|
-
NewRelic::Agent.logger.debug
|
44
|
+
NewRelic::Agent.logger.debug("gRPC Stopping Response Handler")
|
45
45
|
@worker.stop
|
46
46
|
@worker = nil
|
47
47
|
end
|
@@ -21,7 +21,7 @@ module NewRelic::Agent
|
|
21
21
|
|
22
22
|
attr_reader :queue
|
23
23
|
|
24
|
-
def initialize
|
24
|
+
def initialize(max_size = DEFAULT_QUEUE_SIZE)
|
25
25
|
@max_size = max_size
|
26
26
|
@lock = Mutex.new
|
27
27
|
@queue = Queue.new
|
@@ -30,9 +30,9 @@ module NewRelic::Agent
|
|
30
30
|
|
31
31
|
# Dumps the contents of this streaming buffer onto
|
32
32
|
# the given buffer and closes the queue
|
33
|
-
def transfer
|
33
|
+
def transfer(new_buffer)
|
34
34
|
@lock.synchronize do
|
35
|
-
until @queue.empty? do new_buffer.push
|
35
|
+
until @queue.empty? do new_buffer.push(@queue.pop) end
|
36
36
|
@queue.close
|
37
37
|
end
|
38
38
|
end
|
@@ -45,11 +45,11 @@ module NewRelic::Agent
|
|
45
45
|
# When a restart signal is received, the queue is
|
46
46
|
# locked with a mutex, blocking the push until
|
47
47
|
# the queue has restarted.
|
48
|
-
def <<
|
48
|
+
def <<(segment)
|
49
49
|
@lock.synchronize do
|
50
50
|
clear_queue if @queue.size >= @max_size
|
51
|
-
NewRelic::Agent.increment_metric
|
52
|
-
@queue.push
|
51
|
+
NewRelic::Agent.increment_metric(SPANS_SEEN_METRIC)
|
52
|
+
@queue.push(segment)
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
@@ -57,19 +57,19 @@ module NewRelic::Agent
|
|
57
57
|
# supportability metric for the event.
|
58
58
|
def clear_queue
|
59
59
|
@queue.clear
|
60
|
-
NewRelic::Agent.increment_metric
|
60
|
+
NewRelic::Agent.increment_metric(QUEUE_DUMPED_METRIC)
|
61
61
|
end
|
62
62
|
|
63
63
|
# Waits for the queue to be fully consumed or for the
|
64
64
|
# waiting consumers to release.
|
65
65
|
def flush_queue
|
66
|
-
@queue.num_waiting.times { @queue.push
|
66
|
+
@queue.num_waiting.times { @queue.push(nil) }
|
67
67
|
close_queue
|
68
68
|
|
69
69
|
# Logs if we're throwing away spans because nothing's
|
70
70
|
# waiting to take them off the queue.
|
71
71
|
if @queue.num_waiting == 0 && !@queue.empty?
|
72
|
-
NewRelic::Agent.logger.warn
|
72
|
+
NewRelic::Agent.logger.warn("Discarding #{@queue.size} segments on Streaming Buffer")
|
73
73
|
return
|
74
74
|
end
|
75
75
|
|
@@ -94,8 +94,8 @@ module NewRelic::Agent
|
|
94
94
|
return enum_for(:enumerator) unless block_given?
|
95
95
|
loop do
|
96
96
|
if segment = @queue.pop(false)
|
97
|
-
NewRelic::Agent.increment_metric
|
98
|
-
yield
|
97
|
+
NewRelic::Agent.increment_metric(SPANS_SENT_METRIC)
|
98
|
+
yield(transform(segment))
|
99
99
|
|
100
100
|
else
|
101
101
|
raise ClosedQueueError
|
@@ -120,15 +120,15 @@ module NewRelic::Agent
|
|
120
120
|
return enum_for(:enumerator) unless block_given?
|
121
121
|
loop do
|
122
122
|
if proc_or_segment = @queue.pop(false)
|
123
|
-
NewRelic::Agent.increment_metric
|
123
|
+
NewRelic::Agent.increment_metric(SPANS_SENT_METRIC)
|
124
124
|
@batch << transform(proc_or_segment)
|
125
125
|
if @batch.size >= BATCH_SIZE
|
126
|
-
yield
|
126
|
+
yield(SpanBatch.new(spans: @batch))
|
127
127
|
@batch.clear
|
128
128
|
end
|
129
129
|
|
130
130
|
else
|
131
|
-
yield
|
131
|
+
yield(SpanBatch.new(spans: @batch)) unless @batch.empty?
|
132
132
|
raise ClosedQueueError
|
133
133
|
end
|
134
134
|
end
|
@@ -136,7 +136,7 @@ module NewRelic::Agent
|
|
136
136
|
|
137
137
|
private
|
138
138
|
|
139
|
-
def span_event
|
139
|
+
def span_event(proc_or_segment)
|
140
140
|
if proc_or_segment.is_a?(Proc)
|
141
141
|
proc_or_segment.call
|
142
142
|
else
|
@@ -144,8 +144,8 @@ module NewRelic::Agent
|
|
144
144
|
end
|
145
145
|
end
|
146
146
|
|
147
|
-
def transform
|
148
|
-
Span.new
|
147
|
+
def transform(proc_or_segment)
|
148
|
+
Span.new(Transformer.transform(span_event(proc_or_segment)))
|
149
149
|
end
|
150
150
|
end
|
151
151
|
end
|
@@ -13,16 +13,16 @@ module NewRelic::Agent
|
|
13
13
|
extend Forwardable
|
14
14
|
def_delegators :@empty_buffer, :empty?, :push
|
15
15
|
|
16
|
-
def initialize
|
16
|
+
def initialize(max_size = DEFAULT_QUEUE_SIZE)
|
17
17
|
@empty_buffer = NewRelic::EMPTY_ARRAY
|
18
18
|
end
|
19
19
|
|
20
20
|
# updates the seen metric and discards the segment
|
21
|
-
def <<
|
22
|
-
NewRelic::Agent.increment_metric
|
21
|
+
def <<(segment)
|
22
|
+
NewRelic::Agent.increment_metric(SPANS_SEEN_METRIC)
|
23
23
|
end
|
24
24
|
|
25
|
-
def transfer
|
25
|
+
def transfer(new_buffer)
|
26
26
|
# NOOP
|
27
27
|
end
|
28
28
|
|
@@ -8,7 +8,7 @@ module NewRelic::Agent
|
|
8
8
|
module Transformer
|
9
9
|
extend self
|
10
10
|
|
11
|
-
def transform
|
11
|
+
def transform(span_event)
|
12
12
|
intrinsics, user_attributes, agent_attributes = span_event
|
13
13
|
{
|
14
14
|
"trace_id" => intrinsics[NewRelic::Agent::SpanEventPrimitive::TRACE_ID_KEY],
|
@@ -34,17 +34,16 @@ module NewRelic::Agent
|
|
34
34
|
KLASS_TO_ARG[BigDecimal] = :double_value
|
35
35
|
end
|
36
36
|
|
37
|
-
def safe_param_name
|
37
|
+
def safe_param_name(value)
|
38
38
|
KLASS_TO_ARG[value.class] || raise("Unhandled class #{value.class.name}")
|
39
39
|
end
|
40
40
|
|
41
|
-
def hash_to_attributes
|
41
|
+
def hash_to_attributes(values)
|
42
42
|
values.map do |key, value|
|
43
43
|
begin
|
44
44
|
[key, AttributeValue.new(safe_param_name(value) => value)]
|
45
45
|
rescue => e
|
46
|
-
|
47
|
-
puts [key, value].inspect
|
46
|
+
NewRelic::Agent.logger.debug("Infinite tracing transformer error: #{e.inspect}")
|
48
47
|
nil
|
49
48
|
end
|
50
49
|
end.to_h
|
@@ -12,7 +12,7 @@ module NewRelic::Agent
|
|
12
12
|
class Worker
|
13
13
|
attr_reader :name, :error
|
14
14
|
|
15
|
-
def initialize
|
15
|
+
def initialize(name, &job)
|
16
16
|
@name = name
|
17
17
|
@job = job
|
18
18
|
@error = nil
|
@@ -33,16 +33,16 @@ module NewRelic::Agent
|
|
33
33
|
!!@error
|
34
34
|
end
|
35
35
|
|
36
|
-
def join
|
36
|
+
def join(timeout = nil)
|
37
37
|
return unless @worker_thread
|
38
|
-
NewRelic::Agent.logger.debug
|
39
|
-
@worker_thread.join
|
38
|
+
NewRelic::Agent.logger.debug("joining worker #{@name} thread...")
|
39
|
+
@worker_thread.join(timeout)
|
40
40
|
end
|
41
41
|
|
42
42
|
def stop
|
43
43
|
@lock.synchronize do
|
44
44
|
return unless @worker_thread
|
45
|
-
NewRelic::Agent.logger.debug
|
45
|
+
NewRelic::Agent.logger.debug("stopping worker #{@name} thread...")
|
46
46
|
@worker_thread.kill
|
47
47
|
@worker_thread = nil
|
48
48
|
end
|
@@ -51,7 +51,7 @@ module NewRelic::Agent
|
|
51
51
|
private
|
52
52
|
|
53
53
|
def start_thread
|
54
|
-
NewRelic::Agent.logger.debug
|
54
|
+
NewRelic::Agent.logger.debug("starting worker #{@name} thread...")
|
55
55
|
@worker_thread = Thread.new do
|
56
56
|
catch(:exit) do
|
57
57
|
begin
|
@@ -63,7 +63,7 @@ module NewRelic::Agent
|
|
63
63
|
end
|
64
64
|
end
|
65
65
|
@worker_thread.abort_on_exception = true
|
66
|
-
if @worker_thread.respond_to?
|
66
|
+
if @worker_thread.respond_to?(:report_on_exception)
|
67
67
|
@worker_thread.report_on_exception = NewRelic::Agent.config[:log_level] == "debug"
|
68
68
|
end
|
69
69
|
end
|
data/lib/infinite_tracing.rb
CHANGED
@@ -7,7 +7,7 @@ require 'uri'
|
|
7
7
|
|
8
8
|
require 'newrelic_rpm'
|
9
9
|
|
10
|
-
NewRelic::Agent.logger.debug
|
10
|
+
NewRelic::Agent.logger.debug("Detected New Relic Infinite Tracing Gem")
|
11
11
|
|
12
12
|
require 'infinite_tracing/version'
|
13
13
|
require 'infinite_tracing/config'
|
@@ -20,7 +20,7 @@ DependencyDetection.defer do
|
|
20
20
|
end
|
21
21
|
|
22
22
|
executes do
|
23
|
-
NewRelic::Agent.logger.debug
|
23
|
+
NewRelic::Agent.logger.debug("Loading New Relic Infinite Tracing Library")
|
24
24
|
|
25
25
|
require 'infinite_tracing/proto'
|
26
26
|
|
@@ -7,7 +7,7 @@ require 'uri'
|
|
7
7
|
|
8
8
|
require 'newrelic_rpm'
|
9
9
|
|
10
|
-
NewRelic::Agent.logger.debug
|
10
|
+
NewRelic::Agent.logger.debug("Detected New Relic Infinite Tracing Gem")
|
11
11
|
|
12
12
|
require 'new_relic/infinite_tracing/version'
|
13
13
|
require 'new_relic/infinite_tracing/config'
|
@@ -20,7 +20,7 @@ DependencyDetection.defer do
|
|
20
20
|
end
|
21
21
|
|
22
22
|
executes do
|
23
|
-
NewRelic::Agent.logger.debug
|
23
|
+
NewRelic::Agent.logger.debug("Loading New Relic Infinite Tracing Library")
|
24
24
|
|
25
25
|
require 'new_relic/infinite_tracing/proto'
|
26
26
|
|
@@ -12,13 +12,13 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
12
12
|
require 'new_relic/version'
|
13
13
|
|
14
14
|
Gem::Specification.new do |s|
|
15
|
-
def self.copy_files
|
16
|
-
subfolder = File.expand_path
|
15
|
+
def self.copy_files(filelist)
|
16
|
+
subfolder = File.expand_path(File.dirname(__FILE__))
|
17
17
|
|
18
18
|
filelist.each do |filename|
|
19
19
|
source_full_filename = File.expand_path(filename)
|
20
20
|
dest_full_filename = File.join(subfolder, File.basename(filename))
|
21
|
-
FileUtils.cp
|
21
|
+
FileUtils.cp(source_full_filename, dest_full_filename)
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
@@ -27,12 +27,12 @@ Gem::Specification.new do |s|
|
|
27
27
|
"../CONTRIBUTING.md"
|
28
28
|
]
|
29
29
|
|
30
|
-
self.copy_files
|
30
|
+
self.copy_files(shared_files)
|
31
31
|
|
32
32
|
s.name = "newrelic-infinite_tracing"
|
33
33
|
s.version = NewRelic::VERSION::STRING
|
34
34
|
s.required_ruby_version = '>= 2.5.0'
|
35
|
-
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to?
|
35
|
+
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to?(:required_rubygems_version=)
|
36
36
|
s.authors = ["Tanna McClure", "Kayla Reopelle", "James Bunch", "Hannah Ramadan"]
|
37
37
|
s.licenses = ['Apache-2.0']
|
38
38
|
s.description = <<-EOS
|
@@ -70,7 +70,6 @@ Gem or plugin, hosted on https://github.com/newrelic/newrelic-ruby-agent/
|
|
70
70
|
|
71
71
|
s.homepage = "https://github.com/newrelic/newrelic-ruby-agent/tree/main/infinite_tracing"
|
72
72
|
s.require_paths = ["lib", "infinite_tracing"]
|
73
|
-
s.rubygems_version = Gem::VERSION
|
74
73
|
s.summary = "New Relic Infinite Tracing for the Ruby agent"
|
75
74
|
|
76
75
|
s.add_dependency 'newrelic_rpm', NewRelic::VERSION::STRING
|
@@ -85,8 +84,8 @@ Gem or plugin, hosted on https://github.com/newrelic/newrelic-ruby-agent/
|
|
85
84
|
s.add_development_dependency 'pry-stack_explorer', '~> 0.4.9'
|
86
85
|
s.add_development_dependency 'guard', '~> 2.16.0'
|
87
86
|
s.add_development_dependency 'guard-minitest', '~> 2.4.0'
|
88
|
-
s.add_development_dependency 'hometown', '~> 0.2.5'
|
89
87
|
s.add_development_dependency 'bundler'
|
88
|
+
s.add_development_dependency 'simplecov'
|
90
89
|
|
91
90
|
s.add_development_dependency 'grpc-tools', "~> 1.14"
|
92
91
|
end
|
data/tasks/all.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# This file is distributed under New Relic's license terms.
|
3
3
|
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
4
|
+
# frozen_string_literal: true
|
4
5
|
|
5
6
|
# This is required to load in task definitions
|
6
7
|
Dir.glob(File.join(File.dirname(__FILE__), '*.rake')) do |file|
|
data/tasks/proto.rake
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# This file is distributed under New Relic's license terms.
|
3
3
|
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
4
|
+
# frozen_string_literal: true
|
4
5
|
|
5
6
|
namespace :proto do
|
6
7
|
desc "Generate proto files"
|
7
8
|
|
8
9
|
task :generate do
|
9
|
-
def extract_license_terms
|
10
|
+
def extract_license_terms(file_contents)
|
10
11
|
text = []
|
11
12
|
text << file_contents.shift while !file_contents.empty? && file_contents[0] =~ /^#/
|
12
13
|
text << ""
|
@@ -15,11 +16,11 @@ namespace :proto do
|
|
15
16
|
|
16
17
|
# adds the NewRelic License notice to the top of the generated files
|
17
18
|
# Removes require lines since these are replicated in the proto.rb file.
|
18
|
-
def add_license_preamble_and_remove_requires
|
19
|
+
def add_license_preamble_and_remove_requires(output_path)
|
19
20
|
gemspec_path = File.expand_path(File.join(output_path, '..', '..', '..', '..', '..'))
|
20
|
-
license_terms = extract_license_terms
|
21
|
-
Dir.glob(File.join
|
22
|
-
contents = File.readlines
|
21
|
+
license_terms = extract_license_terms(File.readlines(File.join(gemspec_path, "Gemfile")))
|
22
|
+
Dir.glob(File.join(output_path, "*.rb")) do |filename|
|
23
|
+
contents = File.readlines(filename)
|
23
24
|
contents.reject! { |r| r =~ /^\s*require\s.*$/ }
|
24
25
|
File.open(filename, 'w') do |output|
|
25
26
|
output.puts license_terms
|
@@ -28,11 +29,11 @@ namespace :proto do
|
|
28
29
|
end
|
29
30
|
end
|
30
31
|
|
31
|
-
gem_folder = File.expand_path
|
32
|
-
proto_filename = File.join
|
33
|
-
output_path = File.join
|
32
|
+
gem_folder = File.expand_path(File.join(File.dirname(__FILE__), ".."))
|
33
|
+
proto_filename = File.join(gem_folder, "lib", "new_relic", "proto", "infinite_tracing.proto")
|
34
|
+
output_path = File.join(gem_folder, "lib", "new_relic", "infinite_tracing", "proto")
|
34
35
|
|
35
|
-
FileUtils.mkdir_p
|
36
|
+
FileUtils.mkdir_p(output_path)
|
36
37
|
cmd = [
|
37
38
|
"grpc_tools_ruby_protoc",
|
38
39
|
"-I#{gem_folder}/lib/new_relic/proto",
|
@@ -40,7 +41,7 @@ namespace :proto do
|
|
40
41
|
"--grpc_out=#{output_path} #{proto_filename}"
|
41
42
|
].join(" ")
|
42
43
|
|
43
|
-
if system
|
44
|
+
if system(cmd)
|
44
45
|
puts "Proto file generated!"
|
45
46
|
add_license_preamble_and_remove_requires output_path
|
46
47
|
else
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: newrelic-infinite_tracing
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 8.
|
4
|
+
version: 8.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tanna McClure
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2022-
|
14
|
+
date: 2022-08-17 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: newrelic_rpm
|
@@ -19,14 +19,14 @@ dependencies:
|
|
19
19
|
requirements:
|
20
20
|
- - '='
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 8.
|
22
|
+
version: 8.10.0
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
27
|
- - '='
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: 8.
|
29
|
+
version: 8.10.0
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: grpc
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -168,21 +168,21 @@ dependencies:
|
|
168
168
|
- !ruby/object:Gem::Version
|
169
169
|
version: 2.4.0
|
170
170
|
- !ruby/object:Gem::Dependency
|
171
|
-
name:
|
171
|
+
name: bundler
|
172
172
|
requirement: !ruby/object:Gem::Requirement
|
173
173
|
requirements:
|
174
|
-
- - "
|
174
|
+
- - ">="
|
175
175
|
- !ruby/object:Gem::Version
|
176
|
-
version: 0
|
176
|
+
version: '0'
|
177
177
|
type: :development
|
178
178
|
prerelease: false
|
179
179
|
version_requirements: !ruby/object:Gem::Requirement
|
180
180
|
requirements:
|
181
|
-
- - "
|
181
|
+
- - ">="
|
182
182
|
- !ruby/object:Gem::Version
|
183
|
-
version: 0
|
183
|
+
version: '0'
|
184
184
|
- !ruby/object:Gem::Dependency
|
185
|
-
name:
|
185
|
+
name: simplecov
|
186
186
|
requirement: !ruby/object:Gem::Requirement
|
187
187
|
requirements:
|
188
188
|
- - ">="
|