newrelic_rpm 9.1.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 +27 -0
- data/CHANGELOG.md +841 -7
- data/CONTRIBUTING.md +2 -9
- data/README.md +25 -22
- data/Rakefile +2 -2
- data/bin/newrelic +3 -9
- data/bin/newrelic_rpm +15 -0
- data/init.rb +2 -2
- data/lib/boot/strap.rb +102 -0
- data/lib/new_relic/agent/agent.rb +11 -2
- data/lib/new_relic/agent/agent_helpers/connect.rb +13 -8
- data/lib/new_relic/agent/agent_helpers/harvest.rb +3 -0
- data/lib/new_relic/agent/agent_helpers/shutdown.rb +4 -1
- data/lib/new_relic/agent/agent_helpers/special_startup.rb +1 -1
- data/lib/new_relic/agent/agent_helpers/start_worker_thread.rb +4 -3
- data/lib/new_relic/agent/agent_helpers/startup.rb +11 -3
- data/lib/new_relic/agent/agent_logger.rb +3 -1
- data/lib/new_relic/agent/attribute_filter.rb +3 -3
- data/lib/new_relic/agent/attribute_pre_filtering.rb +109 -0
- data/lib/new_relic/agent/aws.rb +68 -0
- data/lib/new_relic/agent/configuration/default_source.rb +918 -166
- data/lib/new_relic/agent/configuration/environment_source.rb +15 -3
- data/lib/new_relic/agent/configuration/high_security_source.rb +1 -0
- data/lib/new_relic/agent/configuration/manager.rb +72 -11
- data/lib/new_relic/agent/configuration/security_policy_source.rb +11 -0
- data/lib/new_relic/agent/configuration/yaml_source.rb +22 -2
- data/lib/new_relic/agent/connect/request_builder.rb +1 -1
- data/lib/new_relic/agent/custom_event_aggregator.rb +27 -1
- 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/mongo/metric_translator.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/distributed_trace_payload.rb +4 -8
- data/lib/new_relic/agent/distributed_tracing.rb +5 -3
- data/lib/new_relic/agent/error_collector.rb +40 -11
- data/lib/new_relic/agent/event_loop.rb +1 -1
- data/lib/new_relic/agent/external.rb +2 -0
- data/lib/new_relic/agent/harvester.rb +1 -1
- data/lib/new_relic/agent/health_check.rb +136 -0
- data/lib/new_relic/agent/http_clients/abstract.rb +4 -0
- data/lib/new_relic/agent/http_clients/async_http_wrappers.rb +80 -0
- data/lib/new_relic/agent/http_clients/curb_wrappers.rb +1 -3
- data/lib/new_relic/agent/http_clients/ethon_wrappers.rb +109 -0
- data/lib/new_relic/agent/http_clients/excon_wrappers.rb +0 -3
- data/lib/new_relic/agent/http_clients/http_rb_wrappers.rb +1 -3
- data/lib/new_relic/agent/http_clients/httpclient_wrappers.rb +0 -3
- data/lib/new_relic/agent/http_clients/httpx_wrappers.rb +91 -0
- data/lib/new_relic/agent/http_clients/net_http_wrappers.rb +1 -4
- data/lib/new_relic/agent/http_clients/typhoeus_wrappers.rb +0 -3
- data/lib/new_relic/agent/http_clients/uri_util.rb +1 -1
- data/lib/new_relic/agent/instrumentation/action_controller_other_subscriber.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 +3 -16
- data/lib/new_relic/agent/instrumentation/active_record.rb +8 -13
- data/lib/new_relic/agent/instrumentation/active_record_helper.rb +8 -5
- data/lib/new_relic/agent/instrumentation/active_record_notifications.rb +13 -10
- 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/chain.rb +69 -0
- data/lib/new_relic/agent/instrumentation/active_support_broadcast_logger/instrumentation.rb +17 -0
- data/lib/new_relic/agent/instrumentation/active_support_broadcast_logger/prepend.rb +37 -0
- data/lib/new_relic/agent/instrumentation/active_support_broadcast_logger.rb +21 -0
- data/lib/new_relic/agent/instrumentation/active_support_logger/instrumentation.rb +4 -0
- data/lib/new_relic/agent/instrumentation/active_support_logger.rb +3 -3
- data/lib/new_relic/agent/instrumentation/async_http/chain.rb +23 -0
- data/lib/new_relic/agent/instrumentation/async_http/instrumentation.rb +37 -0
- data/lib/new_relic/agent/instrumentation/async_http/prepend.rb +15 -0
- data/lib/new_relic/agent/instrumentation/async_http.rb +27 -0
- 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/chain.rb +1 -1
- data/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb +23 -0
- data/lib/new_relic/agent/instrumentation/bunny.rb +4 -5
- data/lib/new_relic/agent/instrumentation/concurrent_ruby/chain.rb +1 -1
- data/lib/new_relic/agent/instrumentation/concurrent_ruby/instrumentation.rb +3 -4
- data/lib/new_relic/agent/instrumentation/concurrent_ruby/prepend.rb +1 -1
- data/lib/new_relic/agent/instrumentation/concurrent_ruby.rb +2 -3
- data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +5 -2
- data/lib/new_relic/agent/instrumentation/curb/instrumentation.rb +4 -0
- data/lib/new_relic/agent/instrumentation/curb.rb +4 -5
- data/lib/new_relic/agent/instrumentation/delayed_job/chain.rb +1 -0
- data/lib/new_relic/agent/instrumentation/delayed_job/instrumentation.rb +3 -0
- 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 +2 -3
- data/lib/new_relic/agent/instrumentation/elasticsearch/instrumentation.rb +65 -10
- data/lib/new_relic/agent/instrumentation/elasticsearch.rb +2 -4
- data/lib/new_relic/agent/instrumentation/ethon/chain.rb +39 -0
- data/lib/new_relic/agent/instrumentation/ethon/instrumentation.rb +105 -0
- data/lib/new_relic/agent/instrumentation/ethon/prepend.rb +35 -0
- data/lib/new_relic/agent/instrumentation/ethon.rb +35 -0
- data/lib/new_relic/agent/instrumentation/excon/middleware.rb +3 -0
- data/lib/new_relic/agent/instrumentation/excon.rb +1 -17
- data/lib/new_relic/agent/instrumentation/fiber/chain.rb +11 -4
- data/lib/new_relic/agent/instrumentation/fiber/instrumentation.rb +2 -6
- data/lib/new_relic/agent/instrumentation/fiber/prepend.rb +10 -3
- data/lib/new_relic/agent/instrumentation/fiber.rb +1 -3
- data/lib/new_relic/agent/instrumentation/grape/instrumentation.rb +4 -3
- data/lib/new_relic/agent/instrumentation/grape.rb +1 -1
- data/lib/new_relic/agent/instrumentation/grpc/client/chain.rb +1 -1
- data/lib/new_relic/agent/instrumentation/grpc/client/instrumentation.rb +5 -2
- data/lib/new_relic/agent/instrumentation/grpc/client/prepend.rb +1 -1
- data/lib/new_relic/agent/instrumentation/grpc/client/request_wrapper.rb +1 -1
- data/lib/new_relic/agent/instrumentation/grpc/server/instrumentation.rb +5 -1
- data/lib/new_relic/agent/instrumentation/grpc_client.rb +2 -2
- data/lib/new_relic/agent/instrumentation/grpc_server.rb +2 -2
- data/lib/new_relic/agent/instrumentation/httpclient/instrumentation.rb +4 -0
- data/lib/new_relic/agent/instrumentation/httpclient.rb +1 -5
- data/lib/new_relic/agent/instrumentation/httprb/instrumentation.rb +4 -0
- data/lib/new_relic/agent/instrumentation/httprb.rb +0 -1
- data/lib/new_relic/agent/instrumentation/httpx/chain.rb +20 -0
- data/lib/new_relic/agent/instrumentation/httpx/instrumentation.rb +51 -0
- data/lib/new_relic/agent/instrumentation/httpx/prepend.rb +15 -0
- data/lib/new_relic/agent/instrumentation/httpx.rb +23 -0
- data/lib/new_relic/agent/instrumentation/logger/instrumentation.rb +3 -0
- 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 +4 -2
- data/lib/new_relic/agent/instrumentation/memcache/helper.rb +2 -2
- data/lib/new_relic/agent/instrumentation/memcache/instrumentation.rb +13 -4
- data/lib/new_relic/agent/instrumentation/memcache/prepend.rb +4 -2
- data/lib/new_relic/agent/instrumentation/memcache.rb +4 -5
- data/lib/new_relic/agent/instrumentation/mongodb_command_subscriber.rb +3 -5
- data/lib/new_relic/agent/instrumentation/net_http/instrumentation.rb +13 -3
- data/lib/new_relic/agent/instrumentation/net_http.rb +2 -1
- data/lib/new_relic/agent/instrumentation/notifications_subscriber.rb +4 -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/new_relic/agent/instrumentation/opensearch/prepend.rb +13 -0
- data/lib/new_relic/agent/instrumentation/opensearch.rb +23 -0
- data/lib/new_relic/agent/instrumentation/padrino/instrumentation.rb +4 -0
- data/lib/new_relic/agent/instrumentation/padrino.rb +3 -3
- data/lib/new_relic/agent/instrumentation/queue_time.rb +1 -1
- data/lib/new_relic/agent/instrumentation/rack/instrumentation.rb +9 -0
- data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +4 -0
- data/lib/new_relic/agent/instrumentation/rails_notifications/action_cable.rb +1 -1
- data/lib/new_relic/agent/instrumentation/rails_notifications/action_controller.rb +10 -5
- data/lib/new_relic/agent/instrumentation/rake/instrumentation.rb +4 -0
- 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 +18 -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/instrumentation.rb +4 -0
- data/lib/new_relic/agent/instrumentation/resque.rb +8 -6
- data/lib/new_relic/agent/instrumentation/roda/chain.rb +43 -0
- data/lib/new_relic/agent/instrumentation/roda/ignorer.rb +45 -0
- data/lib/new_relic/agent/instrumentation/roda/instrumentation.rb +68 -0
- data/lib/new_relic/agent/instrumentation/roda/prepend.rb +24 -0
- data/lib/new_relic/agent/instrumentation/roda/roda_transaction_namer.rb +29 -0
- data/lib/new_relic/agent/instrumentation/roda.rb +36 -0
- 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/chain.rb +36 -0
- data/lib/new_relic/agent/instrumentation/ruby_openai/instrumentation.rb +196 -0
- data/lib/new_relic/agent/instrumentation/ruby_openai/prepend.rb +20 -0
- data/lib/new_relic/agent/instrumentation/ruby_openai.rb +35 -0
- data/lib/new_relic/agent/instrumentation/sequel.rb +1 -1
- data/lib/new_relic/agent/instrumentation/sidekiq/client.rb +4 -0
- 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/server.rb +26 -3
- data/lib/new_relic/agent/instrumentation/sidekiq.rb +13 -16
- data/lib/new_relic/agent/instrumentation/sinatra/ignorer.rb +1 -1
- data/lib/new_relic/agent/instrumentation/sinatra/instrumentation.rb +4 -0
- data/lib/new_relic/agent/instrumentation/sinatra/transaction_namer.rb +1 -3
- data/lib/new_relic/agent/instrumentation/sinatra.rb +3 -19
- data/lib/new_relic/agent/instrumentation/stripe.rb +28 -0
- data/lib/new_relic/agent/instrumentation/stripe_subscriber.rb +98 -0
- data/lib/new_relic/agent/instrumentation/thread/chain.rb +1 -1
- data/lib/new_relic/agent/instrumentation/thread/instrumentation.rb +1 -5
- data/lib/new_relic/agent/instrumentation/thread/prepend.rb +1 -1
- data/lib/new_relic/agent/instrumentation/thread.rb +0 -2
- data/lib/new_relic/agent/instrumentation/tilt/instrumentation.rb +4 -0
- data/lib/new_relic/agent/instrumentation/tilt.rb +0 -4
- data/lib/new_relic/agent/instrumentation/typhoeus/instrumentation.rb +7 -3
- data/lib/new_relic/agent/instrumentation/typhoeus.rb +0 -1
- data/lib/new_relic/agent/instrumentation/view_component/chain.rb +21 -0
- data/lib/new_relic/agent/instrumentation/view_component/instrumentation.rb +45 -0
- data/lib/{tasks/instrumentation_generator/templates/instrumentation.tt → new_relic/agent/instrumentation/view_component/prepend.rb} +4 -4
- data/lib/new_relic/agent/instrumentation/view_component.rb +24 -0
- data/lib/new_relic/agent/javascript_instrumentor.rb +2 -4
- data/lib/new_relic/agent/llm/chat_completion_message.rb +25 -0
- data/lib/new_relic/agent/llm/chat_completion_summary.rb +66 -0
- data/lib/new_relic/agent/llm/embedding.rb +60 -0
- data/lib/new_relic/agent/llm/llm_event.rb +95 -0
- data/lib/new_relic/agent/llm/response_headers.rb +80 -0
- data/lib/new_relic/agent/llm.rb +49 -0
- data/lib/new_relic/agent/local_log_decorator.rb +20 -3
- data/lib/new_relic/agent/log_event_aggregator.rb +149 -26
- data/lib/new_relic/agent/log_event_attributes.rb +115 -0
- data/lib/new_relic/agent/logging.rb +5 -5
- data/lib/new_relic/agent/messaging.rb +18 -7
- data/lib/new_relic/agent/method_tracer.rb +4 -1
- data/lib/new_relic/agent/method_tracer_helpers.rb +26 -5
- data/lib/new_relic/agent/monitors/inbound_request_monitor.rb +1 -1
- data/lib/new_relic/agent/monitors/synthetics_monitor.rb +12 -1
- data/lib/new_relic/agent/new_relic_service/encoders.rb +2 -2
- data/lib/new_relic/agent/new_relic_service/json_marshaller.rb +2 -2
- data/lib/new_relic/agent/new_relic_service.rb +61 -28
- data/lib/new_relic/agent/obfuscator.rb +0 -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/pipe_channel_manager.rb +2 -2
- data/lib/new_relic/agent/pipe_service.rb +1 -1
- data/lib/new_relic/agent/rules_engine/segment_terms_rule.rb +1 -2
- data/lib/new_relic/agent/rules_engine.rb +1 -1
- data/lib/new_relic/agent/sampler.rb +1 -0
- 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 +406 -0
- 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 +32 -15
- data/lib/new_relic/agent/sql_sampler.rb +0 -1
- data/lib/new_relic/agent/system_info.rb +40 -0
- data/lib/new_relic/agent/threading/agent_thread.rb +1 -2
- data/lib/new_relic/agent/threading/backtrace_node.rb +10 -1
- data/lib/new_relic/agent/tracer.rb +16 -16
- data/lib/new_relic/agent/transaction/abstract_segment.rb +103 -41
- 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/distributed_tracing.rb +7 -8
- data/lib/new_relic/agent/transaction/external_request_segment.rb +5 -12
- data/lib/new_relic/agent/transaction/message_broker_segment.rb +5 -3
- data/lib/new_relic/agent/transaction/request_attributes.rb +54 -11
- data/lib/new_relic/agent/transaction/trace_context.rb +34 -5
- data/lib/new_relic/agent/transaction/tracing.rb +20 -4
- data/lib/new_relic/agent/transaction.rb +38 -13
- data/lib/new_relic/agent/transaction_error_primitive.rb +39 -19
- data/lib/new_relic/agent/transaction_event_primitive.rb +19 -0
- 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/gcp.rb +1 -3
- data/lib/new_relic/agent/utilization/vendor.rb +5 -7
- data/lib/new_relic/agent/utilization_data.rb +40 -5
- data/lib/new_relic/agent/vm/{mri_vm.rb → c_ruby_vm.rb} +10 -18
- data/lib/new_relic/agent/vm.rb +2 -2
- data/lib/new_relic/agent/worker_loop.rb +1 -1
- data/lib/new_relic/agent.rb +286 -17
- data/lib/new_relic/base64.rb +25 -0
- data/lib/new_relic/cli/command.rb +6 -3
- data/lib/new_relic/constants.rb +8 -0
- data/lib/new_relic/control/class_methods.rb +1 -7
- 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/rails.rb +17 -5
- data/lib/new_relic/control/frameworks/rails4.rb +1 -3
- data/lib/new_relic/control/frameworks/roda.rb +20 -0
- data/lib/new_relic/control/instance_methods.rb +13 -0
- data/lib/new_relic/control/instrumentation.rb +2 -16
- 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 +25 -13
- data/lib/new_relic/environment_report.rb +2 -2
- data/lib/new_relic/helper.rb +22 -0
- data/lib/new_relic/language_support.rb +12 -1
- data/lib/new_relic/latest_changes.rb +1 -1
- data/lib/new_relic/local_environment.rb +31 -18
- data/lib/new_relic/noticed_error.rb +5 -2
- data/lib/new_relic/rack/agent_hooks.rb +1 -1
- data/lib/new_relic/rack/agent_middleware.rb +0 -16
- data/lib/new_relic/rack/browser_monitoring.rb +29 -13
- data/lib/new_relic/supportability_helper.rb +5 -1
- data/lib/new_relic/thread_local_storage.rb +31 -0
- data/lib/new_relic/traced_thread.rb +2 -3
- data/lib/new_relic/version.rb +1 -1
- data/lib/sequel/extensions/new_relic_instrumentation.rb +4 -3
- data/lib/tasks/bump_version.rake +21 -0
- data/lib/tasks/config.rake +11 -5
- data/lib/tasks/coverage_report.rake +1 -1
- data/lib/tasks/gha.rake +31 -0
- data/lib/tasks/helpers/config.html.erb +94 -0
- data/lib/tasks/helpers/format.rb +11 -7
- data/lib/tasks/helpers/newrelicyml.rb +211 -0
- data/lib/tasks/helpers/version_bump.rb +62 -0
- data/lib/tasks/newrelic.rb +1 -0
- data/lib/tasks/newrelicyml.rake +13 -0
- data/lib/tasks/tests.rake +71 -0
- data/newrelic.yml +657 -251
- data/newrelic_rpm.gemspec +17 -10
- data/test/agent_helper.rb +38 -4
- metadata +230 -44
- data/.gitignore +0 -43
- data/.project +0 -23
- data/.rubocop.yml +0 -1909
- data/.rubocop_todo.yml +0 -61
- data/.simplecov +0 -15
- data/.snyk +0 -11
- data/.yardopts +0 -27
- data/Brewfile +0 -12
- data/DOCKER.md +0 -167
- data/Dockerfile +0 -10
- data/Guardfile +0 -26
- data/bin/newrelic_cmd +0 -6
- data/config/database.yml +0 -5
- data/config.dot +0 -278
- data/docker-compose.yml +0 -107
- data/lefthook.yml +0 -9
- data/lib/new_relic/agent/range_extensions.rb +0 -27
- data/lib/tasks/helpers/removers.rb +0 -33
- 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 -22
- data/lib/tasks/instrumentation_generator/templates/chain_method.tt +0 -8
- 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
- data/lib/tasks/multiverse.rake +0 -6
- data/lib/tasks/multiverse.rb +0 -83
|
@@ -0,0 +1,36 @@
|
|
|
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
|
+
module NewRelic::Agent::Instrumentation
|
|
6
|
+
module OpenAI::Chain
|
|
7
|
+
def self.instrument!
|
|
8
|
+
::OpenAI::Client.class_eval do
|
|
9
|
+
include NewRelic::Agent::Instrumentation::OpenAI
|
|
10
|
+
|
|
11
|
+
alias_method(:json_post_without_new_relic, :json_post)
|
|
12
|
+
|
|
13
|
+
# In versions 4.0.0+ json_post is an instance method
|
|
14
|
+
# defined in the OpenAI::HTTP module, included by the
|
|
15
|
+
# OpenAI::Client class
|
|
16
|
+
def json_post(**kwargs)
|
|
17
|
+
json_post_with_new_relic(**kwargs) do
|
|
18
|
+
json_post_without_new_relic(**kwargs)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# In versions below 4.0.0 json_post is a class method
|
|
23
|
+
# on OpenAI::Client
|
|
24
|
+
class << self
|
|
25
|
+
alias_method(:json_post_without_new_relic, :json_post)
|
|
26
|
+
|
|
27
|
+
def json_post(**kwargs)
|
|
28
|
+
json_post_with_new_relic(**kwargs) do
|
|
29
|
+
json_post_without_new_relic(**kwargs)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,196 @@
|
|
|
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
|
+
module NewRelic::Agent::Instrumentation
|
|
6
|
+
module OpenAI
|
|
7
|
+
VENDOR = 'openAI' # AIM expects this capitalization style for the UI
|
|
8
|
+
INSTRUMENTATION_NAME = NewRelic::Agent.base_name(name)
|
|
9
|
+
EMBEDDINGS_PATH = '/embeddings'
|
|
10
|
+
CHAT_COMPLETIONS_PATH = '/chat/completions'
|
|
11
|
+
EMBEDDINGS_SEGMENT_NAME = 'Llm/embedding/OpenAI/embeddings'
|
|
12
|
+
CHAT_COMPLETIONS_SEGMENT_NAME = 'Llm/completion/OpenAI/chat'
|
|
13
|
+
|
|
14
|
+
def json_post_with_new_relic(path:, parameters:)
|
|
15
|
+
return yield unless path == EMBEDDINGS_PATH || path == CHAT_COMPLETIONS_PATH
|
|
16
|
+
|
|
17
|
+
NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
|
|
18
|
+
NewRelic::Agent::Llm::LlmEvent.set_llm_agent_attribute_on_transaction
|
|
19
|
+
record_openai_metric
|
|
20
|
+
|
|
21
|
+
if path == EMBEDDINGS_PATH
|
|
22
|
+
embeddings_instrumentation(parameters) { yield }
|
|
23
|
+
elsif path == CHAT_COMPLETIONS_PATH
|
|
24
|
+
chat_completions_instrumentation(parameters) { yield }
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def embeddings_instrumentation(parameters)
|
|
31
|
+
segment = NewRelic::Agent::Tracer.start_segment(name: EMBEDDINGS_SEGMENT_NAME)
|
|
32
|
+
event = create_embeddings_event(parameters)
|
|
33
|
+
segment.llm_event = event
|
|
34
|
+
begin
|
|
35
|
+
response = NewRelic::Agent::Tracer.capture_segment_error(segment) { yield }
|
|
36
|
+
# TODO: Remove !response.include?('error') when we drop support for versions below 4.0.0
|
|
37
|
+
add_embeddings_response_params(response, event) if response && !response.include?('error')
|
|
38
|
+
|
|
39
|
+
response
|
|
40
|
+
ensure
|
|
41
|
+
finish(segment, event)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def chat_completions_instrumentation(parameters)
|
|
46
|
+
segment = NewRelic::Agent::Tracer.start_segment(name: CHAT_COMPLETIONS_SEGMENT_NAME)
|
|
47
|
+
event = create_chat_completion_summary(parameters)
|
|
48
|
+
segment.llm_event = event
|
|
49
|
+
messages = create_chat_completion_messages(parameters, event.id)
|
|
50
|
+
|
|
51
|
+
begin
|
|
52
|
+
response = NewRelic::Agent::Tracer.capture_segment_error(segment) { yield }
|
|
53
|
+
# TODO: Remove !response.include?('error') when we drop support for versions below 4.0.0
|
|
54
|
+
if response && !response.include?('error')
|
|
55
|
+
add_chat_completion_response_params(parameters, response, event)
|
|
56
|
+
messages = update_chat_completion_messages(messages, response, event)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
response
|
|
60
|
+
ensure
|
|
61
|
+
finish(segment, event)
|
|
62
|
+
messages&.each { |m| m.record }
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def create_chat_completion_summary(parameters)
|
|
67
|
+
NewRelic::Agent::Llm::ChatCompletionSummary.new(
|
|
68
|
+
vendor: VENDOR,
|
|
69
|
+
request_max_tokens: (parameters[:max_tokens] || parameters['max_tokens'])&.to_i,
|
|
70
|
+
request_model: parameters[:model] || parameters['model'],
|
|
71
|
+
request_temperature: (parameters[:temperature] || parameters['temperature'])&.to_f,
|
|
72
|
+
metadata: llm_custom_attributes
|
|
73
|
+
)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def create_embeddings_event(parameters)
|
|
77
|
+
event = NewRelic::Agent::Llm::Embedding.new(
|
|
78
|
+
vendor: VENDOR,
|
|
79
|
+
request_model: parameters[:model] || parameters['model'],
|
|
80
|
+
metadata: llm_custom_attributes
|
|
81
|
+
)
|
|
82
|
+
add_input(event, (parameters[:input] || parameters['input']))
|
|
83
|
+
|
|
84
|
+
event
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def add_chat_completion_response_params(parameters, response, event)
|
|
88
|
+
event.response_number_of_messages = (parameters[:messages] || parameters['messages']).size + response['choices'].size
|
|
89
|
+
# The response hash always returns keys as strings, so we don't need to run an || check here
|
|
90
|
+
event.response_model = response['model']
|
|
91
|
+
event.response_choices_finish_reason = response['choices'][0]['finish_reason']
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def add_embeddings_response_params(response, event)
|
|
95
|
+
event.response_model = response['model']
|
|
96
|
+
event.token_count = calculate_token_count(event.request_model, event.input)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def create_chat_completion_messages(parameters, summary_id)
|
|
100
|
+
(parameters[:messages] || parameters['messages']).map.with_index do |message, index|
|
|
101
|
+
msg = NewRelic::Agent::Llm::ChatCompletionMessage.new(
|
|
102
|
+
role: message[:role] || message['role'],
|
|
103
|
+
sequence: index,
|
|
104
|
+
completion_id: summary_id,
|
|
105
|
+
vendor: VENDOR
|
|
106
|
+
)
|
|
107
|
+
add_content(msg, (message[:content] || message['content']))
|
|
108
|
+
|
|
109
|
+
msg
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def create_chat_completion_response_messages(response, sequence_origin, summary_id)
|
|
114
|
+
response['choices'].map.with_index(sequence_origin) do |choice, index|
|
|
115
|
+
msg = NewRelic::Agent::Llm::ChatCompletionMessage.new(
|
|
116
|
+
role: choice['message']['role'],
|
|
117
|
+
sequence: index,
|
|
118
|
+
completion_id: summary_id,
|
|
119
|
+
vendor: VENDOR,
|
|
120
|
+
is_response: true
|
|
121
|
+
)
|
|
122
|
+
add_content(msg, choice['message']['content'])
|
|
123
|
+
|
|
124
|
+
msg
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def update_chat_completion_messages(messages, response, summary)
|
|
129
|
+
messages += create_chat_completion_response_messages(response, messages.size, summary.id)
|
|
130
|
+
response_id = response['id'] || NewRelic::Agent::GuidGenerator.generate_guid
|
|
131
|
+
messages.each do |message|
|
|
132
|
+
message.id = "#{response_id}-#{message.sequence}"
|
|
133
|
+
message.request_id = summary.request_id
|
|
134
|
+
message.response_model = response['model']
|
|
135
|
+
message.metadata = llm_custom_attributes
|
|
136
|
+
|
|
137
|
+
model = message.is_response ? message.response_model : summary.request_model
|
|
138
|
+
|
|
139
|
+
message.token_count = calculate_token_count(model, message.content)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def calculate_token_count(model, content)
|
|
144
|
+
return unless NewRelic::Agent.llm_token_count_callback
|
|
145
|
+
|
|
146
|
+
begin
|
|
147
|
+
count = NewRelic::Agent.llm_token_count_callback.call({model: model, content: content})
|
|
148
|
+
rescue => e
|
|
149
|
+
NewRelic::Agent.logger.warn("Error calculating token count using the provided proc. Error: #{e}'")
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
count if count.is_a?(Integer) && count > 0
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def record_content_enabled?
|
|
156
|
+
NewRelic::Agent.config[:'ai_monitoring.record_content.enabled']
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def add_content(message, content)
|
|
160
|
+
message.content = content if record_content_enabled?
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def add_input(event, input)
|
|
164
|
+
event.input = input if record_content_enabled?
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def llm_custom_attributes
|
|
168
|
+
NewRelic::Agent::Tracer.current_transaction&.attributes&.custom_attributes&.select { |k| k.to_s.match(/llm.*/) }
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def record_openai_metric
|
|
172
|
+
NewRelic::Agent.record_metric(nr_supportability_metric, 0.0)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def segment_noticed_error?(segment)
|
|
176
|
+
segment&.noticed_error
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def nr_supportability_metric
|
|
180
|
+
@nr_supportability_metric ||= "Supportability/Ruby/ML/OpenAI/#{::OpenAI::VERSION}"
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def finish(segment, event)
|
|
184
|
+
segment&.finish
|
|
185
|
+
|
|
186
|
+
return unless event
|
|
187
|
+
|
|
188
|
+
if segment
|
|
189
|
+
event.error = true if segment_noticed_error?(segment)
|
|
190
|
+
event.duration = segment.duration
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
event.record
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
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
|
+
module NewRelic::Agent::Instrumentation
|
|
6
|
+
module OpenAI::Prepend
|
|
7
|
+
include NewRelic::Agent::Instrumentation::OpenAI
|
|
8
|
+
|
|
9
|
+
# In versions 4.0.0+ json_post is an instance method defined in the
|
|
10
|
+
# OpenAI::HTTP module, included by the OpenAI::Client class.
|
|
11
|
+
#
|
|
12
|
+
# In versions below 4.0.0 json_post is a class method on OpenAI::Client.
|
|
13
|
+
#
|
|
14
|
+
# Dependency detection will apply the instrumentation to the correct scope,
|
|
15
|
+
# so we don't need to change the code here.
|
|
16
|
+
def json_post(**kwargs)
|
|
17
|
+
json_post_with_new_relic(**kwargs) { super }
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
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_relative 'ruby_openai/instrumentation'
|
|
6
|
+
require_relative 'ruby_openai/chain'
|
|
7
|
+
require_relative 'ruby_openai/prepend'
|
|
8
|
+
|
|
9
|
+
DependencyDetection.defer do
|
|
10
|
+
named :'ruby_openai'
|
|
11
|
+
|
|
12
|
+
depends_on do
|
|
13
|
+
NewRelic::Agent.config[:'ai_monitoring.enabled'] &&
|
|
14
|
+
defined?(OpenAI) && defined?(OpenAI::Client) &&
|
|
15
|
+
NewRelic::Helper.version_satisfied?(OpenAI::VERSION, '>=', '3.4.0')
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
executes do
|
|
19
|
+
if use_prepend?
|
|
20
|
+
# TODO: Remove condition when we drop support for versions below 5.0.0
|
|
21
|
+
if NewRelic::Helper.version_satisfied?(OpenAI::VERSION, '>=', '5.0.0')
|
|
22
|
+
prepend_instrument OpenAI::Client,
|
|
23
|
+
NewRelic::Agent::Instrumentation::OpenAI::Prepend,
|
|
24
|
+
NewRelic::Agent::Instrumentation::OpenAI::VENDOR
|
|
25
|
+
else
|
|
26
|
+
prepend_instrument OpenAI::Client.singleton_class,
|
|
27
|
+
NewRelic::Agent::Instrumentation::OpenAI::Prepend,
|
|
28
|
+
NewRelic::Agent::Instrumentation::OpenAI::VENDOR
|
|
29
|
+
end
|
|
30
|
+
else
|
|
31
|
+
chain_instrument NewRelic::Agent::Instrumentation::OpenAI::Chain,
|
|
32
|
+
NewRelic::Agent::Instrumentation::OpenAI::VENDOR
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -30,7 +30,7 @@ DependencyDetection.defer do
|
|
|
30
30
|
else
|
|
31
31
|
NewRelic::Agent.logger.info('Detected Sequel version %s.' % [Sequel::VERSION])
|
|
32
32
|
NewRelic::Agent.logger.info('Please see additional documentation: ' +
|
|
33
|
-
'https://newrelic.com/docs/ruby/sequel-instrumentation')
|
|
33
|
+
'https://docs.newrelic.com/docs/apm/agents/ruby-agent/frameworks/sequel-instrumentation/')
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
Sequel.synchronize { Sequel::DATABASES.dup }.each do |db|
|
|
@@ -6,7 +6,11 @@ module NewRelic::Agent::Instrumentation::Sidekiq
|
|
|
6
6
|
class Client
|
|
7
7
|
include Sidekiq::ClientMiddleware if defined?(Sidekiq::ClientMiddleware)
|
|
8
8
|
|
|
9
|
+
INSTRUMENTATION_NAME = 'SidekiqClient'
|
|
10
|
+
|
|
9
11
|
def call(_worker_class, job, *_)
|
|
12
|
+
NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
|
|
13
|
+
|
|
10
14
|
job[NewRelic::NEWRELIC_KEY] ||= distributed_tracing_headers if ::NewRelic::Agent.config[:'distributed_tracing.enabled']
|
|
11
15
|
yield
|
|
12
16
|
end
|
|
@@ -0,0 +1,24 @@
|
|
|
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
|
+
if defined?(Sidekiq::DelayExtensions)
|
|
6
|
+
class Sidekiq::DelayExtensions::GenericJob
|
|
7
|
+
def newrelic_trace_args(msg, queue)
|
|
8
|
+
(target, method_name, *) = ::Sidekiq::DelayExtensions::YAML.unsafe_load(msg['args'][0])
|
|
9
|
+
|
|
10
|
+
if target.is_a?(String)
|
|
11
|
+
target = target.constantize
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
{
|
|
15
|
+
:name => method_name,
|
|
16
|
+
:class_name => target.class.name,
|
|
17
|
+
:category => 'OtherTransaction/SidekiqJob'
|
|
18
|
+
}
|
|
19
|
+
rescue => e
|
|
20
|
+
NewRelic::Agent.logger.error('Failure during deserializing YAML for Sidekiq::DelayExtensions::GenericJob', e)
|
|
21
|
+
NewRelic::Agent::Instrumentation::Sidekiq::Server.default_trace_args(msg)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
# Delayed extensions are disabled by default in Sidekiq 5 and 6 and
|
|
7
7
|
# were removed entirely in Sidekiq 7.
|
|
8
8
|
#
|
|
9
|
-
# see https://github.com/
|
|
9
|
+
# see https://github.com/sidekiq/sidekiq/issues/5076 for the discussion
|
|
10
10
|
# of the removal, which includes mentions of alternatives
|
|
11
|
-
if defined?(Sidekiq::VERSION) && Sidekiq::VERSION < '7.0.0'
|
|
11
|
+
if defined?(Sidekiq::VERSION) && NewRelic::Helper.version_satisfied?(Sidekiq::VERSION, '<', '7.0.0')
|
|
12
12
|
class Sidekiq::Extensions::DelayedClass
|
|
13
13
|
def newrelic_trace_args(msg, queue)
|
|
14
14
|
(target, method_name, _args) = if YAML.respond_to?(:unsafe_load)
|
|
@@ -7,9 +7,16 @@ module NewRelic::Agent::Instrumentation::Sidekiq
|
|
|
7
7
|
include NewRelic::Agent::Instrumentation::ControllerInstrumentation
|
|
8
8
|
include Sidekiq::ServerMiddleware if defined?(Sidekiq::ServerMiddleware)
|
|
9
9
|
|
|
10
|
+
ATTRIBUTE_BASE_NAMESPACE = 'sidekiq.args'
|
|
11
|
+
ATTRIBUTE_FILTER_TYPES = %i[include exclude].freeze
|
|
12
|
+
ATTRIBUTE_JOB_NAMESPACE = :"job.#{ATTRIBUTE_BASE_NAMESPACE}"
|
|
13
|
+
INSTRUMENTATION_NAME = 'SidekiqServer'
|
|
14
|
+
|
|
10
15
|
# Client middleware has additional parameters, and our tests use the
|
|
11
16
|
# middleware client-side to work inline.
|
|
12
17
|
def call(worker, msg, queue, *_)
|
|
18
|
+
NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
|
|
19
|
+
|
|
13
20
|
trace_args = if worker.respond_to?(:newrelic_trace_args)
|
|
14
21
|
worker.newrelic_trace_args(msg, queue)
|
|
15
22
|
else
|
|
@@ -18,10 +25,16 @@ module NewRelic::Agent::Instrumentation::Sidekiq
|
|
|
18
25
|
trace_headers = msg.delete(NewRelic::NEWRELIC_KEY)
|
|
19
26
|
|
|
20
27
|
perform_action_with_newrelic_trace(trace_args) do
|
|
21
|
-
NewRelic::Agent::Transaction.merge_untrusted_agent_attributes(
|
|
22
|
-
NewRelic::Agent::
|
|
28
|
+
NewRelic::Agent::Transaction.merge_untrusted_agent_attributes(
|
|
29
|
+
NewRelic::Agent::AttributePreFiltering.pre_filter(msg['args'], self.class.nr_attribute_options),
|
|
30
|
+
ATTRIBUTE_JOB_NAMESPACE,
|
|
31
|
+
NewRelic::Agent::AttributeFilter::DST_NONE
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
if ::NewRelic::Agent.config[:'distributed_tracing.enabled'] && trace_headers&.any?
|
|
35
|
+
::NewRelic::Agent::DistributedTracing::accept_distributed_trace_headers(trace_headers, 'Other')
|
|
36
|
+
end
|
|
23
37
|
|
|
24
|
-
::NewRelic::Agent::DistributedTracing::accept_distributed_trace_headers(trace_headers, 'Other') if ::NewRelic::Agent.config[:'distributed_tracing.enabled'] && trace_headers&.any?
|
|
25
38
|
yield
|
|
26
39
|
end
|
|
27
40
|
end
|
|
@@ -33,5 +46,15 @@ module NewRelic::Agent::Instrumentation::Sidekiq
|
|
|
33
46
|
:category => 'OtherTransaction/SidekiqJob'
|
|
34
47
|
}
|
|
35
48
|
end
|
|
49
|
+
|
|
50
|
+
def self.nr_attribute_options
|
|
51
|
+
@nr_attribute_options ||= begin
|
|
52
|
+
ATTRIBUTE_FILTER_TYPES.each_with_object({}) do |type, opts|
|
|
53
|
+
pattern =
|
|
54
|
+
NewRelic::Agent::AttributePreFiltering.formulate_regexp_union(:"#{ATTRIBUTE_BASE_NAMESPACE}.#{type}")
|
|
55
|
+
opts[type] = pattern if pattern
|
|
56
|
+
end.merge(attribute_namespace: ATTRIBUTE_JOB_NAMESPACE)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
36
59
|
end
|
|
37
60
|
end
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# This file is distributed under New Relic's license terms.
|
|
2
2
|
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
|
3
3
|
# frozen_string_literal: true
|
|
4
|
+
|
|
4
5
|
require_relative 'sidekiq/client'
|
|
5
6
|
require_relative 'sidekiq/server'
|
|
6
7
|
require_relative 'sidekiq/extensions/delayed_class'
|
|
8
|
+
require_relative 'sidekiq/extensions/delay_extensions'
|
|
7
9
|
|
|
8
10
|
DependencyDetection.defer do
|
|
9
11
|
@name = :sidekiq
|
|
@@ -28,28 +30,23 @@ DependencyDetection.defer do
|
|
|
28
30
|
chain.add(NewRelic::Agent::Instrumentation::Sidekiq::Client)
|
|
29
31
|
end
|
|
30
32
|
config.server_middleware do |chain|
|
|
31
|
-
|
|
33
|
+
# We started prepending v chaining NR middleware in 9.18.0 in response to:
|
|
34
|
+
# https://github.com/newrelic/newrelic-ruby-agent/issues/3037
|
|
35
|
+
# This way, exceptions resolved by Sidekiq's own middleware are not reported in the agent
|
|
36
|
+
if chain.respond_to?(:prepend)
|
|
37
|
+
chain.prepend(NewRelic::Agent::Instrumentation::Sidekiq::Server)
|
|
38
|
+
else
|
|
39
|
+
chain.add(NewRelic::Agent::Instrumentation::Sidekiq::Server)
|
|
40
|
+
end
|
|
32
41
|
end
|
|
33
42
|
|
|
34
43
|
if config.respond_to?(:error_handlers)
|
|
35
|
-
|
|
44
|
+
# Sidekiq 3.0.0 - 7.1.4 expect error_handlers to have 2 arguments
|
|
45
|
+
# Sidekiq 7.1.5+ expect error_handlers to have 3 arguments
|
|
46
|
+
config.error_handlers << proc do |error, _ctx, *_|
|
|
36
47
|
NewRelic::Agent.notice_error(error)
|
|
37
48
|
end
|
|
38
49
|
end
|
|
39
50
|
end
|
|
40
51
|
end
|
|
41
|
-
|
|
42
|
-
executes do
|
|
43
|
-
next unless Gem::Version.new(Sidekiq::VERSION) < Gem::Version.new('5.0.0')
|
|
44
|
-
|
|
45
|
-
deprecation_msg = 'Instrumentation for Sidekiq versions below 5.0.0 is deprecated.' \
|
|
46
|
-
'They will stop being monitored in version 9.0.0. ' \
|
|
47
|
-
'Please upgrade your Sidekiq version to continue receiving full support. '
|
|
48
|
-
|
|
49
|
-
NewRelic::Agent.logger.log_once(
|
|
50
|
-
:warn,
|
|
51
|
-
:deprecated_sidekiq_version,
|
|
52
|
-
deprecation_msg
|
|
53
|
-
)
|
|
54
|
-
end
|
|
55
52
|
end
|
|
@@ -33,7 +33,7 @@ module NewRelic::Agent::Instrumentation
|
|
|
33
33
|
set(:newrelic_ignores, Hash.new([])) if !respond_to?(:newrelic_ignores)
|
|
34
34
|
|
|
35
35
|
# If we call an ignore without a route, it applies to the whole app
|
|
36
|
-
routes = [
|
|
36
|
+
routes = [::NewRelic::ASTERISK] if routes.empty?
|
|
37
37
|
|
|
38
38
|
settings.newrelic_ignores[type] += routes.map do |r|
|
|
39
39
|
# Ugly sending to private Base#compile, but we want to mimic
|
|
@@ -13,6 +13,8 @@ module NewRelic::Agent::Instrumentation
|
|
|
13
13
|
module Tracer
|
|
14
14
|
include ::NewRelic::Agent::Instrumentation::ControllerInstrumentation
|
|
15
15
|
|
|
16
|
+
INSTRUMENTATION_NAME = 'Sinatra'
|
|
17
|
+
|
|
16
18
|
def self.included(clazz)
|
|
17
19
|
clazz.extend(self)
|
|
18
20
|
end
|
|
@@ -90,6 +92,8 @@ module NewRelic::Agent::Instrumentation
|
|
|
90
92
|
end
|
|
91
93
|
|
|
92
94
|
def dispatch_with_tracing
|
|
95
|
+
NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
|
|
96
|
+
|
|
93
97
|
request_params = get_request_params
|
|
94
98
|
filtered_params = ::NewRelic::Agent::ParameterFiltering::apply_filters(request.env, request_params || {})
|
|
95
99
|
|
|
@@ -25,14 +25,12 @@ module NewRelic
|
|
|
25
25
|
transaction_name(::NewRelic::Agent::UNKNOWN_METRIC, request)
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
ROOT = '/'.freeze
|
|
29
|
-
|
|
30
28
|
def transaction_name(route_text, request)
|
|
31
29
|
verb = http_verb(request)
|
|
32
30
|
|
|
33
31
|
route_text = route_text.source if route_text.is_a?(Regexp)
|
|
34
32
|
name = route_text.gsub(%r{^[/^\\A]*(.*?)[/\$\?\\z]*$}, '\1')
|
|
35
|
-
name = ROOT if name.empty?
|
|
33
|
+
name = NewRelic::ROOT if name.empty?
|
|
36
34
|
name = "#{verb} #{name}" unless verb.nil?
|
|
37
35
|
name
|
|
38
36
|
rescue => e
|
|
@@ -16,10 +16,6 @@ DependencyDetection.defer do
|
|
|
16
16
|
depends_on { Sinatra::Base.private_method_defined?(:process_route) }
|
|
17
17
|
depends_on { Sinatra::Base.private_method_defined?(:route_eval) }
|
|
18
18
|
|
|
19
|
-
executes do
|
|
20
|
-
NewRelic::Agent.logger.info('Installing Sinatra instrumentation')
|
|
21
|
-
end
|
|
22
|
-
|
|
23
19
|
executes do
|
|
24
20
|
if use_prepend?
|
|
25
21
|
prepend_instrument Sinatra::Base, NewRelic::Agent::Instrumentation::Sinatra::Prepend
|
|
@@ -32,27 +28,15 @@ DependencyDetection.defer do
|
|
|
32
28
|
end
|
|
33
29
|
|
|
34
30
|
executes do
|
|
31
|
+
supportability_name = NewRelic::Agent::Instrumentation::Sinatra::Tracer::INSTRUMENTATION_NAME
|
|
35
32
|
# These requires are inside an executes block because they require rack, and
|
|
36
33
|
# we can't be sure that rack is available when this file is first required.
|
|
37
34
|
require 'new_relic/rack/agent_hooks'
|
|
38
35
|
require 'new_relic/rack/browser_monitoring'
|
|
39
36
|
if use_prepend?
|
|
40
|
-
prepend_instrument Sinatra::Base.singleton_class, NewRelic::Agent::Instrumentation::Sinatra::Build::Prepend
|
|
37
|
+
prepend_instrument Sinatra::Base.singleton_class, NewRelic::Agent::Instrumentation::Sinatra::Build::Prepend, supportability_name
|
|
41
38
|
else
|
|
42
|
-
chain_instrument NewRelic::Agent::Instrumentation::Sinatra::Build::Chain
|
|
39
|
+
chain_instrument NewRelic::Agent::Instrumentation::Sinatra::Build::Chain, supportability_name
|
|
43
40
|
end
|
|
44
41
|
end
|
|
45
|
-
|
|
46
|
-
executes do
|
|
47
|
-
next unless Gem::Version.new(Sinatra::VERSION) < Gem::Version.new('2.0.0')
|
|
48
|
-
|
|
49
|
-
deprecation_msg = 'The Ruby Agent is dropping support for Sinatra versions below 2.0.0 ' \
|
|
50
|
-
'in version 9.0.0. Please upgrade your Sinatra version to continue receiving full compatibility. ' \
|
|
51
|
-
|
|
52
|
-
NewRelic::Agent.logger.log_once(
|
|
53
|
-
:warn,
|
|
54
|
-
:deprecated_sinatra_version,
|
|
55
|
-
deprecation_msg
|
|
56
|
-
)
|
|
57
|
-
end
|
|
58
42
|
end
|
|
@@ -0,0 +1,28 @@
|
|
|
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 'new_relic/agent/instrumentation/stripe_subscriber'
|
|
6
|
+
|
|
7
|
+
DependencyDetection.defer do
|
|
8
|
+
named :stripe
|
|
9
|
+
|
|
10
|
+
depends_on do
|
|
11
|
+
NewRelic::Agent.config[:'instrumentation.stripe'] == 'enabled'
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
depends_on do
|
|
15
|
+
defined?(Stripe) &&
|
|
16
|
+
NewRelic::Helper.version_satisfied?(Stripe::VERSION, '>=', '5.38.0')
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
executes do
|
|
20
|
+
NewRelic::Agent.logger.info('Installing Stripe instrumentation')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
executes do
|
|
24
|
+
newrelic_subscriber = NewRelic::Agent::Instrumentation::StripeSubscriber.new
|
|
25
|
+
Stripe::Instrumentation.subscribe(:request_begin) { |event| newrelic_subscriber.start_segment(event) }
|
|
26
|
+
Stripe::Instrumentation.subscribe(:request_end) { |event| newrelic_subscriber.finish_segment(event) }
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
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
|
+
module NewRelic
|
|
6
|
+
module Agent
|
|
7
|
+
module Instrumentation
|
|
8
|
+
class StripeSubscriber
|
|
9
|
+
DEFAULT_DESTINATIONS = AttributeFilter::DST_SPAN_EVENTS
|
|
10
|
+
EVENT_ATTRIBUTES = %i[http_status method num_retries path request_id].freeze
|
|
11
|
+
ATTRIBUTE_NAMESPACE = 'stripe.user_data'
|
|
12
|
+
ATTRIBUTE_FILTER_TYPES = %i[include exclude].freeze
|
|
13
|
+
PATH_PORTION_PATTERN = %r{^/([^/]+/[^/]+)(?:/|\z)}.freeze
|
|
14
|
+
|
|
15
|
+
def start_segment(event)
|
|
16
|
+
return unless is_execution_traced?
|
|
17
|
+
|
|
18
|
+
segment = NewRelic::Agent::Tracer.start_segment(name: metric_name(event))
|
|
19
|
+
event.user_data[:newrelic_segment] = segment
|
|
20
|
+
rescue => e
|
|
21
|
+
NewRelic::Agent.logger.error("Error starting New Relic Stripe segment: #{e}")
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def finish_segment(event)
|
|
25
|
+
return unless is_execution_traced?
|
|
26
|
+
|
|
27
|
+
segment = remove_and_return_nr_segment(event)
|
|
28
|
+
add_stripe_attributes(segment, event)
|
|
29
|
+
add_custom_attributes(segment, event)
|
|
30
|
+
rescue => e
|
|
31
|
+
NewRelic::Agent.logger.error("Error finishing New Relic Stripe segment: #{e}")
|
|
32
|
+
ensure
|
|
33
|
+
segment&.finish
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def is_execution_traced?
|
|
39
|
+
NewRelic::Agent::Tracer.state.is_execution_traced?
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def metric_name(event)
|
|
43
|
+
# Grab only the first 2 items from the slash (/) delimited event path.
|
|
44
|
+
# These items are the API version string and the category. Grabbing
|
|
45
|
+
# any more of the path will result in unique method names that will
|
|
46
|
+
# easily grow to be too numerous to sort through in the UI and
|
|
47
|
+
# possibly even violate default New Relic metric count thresholds.
|
|
48
|
+
# See newrelic/newrelic-ruby-agent#2654 and
|
|
49
|
+
# newrelic/newrelic-ruby-agent#2709 for more details.
|
|
50
|
+
#
|
|
51
|
+
# In Ruby v3.4 benchmarks, using regex to get at the first two path
|
|
52
|
+
# elements was seen as more performant than using String#split.
|
|
53
|
+
#
|
|
54
|
+
# Regex legend:
|
|
55
|
+
#
|
|
56
|
+
# ^ = starts with
|
|
57
|
+
# / = a literal '/'
|
|
58
|
+
# () = capture
|
|
59
|
+
# (?:) = don't capture
|
|
60
|
+
# [^/]+ = 1 or more characters that are not '/'
|
|
61
|
+
# /|\z = a literal '/' OR the end of the string
|
|
62
|
+
path_portion = event.path =~ PATH_PORTION_PATTERN ? Regexp.last_match(1) : NewRelic::UNKNOWN
|
|
63
|
+
"Stripe/#{path_portion}/#{event.method}"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def add_stripe_attributes(segment, event)
|
|
67
|
+
EVENT_ATTRIBUTES.each do |attribute|
|
|
68
|
+
segment.add_agent_attribute("stripe_#{attribute}", event.send(attribute), DEFAULT_DESTINATIONS)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def add_custom_attributes(segment, event)
|
|
73
|
+
return if NewRelic::Agent.config[:'stripe.user_data.include'].empty?
|
|
74
|
+
|
|
75
|
+
filtered_attributes = NewRelic::Agent::AttributePreFiltering.pre_filter_hash(event.user_data, nr_attribute_options)
|
|
76
|
+
filtered_attributes.each do |key, value|
|
|
77
|
+
segment.add_agent_attribute("stripe_user_data_#{key}", value, DEFAULT_DESTINATIONS)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def nr_attribute_options
|
|
82
|
+
ATTRIBUTE_FILTER_TYPES.each_with_object({}) do |type, opts|
|
|
83
|
+
pattern =
|
|
84
|
+
NewRelic::Agent::AttributePreFiltering.formulate_regexp_union(:"#{ATTRIBUTE_NAMESPACE}.#{type}")
|
|
85
|
+
opts[type] = pattern if pattern
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def remove_and_return_nr_segment(event)
|
|
90
|
+
segment = event.user_data[:newrelic_segment]
|
|
91
|
+
event.user_data.delete(:newrelic_segment)
|
|
92
|
+
|
|
93
|
+
segment
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|