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
|
@@ -14,7 +14,7 @@ module NewRelic::Agent::Instrumentation
|
|
|
14
14
|
alias_method(:initialize_without_new_relic, :initialize)
|
|
15
15
|
|
|
16
16
|
def initialize(*args, &block)
|
|
17
|
-
traced_block = add_thread_tracing(
|
|
17
|
+
traced_block = add_thread_tracing(&block)
|
|
18
18
|
initialize_with_newrelic_tracing { initialize_without_new_relic(*args, &traced_block) }
|
|
19
19
|
end
|
|
20
20
|
end
|
|
@@ -16,11 +16,7 @@ module NewRelic
|
|
|
16
16
|
def add_thread_tracing(*args, &block)
|
|
17
17
|
return block if !NewRelic::Agent::Tracer.thread_tracing_enabled?
|
|
18
18
|
|
|
19
|
-
NewRelic::Agent::Tracer.thread_block_with_current_transaction(
|
|
20
|
-
*args,
|
|
21
|
-
segment_name: 'Ruby/Thread',
|
|
22
|
-
&block
|
|
23
|
-
)
|
|
19
|
+
NewRelic::Agent::Tracer.thread_block_with_current_transaction(&block)
|
|
24
20
|
end
|
|
25
21
|
end
|
|
26
22
|
end
|
|
@@ -12,7 +12,7 @@ module NewRelic
|
|
|
12
12
|
include NewRelic::Agent::Instrumentation::MonitoredThread
|
|
13
13
|
|
|
14
14
|
def initialize(*args, &block)
|
|
15
|
-
traced_block = add_thread_tracing(
|
|
15
|
+
traced_block = add_thread_tracing(&block)
|
|
16
16
|
initialize_with_newrelic_tracing { super(*args, &traced_block) }
|
|
17
17
|
end
|
|
18
18
|
end
|
|
@@ -6,6 +6,8 @@ module NewRelic
|
|
|
6
6
|
module Agent
|
|
7
7
|
module Instrumentation
|
|
8
8
|
module Tilt
|
|
9
|
+
INSTRUMENTATION_NAME = NewRelic::Agent.base_name(name)
|
|
10
|
+
|
|
9
11
|
def metric_name(klass, file)
|
|
10
12
|
"View/#{klass}/#{file}/Rendering"
|
|
11
13
|
end
|
|
@@ -21,6 +23,8 @@ module NewRelic
|
|
|
21
23
|
end
|
|
22
24
|
|
|
23
25
|
def render_with_tracing(*args, &block)
|
|
26
|
+
NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
|
|
27
|
+
|
|
24
28
|
begin
|
|
25
29
|
finishable = Tracer.start_segment(
|
|
26
30
|
name: metric_name(self.class, create_filename_for_metric(self.file))
|
|
@@ -11,10 +11,6 @@ DependencyDetection.defer do
|
|
|
11
11
|
|
|
12
12
|
depends_on { defined?(Tilt) }
|
|
13
13
|
|
|
14
|
-
executes do
|
|
15
|
-
NewRelic::Agent.logger.info('Installing Tilt instrumentation')
|
|
16
|
-
end
|
|
17
|
-
|
|
18
14
|
executes do
|
|
19
15
|
if use_prepend?
|
|
20
16
|
prepend_instrument Tilt::Template, NewRelic::Agent::Instrumentation::Tilt::Prepend
|
|
@@ -8,11 +8,11 @@ module NewRelic
|
|
|
8
8
|
module Typhoeus
|
|
9
9
|
HYDRA_SEGMENT_NAME = 'External/Multiple/Typhoeus::Hydra/run'
|
|
10
10
|
NOTICEABLE_ERROR_CLASS = 'Typhoeus::Errors::TyphoeusError'
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
EARLIEST_VERSION = '0.5.3'
|
|
12
|
+
INSTRUMENTATION_NAME = NewRelic::Agent.base_name(name)
|
|
13
13
|
|
|
14
14
|
def self.is_supported_version?
|
|
15
|
-
|
|
15
|
+
NewRelic::Helper.version_satisfied?(::Typhoeus::VERSION, '>=', EARLIEST_VERSION)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def self.request_is_hydra_enabled?(request)
|
|
@@ -31,6 +31,8 @@ module NewRelic
|
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
def with_tracing
|
|
34
|
+
NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
|
|
35
|
+
|
|
34
36
|
segment = NewRelic::Agent::Tracer.start_segment(name: HYDRA_SEGMENT_NAME)
|
|
35
37
|
instance_variable_set(:@__newrelic_hydra_segment, segment)
|
|
36
38
|
begin
|
|
@@ -41,6 +43,8 @@ module NewRelic
|
|
|
41
43
|
end
|
|
42
44
|
|
|
43
45
|
def self.trace(request)
|
|
46
|
+
NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
|
|
47
|
+
|
|
44
48
|
state = NewRelic::Agent::Tracer.state
|
|
45
49
|
return unless state.is_execution_traced?
|
|
46
50
|
|
|
@@ -0,0 +1,21 @@
|
|
|
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 ViewComponent::Chain
|
|
7
|
+
def self.instrument!
|
|
8
|
+
::ViewComponent::Base.class_eval do
|
|
9
|
+
include NewRelic::Agent::Instrumentation::ViewComponent
|
|
10
|
+
|
|
11
|
+
alias_method(:render_in_without_tracing, :render_in)
|
|
12
|
+
|
|
13
|
+
def render_in(*args)
|
|
14
|
+
render_in_with_tracing(*args) do
|
|
15
|
+
render_in_without_tracing(*args)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
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 ViewComponent
|
|
7
|
+
INSTRUMENTATION_NAME = NewRelic::Agent.base_name(name)
|
|
8
|
+
|
|
9
|
+
def render_in_with_tracing(*args)
|
|
10
|
+
NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
|
|
11
|
+
|
|
12
|
+
begin
|
|
13
|
+
segment = NewRelic::Agent::Tracer.start_segment(name: metric_name)
|
|
14
|
+
yield
|
|
15
|
+
rescue => e
|
|
16
|
+
NewRelic::Agent.notice_error(e)
|
|
17
|
+
raise
|
|
18
|
+
ensure
|
|
19
|
+
segment&.finish
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def metric_name
|
|
24
|
+
# ViewComponent determines a component's identifier differently depending on the version
|
|
25
|
+
# https://github.com/ViewComponent/view_component/pull/2153
|
|
26
|
+
component_identifier = defined?(self.class.source_location) ? self.class.source_location : self.class.identifier
|
|
27
|
+
|
|
28
|
+
"View/#{metric_path(component_identifier)}/#{self.class.name}"
|
|
29
|
+
rescue => e
|
|
30
|
+
NewRelic::Agent.logger.error('Error identifying View Component metric name', e)
|
|
31
|
+
|
|
32
|
+
'View/component'
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def metric_path(identifier)
|
|
36
|
+
return 'component' unless identifier
|
|
37
|
+
|
|
38
|
+
if (parts = identifier.split('/')).size > 1
|
|
39
|
+
parts[-2..-1].join('/') # Get filepath by assuming the Rails' structure: app/components/home/example_component.rb
|
|
40
|
+
else
|
|
41
|
+
NewRelic::Agent::UNKNOWN_METRIC
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
# frozen_string_literal: true
|
|
4
4
|
|
|
5
5
|
module NewRelic::Agent::Instrumentation
|
|
6
|
-
module
|
|
6
|
+
module ViewComponent::Prepend
|
|
7
|
+
include NewRelic::Agent::Instrumentation::ViewComponent
|
|
7
8
|
|
|
8
|
-
def
|
|
9
|
-
|
|
10
|
-
yield
|
|
9
|
+
def render_in(*args)
|
|
10
|
+
render_in_with_tracing(*args) { super }
|
|
11
11
|
end
|
|
12
12
|
end
|
|
13
13
|
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
|
+
require_relative 'view_component/instrumentation'
|
|
6
|
+
require_relative 'view_component/chain'
|
|
7
|
+
require_relative 'view_component/prepend'
|
|
8
|
+
|
|
9
|
+
DependencyDetection.defer do
|
|
10
|
+
named :view_component
|
|
11
|
+
|
|
12
|
+
depends_on do
|
|
13
|
+
defined?(ViewComponent) &&
|
|
14
|
+
ViewComponent::Base.method_defined?(:render_in)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
executes do
|
|
18
|
+
if use_prepend?
|
|
19
|
+
prepend_instrument ViewComponent::Base, NewRelic::Agent::Instrumentation::ViewComponent::Prepend
|
|
20
|
+
else
|
|
21
|
+
chain_instrument NewRelic::Agent::Instrumentation::ViewComponent::Chain
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -2,7 +2,6 @@
|
|
|
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 'base64'
|
|
6
5
|
require 'json'
|
|
7
6
|
require 'new_relic/agent/obfuscator'
|
|
8
7
|
|
|
@@ -165,9 +164,8 @@ module NewRelic
|
|
|
165
164
|
|
|
166
165
|
def add_ssl_for_http(data)
|
|
167
166
|
ssl_for_http = NewRelic::Agent.config[:'browser_monitoring.ssl_for_http']
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
end
|
|
167
|
+
|
|
168
|
+
data[SSL_FOR_HTTP_KEY] = ssl_for_http if ssl_for_http
|
|
171
169
|
end
|
|
172
170
|
|
|
173
171
|
def add_attributes(data, txn)
|
|
@@ -0,0 +1,25 @@
|
|
|
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 Llm
|
|
8
|
+
class ChatCompletionMessage < LlmEvent
|
|
9
|
+
ATTRIBUTES = %i[content role sequence completion_id token_count
|
|
10
|
+
is_response]
|
|
11
|
+
EVENT_NAME = 'LlmChatCompletionMessage'
|
|
12
|
+
|
|
13
|
+
attr_accessor(*ATTRIBUTES)
|
|
14
|
+
|
|
15
|
+
def attributes
|
|
16
|
+
LlmEvent::ATTRIBUTES + ATTRIBUTES
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def event_name
|
|
20
|
+
EVENT_NAME
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
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 'response_headers'
|
|
6
|
+
|
|
7
|
+
module NewRelic
|
|
8
|
+
module Agent
|
|
9
|
+
module Llm
|
|
10
|
+
class ChatCompletionSummary < LlmEvent
|
|
11
|
+
include ResponseHeaders
|
|
12
|
+
|
|
13
|
+
ATTRIBUTES = %i[request_max_tokens response_number_of_messages
|
|
14
|
+
request_model response_choices_finish_reason request_temperature
|
|
15
|
+
duration error]
|
|
16
|
+
ATTRIBUTE_NAME_EXCEPTIONS = {
|
|
17
|
+
response_number_of_messages: 'response.number_of_messages',
|
|
18
|
+
request_model: 'request.model',
|
|
19
|
+
response_choices_finish_reason: 'response.choices.finish_reason',
|
|
20
|
+
request_temperature: 'request.temperature'
|
|
21
|
+
}
|
|
22
|
+
ERROR_COMPLETION_ID = 'completion_id'
|
|
23
|
+
EVENT_NAME = 'LlmChatCompletionSummary'
|
|
24
|
+
|
|
25
|
+
attr_accessor(*ATTRIBUTES)
|
|
26
|
+
|
|
27
|
+
def attributes
|
|
28
|
+
LlmEvent::ATTRIBUTES + ResponseHeaders::ATTRIBUTES + ATTRIBUTES
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def attribute_name_exceptions
|
|
32
|
+
# TODO: OLD RUBIES < 2.6
|
|
33
|
+
# Hash#merge accepts multiple arguments in 2.6
|
|
34
|
+
# Remove condition once support for Ruby <2.6 is dropped
|
|
35
|
+
if NewRelic::Helper.version_satisfied?(RUBY_VERSION, '>=', '2.6.0')
|
|
36
|
+
LlmEvent::ATTRIBUTE_NAME_EXCEPTIONS.merge(ResponseHeaders::ATTRIBUTE_NAME_EXCEPTIONS, ATTRIBUTE_NAME_EXCEPTIONS)
|
|
37
|
+
else
|
|
38
|
+
LlmEvent::ATTRIBUTE_NAME_EXCEPTIONS.merge(ResponseHeaders::ATTRIBUTE_NAME_EXCEPTIONS).merge(ATTRIBUTE_NAME_EXCEPTIONS)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def event_name
|
|
43
|
+
EVENT_NAME
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def error_attributes(exception)
|
|
47
|
+
attrs = {ERROR_COMPLETION_ID => id}
|
|
48
|
+
|
|
49
|
+
error_attributes_from_response(exception, attrs)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def error_attributes_from_response(exception, attrs)
|
|
55
|
+
return attrs unless exception.respond_to?(:response)
|
|
56
|
+
|
|
57
|
+
attrs[ERROR_ATTRIBUTE_STATUS_CODE] = exception.response.dig(:status)
|
|
58
|
+
attrs[ERROR_ATTRIBUTE_CODE] = exception.response.dig(:body, ERROR_STRING, CODE_STRING)
|
|
59
|
+
attrs[ERROR_ATTRIBUTE_PARAM] = exception.response.dig(:body, ERROR_STRING, PARAM_STRING)
|
|
60
|
+
|
|
61
|
+
attrs
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
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 Llm
|
|
8
|
+
class Embedding < LlmEvent
|
|
9
|
+
include ResponseHeaders
|
|
10
|
+
|
|
11
|
+
ATTRIBUTES = %i[input request_model token_count duration error].freeze
|
|
12
|
+
ATTRIBUTE_NAME_EXCEPTIONS = {
|
|
13
|
+
request_model: 'request.model'
|
|
14
|
+
}.freeze
|
|
15
|
+
ERROR_EMBEDDING_ID = 'embedding_id'
|
|
16
|
+
EVENT_NAME = 'LlmEmbedding'
|
|
17
|
+
|
|
18
|
+
attr_accessor(*ATTRIBUTES)
|
|
19
|
+
|
|
20
|
+
def attributes
|
|
21
|
+
LlmEvent::ATTRIBUTES + ResponseHeaders::ATTRIBUTES + ATTRIBUTES
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def attribute_name_exceptions
|
|
25
|
+
# TODO: OLD RUBIES < 2.6
|
|
26
|
+
# Hash#merge accepts multiple arguments in 2.6
|
|
27
|
+
# Remove condition once support for Ruby <2.6 is dropped
|
|
28
|
+
if NewRelic::Helper.version_satisfied?(RUBY_VERSION, '>=', '2.6.0')
|
|
29
|
+
LlmEvent::ATTRIBUTE_NAME_EXCEPTIONS.merge(ResponseHeaders::ATTRIBUTE_NAME_EXCEPTIONS, ATTRIBUTE_NAME_EXCEPTIONS)
|
|
30
|
+
else
|
|
31
|
+
LlmEvent::ATTRIBUTE_NAME_EXCEPTIONS.merge(ResponseHeaders::ATTRIBUTE_NAME_EXCEPTIONS).merge(ATTRIBUTE_NAME_EXCEPTIONS)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def event_name
|
|
36
|
+
EVENT_NAME
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def error_attributes(exception)
|
|
40
|
+
attrs = {}
|
|
41
|
+
attrs[ERROR_EMBEDDING_ID] = id
|
|
42
|
+
|
|
43
|
+
error_attributes_from_response(exception, attrs)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def error_attributes_from_response(exception, attrs)
|
|
49
|
+
return attrs unless exception.respond_to?(:response)
|
|
50
|
+
|
|
51
|
+
attrs[ERROR_ATTRIBUTE_STATUS_CODE] = exception.response.dig(:status)
|
|
52
|
+
attrs[ERROR_ATTRIBUTE_CODE] = exception.response.dig(:body, ERROR_STRING, CODE_STRING)
|
|
53
|
+
attrs[ERROR_ATTRIBUTE_PARAM] = exception.response.dig(:body, ERROR_STRING, PARAM_STRING)
|
|
54
|
+
|
|
55
|
+
attrs
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
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 Llm
|
|
8
|
+
class LlmEvent
|
|
9
|
+
# Every subclass must define its own ATTRIBUTES constant, an array of symbols representing
|
|
10
|
+
# that class's unique attributes
|
|
11
|
+
ATTRIBUTES = %i[id request_id span_id trace_id response_model vendor
|
|
12
|
+
ingest_source metadata]
|
|
13
|
+
# These attributes should not be passed as arguments to initialize and will be set by the agent
|
|
14
|
+
AGENT_DEFINED_ATTRIBUTES = %i[span_id trace_id ingest_source]
|
|
15
|
+
# Some attributes have names that can't be written as symbols used for metaprogramming.
|
|
16
|
+
# The ATTRIBUTE_NAME_EXCEPTIONS hash should use the symbolized version of the name as the key
|
|
17
|
+
# and the string version expected by the UI as the value.
|
|
18
|
+
ATTRIBUTE_NAME_EXCEPTIONS = {response_model: 'response.model'}
|
|
19
|
+
INGEST_SOURCE = 'Ruby'
|
|
20
|
+
ERROR_ATTRIBUTE_STATUS_CODE = 'http.statusCode'
|
|
21
|
+
ERROR_ATTRIBUTE_CODE = 'error.code'
|
|
22
|
+
ERROR_ATTRIBUTE_PARAM = 'error.param'
|
|
23
|
+
ERROR_STRING = 'error'
|
|
24
|
+
CODE_STRING = 'code'
|
|
25
|
+
PARAM_STRING = 'param'
|
|
26
|
+
|
|
27
|
+
attr_accessor(*ATTRIBUTES)
|
|
28
|
+
|
|
29
|
+
def self.set_llm_agent_attribute_on_transaction
|
|
30
|
+
NewRelic::Agent::Transaction.add_agent_attribute(:llm, true, NewRelic::Agent::AttributeFilter::DST_TRANSACTION_EVENTS)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# This initialize method is used for all subclasses.
|
|
34
|
+
# It leverages the subclass's `attributes` method to iterate through
|
|
35
|
+
# all the attributes for that subclass.
|
|
36
|
+
# It assigns instance variables for all arguments passed to the method.
|
|
37
|
+
# It also assigns agent-defined attributes.
|
|
38
|
+
def initialize(opts = {})
|
|
39
|
+
(attributes - AGENT_DEFINED_ATTRIBUTES).each do |attr|
|
|
40
|
+
instance_variable_set(:"@#{attr}", opts[attr]) if opts.key?(attr)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
@id = id || NewRelic::Agent::GuidGenerator.generate_guid
|
|
44
|
+
@span_id = NewRelic::Agent::Tracer.current_span_id
|
|
45
|
+
@trace_id = NewRelic::Agent::Tracer.current_trace_id
|
|
46
|
+
@ingest_source = INGEST_SOURCE
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# All subclasses use event_attributes to get a full hash of all
|
|
50
|
+
# attributes and their values
|
|
51
|
+
def event_attributes
|
|
52
|
+
attributes_hash = attributes.each_with_object({}) do |attr, hash|
|
|
53
|
+
hash[replace_attr_with_string(attr)] = instance_variable_get(:"@#{attr}")
|
|
54
|
+
end
|
|
55
|
+
attributes_hash.merge!(metadata) && attributes_hash.delete(:metadata) if !metadata.nil?
|
|
56
|
+
|
|
57
|
+
attributes_hash
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Subclasses define an attributes method to concatenate attributes
|
|
61
|
+
# defined across their ancestors and other modules
|
|
62
|
+
def attributes
|
|
63
|
+
ATTRIBUTES
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Subclasses that record events will override this method
|
|
67
|
+
def event_name
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Some attribute names include periods, which aren't valid values for
|
|
71
|
+
# Ruby method names. This method returns a Hash with the key as the
|
|
72
|
+
# Ruby symbolized version of the attribute and the value as the
|
|
73
|
+
# period-delimited string expected upstream.
|
|
74
|
+
def attribute_name_exceptions
|
|
75
|
+
ATTRIBUTE_NAME_EXCEPTIONS
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def record
|
|
79
|
+
NewRelic::Agent.record_custom_event(event_name, event_attributes)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Subclasses that add attributes to noticed errors will override this method
|
|
83
|
+
def error_attributes(exception)
|
|
84
|
+
NewRelic::EMPTY_HASH
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
private
|
|
88
|
+
|
|
89
|
+
def replace_attr_with_string(attr)
|
|
90
|
+
attribute_name_exceptions.fetch(attr, attr)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
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 Llm
|
|
8
|
+
module ResponseHeaders
|
|
9
|
+
ATTRIBUTES = %i[response_organization llm_version ratelimit_limit_requests
|
|
10
|
+
ratelimit_limit_tokens ratelimit_remaining_requests
|
|
11
|
+
ratelimit_remaining_tokens ratelimit_reset_requests
|
|
12
|
+
ratelimit_reset_tokens ratelimit_limit_tokens_usage_based
|
|
13
|
+
ratelimit_reset_tokens_usage_based
|
|
14
|
+
ratelimit_remaining_tokens_usage_based].freeze
|
|
15
|
+
|
|
16
|
+
ATTRIBUTE_NAME_EXCEPTIONS = {
|
|
17
|
+
response_organization: 'response.organization',
|
|
18
|
+
llm_version: 'response.headers.llmVersion',
|
|
19
|
+
ratelimit_limit_requests: 'response.headers.ratelimitLimitRequests',
|
|
20
|
+
ratelimit_limit_tokens: 'response.headers.ratelimitLimitTokens',
|
|
21
|
+
ratelimit_remaining_requests: 'response.headers.ratelimitRemainingRequests',
|
|
22
|
+
ratelimit_remaining_tokens: 'response.headers.ratelimitRemainingTokens',
|
|
23
|
+
ratelimit_reset_requests: 'response.headers.ratelimitResetRequests',
|
|
24
|
+
ratelimit_reset_tokens: 'response.headers.ratelimitResetTokens',
|
|
25
|
+
ratelimit_limit_tokens_usage_based: 'response.headers.ratelimitLimitTokensUsageBased',
|
|
26
|
+
ratelimit_reset_tokens_usage_based: 'response.headers.ratelimitResetTokensUsageBased',
|
|
27
|
+
ratelimit_remaining_tokens_usage_based: 'response.headers.ratelimitRemainingTokensUsageBased'
|
|
28
|
+
}.freeze
|
|
29
|
+
|
|
30
|
+
OPENAI_ORGANIZATION = 'openai-organization'
|
|
31
|
+
OPENAI_VERSION = 'openai-version'
|
|
32
|
+
X_RATELIMIT_LIMIT_REQUESTS = 'x-ratelimit-limit-requests'
|
|
33
|
+
X_RATELIMIT_LIMIT_TOKENS = 'x-ratelimit-limit-tokens'
|
|
34
|
+
X_RATELIMIT_REMAINING_REQUESTS = 'x-ratelimit-remaining-requests'
|
|
35
|
+
X_RATELIMIT_REMAINING_TOKENS = 'x-ratelimit-remaining-tokens'
|
|
36
|
+
X_RATELIMIT_RESET_REQUESTS = 'x-ratelimit-reset-requests'
|
|
37
|
+
X_RATELIMIT_RESET_TOKENS = 'x-ratelimit-reset-tokens'
|
|
38
|
+
X_RATELIMIT_LIMIT_TOKENS_USAGE_BASED = 'x-ratelimit-limit-tokens-usage-based'
|
|
39
|
+
X_RATELIMIT_RESET_TOKENS_USAGE_BASED = 'x-ratelimit-reset-tokens-usage-based'
|
|
40
|
+
X_RATELIMIT_REMAINING_TOKENS_USAGE_BASED = 'x-ratelimit-remaining-tokens-usage-based'
|
|
41
|
+
X_REQUEST_ID = 'x-request-id'
|
|
42
|
+
|
|
43
|
+
attr_accessor(*ATTRIBUTES)
|
|
44
|
+
|
|
45
|
+
# Headers is a hash of Net::HTTP response headers
|
|
46
|
+
def populate_openai_response_headers(headers)
|
|
47
|
+
# Embedding, ChatCompletionSummary, and ChatCompletionMessage all need
|
|
48
|
+
# request_id, so it's defined in LlmEvent. ChatCompletionMessage
|
|
49
|
+
# adds the attribute via ChatCompletionSummary.
|
|
50
|
+
self.request_id = headers[X_REQUEST_ID]&.first
|
|
51
|
+
self.response_organization = headers[OPENAI_ORGANIZATION]&.first
|
|
52
|
+
self.llm_version = headers[OPENAI_VERSION]&.first
|
|
53
|
+
self.ratelimit_limit_requests = headers[X_RATELIMIT_LIMIT_REQUESTS]&.first.to_i
|
|
54
|
+
self.ratelimit_limit_tokens = headers[X_RATELIMIT_LIMIT_TOKENS]&.first.to_i
|
|
55
|
+
remaining_headers(headers)
|
|
56
|
+
reset_headers(headers)
|
|
57
|
+
tokens_usage_based_headers(headers)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
def remaining_headers(headers)
|
|
63
|
+
self.ratelimit_remaining_requests = headers[X_RATELIMIT_REMAINING_REQUESTS]&.first.to_i
|
|
64
|
+
self.ratelimit_remaining_tokens = headers[X_RATELIMIT_REMAINING_TOKENS]&.first.to_i
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def reset_headers(headers)
|
|
68
|
+
self.ratelimit_reset_requests = headers[X_RATELIMIT_RESET_REQUESTS]&.first
|
|
69
|
+
self.ratelimit_reset_tokens = headers[X_RATELIMIT_RESET_TOKENS]&.first
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def tokens_usage_based_headers(headers)
|
|
73
|
+
self.ratelimit_limit_tokens_usage_based = headers[X_RATELIMIT_LIMIT_TOKENS_USAGE_BASED]&.first.to_i
|
|
74
|
+
self.ratelimit_reset_tokens_usage_based = headers[X_RATELIMIT_RESET_TOKENS_USAGE_BASED]&.first
|
|
75
|
+
self.ratelimit_remaining_tokens_usage_based = headers[X_RATELIMIT_REMAINING_TOKENS_USAGE_BASED]&.first.to_i
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -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_relative 'llm/llm_event'
|
|
6
|
+
require_relative 'llm/chat_completion_message'
|
|
7
|
+
require_relative 'llm/chat_completion_summary'
|
|
8
|
+
require_relative 'llm/embedding'
|
|
9
|
+
require_relative 'llm/response_headers'
|
|
10
|
+
|
|
11
|
+
module NewRelic
|
|
12
|
+
module Agent
|
|
13
|
+
class LLM
|
|
14
|
+
INPUT = 'input'
|
|
15
|
+
CONTENT = 'content'
|
|
16
|
+
SEGMENT_PATTERN = %r{Llm/.+/OpenAI/.+}.freeze
|
|
17
|
+
|
|
18
|
+
def self.instrumentation_enabled?
|
|
19
|
+
NewRelic::Agent.config[:'ai_monitoring.enabled']
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# LLM content-related attributes are exempt from the 4095 byte limit
|
|
23
|
+
def self.exempt_event_attribute?(type, key)
|
|
24
|
+
return false unless instrumentation_enabled?
|
|
25
|
+
|
|
26
|
+
(type == NewRelic::Agent::Llm::Embedding::EVENT_NAME && key == INPUT) ||
|
|
27
|
+
(type == NewRelic::Agent::Llm::ChatCompletionMessage::EVENT_NAME && key == CONTENT)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.openai?
|
|
31
|
+
@openai ||= %i[prepend chain].include?(NewRelic::Agent.config[:'instrumentation.ruby_openai']) &&
|
|
32
|
+
NewRelic::Agent.config[:'ai_monitoring.enabled']
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Used in NetHTTP instrumentation
|
|
36
|
+
def self.openai_parent?(segment)
|
|
37
|
+
return false unless openai?
|
|
38
|
+
|
|
39
|
+
segment&.parent&.name&.match?(SEGMENT_PATTERN)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.populate_openai_response_headers(response, parent)
|
|
43
|
+
return unless parent.instance_variable_defined?(:@llm_event)
|
|
44
|
+
|
|
45
|
+
parent.llm_event.populate_openai_response_headers(response.to_hash)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -9,9 +9,15 @@ module NewRelic
|
|
|
9
9
|
extend self
|
|
10
10
|
|
|
11
11
|
def decorate(message)
|
|
12
|
-
return message
|
|
12
|
+
return message if !decorating_enabled? || message.nil?
|
|
13
13
|
|
|
14
14
|
metadata = NewRelic::Agent.linking_metadata
|
|
15
|
+
|
|
16
|
+
if message.is_a?(Hash)
|
|
17
|
+
message.merge!(metadata) unless message.frozen?
|
|
18
|
+
return
|
|
19
|
+
end
|
|
20
|
+
|
|
15
21
|
formatted_metadata = " NR-LINKING|#{metadata[ENTITY_GUID_KEY]}|#{metadata[HOSTNAME_KEY]}|" \
|
|
16
22
|
"#{metadata[TRACE_ID_KEY]}|#{metadata[SPAN_ID_KEY]}|" \
|
|
17
23
|
"#{escape_entity_name(metadata[ENTITY_NAME_KEY])}|"
|
|
@@ -23,14 +29,25 @@ module NewRelic
|
|
|
23
29
|
|
|
24
30
|
def decorating_enabled?
|
|
25
31
|
NewRelic::Agent.config[:'application_logging.enabled'] &&
|
|
26
|
-
NewRelic::Agent::Instrumentation::Logger.enabled?
|
|
32
|
+
(NewRelic::Agent::Instrumentation::Logger.enabled? ||
|
|
33
|
+
NewRelic::Agent::Instrumentation::LogStasher.enabled?) &&
|
|
27
34
|
NewRelic::Agent.config[:'application_logging.local_decorating.enabled']
|
|
28
35
|
end
|
|
29
36
|
|
|
30
37
|
def escape_entity_name(entity_name)
|
|
31
38
|
return unless entity_name
|
|
32
39
|
|
|
33
|
-
|
|
40
|
+
# TODO: OLD RUBIES 3.3
|
|
41
|
+
# URI version 1.0 marked URI::RFC3986_PARSER.escape as obsolete,
|
|
42
|
+
# which URI::DEFAULT_PARSER is an alias for.
|
|
43
|
+
# URI version 1.0+ will ship with Ruby 3.4
|
|
44
|
+
# Once we drop support for Rubies below 3.4, we can use the
|
|
45
|
+
# URI::RFC2396 parser exclusively.
|
|
46
|
+
if NewRelic::Helper.version_satisfied?(URI::VERSION, '>=', '1.0')
|
|
47
|
+
URI::RFC2396_PARSER.escape(entity_name)
|
|
48
|
+
else
|
|
49
|
+
URI::DEFAULT_PARSER.escape(entity_name)
|
|
50
|
+
end
|
|
34
51
|
end
|
|
35
52
|
end
|
|
36
53
|
end
|