newrelic_rpm 9.9.0 → 9.21.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/.build_ignore +1 -0
- data/CHANGELOG.md +463 -1
- data/CONTRIBUTING.md +2 -2
- data/README.md +16 -17
- data/Rakefile +1 -1
- data/lib/boot/strap.rb +102 -0
- data/lib/new_relic/agent/agent.rb +6 -0
- data/lib/new_relic/agent/agent_helpers/connect.rb +3 -0
- data/lib/new_relic/agent/agent_helpers/harvest.rb +3 -0
- data/lib/new_relic/agent/agent_helpers/shutdown.rb +3 -0
- data/lib/new_relic/agent/agent_helpers/start_worker_thread.rb +1 -0
- data/lib/new_relic/agent/agent_helpers/startup.rb +7 -0
- data/lib/new_relic/agent/agent_logger.rb +1 -0
- data/lib/new_relic/agent/aws.rb +68 -0
- data/lib/new_relic/agent/configuration/default_source.rb +603 -105
- data/lib/new_relic/agent/configuration/environment_source.rb +5 -1
- data/lib/new_relic/agent/configuration/manager.rb +28 -2
- data/lib/new_relic/agent/configuration/yaml_source.rb +7 -2
- data/lib/new_relic/agent/database/obfuscation_helpers.rb +11 -11
- data/lib/new_relic/agent/database/obfuscator.rb +1 -0
- data/lib/new_relic/agent/database.rb +41 -1
- data/lib/new_relic/agent/database_adapter.rb +1 -1
- data/lib/new_relic/agent/datastores/redis.rb +1 -1
- data/lib/new_relic/agent/distributed_tracing/cross_app_tracing.rb +1 -1
- data/lib/new_relic/agent/distributed_tracing.rb +4 -2
- data/lib/new_relic/agent/error_collector.rb +37 -10
- data/lib/new_relic/agent/external.rb +2 -0
- data/lib/new_relic/agent/health_check.rb +136 -0
- data/lib/new_relic/agent/http_clients/uri_util.rb +1 -1
- data/lib/new_relic/agent/instrumentation/action_dispatch.rb +1 -1
- data/lib/new_relic/agent/instrumentation/action_dispatch_subscriber.rb +1 -1
- data/lib/new_relic/agent/instrumentation/action_mailbox.rb +1 -1
- data/lib/new_relic/agent/instrumentation/action_mailer.rb +1 -1
- data/lib/new_relic/agent/instrumentation/active_job.rb +1 -1
- data/lib/new_relic/agent/instrumentation/active_job_subscriber.rb +6 -2
- data/lib/new_relic/agent/instrumentation/active_merchant.rb +0 -13
- data/lib/new_relic/agent/instrumentation/active_record.rb +7 -12
- data/lib/new_relic/agent/instrumentation/active_record_helper.rb +7 -3
- data/lib/new_relic/agent/instrumentation/active_record_notifications.rb +11 -9
- data/lib/new_relic/agent/instrumentation/active_record_prepend.rb +2 -2
- data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +9 -16
- data/lib/new_relic/agent/instrumentation/active_support_broadcast_logger.rb +0 -2
- data/lib/new_relic/agent/instrumentation/active_support_logger.rb +0 -2
- data/lib/new_relic/agent/instrumentation/async_http.rb +2 -3
- data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/chain.rb +21 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/instrumentation.rb +66 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/prepend.rb +15 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_firehose.rb +22 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/chain.rb +21 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/instrumentation.rb +91 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/prepend.rb +15 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis.rb +22 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_lambda/chain.rb +33 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_lambda/instrumentation.rb +93 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_lambda/prepend.rb +23 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_lambda.rb +23 -0
- data/lib/new_relic/agent/instrumentation/aws_sqs/chain.rb +37 -0
- data/lib/new_relic/agent/instrumentation/aws_sqs/instrumentation.rb +67 -0
- data/lib/new_relic/agent/instrumentation/aws_sqs/prepend.rb +21 -0
- data/lib/new_relic/agent/instrumentation/aws_sqs.rb +23 -0
- data/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb +14 -0
- data/lib/new_relic/agent/instrumentation/bunny.rb +3 -4
- data/lib/new_relic/agent/instrumentation/concurrent_ruby.rb +1 -3
- data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +4 -0
- data/lib/new_relic/agent/instrumentation/curb.rb +4 -5
- data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +0 -23
- data/lib/new_relic/agent/instrumentation/dynamodb/chain.rb +27 -0
- data/lib/new_relic/agent/instrumentation/dynamodb/instrumentation.rb +64 -0
- data/lib/new_relic/agent/instrumentation/dynamodb/prepend.rb +19 -0
- data/lib/new_relic/agent/instrumentation/dynamodb.rb +23 -0
- data/lib/new_relic/agent/instrumentation/elasticsearch/chain.rb +1 -2
- data/lib/new_relic/agent/instrumentation/elasticsearch/instrumentation.rb +53 -7
- data/lib/new_relic/agent/instrumentation/elasticsearch.rb +1 -3
- data/lib/new_relic/agent/instrumentation/ethon.rb +1 -5
- data/lib/new_relic/agent/instrumentation/excon.rb +1 -17
- data/lib/new_relic/agent/instrumentation/fiber/chain.rb +1 -1
- data/lib/new_relic/agent/instrumentation/fiber/prepend.rb +1 -1
- data/lib/new_relic/agent/instrumentation/fiber.rb +0 -2
- data/lib/new_relic/agent/instrumentation/grape/instrumentation.rb +0 -3
- data/lib/new_relic/agent/instrumentation/grape.rb +1 -1
- data/lib/new_relic/agent/instrumentation/grpc/client/instrumentation.rb +0 -1
- data/lib/new_relic/agent/instrumentation/httpclient.rb +1 -5
- data/lib/new_relic/agent/instrumentation/httprb.rb +0 -1
- data/lib/new_relic/agent/instrumentation/httpx/instrumentation.rb +1 -1
- data/lib/new_relic/agent/instrumentation/httpx.rb +1 -5
- data/lib/new_relic/agent/instrumentation/logger.rb +1 -3
- data/lib/new_relic/agent/instrumentation/logstasher/chain.rb +21 -0
- data/lib/new_relic/agent/instrumentation/logstasher/instrumentation.rb +24 -0
- data/lib/new_relic/agent/instrumentation/logstasher/prepend.rb +13 -0
- data/lib/new_relic/agent/instrumentation/logstasher.rb +25 -0
- data/lib/new_relic/agent/instrumentation/memcache/dalli.rb +1 -1
- data/lib/new_relic/agent/instrumentation/memcache/helper.rb +2 -2
- data/lib/new_relic/agent/instrumentation/memcache/instrumentation.rb +1 -1
- data/lib/new_relic/agent/instrumentation/memcache/prepend.rb +1 -1
- data/lib/new_relic/agent/instrumentation/memcache.rb +0 -1
- data/lib/new_relic/agent/instrumentation/mongodb_command_subscriber.rb +1 -1
- data/lib/new_relic/agent/instrumentation/net_http/instrumentation.rb +3 -3
- data/lib/new_relic/agent/instrumentation/net_http.rb +2 -1
- data/lib/new_relic/agent/instrumentation/notifications_subscriber.rb +0 -2
- data/lib/new_relic/agent/instrumentation/opensearch/chain.rb +21 -0
- data/lib/new_relic/agent/instrumentation/opensearch/instrumentation.rb +66 -0
- data/lib/{tasks/instrumentation_generator/templates/instrumentation.tt → new_relic/agent/instrumentation/opensearch/prepend.rb} +4 -4
- data/lib/new_relic/agent/instrumentation/opensearch.rb +23 -0
- data/lib/new_relic/agent/instrumentation/padrino.rb +3 -3
- data/lib/new_relic/agent/instrumentation/rack/instrumentation.rb +3 -0
- data/lib/new_relic/agent/instrumentation/rails_notifications/action_controller.rb +9 -5
- data/lib/new_relic/agent/instrumentation/rake.rb +1 -2
- data/lib/new_relic/agent/instrumentation/rdkafka/chain.rb +72 -0
- data/lib/new_relic/agent/instrumentation/rdkafka/instrumentation.rb +70 -0
- data/lib/new_relic/agent/instrumentation/rdkafka/prepend.rb +67 -0
- data/lib/new_relic/agent/instrumentation/rdkafka.rb +25 -0
- data/lib/new_relic/agent/instrumentation/redis/cluster_middleware.rb +26 -0
- data/lib/new_relic/agent/instrumentation/redis/constants.rb +2 -2
- data/lib/new_relic/agent/instrumentation/redis/instrumentation.rb +14 -11
- data/lib/new_relic/agent/instrumentation/redis/middleware.rb +3 -0
- data/lib/new_relic/agent/instrumentation/redis.rb +11 -5
- data/lib/new_relic/agent/instrumentation/resque.rb +8 -6
- data/lib/new_relic/agent/instrumentation/roda.rb +5 -5
- data/lib/new_relic/agent/instrumentation/ruby_kafka/chain.rb +55 -0
- data/lib/new_relic/agent/instrumentation/ruby_kafka/instrumentation.rb +67 -0
- data/lib/new_relic/agent/instrumentation/ruby_kafka/prepend.rb +60 -0
- data/lib/new_relic/agent/instrumentation/ruby_kafka.rb +25 -0
- data/lib/new_relic/agent/instrumentation/ruby_openai.rb +2 -2
- data/lib/new_relic/agent/instrumentation/sidekiq/extensions/delay_extensions.rb +24 -0
- data/lib/new_relic/agent/instrumentation/sidekiq/extensions/delayed_class.rb +2 -2
- data/lib/new_relic/agent/instrumentation/sidekiq.rb +9 -15
- data/lib/new_relic/agent/instrumentation/sinatra.rb +3 -19
- data/lib/new_relic/agent/instrumentation/stripe.rb +1 -1
- data/lib/new_relic/agent/instrumentation/stripe_subscriber.rb +22 -1
- data/lib/new_relic/agent/instrumentation/thread.rb +0 -2
- data/lib/new_relic/agent/instrumentation/tilt.rb +0 -4
- data/lib/new_relic/agent/instrumentation/typhoeus/instrumentation.rb +2 -2
- data/lib/new_relic/agent/instrumentation/typhoeus.rb +0 -1
- data/lib/new_relic/agent/instrumentation/view_component/instrumentation.rb +11 -5
- data/lib/new_relic/agent/instrumentation/view_component.rb +0 -2
- data/lib/new_relic/agent/javascript_instrumentor.rb +2 -3
- data/lib/new_relic/agent/llm/chat_completion_summary.rb +1 -1
- data/lib/new_relic/agent/llm/embedding.rb +1 -1
- data/lib/new_relic/agent/local_log_decorator.rb +20 -3
- data/lib/new_relic/agent/log_event_aggregator.rb +119 -28
- data/lib/new_relic/agent/logging.rb +1 -1
- data/lib/new_relic/agent/messaging.rb +16 -5
- data/lib/new_relic/agent/method_tracer.rb +3 -0
- data/lib/new_relic/agent/monitors/inbound_request_monitor.rb +1 -1
- data/lib/new_relic/agent/monitors/synthetics_monitor.rb +1 -1
- data/lib/new_relic/agent/new_relic_service/json_marshaller.rb +2 -2
- data/lib/new_relic/agent/new_relic_service.rb +8 -2
- data/lib/new_relic/agent/opentelemetry/context/propagation/trace_propagator.rb +66 -0
- data/lib/new_relic/agent/opentelemetry/context/propagation.rb +15 -0
- data/lib/{tasks/instrumentation_generator/templates/Envfile.tt → new_relic/agent/opentelemetry/context.rb} +9 -5
- data/lib/new_relic/agent/opentelemetry/trace/span.rb +31 -0
- data/lib/new_relic/agent/opentelemetry/trace/tracer.rb +129 -0
- data/lib/new_relic/agent/opentelemetry/trace/tracer_provider.rb +18 -0
- data/lib/new_relic/agent/opentelemetry/trace.rb +15 -0
- data/lib/new_relic/agent/opentelemetry/transaction_patch.rb +69 -0
- data/lib/new_relic/agent/opentelemetry_bridge.rb +32 -0
- data/lib/new_relic/agent/parameter_filtering.rb +1 -1
- data/lib/new_relic/agent/samplers/cpu_sampler.rb +1 -1
- data/lib/new_relic/agent/samplers/memory_sampler.rb +1 -1
- data/lib/new_relic/agent/serverless_handler.rb +247 -12
- data/lib/new_relic/agent/serverless_handler_event_sources.json +155 -0
- data/lib/new_relic/agent/serverless_handler_event_sources.rb +49 -0
- data/lib/new_relic/agent/span_event_primitive.rb +16 -11
- data/lib/new_relic/agent/system_info.rb +14 -0
- data/lib/new_relic/agent/threading/backtrace_node.rb +10 -1
- data/lib/new_relic/agent/tracer.rb +1 -1
- data/lib/new_relic/agent/transaction/abstract_segment.rb +2 -1
- data/lib/new_relic/agent/transaction/datastore_segment.rb +1 -1
- data/lib/new_relic/agent/transaction/distributed_tracer.rb +3 -3
- data/lib/new_relic/agent/transaction/external_request_segment.rb +0 -10
- data/lib/new_relic/agent/transaction/message_broker_segment.rb +4 -1
- data/lib/new_relic/agent/transaction/request_attributes.rb +14 -7
- data/lib/new_relic/agent/transaction/trace_context.rb +34 -5
- data/lib/new_relic/agent/transaction/tracing.rb +3 -3
- data/lib/new_relic/agent/transaction.rb +4 -7
- data/lib/new_relic/agent/transaction_time_aggregator.rb +1 -1
- data/lib/new_relic/agent/utilization/ecs.rb +22 -0
- data/lib/new_relic/agent/utilization/ecs_v4.rb +22 -0
- data/lib/new_relic/agent/utilization_data.rb +40 -5
- data/lib/new_relic/agent/vm/c_ruby_vm.rb +3 -3
- data/lib/new_relic/agent.rb +124 -2
- data/lib/new_relic/constants.rb +1 -0
- data/lib/new_relic/control/frameworks/grape.rb +14 -0
- data/lib/new_relic/control/frameworks/padrino.rb +14 -0
- data/lib/new_relic/control/frameworks/rails4.rb +1 -3
- data/lib/new_relic/control/instance_methods.rb +6 -0
- data/lib/new_relic/control/instrumentation.rb +1 -1
- data/lib/new_relic/control/private_instance_methods.rb +4 -0
- data/lib/new_relic/control/security_interface.rb +57 -0
- data/lib/new_relic/control.rb +1 -1
- data/lib/new_relic/dependency_detection.rb +11 -14
- data/lib/new_relic/environment_report.rb +2 -2
- data/lib/new_relic/helper.rb +22 -0
- data/lib/new_relic/language_support.rb +3 -1
- data/lib/new_relic/local_environment.rb +1 -4
- data/lib/new_relic/rack/browser_monitoring.rb +20 -8
- data/lib/new_relic/version.rb +1 -1
- data/lib/sequel/extensions/new_relic_instrumentation.rb +3 -2
- data/lib/tasks/config.rake +7 -3
- data/lib/tasks/gha.rake +31 -0
- data/lib/tasks/helpers/config.html.erb +3 -2
- data/lib/tasks/helpers/format.rb +1 -1
- data/lib/tasks/helpers/newrelicyml.rb +80 -13
- data/newrelic.yml +425 -162
- data/newrelic_rpm.gemspec +3 -1
- data/test/agent_helper.rb +24 -2
- metadata +91 -22
- data/lib/tasks/instrumentation_generator/README.md +0 -63
- data/lib/tasks/instrumentation_generator/TODO.md +0 -33
- data/lib/tasks/instrumentation_generator/instrumentation.thor +0 -121
- data/lib/tasks/instrumentation_generator/templates/chain.tt +0 -21
- data/lib/tasks/instrumentation_generator/templates/chain_method.tt +0 -7
- data/lib/tasks/instrumentation_generator/templates/dependency_detection.tt +0 -29
- data/lib/tasks/instrumentation_generator/templates/instrumentation_method.tt +0 -3
- data/lib/tasks/instrumentation_generator/templates/newrelic.yml.tt +0 -19
- data/lib/tasks/instrumentation_generator/templates/prepend.tt +0 -13
- data/lib/tasks/instrumentation_generator/templates/prepend_method.tt +0 -3
- data/lib/tasks/instrumentation_generator/templates/test.tt +0 -15
@@ -4,13 +4,13 @@
|
|
4
4
|
|
5
5
|
require 'json'
|
6
6
|
require 'new_relic/base64'
|
7
|
+
require 'uri'
|
8
|
+
|
9
|
+
require_relative 'serverless_handler_event_sources'
|
7
10
|
|
8
11
|
module NewRelic
|
9
12
|
module Agent
|
10
13
|
class ServerlessHandler
|
11
|
-
ATTRIBUTE_ARN = 'aws.lambda.arn'
|
12
|
-
ATTRIBUTE_COLD_START = 'aws.lambda.coldStart'
|
13
|
-
ATTRIBUTE_REQUEST_ID = 'aws.requestId'
|
14
14
|
AGENT_ATTRIBUTE_DESTINATIONS = NewRelic::Agent::AttributeFilter::DST_TRANSACTION_TRACER |
|
15
15
|
NewRelic::Agent::AttributeFilter::DST_TRANSACTION_EVENTS
|
16
16
|
EXECUTION_ENVIRONMENT = "AWS_Lambda_ruby#{RUBY_VERSION.rpartition('.').first}".freeze
|
@@ -22,12 +22,15 @@ module NewRelic
|
|
22
22
|
SUPPORTABILITY_METRIC = 'Supportability/AWSLambda/HandlerInvocation'
|
23
23
|
FUNCTION_NAME = 'lambda_function'
|
24
24
|
PAYLOAD_VERSION = ENV.fetch('NEW_RELIC_SERVERLESS_PAYLOAD_VERSION', 2)
|
25
|
+
DIGIT = /\d/
|
26
|
+
EVENT_SOURCES = NewRelic::Agent::ServerlessHandlerEventSources.to_hash
|
25
27
|
|
26
28
|
def self.env_var_set?
|
27
29
|
ENV.key?(LAMBDA_ENVIRONMENT_VARIABLE)
|
28
30
|
end
|
29
31
|
|
30
32
|
def initialize
|
33
|
+
@event = nil
|
31
34
|
@context = nil
|
32
35
|
@payloads = {}
|
33
36
|
end
|
@@ -35,12 +38,19 @@ module NewRelic
|
|
35
38
|
def invoke_lambda_function_with_new_relic(event:, context:, method_name:, namespace: nil)
|
36
39
|
NewRelic::Agent.increment_metric(SUPPORTABILITY_METRIC)
|
37
40
|
|
38
|
-
@context = context
|
41
|
+
@event, @context = event, context
|
42
|
+
|
43
|
+
txn_name = function_name
|
44
|
+
if ENV['NEW_RELIC_APM_LAMBDA_MODE'] == 'true'
|
45
|
+
source = event_source_event_info['name'] if event_source_event_info
|
46
|
+
txn_name = "#{source.upcase} #{txn_name}" if source
|
47
|
+
end
|
39
48
|
|
40
|
-
NewRelic::Agent::Tracer.in_transaction(category:
|
41
|
-
|
49
|
+
NewRelic::Agent::Tracer.in_transaction(category: category, name: txn_name) do
|
50
|
+
prep_transaction
|
42
51
|
|
43
|
-
NewRelic::LanguageSupport.constantize(namespace)
|
52
|
+
process_response(NewRelic::LanguageSupport.constantize(namespace)
|
53
|
+
.send(method_name, event: event, context: context))
|
44
54
|
end
|
45
55
|
ensure
|
46
56
|
harvest!
|
@@ -86,6 +96,12 @@ module NewRelic
|
|
86
96
|
|
87
97
|
private
|
88
98
|
|
99
|
+
def prep_transaction
|
100
|
+
process_api_gateway_info
|
101
|
+
process_headers
|
102
|
+
add_agent_attributes
|
103
|
+
end
|
104
|
+
|
89
105
|
def harvest!
|
90
106
|
NewRelic::Agent.instance.harvest_and_send_analytic_event_data
|
91
107
|
NewRelic::Agent.instance.harvest_and_send_custom_event_data
|
@@ -109,6 +125,11 @@ module NewRelic
|
|
109
125
|
ENV.fetch(LAMBDA_ENVIRONMENT_VARIABLE, FUNCTION_NAME)
|
110
126
|
end
|
111
127
|
|
128
|
+
def category
|
129
|
+
@category ||=
|
130
|
+
@event&.dig('requestContext', 'http', 'method') || @event&.fetch('httpMethod', nil) ? :web : :other
|
131
|
+
end
|
132
|
+
|
112
133
|
def write_output
|
113
134
|
string = PAYLOAD_VERSION == 1 ? payload_v1 : payload_v2
|
114
135
|
|
@@ -120,7 +141,7 @@ module NewRelic
|
|
120
141
|
"BEGIN PAYLOAD>>>\n#{string}\n<<<END PAYLOAD"
|
121
142
|
end
|
122
143
|
|
123
|
-
def payload_v1
|
144
|
+
def payload_v1 # New Relic serverless payload v1
|
124
145
|
payload_hash = {'metadata' => metadata, 'data' => @payloads}
|
125
146
|
json = NewRelic::Agent.agent.service.marshaller.dump(payload_hash)
|
126
147
|
gzipped = NewRelic::Agent::NewRelicService::Encoders::Compressed::Gzip.encode(json)
|
@@ -129,7 +150,7 @@ module NewRelic
|
|
129
150
|
::JSON.dump(array)
|
130
151
|
end
|
131
152
|
|
132
|
-
def payload_v2
|
153
|
+
def payload_v2 # New Relic serverless payload v2
|
133
154
|
json = NewRelic::Agent.agent.service.marshaller.dump(@payloads)
|
134
155
|
gzipped = NewRelic::Agent::NewRelicService::Encoders::Compressed::Gzip.encode(json)
|
135
156
|
base64_encoded = NewRelic::Base64.strict_encode64(gzipped)
|
@@ -137,6 +158,88 @@ module NewRelic
|
|
137
158
|
::JSON.dump(array)
|
138
159
|
end
|
139
160
|
|
161
|
+
def determine_api_gateway_version
|
162
|
+
return unless @event
|
163
|
+
|
164
|
+
version = @event.fetch('version', '')
|
165
|
+
if version.start_with?('2.')
|
166
|
+
return 2
|
167
|
+
elsif version.start_with?('1.')
|
168
|
+
return 1
|
169
|
+
end
|
170
|
+
|
171
|
+
headers = headers_from_event
|
172
|
+
return unless headers
|
173
|
+
|
174
|
+
if @event.dig('requestContext', 'http', 'path') && @event.dig('requestContext', 'http', 'method')
|
175
|
+
2
|
176
|
+
elsif @event.fetch('path', nil) && @event.fetch('httpMethod', nil)
|
177
|
+
1
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def process_api_gateway_info
|
182
|
+
api_v = determine_api_gateway_version
|
183
|
+
return unless api_v
|
184
|
+
|
185
|
+
info = api_v == 2 ? info_for_api_gateway_v2 : info_for_api_gateway_v1
|
186
|
+
info[:query_parameters] = @event.fetch('queryStringParameters', nil)
|
187
|
+
|
188
|
+
@http_method = info[:method]
|
189
|
+
@http_uri = http_uri(info)
|
190
|
+
end
|
191
|
+
|
192
|
+
def http_uri(info)
|
193
|
+
return unless info[:host] && info[:path]
|
194
|
+
|
195
|
+
url_str = "https://#{info[:host]}"
|
196
|
+
url_str += ":#{info[:port]}" unless info[:host].match?(':')
|
197
|
+
url_str += "#{info[:path]}"
|
198
|
+
|
199
|
+
if info[:query_parameters]
|
200
|
+
qp = info[:query_parameters].map { |k, v| "#{k}=#{v}" }.join('&')
|
201
|
+
url_str += "?#{qp}"
|
202
|
+
end
|
203
|
+
|
204
|
+
URI.parse(url_str)
|
205
|
+
rescue StandardError => e
|
206
|
+
NewRelic::Agent.logger.error "ServerlessHandler failed to parse the source HTTP URI: #{e}"
|
207
|
+
end
|
208
|
+
|
209
|
+
def info_for_api_gateway_v2
|
210
|
+
ctx = @event.fetch('requestContext', nil)
|
211
|
+
return {} unless ctx
|
212
|
+
|
213
|
+
{method: ctx.dig('http', 'method'),
|
214
|
+
path: ctx.dig('http', 'path'),
|
215
|
+
host: ctx.fetch('domainName', @event.dig('headers', 'Host')),
|
216
|
+
port: @event.dig('headers', 'X-Forwarded-Port') || 443}
|
217
|
+
end
|
218
|
+
|
219
|
+
def info_for_api_gateway_v1
|
220
|
+
headers = headers_from_event
|
221
|
+
{method: @event.fetch('httpMethod', nil),
|
222
|
+
path: @event.fetch('path', nil),
|
223
|
+
host: headers.fetch('Host', nil),
|
224
|
+
port: headers.fetch('X-Forwarded-Port', 443)}
|
225
|
+
end
|
226
|
+
|
227
|
+
def process_headers
|
228
|
+
return unless ::NewRelic::Agent.config[:'distributed_tracing.enabled']
|
229
|
+
|
230
|
+
headers = headers_from_event
|
231
|
+
return unless headers && !headers.empty?
|
232
|
+
|
233
|
+
dt_headers = headers.fetch(NewRelic::NEWRELIC_KEY, nil)
|
234
|
+
return unless dt_headers
|
235
|
+
|
236
|
+
::NewRelic::Agent::DistributedTracing::accept_distributed_trace_headers(dt_headers, 'Other')
|
237
|
+
end
|
238
|
+
|
239
|
+
def headers_from_event
|
240
|
+
@headers ||= @event&.dig('requestContext', 'http') || @event&.dig('headers')
|
241
|
+
end
|
242
|
+
|
140
243
|
def use_named_pipe?
|
141
244
|
return @use_named_pipe if defined?(@use_named_pipe)
|
142
245
|
|
@@ -146,15 +249,142 @@ module NewRelic
|
|
146
249
|
def add_agent_attributes
|
147
250
|
return unless NewRelic::Agent::Tracer.current_transaction
|
148
251
|
|
149
|
-
add_agent_attribute(
|
150
|
-
add_agent_attribute(
|
151
|
-
add_agent_attribute(
|
252
|
+
add_agent_attribute('aws.lambda.coldStart', true) if cold?
|
253
|
+
add_agent_attribute('aws.lambda.arn', @context.invoked_function_arn)
|
254
|
+
add_agent_attribute('aws.requestId', @context.aws_request_id)
|
255
|
+
|
256
|
+
add_event_source_attributes
|
257
|
+
add_http_attributes if api_gateway_event?
|
258
|
+
end
|
259
|
+
|
260
|
+
def add_http_attributes
|
261
|
+
return unless category == :web
|
262
|
+
|
263
|
+
if @http_uri
|
264
|
+
add_agent_attribute('uri.host', @http_uri.host)
|
265
|
+
add_agent_attribute('uri.port', @http_uri.port)
|
266
|
+
if NewRelic::Agent.instance.attribute_filter.allows_key?('http.url', AttributeFilter::DST_SPAN_EVENTS)
|
267
|
+
add_agent_attribute('http.url', @http_uri.to_s)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
if @http_method
|
272
|
+
add_agent_attribute('http.method', @http_method)
|
273
|
+
add_agent_attribute('http.request.method', @http_method)
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
def api_gateway_event?
|
278
|
+
return false unless @event
|
279
|
+
|
280
|
+
# '1.0' for API Gateway V1, '2.0' for API Gateway V2
|
281
|
+
return true if @event.fetch('version', '').start_with?(DIGIT)
|
282
|
+
|
283
|
+
return false unless headers_from_event
|
284
|
+
|
285
|
+
# API Gateway V1 - look for toplevel 'path' and 'httpMethod' keys if a version is unset
|
286
|
+
return true if @event.fetch('path', nil) && @event.fetch('httpMethod', nil)
|
287
|
+
|
288
|
+
# API Gateway V2 - look for 'requestContext/http' inner nested 'path' and 'method' keys if a version is unset
|
289
|
+
return true if @event.dig('requestContext', 'http', 'path') && @event.dig('requestContext', 'http', 'method')
|
290
|
+
|
291
|
+
false
|
292
|
+
end
|
293
|
+
|
294
|
+
def add_event_source_attributes
|
295
|
+
arn = event_source_arn
|
296
|
+
add_agent_attribute('aws.lambda.eventSource.arn', arn) if arn
|
297
|
+
|
298
|
+
info = event_source_event_info
|
299
|
+
return unless info
|
300
|
+
|
301
|
+
add_agent_attribute('aws.lambda.eventSource.eventType', info['name'])
|
302
|
+
|
303
|
+
info['attributes'].each do |name, elements|
|
304
|
+
next if elements.empty?
|
305
|
+
|
306
|
+
size = false
|
307
|
+
if elements.last.eql?('#size')
|
308
|
+
elements = elements.dup
|
309
|
+
elements.pop
|
310
|
+
size = true
|
311
|
+
end
|
312
|
+
value = @event.dig(*elements)
|
313
|
+
value = value.size if size
|
314
|
+
next unless value
|
315
|
+
|
316
|
+
add_agent_attribute(name, value)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
def event_source_arn
|
321
|
+
return unless @event
|
322
|
+
|
323
|
+
# SQS/Kinesis Stream/DynamoDB/CodeCommit/S3/SNS
|
324
|
+
return event_source_arn_for_records if @event.fetch('Records', nil)
|
325
|
+
|
326
|
+
# Kinesis Firehose
|
327
|
+
ds_arn = @event.fetch('deliveryStreamArn', nil) if @event.fetch('records', nil)
|
328
|
+
return ds_arn if ds_arn
|
329
|
+
|
330
|
+
# ELB
|
331
|
+
elb_arn = @event.dig('requestContext', 'elb', 'targetGroupArn')
|
332
|
+
return elb_arn if elb_arn
|
333
|
+
|
334
|
+
# (other)
|
335
|
+
es_arn = @event.dig('resources', 0)
|
336
|
+
return es_arn if es_arn
|
337
|
+
|
338
|
+
NewRelic::Agent.logger.debug 'Unable to determine an event source arn'
|
339
|
+
|
340
|
+
nil
|
341
|
+
end
|
342
|
+
|
343
|
+
def event_source_event_info
|
344
|
+
return unless @event
|
345
|
+
|
346
|
+
# if every required key for a source is found, consider that source
|
347
|
+
# to be a match
|
348
|
+
EVENT_SOURCES.each_value do |info|
|
349
|
+
return info unless info['required_keys'].detect { |r| @event.dig(*r).nil? }
|
350
|
+
end
|
351
|
+
|
352
|
+
nil
|
353
|
+
end
|
354
|
+
|
355
|
+
def event_source_arn_for_records
|
356
|
+
record = @event['Records'].first
|
357
|
+
unless record
|
358
|
+
NewRelic::Agent.logger.debug "Unable to find any records in the event's 'Records' array"
|
359
|
+
return
|
360
|
+
end
|
361
|
+
|
362
|
+
arn = record.fetch('eventSourceARN', nil) || # SQS/Kinesis Stream/DynamoDB/CodeCommit
|
363
|
+
record.dig('s3', 'bucket', 'arn') || # S3
|
364
|
+
record.fetch('EventSubscriptionArn', nil) # SNS
|
365
|
+
|
366
|
+
unless arn
|
367
|
+
NewRelic::Agent.logger.debug "Unable to determine an event source arn from the event's 'Records' array"
|
368
|
+
end
|
369
|
+
|
370
|
+
arn
|
152
371
|
end
|
153
372
|
|
154
373
|
def add_agent_attribute(attribute, value)
|
155
374
|
NewRelic::Agent::Tracer.current_transaction.add_agent_attribute(attribute, value, AGENT_ATTRIBUTE_DESTINATIONS)
|
156
375
|
end
|
157
376
|
|
377
|
+
def process_response(response)
|
378
|
+
return response unless category == :web && response.respond_to?(:fetch)
|
379
|
+
|
380
|
+
http_status = response.fetch(:statusCode, response.fetch('statusCode', nil))
|
381
|
+
return unless http_status
|
382
|
+
|
383
|
+
add_agent_attribute('http.statusCode', http_status)
|
384
|
+
|
385
|
+
response
|
386
|
+
end
|
387
|
+
|
158
388
|
def cold?
|
159
389
|
return @cold if defined?(@cold)
|
160
390
|
|
@@ -163,7 +393,12 @@ module NewRelic
|
|
163
393
|
end
|
164
394
|
|
165
395
|
def reset!
|
396
|
+
@event = nil
|
397
|
+
@category = nil
|
166
398
|
@context = nil
|
399
|
+
@headers = nil
|
400
|
+
@http_method = nil
|
401
|
+
@http_uri = nil
|
167
402
|
@payloads.replace({})
|
168
403
|
end
|
169
404
|
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
{
|
2
|
+
"alb": {
|
3
|
+
"attributes": {},
|
4
|
+
"name": "alb",
|
5
|
+
"required_keys": [
|
6
|
+
"httpMethod",
|
7
|
+
"requestContext.elb"
|
8
|
+
]
|
9
|
+
},
|
10
|
+
|
11
|
+
"apiGateway": {
|
12
|
+
"attributes": {
|
13
|
+
"aws.lambda.eventSource.accountId": "requestContext.accountId",
|
14
|
+
"aws.lambda.eventSource.apiId": "requestContext.apiId",
|
15
|
+
"aws.lambda.eventSource.resourceId": "requestContext.resourceId",
|
16
|
+
"aws.lambda.eventSource.resourcePath": "requestContext.resourcePath",
|
17
|
+
"aws.lambda.eventSource.stage": "requestContext.stage"
|
18
|
+
},
|
19
|
+
"name": "apiGateway",
|
20
|
+
"required_keys": [
|
21
|
+
"headers",
|
22
|
+
"httpMethod",
|
23
|
+
"path",
|
24
|
+
"requestContext",
|
25
|
+
"requestContext.stage"
|
26
|
+
]
|
27
|
+
},
|
28
|
+
|
29
|
+
"apiGatewayV2": {
|
30
|
+
"attributes": {
|
31
|
+
"aws.lambda.eventSource.accountId": "requestContext.accountId",
|
32
|
+
"aws.lambda.eventSource.apiId": "requestContext.apiId",
|
33
|
+
"aws.lambda.eventSource.stage": "requestContext.stage"
|
34
|
+
},
|
35
|
+
"name": "apiGatewayV2",
|
36
|
+
"required_keys": [
|
37
|
+
"version",
|
38
|
+
"headers",
|
39
|
+
"requestContext.http",
|
40
|
+
"requestContext.http.path",
|
41
|
+
"requestContext.http.method",
|
42
|
+
"requestContext.stage"
|
43
|
+
]
|
44
|
+
},
|
45
|
+
|
46
|
+
"cloudFront": {
|
47
|
+
"attributes": {},
|
48
|
+
"name": "cloudFront",
|
49
|
+
"required_keys": [
|
50
|
+
"Records[0].cf"
|
51
|
+
]
|
52
|
+
},
|
53
|
+
|
54
|
+
"cloudWatchScheduled": {
|
55
|
+
"attributes": {
|
56
|
+
"aws.lambda.eventSource.account": "account",
|
57
|
+
"aws.lambda.eventSource.id": "id",
|
58
|
+
"aws.lambda.eventSource.region": "region",
|
59
|
+
"aws.lambda.eventSource.resource": "resources[0]",
|
60
|
+
"aws.lambda.eventSource.time": "time"
|
61
|
+
},
|
62
|
+
"name": "cloudWatch_scheduled",
|
63
|
+
"required_keys": [
|
64
|
+
"detail-type",
|
65
|
+
"source"
|
66
|
+
]
|
67
|
+
},
|
68
|
+
|
69
|
+
"dynamoStreams": {
|
70
|
+
"attributes": {
|
71
|
+
"aws.lambda.eventSource.length": "Records.length"
|
72
|
+
},
|
73
|
+
"name": "dynamo_streams",
|
74
|
+
"required_keys": [
|
75
|
+
"Records[0].dynamodb"
|
76
|
+
]
|
77
|
+
},
|
78
|
+
|
79
|
+
"firehose": {
|
80
|
+
"attributes": {
|
81
|
+
"aws.lambda.eventSource.length": "records.length",
|
82
|
+
"aws.lambda.eventSource.region": "region"
|
83
|
+
},
|
84
|
+
"name": "firehose",
|
85
|
+
"required_keys": [
|
86
|
+
"deliveryStreamArn",
|
87
|
+
"records[0].kinesisRecordMetadata"
|
88
|
+
]
|
89
|
+
},
|
90
|
+
|
91
|
+
"kinesis": {
|
92
|
+
"attributes": {
|
93
|
+
"aws.lambda.eventSource.length": "Records.length",
|
94
|
+
"aws.lambda.eventSource.region": "Records[0].awsRegion"
|
95
|
+
},
|
96
|
+
"name": "kinesis",
|
97
|
+
"required_keys": [
|
98
|
+
"Records[0].kinesis"
|
99
|
+
]
|
100
|
+
},
|
101
|
+
|
102
|
+
"s3": {
|
103
|
+
"attributes": {
|
104
|
+
"aws.lambda.eventSource.bucketName": "Records[0].s3.bucket.name",
|
105
|
+
"aws.lambda.eventSource.eventName": "Records[0].eventName",
|
106
|
+
"aws.lambda.eventSource.eventTime": "Records[0].eventTime",
|
107
|
+
"aws.lambda.eventSource.length": "Records.length",
|
108
|
+
"aws.lambda.eventSource.objectKey": "Records[0].s3.object.key",
|
109
|
+
"aws.lambda.eventSource.objectSequencer": "Records[0].s3.object.sequencer",
|
110
|
+
"aws.lambda.eventSource.objectSize": "Records[0].s3.object.size",
|
111
|
+
"aws.lambda.eventSource.region": "Records[0].awsRegion"
|
112
|
+
},
|
113
|
+
"name": "s3",
|
114
|
+
"required_keys": [
|
115
|
+
"Records[0].s3"
|
116
|
+
]
|
117
|
+
},
|
118
|
+
|
119
|
+
"ses": {
|
120
|
+
"attributes": {
|
121
|
+
"aws.lambda.eventSource.date": "Records[0].ses.mail.commonHeaders.date",
|
122
|
+
"aws.lambda.eventSource.length": "Records.length",
|
123
|
+
"aws.lambda.eventSource.messageId": "Records[0].ses.mail.commonHeaders.messageId",
|
124
|
+
"aws.lambda.eventSource.returnPath": "Records[0].ses.mail.commonHeaders.returnPath"
|
125
|
+
},
|
126
|
+
"name": "ses",
|
127
|
+
"required_keys": [
|
128
|
+
"Records[0].ses"
|
129
|
+
]
|
130
|
+
},
|
131
|
+
|
132
|
+
"sns": {
|
133
|
+
"attributes": {
|
134
|
+
"aws.lambda.eventSource.length": "Records.length",
|
135
|
+
"aws.lambda.eventSource.messageId": "Records[0].Sns.MessageId",
|
136
|
+
"aws.lambda.eventSource.timestamp": "Records[0].Sns.Timestamp",
|
137
|
+
"aws.lambda.eventSource.topicArn": "Records[0].Sns.TopicArn",
|
138
|
+
"aws.lambda.eventSource.type": "Records[0].Sns.Type"
|
139
|
+
},
|
140
|
+
"name": "sns",
|
141
|
+
"required_keys": [
|
142
|
+
"Records[0].Sns"
|
143
|
+
]
|
144
|
+
},
|
145
|
+
|
146
|
+
"sqs": {
|
147
|
+
"attributes": {
|
148
|
+
"aws.lambda.eventSource.length": "Records.length"
|
149
|
+
},
|
150
|
+
"name": "sqs",
|
151
|
+
"required_keys": [
|
152
|
+
"Records[0].receiptHandle"
|
153
|
+
]
|
154
|
+
}
|
155
|
+
}
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# This file is distributed under New Relic's license terms.
|
2
|
+
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
module NewRelic
|
8
|
+
module Agent
|
9
|
+
# ServerlessHandlerEventSources - New Relic's language agent devs maintain
|
10
|
+
# a cross-agent JSON map of all AWS resources with the potential to invoke
|
11
|
+
# an AWS Lambda function by issuing it an event. This map is used to glean
|
12
|
+
# source specific attributes while instrumenting the function's invocation.
|
13
|
+
#
|
14
|
+
# Given that the event arrives as a Ruby hash argument to the AWS Lambda
|
15
|
+
# function, the JSON map's values need to be converted into arrays that can
|
16
|
+
# be passed to `Hash#dig`. So a value such as `'records[0].name'` needs to
|
17
|
+
# be converted to `['records', 0, 'name']`. This class's `.to_hash` method
|
18
|
+
# yields the converted data.
|
19
|
+
#
|
20
|
+
# Furthermore, `.length` calls are converted to Ruby `#size` notation to
|
21
|
+
# denote that a method call must be performed on the dug value.
|
22
|
+
class ServerlessHandlerEventSources
|
23
|
+
JSON_SOURCE = File.join(File.dirname(__FILE__), 'serverless_handler_event_sources.json').freeze
|
24
|
+
JSON_RAW = JSON.parse(File.read(JSON_SOURCE)).freeze
|
25
|
+
|
26
|
+
def self.to_hash
|
27
|
+
JSON_RAW.each_with_object({}) do |(type, info), hash|
|
28
|
+
hash[type] = {'attributes' => {},
|
29
|
+
'name' => info['name'],
|
30
|
+
'required_keys' => []}
|
31
|
+
info['attributes'].each { |attr, value| hash[type]['attributes'][attr] = transform(value) }
|
32
|
+
info['required_keys'].each { |key| hash[type]['required_keys'].push(transform(key)) }
|
33
|
+
end.freeze
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.transform(value)
|
37
|
+
value.gsub(/\[(\d+)\]/, '.\1').split('.').map do |e|
|
38
|
+
if e.match?(/^\d+$/)
|
39
|
+
e.to_i
|
40
|
+
elsif e == 'length'
|
41
|
+
'#size'
|
42
|
+
else
|
43
|
+
e
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -40,10 +40,12 @@ module NewRelic
|
|
40
40
|
SERVER_ADDRESS_KEY = 'server.address'
|
41
41
|
SERVER_PORT_KEY = 'server.port'
|
42
42
|
SPAN_KIND_KEY = 'span.kind'
|
43
|
+
STACKTRACE_KEY = 'code.stacktrace'
|
43
44
|
ENTRY_POINT_KEY = 'nr.entryPoint'
|
44
45
|
TRUSTED_PARENT_KEY = 'trustedParentId'
|
45
46
|
TRACING_VENDORS_KEY = 'tracingVendors'
|
46
47
|
TRANSACTION_NAME_KEY = 'transaction.name'
|
48
|
+
THREAD_ID_KEY = 'thread.id'
|
47
49
|
|
48
50
|
# Strings for static values of the event structure
|
49
51
|
EVENT_TYPE = 'Span'
|
@@ -52,6 +54,8 @@ module NewRelic
|
|
52
54
|
DATASTORE_CATEGORY = 'datastore'
|
53
55
|
CLIENT = 'client'
|
54
56
|
|
57
|
+
DB_STATEMENT_MAX_BYTES = 4096
|
58
|
+
|
55
59
|
# Builds a Hash of error attributes as well as the Span ID when
|
56
60
|
# an error is present. Otherwise, returns nil when no error present.
|
57
61
|
def error_attributes(segment)
|
@@ -79,17 +83,13 @@ module NewRelic
|
|
79
83
|
intrinsics[SPAN_KIND_KEY] = CLIENT
|
80
84
|
intrinsics[SERVER_ADDRESS_KEY] = segment.uri.host
|
81
85
|
intrinsics[SERVER_PORT_KEY] = segment.uri.port
|
82
|
-
agent_attributes =
|
86
|
+
agent_attributes = {}
|
83
87
|
|
84
88
|
if allowed?(HTTP_URL_KEY)
|
85
89
|
agent_attributes[HTTP_URL_KEY] = truncate(segment.uri)
|
86
90
|
end
|
87
91
|
|
88
|
-
|
89
|
-
agent_attributes.merge!(agent_attributes(segment))
|
90
|
-
end
|
91
|
-
|
92
|
-
[intrinsics, custom_attributes(segment), agent_attributes]
|
92
|
+
[intrinsics, custom_attributes(segment), agent_attributes.merge(agent_attributes(segment))]
|
93
93
|
end
|
94
94
|
|
95
95
|
def for_datastore_segment(segment) # rubocop:disable Metrics/AbcSize
|
@@ -99,7 +99,7 @@ module NewRelic
|
|
99
99
|
intrinsics[SPAN_KIND_KEY] = CLIENT
|
100
100
|
intrinsics[CATEGORY_KEY] = DATASTORE_CATEGORY
|
101
101
|
|
102
|
-
agent_attributes =
|
102
|
+
agent_attributes = {}
|
103
103
|
|
104
104
|
if segment.database_name && allowed?(DB_INSTANCE_KEY)
|
105
105
|
agent_attributes[DB_INSTANCE_KEY] = truncate(segment.database_name)
|
@@ -118,12 +118,16 @@ module NewRelic
|
|
118
118
|
agent_attributes[DB_SYSTEM_KEY] = segment.product if allowed?(DB_SYSTEM_KEY)
|
119
119
|
|
120
120
|
if segment.sql_statement && allowed?(DB_STATEMENT_KEY)
|
121
|
-
agent_attributes[DB_STATEMENT_KEY] = truncate(segment.sql_statement.safe_sql,
|
121
|
+
agent_attributes[DB_STATEMENT_KEY] = truncate(segment.sql_statement.safe_sql, DB_STATEMENT_MAX_BYTES)
|
122
122
|
elsif segment.nosql_statement && allowed?(DB_STATEMENT_KEY)
|
123
|
-
agent_attributes[DB_STATEMENT_KEY] = truncate(segment.nosql_statement,
|
123
|
+
agent_attributes[DB_STATEMENT_KEY] = truncate(segment.nosql_statement, DB_STATEMENT_MAX_BYTES)
|
124
|
+
end
|
125
|
+
|
126
|
+
if segment.params[:backtrace]
|
127
|
+
agent_attributes[STACKTRACE_KEY] = segment.params[:backtrace]
|
124
128
|
end
|
125
129
|
|
126
|
-
[intrinsics, custom_attributes(segment), agent_attributes]
|
130
|
+
[intrinsics, custom_attributes(segment), agent_attributes.merge(agent_attributes(segment))]
|
127
131
|
end
|
128
132
|
|
129
133
|
private
|
@@ -137,7 +141,8 @@ module NewRelic
|
|
137
141
|
PRIORITY_KEY => segment.transaction.priority,
|
138
142
|
TIMESTAMP_KEY => milliseconds_since_epoch(segment),
|
139
143
|
DURATION_KEY => segment.duration,
|
140
|
-
NAME_KEY => segment.name
|
144
|
+
NAME_KEY => segment.name,
|
145
|
+
THREAD_ID_KEY => segment.thread_id
|
141
146
|
}
|
142
147
|
|
143
148
|
# with infinite-tracing, transactions may or may not be sampled!
|
@@ -19,6 +19,20 @@ module NewRelic
|
|
19
19
|
RbConfig::CONFIG['target_os']
|
20
20
|
end
|
21
21
|
|
22
|
+
def self.os_distribution
|
23
|
+
case
|
24
|
+
when darwin? then :darwin
|
25
|
+
when linux? then :linux
|
26
|
+
when bsd? then :bsd
|
27
|
+
when windows? then :windows
|
28
|
+
else ruby_os_identifier
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.windows?
|
33
|
+
!!(ruby_os_identifier[/mingw|mswin/i])
|
34
|
+
end
|
35
|
+
|
22
36
|
def self.darwin?
|
23
37
|
!!(ruby_os_identifier =~ /darwin/i)
|
24
38
|
end
|
@@ -125,7 +125,16 @@ module NewRelic
|
|
125
125
|
|
126
126
|
# Returns [filename, method, line number]
|
127
127
|
def parse_backtrace_frame(frame)
|
128
|
-
|
128
|
+
# TODO: OLD RUBIES - Ruby 3.3
|
129
|
+
# The (?:`|') non-capturing group can be removed when the agent
|
130
|
+
# drops support for Ruby 3.3
|
131
|
+
# This group is used to capture the pre-Ruby 3.4.0 backtrace syntax.
|
132
|
+
# Example frame:
|
133
|
+
# Ruby 3.3.0 and below
|
134
|
+
# "irb.rb:69:in `catch'"
|
135
|
+
# Ruby 3.4.0+
|
136
|
+
# "irb.rb:69:in 'Kernel#catch'"
|
137
|
+
frame =~ /([^:]*)(\:(\d+))?\:in (?:`|')(.*)'/
|
129
138
|
[$1, $4, $3] # sic
|
130
139
|
end
|
131
140
|
end
|