newrelic_rpm 8.5.0 → 8.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +28 -1
- data/LICENSE +0 -6
- data/README.md +16 -18
- data/THIRD_PARTY_NOTICES.md +14 -199
- data/lib/new_relic/agent/agent.rb +21 -0
- data/lib/new_relic/agent/agent_logger.rb +7 -0
- data/lib/new_relic/agent/audit_logger.rb +4 -0
- data/lib/new_relic/agent/configuration/default_source.rb +72 -14
- data/lib/new_relic/agent/configuration/event_harvest_config.rb +4 -2
- data/lib/new_relic/agent/configuration/server_source.rb +1 -0
- data/lib/new_relic/agent/hostname.rb +16 -10
- data/lib/new_relic/agent/instrumentation/active_support_logger/chain.rb +23 -0
- data/lib/new_relic/agent/instrumentation/active_support_logger/instrumentation.rb +20 -0
- data/lib/new_relic/agent/instrumentation/active_support_logger/prepend.rb +12 -0
- data/lib/new_relic/agent/instrumentation/active_support_logger.rb +24 -0
- data/lib/new_relic/agent/instrumentation/curb/chain.rb +1 -1
- data/lib/new_relic/agent/instrumentation/curb/prepend.rb +1 -1
- data/lib/new_relic/agent/instrumentation/logger/instrumentation.rb +18 -18
- data/lib/new_relic/agent/instrumentation/logger.rb +4 -3
- data/lib/new_relic/agent/linking_metadata.rb +45 -0
- data/lib/new_relic/agent/local_log_decorator.rb +37 -0
- data/lib/new_relic/agent/log_event_aggregator.rb +234 -0
- data/lib/new_relic/agent/log_priority.rb +20 -0
- data/lib/new_relic/agent/new_relic_service.rb +14 -7
- data/lib/new_relic/agent/pipe_service.rb +4 -0
- data/lib/new_relic/agent/samplers/memory_sampler.rb +6 -1
- data/lib/new_relic/agent/transaction.rb +11 -0
- data/lib/new_relic/agent.rb +4 -14
- data/lib/new_relic/helper.rb +40 -0
- data/lib/new_relic/version.rb +1 -1
- data/lib/tasks/config.rake +3 -3
- data/newrelic.yml +20 -4
- data/newrelic_rpm.gemspec +1 -0
- data/test/agent_helper.rb +18 -4
- metadata +24 -3
- data/ROADMAP.md +0 -24
@@ -0,0 +1,234 @@
|
|
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
|
+
|
5
|
+
require 'new_relic/agent/event_aggregator'
|
6
|
+
require 'new_relic/agent/log_priority'
|
7
|
+
|
8
|
+
module NewRelic
|
9
|
+
module Agent
|
10
|
+
class LogEventAggregator < EventAggregator
|
11
|
+
# Per-message keys
|
12
|
+
LEVEL_KEY = "log.level".freeze
|
13
|
+
MESSAGE_KEY = "message".freeze
|
14
|
+
TIMESTAMP_KEY = "timestamp".freeze
|
15
|
+
PRIORITY_KEY = "priority".freeze
|
16
|
+
|
17
|
+
# Metric keys
|
18
|
+
LINES = "Logging/lines".freeze
|
19
|
+
DROPPED_METRIC = "Logging/Forwarding/Dropped".freeze
|
20
|
+
SEEN_METRIC = "Supportability/Logging/Forwarding/Seen".freeze
|
21
|
+
SENT_METRIC = "Supportability/Logging/Forwarding/Sent".freeze
|
22
|
+
OVERALL_SUPPORTABILITY_FORMAT = "Supportability/Logging/Ruby/Logger/%s".freeze
|
23
|
+
METRICS_SUPPORTABILITY_FORMAT = "Supportability/Logging/Metrics/Ruby/%s".freeze
|
24
|
+
FORWARDING_SUPPORTABILITY_FORMAT = "Supportability/Logging/Forwarding/Ruby/%s".freeze
|
25
|
+
DECORATING_SUPPORTABILITY_FORMAT = "Supportability/Logging/LocalDecorating/Ruby/%s".freeze
|
26
|
+
MAX_BYTES = 32768 # 32 * 1024 bytes (32 kibibytes)
|
27
|
+
|
28
|
+
named :LogEventAggregator
|
29
|
+
buffer_class PrioritySampledBuffer
|
30
|
+
|
31
|
+
capacity_key :'application_logging.forwarding.max_samples_stored'
|
32
|
+
enabled_key :'application_logging.enabled'
|
33
|
+
|
34
|
+
# Config keys
|
35
|
+
OVERALL_ENABLED_KEY = :'application_logging.enabled'
|
36
|
+
METRICS_ENABLED_KEY = :'application_logging.metrics.enabled'
|
37
|
+
FORWARDING_ENABLED_KEY = :'application_logging.forwarding.enabled'
|
38
|
+
DECORATING_ENABLED_KEY = :'application_logging.local_decorating.enabled'
|
39
|
+
|
40
|
+
def initialize(events)
|
41
|
+
super(events)
|
42
|
+
@counter_lock = Mutex.new
|
43
|
+
@seen = 0
|
44
|
+
@seen_by_severity = Hash.new(0)
|
45
|
+
@high_security = NewRelic::Agent.config[:high_security]
|
46
|
+
@instrumentation_logger_enabled = NewRelic::Agent::Instrumentation::Logger.enabled?
|
47
|
+
register_for_done_configuring(events)
|
48
|
+
end
|
49
|
+
|
50
|
+
def capacity
|
51
|
+
@buffer.capacity
|
52
|
+
end
|
53
|
+
|
54
|
+
def record(formatted_message, severity)
|
55
|
+
return unless enabled?
|
56
|
+
|
57
|
+
severity = "UNKNOWN" if severity.nil? || severity.empty?
|
58
|
+
|
59
|
+
if NewRelic::Agent.config[METRICS_ENABLED_KEY]
|
60
|
+
@counter_lock.synchronize do
|
61
|
+
@seen += 1
|
62
|
+
@seen_by_severity[severity] += 1
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
return if formatted_message.nil? || formatted_message.empty?
|
67
|
+
return unless NewRelic::Agent.config[:'application_logging.forwarding.enabled']
|
68
|
+
return if @high_security
|
69
|
+
|
70
|
+
txn = NewRelic::Agent::Transaction.tl_current
|
71
|
+
priority = LogPriority.priority_for(txn)
|
72
|
+
|
73
|
+
if txn
|
74
|
+
return txn.add_log_event(create_event(priority, formatted_message, severity))
|
75
|
+
else
|
76
|
+
return @lock.synchronize do
|
77
|
+
@buffer.append(priority: priority) do
|
78
|
+
create_event(priority, formatted_message, severity)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
rescue
|
83
|
+
nil
|
84
|
+
end
|
85
|
+
|
86
|
+
def record_batch txn, logs
|
87
|
+
# Ensure we have the same shared priority
|
88
|
+
priority = LogPriority.priority_for(txn)
|
89
|
+
logs.each do |log|
|
90
|
+
log.first[PRIORITY_KEY] = priority
|
91
|
+
end
|
92
|
+
|
93
|
+
@lock.synchronize do
|
94
|
+
logs.each do |log|
|
95
|
+
@buffer.append(event: log)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def create_event priority, formatted_message, severity
|
101
|
+
formatted_message = truncate_message(formatted_message)
|
102
|
+
|
103
|
+
event = LinkingMetadata.append_trace_linking_metadata({
|
104
|
+
LEVEL_KEY => severity,
|
105
|
+
MESSAGE_KEY => formatted_message,
|
106
|
+
TIMESTAMP_KEY => Process.clock_gettime(Process::CLOCK_REALTIME) * 1000
|
107
|
+
})
|
108
|
+
|
109
|
+
[
|
110
|
+
{
|
111
|
+
PrioritySampledBuffer::PRIORITY_KEY => priority
|
112
|
+
},
|
113
|
+
event
|
114
|
+
]
|
115
|
+
end
|
116
|
+
|
117
|
+
# Because our transmission format (MELT) is different than historical
|
118
|
+
# agent payloads, extract the munging here to keep the service focused
|
119
|
+
# on the general harvest + transmit instead of the format.
|
120
|
+
#
|
121
|
+
# Payload shape matches the publicly documented MELT format.
|
122
|
+
# https://docs.newrelic.com/docs/logs/log-api/introduction-log-api
|
123
|
+
#
|
124
|
+
# We have to keep the aggregated payloads in a separate shape, though, to
|
125
|
+
# work with the priority sampling buffers
|
126
|
+
def self.payload_to_melt_format(data)
|
127
|
+
common_attributes = LinkingMetadata.append_service_linking_metadata({})
|
128
|
+
|
129
|
+
# To save on unnecessary data transmission, trim the entity.type
|
130
|
+
# sent by classic logs-in-context
|
131
|
+
common_attributes.delete(ENTITY_TYPE_KEY)
|
132
|
+
|
133
|
+
_, items = data
|
134
|
+
payload = [{
|
135
|
+
common: {attributes: common_attributes},
|
136
|
+
logs: items.map(&:last)
|
137
|
+
}]
|
138
|
+
|
139
|
+
return [payload, items.size]
|
140
|
+
end
|
141
|
+
|
142
|
+
def harvest!
|
143
|
+
record_customer_metrics()
|
144
|
+
super
|
145
|
+
end
|
146
|
+
|
147
|
+
def reset!
|
148
|
+
@counter_lock.synchronize do
|
149
|
+
@seen = 0
|
150
|
+
@seen_by_severity.clear
|
151
|
+
end
|
152
|
+
super
|
153
|
+
end
|
154
|
+
|
155
|
+
def enabled?
|
156
|
+
@enabled && @instrumentation_logger_enabled
|
157
|
+
end
|
158
|
+
|
159
|
+
private
|
160
|
+
|
161
|
+
# We record once-per-connect metrics for enabled/disabled state at the
|
162
|
+
# point we consider the configuration stable (i.e. once we've gotten SSC)
|
163
|
+
def register_for_done_configuring(events)
|
164
|
+
events.subscribe(:server_source_configuration_added) do
|
165
|
+
@high_security = NewRelic::Agent.config[:high_security]
|
166
|
+
|
167
|
+
record_configuration_metric(OVERALL_SUPPORTABILITY_FORMAT, OVERALL_ENABLED_KEY)
|
168
|
+
record_configuration_metric(METRICS_SUPPORTABILITY_FORMAT, METRICS_ENABLED_KEY)
|
169
|
+
record_configuration_metric(FORWARDING_SUPPORTABILITY_FORMAT, FORWARDING_ENABLED_KEY)
|
170
|
+
record_configuration_metric(DECORATING_SUPPORTABILITY_FORMAT, DECORATING_ENABLED_KEY)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def record_configuration_metric(format, key)
|
175
|
+
state = NewRelic::Agent.config[key]
|
176
|
+
label = if !enabled?
|
177
|
+
"disabled"
|
178
|
+
else
|
179
|
+
state ? "enabled" : "disabled"
|
180
|
+
end
|
181
|
+
NewRelic::Agent.increment_metric(format % label)
|
182
|
+
end
|
183
|
+
|
184
|
+
def after_harvest metadata
|
185
|
+
dropped_count = metadata[:seen] - metadata[:captured]
|
186
|
+
note_dropped_events(metadata[:seen], dropped_count)
|
187
|
+
record_supportability_metrics(metadata[:seen], metadata[:captured], dropped_count)
|
188
|
+
end
|
189
|
+
|
190
|
+
# To avoid paying the cost of metric recording on every line, we hold
|
191
|
+
# these until harvest before recording them
|
192
|
+
def record_customer_metrics
|
193
|
+
return unless enabled?
|
194
|
+
return unless NewRelic::Agent.config[:'application_logging.metrics.enabled']
|
195
|
+
|
196
|
+
@counter_lock.synchronize do
|
197
|
+
return unless @seen > 0
|
198
|
+
|
199
|
+
NewRelic::Agent.increment_metric(LINES, @seen)
|
200
|
+
@seen_by_severity.each do |(severity, count)|
|
201
|
+
NewRelic::Agent.increment_metric(line_metric_name_by_severity(severity), count)
|
202
|
+
end
|
203
|
+
|
204
|
+
@seen = 0
|
205
|
+
@seen_by_severity.clear
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def line_metric_name_by_severity(severity)
|
210
|
+
@line_metrics ||= {}
|
211
|
+
@line_metrics[severity] ||= "Logging/lines/#{severity}".freeze
|
212
|
+
end
|
213
|
+
|
214
|
+
def note_dropped_events total_count, dropped_count
|
215
|
+
if dropped_count > 0
|
216
|
+
NewRelic::Agent.logger.warn("Dropped #{dropped_count} log events out of #{total_count}.")
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def record_supportability_metrics total_count, captured_count, dropped_count
|
221
|
+
return unless total_count > 0
|
222
|
+
|
223
|
+
NewRelic::Agent.increment_metric(DROPPED_METRIC, dropped_count)
|
224
|
+
NewRelic::Agent.increment_metric(SEEN_METRIC, total_count)
|
225
|
+
NewRelic::Agent.increment_metric(SENT_METRIC, captured_count)
|
226
|
+
end
|
227
|
+
|
228
|
+
def truncate_message(message)
|
229
|
+
return message if message.bytesize <= MAX_BYTES
|
230
|
+
message.byteslice(0...MAX_BYTES)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
@@ -0,0 +1,20 @@
|
|
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
|
+
|
5
|
+
require 'new_relic/agent/event_aggregator'
|
6
|
+
|
7
|
+
# Stateless calculation of priority for a given log event
|
8
|
+
module NewRelic
|
9
|
+
module Agent
|
10
|
+
module LogPriority
|
11
|
+
extend self
|
12
|
+
|
13
|
+
def priority_for(txn)
|
14
|
+
return txn.priority if txn
|
15
|
+
|
16
|
+
rand.round(NewRelic::PRIORITY_PRECISION)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -177,18 +177,25 @@ module NewRelic
|
|
177
177
|
:item_count => items.size)
|
178
178
|
end
|
179
179
|
|
180
|
+
def log_event_data(data)
|
181
|
+
payload, size = LogEventAggregator.payload_to_melt_format(data)
|
182
|
+
invoke_remote(:log_event_data, payload, :item_count => size)
|
183
|
+
end
|
184
|
+
|
180
185
|
def error_event_data(data)
|
181
186
|
metadata, items = data
|
182
|
-
invoke_remote(:error_event_data, [@agent_id, *data], :item_count => items.size)
|
187
|
+
response = invoke_remote(:error_event_data, [@agent_id, *data], :item_count => items.size)
|
183
188
|
NewRelic::Agent.record_metric("Supportability/Events/TransactionError/Sent", :count => items.size)
|
184
189
|
NewRelic::Agent.record_metric("Supportability/Events/TransactionError/Seen", :count => metadata[:events_seen])
|
190
|
+
response
|
185
191
|
end
|
186
192
|
|
187
193
|
def span_event_data(data)
|
188
194
|
metadata, items = data
|
189
|
-
invoke_remote(:span_event_data, [@agent_id, *data], :item_count => items.size)
|
195
|
+
response = invoke_remote(:span_event_data, [@agent_id, *data], :item_count => items.size)
|
190
196
|
NewRelic::Agent.record_metric("Supportability/Events/SpanEvents/Sent", :count => items.size)
|
191
197
|
NewRelic::Agent.record_metric("Supportability/Events/SpanEvents/Seen", :count => metadata[:events_seen])
|
198
|
+
response
|
192
199
|
end
|
193
200
|
|
194
201
|
# We do not compress if content is smaller than 64kb. There are
|
@@ -454,7 +461,7 @@ module NewRelic
|
|
454
461
|
def handle_serialization_error(method, e)
|
455
462
|
NewRelic::Agent.increment_metric("Supportability/serialization_failure")
|
456
463
|
NewRelic::Agent.increment_metric("Supportability/serialization_failure/#{method}")
|
457
|
-
msg = "Failed to serialize #{method} data using #{@marshaller.class
|
464
|
+
msg = "Failed to serialize #{method} data using #{@marshaller.class}: #{e.inspect}"
|
458
465
|
error = SerializationError.new(msg)
|
459
466
|
error.set_backtrace(e.backtrace)
|
460
467
|
raise error
|
@@ -464,11 +471,11 @@ module NewRelic
|
|
464
471
|
serialize_time = serialize_finish_ts && (serialize_finish_ts - start_ts)
|
465
472
|
request_duration = response_check_ts && (response_check_ts - request_send_ts)
|
466
473
|
if request_duration
|
467
|
-
NewRelic::Agent.record_metric("Supportability/Agent/Collector/#{method
|
474
|
+
NewRelic::Agent.record_metric("Supportability/Agent/Collector/#{method}/Duration", request_duration)
|
468
475
|
end
|
469
476
|
if serialize_time
|
470
477
|
NewRelic::Agent.record_metric("Supportability/invoke_remote_serialize", serialize_time)
|
471
|
-
NewRelic::Agent.record_metric("Supportability/invoke_remote_serialize/#{method
|
478
|
+
NewRelic::Agent.record_metric("Supportability/invoke_remote_serialize/#{method}", serialize_time)
|
472
479
|
end
|
473
480
|
end
|
474
481
|
|
@@ -482,8 +489,8 @@ module NewRelic
|
|
482
489
|
# of items as arguments.
|
483
490
|
def record_size_supportability_metrics(method, size_bytes, item_count)
|
484
491
|
metrics = [
|
485
|
-
"Supportability/
|
486
|
-
"Supportability/
|
492
|
+
"Supportability/Ruby/Collector/Output/Bytes",
|
493
|
+
"Supportability/Ruby/Collector/#{method}/Output/Bytes"
|
487
494
|
]
|
488
495
|
# we may not have an item count, in which case, just record 0 for the exclusive time
|
489
496
|
item_count ||= 0
|
@@ -3,6 +3,7 @@
|
|
3
3
|
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
4
4
|
|
5
5
|
require 'new_relic/agent/sampler'
|
6
|
+
require 'new_relic/helper'
|
6
7
|
|
7
8
|
module NewRelic
|
8
9
|
module Agent
|
@@ -46,7 +47,11 @@ module NewRelic
|
|
46
47
|
|
47
48
|
def self.platform
|
48
49
|
if RUBY_PLATFORM =~ /java/
|
49
|
-
|
50
|
+
begin
|
51
|
+
NewRelic::Helper.run_command('uname -s').downcase
|
52
|
+
rescue NewRelic::CommandRunFailedError, NewRelic::CommandExecutableNotFoundError
|
53
|
+
'unknown'
|
54
|
+
end
|
50
55
|
else
|
51
56
|
RUBY_PLATFORM.downcase
|
52
57
|
end
|
@@ -77,6 +77,7 @@ module NewRelic
|
|
77
77
|
|
78
78
|
attr_reader :guid,
|
79
79
|
:metrics,
|
80
|
+
:logs,
|
80
81
|
:gc_start_snapshot,
|
81
82
|
:category,
|
82
83
|
:attributes,
|
@@ -236,6 +237,7 @@ module NewRelic
|
|
236
237
|
|
237
238
|
@exceptions = {}
|
238
239
|
@metrics = TransactionMetrics.new
|
240
|
+
@logs = PrioritySampledBuffer.new(NewRelic::Agent.instance.log_event_aggregator.capacity)
|
239
241
|
@guid = NewRelic::Agent::GuidGenerator.generate_guid
|
240
242
|
|
241
243
|
@ignore_this_transaction = false
|
@@ -533,6 +535,7 @@ module NewRelic
|
|
533
535
|
|
534
536
|
record_exceptions
|
535
537
|
record_transaction_event
|
538
|
+
record_log_events
|
536
539
|
merge_metrics
|
537
540
|
send_transaction_finished_event
|
538
541
|
end
|
@@ -732,6 +735,10 @@ module NewRelic
|
|
732
735
|
agent.transaction_event_recorder.record payload
|
733
736
|
end
|
734
737
|
|
738
|
+
def record_log_events
|
739
|
+
agent.log_event_aggregator.record_batch self, @logs.to_a
|
740
|
+
end
|
741
|
+
|
735
742
|
def queue_time
|
736
743
|
@apdex_start ? @start_time - @apdex_start : 0
|
737
744
|
end
|
@@ -826,6 +833,10 @@ module NewRelic
|
|
826
833
|
attributes.merge_custom_attributes(p)
|
827
834
|
end
|
828
835
|
|
836
|
+
def add_log_event(event)
|
837
|
+
logs.append(event: event)
|
838
|
+
end
|
839
|
+
|
829
840
|
def recording_web_transaction?
|
830
841
|
web_category?(@category)
|
831
842
|
end
|
data/lib/new_relic/agent.rb
CHANGED
@@ -59,6 +59,8 @@ module NewRelic
|
|
59
59
|
require 'new_relic/agent/logging'
|
60
60
|
require 'new_relic/agent/distributed_tracing'
|
61
61
|
require 'new_relic/agent/attribute_processing'
|
62
|
+
require 'new_relic/agent/linking_metadata'
|
63
|
+
require 'new_relic/agent/local_log_decorator'
|
62
64
|
|
63
65
|
require 'new_relic/agent/instrumentation/controller_instrumentation'
|
64
66
|
|
@@ -726,20 +728,8 @@ module NewRelic
|
|
726
728
|
# @api public
|
727
729
|
def linking_metadata
|
728
730
|
metadata = Hash.new
|
729
|
-
metadata
|
730
|
-
metadata
|
731
|
-
metadata[HOSTNAME_KEY] = Hostname.get
|
732
|
-
|
733
|
-
if entity_guid = config[:entity_guid]
|
734
|
-
metadata[ENTITY_GUID_KEY] = entity_guid
|
735
|
-
end
|
736
|
-
|
737
|
-
if trace_id = Tracer.current_trace_id
|
738
|
-
metadata[TRACE_ID_KEY] = trace_id
|
739
|
-
end
|
740
|
-
if span_id = Tracer.current_span_id
|
741
|
-
metadata[SPAN_ID_KEY] = span_id
|
742
|
-
end
|
731
|
+
LinkingMetadata.append_service_linking_metadata(metadata)
|
732
|
+
LinkingMetadata.append_trace_linking_metadata(metadata)
|
743
733
|
metadata
|
744
734
|
end
|
745
735
|
|
data/lib/new_relic/helper.rb
CHANGED
@@ -3,8 +3,12 @@
|
|
3
3
|
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
4
4
|
|
5
5
|
require 'new_relic/language_support'
|
6
|
+
require 'open3'
|
6
7
|
|
7
8
|
module NewRelic
|
9
|
+
class CommandExecutableNotFoundError < StandardError; end
|
10
|
+
class CommandRunFailedError < StandardError; end
|
11
|
+
|
8
12
|
# A singleton for shared generic helper methods
|
9
13
|
module Helper
|
10
14
|
extend self
|
@@ -40,5 +44,41 @@ module NewRelic
|
|
40
44
|
def time_to_millis(time)
|
41
45
|
(time.to_f * 1000).round
|
42
46
|
end
|
47
|
+
|
48
|
+
def run_command(command)
|
49
|
+
executable = command.split(' ').first
|
50
|
+
unless executable_in_path?(executable)
|
51
|
+
raise NewRelic::CommandExecutableNotFoundError.new("Executable not found: '#{executable}'")
|
52
|
+
end
|
53
|
+
|
54
|
+
exception = nil
|
55
|
+
begin
|
56
|
+
output, status = Open3.capture2e(command)
|
57
|
+
rescue => exception
|
58
|
+
end
|
59
|
+
|
60
|
+
if exception || !status.success?
|
61
|
+
message = exception ? "#{exception.class} - #{exception.message}" : output
|
62
|
+
raise NewRelic::CommandRunFailedError.new("Failed to run command '#{command}': #{message}")
|
63
|
+
end
|
64
|
+
|
65
|
+
output.chomp
|
66
|
+
end
|
67
|
+
|
68
|
+
# TODO: Open3 defers the actual excecution of a binary to Process.spawn,
|
69
|
+
# which will raise an Errno::ENOENT exception for a file that
|
70
|
+
# cannot be found. We might want to take the time to evaluate
|
71
|
+
# relying on that Process.spawn behavior instead of checking for
|
72
|
+
# existence ourselves. We'd need to see what it does, how efficient
|
73
|
+
# it is, if it differs in functionality between Ruby versions and
|
74
|
+
# operating systems, etc.
|
75
|
+
def executable_in_path?(executable)
|
76
|
+
return false unless ENV['PATH']
|
77
|
+
|
78
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).any? do |bin_path|
|
79
|
+
executable_path = File.join(bin_path, executable)
|
80
|
+
File.exist?(executable_path) && File.file?(executable_path) && File.executable?(executable_path)
|
81
|
+
end
|
82
|
+
end
|
43
83
|
end
|
44
84
|
end
|
data/lib/new_relic/version.rb
CHANGED
data/lib/tasks/config.rake
CHANGED
@@ -11,8 +11,8 @@ namespace :newrelic do
|
|
11
11
|
DISABLING => 'Use these settings to toggle instrumentation types during agent startup.',
|
12
12
|
ATTRIBUTES => '[Attributes](/docs/features/agent-attributes) are key-value pairs containing information that determines the properties of an event or transaction. These key-value pairs can be viewed within transaction traces in APM, traced errors in APM, transaction events in dashboards, and page views in dashboards. You can customize exactly which attributes will be sent to each of these destinations',
|
13
13
|
"transaction_tracer" => 'The [transaction traces](/docs/apm/traces/transaction-traces/transaction-traces) feature collects detailed information from a selection of transactions, including a summary of the calling sequence, a breakdown of time spent, and a list of SQL queries and their query plans (on mysql and postgresql). Available features depend on your New Relic subscription level.',
|
14
|
-
"error_collector" => 'The agent collects and reports all uncaught exceptions by default. These configuration options allow you to customize the error collection.',
|
15
|
-
"browser_monitoring" =>
|
14
|
+
"error_collector" => 'The agent collects and reports all uncaught exceptions by default. These configuration options allow you to customize the error collection.\nFor information on ignored and expected errors, [see this page on Error Analytics in APM](/docs/agents/manage-apm-agents/agent-data/manage-errors-apm-collect-ignore-or-mark-expected/). To set expected errors via the `NewRelic::Agent.notice_error` Ruby method, [consult the Ruby Agent API](/docs/agents/ruby-agent/api-guides/sending-handled-errors-new-relic/).',
|
15
|
+
"browser_monitoring" => "The browser monitoring [page load timing](/docs/browser/new-relic-browser/page-load-timing/page-load-timing-process) feature (sometimes referred to as real user monitoring or RUM) gives you insight into the performance real users are experiencing with your website. This is accomplished by measuring the time it takes for your users' browsers to download and render your web pages by injecting a small amount of JavaScript code into the header and footer of each page.",
|
16
16
|
"analytics_events" => '[New Relic dashboards](/docs/query-your-data/explore-query-data/dashboards/introduction-new-relic-one-dashboards) is a resource to gather and visualize data about your software and what it says about your business. With it you can quickly and easily create real-time dashboards to get immediate answers about end-user experiences, clickstreams, mobile activities, and server transactions.'
|
17
17
|
}
|
18
18
|
|
@@ -24,7 +24,7 @@ namespace :newrelic do
|
|
24
24
|
config_hash = build_config_hash
|
25
25
|
sections = flatten_config_hash(config_hash)
|
26
26
|
|
27
|
-
puts build_erb(format).result(binding)
|
27
|
+
puts build_erb(format).result(binding).split("\n").map(&:rstrip).join("\n").gsub('. ', '. ')
|
28
28
|
sections # silences unused warning to return this
|
29
29
|
end
|
30
30
|
|
data/newrelic.yml
CHANGED
@@ -26,6 +26,22 @@ common: &default_settings
|
|
26
26
|
# All of the following configuration options are optional. Review them, and
|
27
27
|
# uncomment or edit them if they appear relevant to your application needs.
|
28
28
|
|
29
|
+
# If `true`, all logging-related features for the agent can be enabled or disabled
|
30
|
+
# independently. If `false`, all logging-related features are disabled.
|
31
|
+
# application_logging.enabled: true
|
32
|
+
|
33
|
+
# If `true`, the agent captures log records emitted by this application.
|
34
|
+
# application_logging.forwarding.enabled: false
|
35
|
+
|
36
|
+
# Defines the maximum number of log records to buffer in memory at a time.
|
37
|
+
# application_logging.forwarding.max_samples_stored: 10000
|
38
|
+
|
39
|
+
# If `true`, the agent captures metrics related to logging for this application.
|
40
|
+
# application_logging.metrics.enabled: true
|
41
|
+
|
42
|
+
# If `true`, the agent decorates logs with metadata to link to entities, hosts, traces, and spans.
|
43
|
+
# application_logging.local_decorating.enabled: false
|
44
|
+
|
29
45
|
# If true, enables transaction event sampling.
|
30
46
|
# transaction_events.enabled: true
|
31
47
|
|
@@ -82,10 +98,6 @@ common: &default_settings
|
|
82
98
|
# end.
|
83
99
|
# browser_monitoring.attributes.include: []
|
84
100
|
|
85
|
-
# If true, enables auto-injection of the JavaScript header for page load timing
|
86
|
-
# (sometimes referred to as real user monitoring or RUM).
|
87
|
-
# browser_monitoring.auto_instrument: false
|
88
|
-
|
89
101
|
# This is true by default, this enables auto-injection of the JavaScript header
|
90
102
|
# for page load timing (sometimes referred to as real user monitoring or RUM).
|
91
103
|
# browser_monitoring.auto_instrument: true
|
@@ -317,6 +329,10 @@ common: &default_settings
|
|
317
329
|
# May be one of [auto|prepend|chain|disabled].
|
318
330
|
# instrumentation.logger: auto
|
319
331
|
|
332
|
+
# Controls auto-instrumentation of ActiveSupport::Logger at start up.
|
333
|
+
# May be one of [auto|prepend|chain|disabled].
|
334
|
+
# instrumentation.active_support.logger: auto
|
335
|
+
|
320
336
|
# Controls auto-instrumentation of memcache-client gem for Memcache at start up.
|
321
337
|
# May be one of [auto|prepend|chain|disabled].
|
322
338
|
# instrumentation.memcache_client: auto
|
data/newrelic_rpm.gemspec
CHANGED
@@ -52,6 +52,7 @@ https://github.com/newrelic/newrelic-ruby-agent/
|
|
52
52
|
s.add_development_dependency 'rb-inotify', '0.9.10' # locked to support < Ruby 2.3 (and listen 3.0.8)
|
53
53
|
s.add_development_dependency 'listen', '3.0.8' # locked to support < Ruby 2.3
|
54
54
|
s.add_development_dependency 'minitest', '4.7.5'
|
55
|
+
s.add_development_dependency 'minitest-stub-const', '0.6'
|
55
56
|
s.add_development_dependency 'mocha', '~> 1.9.0'
|
56
57
|
s.add_development_dependency 'yard'
|
57
58
|
s.add_development_dependency 'pry-nav', '~> 0.3.0'
|
data/test/agent_helper.rb
CHANGED
@@ -218,16 +218,30 @@ end
|
|
218
218
|
def assert_stats_has_values stats, expected_spec, expected_attrs
|
219
219
|
expected_attrs.each do |attr, expected_value|
|
220
220
|
actual_value = stats.send(attr)
|
221
|
+
|
222
|
+
msg = "Expected #{attr} for #{expected_spec} to be #{'~' unless attr == :call_count}#{expected_value}, " \
|
223
|
+
"got #{actual_value}.\nActual stats:\n#{dump_stats(stats)}"
|
224
|
+
|
221
225
|
if attr == :call_count
|
222
|
-
|
223
|
-
"Expected #{attr} for #{expected_spec} to be #{expected_value}, got #{actual_value}.\nActual stats:\n#{dump_stats(stats)}")
|
226
|
+
assert_stats_has_values_with_call_count(expected_value, actual_value, msg)
|
224
227
|
else
|
225
|
-
assert_in_delta(expected_value, actual_value, 0.0001,
|
226
|
-
"Expected #{attr} for #{expected_spec} to be ~#{expected_value}, got #{actual_value}.\nActual stats:\n#{dump_stats(stats)}")
|
228
|
+
assert_in_delta(expected_value, actual_value, 0.0001, msg)
|
227
229
|
end
|
228
230
|
end
|
229
231
|
end
|
230
232
|
|
233
|
+
def assert_stats_has_values_with_call_count(expected_value, actual_value, msg)
|
234
|
+
# >, <, >=, <= comparisons
|
235
|
+
if expected_value.to_s =~ /([<>]=?)\s*(\d+)/
|
236
|
+
operator = Regexp.last_match(1).to_sym
|
237
|
+
count = Regexp.last_match(2).to_i
|
238
|
+
assert_operator(actual_value, operator, count, msg)
|
239
|
+
# == comparison
|
240
|
+
else
|
241
|
+
assert_equal(expected_value, actual_value, msg)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
231
245
|
def assert_metrics_recorded expected
|
232
246
|
expected = _normalize_metric_expectations(expected)
|
233
247
|
expected.each do |specish, expected_attrs|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: newrelic_rpm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 8.
|
4
|
+
version: 8.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tanna McClure
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2022-
|
13
|
+
date: 2022-04-04 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rake
|
@@ -68,6 +68,20 @@ dependencies:
|
|
68
68
|
- - '='
|
69
69
|
- !ruby/object:Gem::Version
|
70
70
|
version: 4.7.5
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: minitest-stub-const
|
73
|
+
requirement: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - '='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0.6'
|
78
|
+
type: :development
|
79
|
+
prerelease: false
|
80
|
+
version_requirements: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - '='
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0.6'
|
71
85
|
- !ruby/object:Gem::Dependency
|
72
86
|
name: mocha
|
73
87
|
requirement: !ruby/object:Gem::Requirement
|
@@ -242,7 +256,6 @@ files:
|
|
242
256
|
- Guardfile
|
243
257
|
- LICENSE
|
244
258
|
- README.md
|
245
|
-
- ROADMAP.md
|
246
259
|
- Rakefile
|
247
260
|
- THIRD_PARTY_NOTICES.md
|
248
261
|
- bin/mongrel_rpm
|
@@ -341,6 +354,10 @@ files:
|
|
341
354
|
- lib/new_relic/agent/instrumentation/active_record_subscriber.rb
|
342
355
|
- lib/new_relic/agent/instrumentation/active_storage.rb
|
343
356
|
- lib/new_relic/agent/instrumentation/active_storage_subscriber.rb
|
357
|
+
- lib/new_relic/agent/instrumentation/active_support_logger.rb
|
358
|
+
- lib/new_relic/agent/instrumentation/active_support_logger/chain.rb
|
359
|
+
- lib/new_relic/agent/instrumentation/active_support_logger/instrumentation.rb
|
360
|
+
- lib/new_relic/agent/instrumentation/active_support_logger/prepend.rb
|
344
361
|
- lib/new_relic/agent/instrumentation/acts_as_solr.rb
|
345
362
|
- lib/new_relic/agent/instrumentation/authlogic.rb
|
346
363
|
- lib/new_relic/agent/instrumentation/bunny.rb
|
@@ -441,7 +458,11 @@ files:
|
|
441
458
|
- lib/new_relic/agent/instrumentation/typhoeus/prepend.rb
|
442
459
|
- lib/new_relic/agent/internal_agent_error.rb
|
443
460
|
- lib/new_relic/agent/javascript_instrumentor.rb
|
461
|
+
- lib/new_relic/agent/linking_metadata.rb
|
462
|
+
- lib/new_relic/agent/local_log_decorator.rb
|
463
|
+
- lib/new_relic/agent/log_event_aggregator.rb
|
444
464
|
- lib/new_relic/agent/log_once.rb
|
465
|
+
- lib/new_relic/agent/log_priority.rb
|
445
466
|
- lib/new_relic/agent/logging.rb
|
446
467
|
- lib/new_relic/agent/memory_logger.rb
|
447
468
|
- lib/new_relic/agent/messaging.rb
|