newrelic_rpm 9.13.0 → 9.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/CHANGELOG.md +87 -5
 - data/lib/new_relic/agent/configuration/default_source.rb +82 -1
 - data/lib/new_relic/agent/configuration/environment_source.rb +5 -1
 - data/lib/new_relic/agent/configuration/manager.rb +16 -1
 - data/lib/new_relic/agent/database/obfuscation_helpers.rb +11 -11
 - data/lib/new_relic/agent/instrumentation/dynamodb/instrumentation.rb +3 -2
 - data/lib/new_relic/agent/instrumentation/grape.rb +1 -1
 - data/lib/new_relic/agent/instrumentation/rdkafka/chain.rb +71 -0
 - data/lib/new_relic/agent/instrumentation/rdkafka/instrumentation.rb +70 -0
 - data/lib/new_relic/agent/instrumentation/rdkafka/prepend.rb +66 -0
 - data/lib/new_relic/agent/instrumentation/rdkafka.rb +27 -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 +50 -0
 - data/lib/new_relic/agent/instrumentation/ruby_kafka.rb +27 -0
 - data/lib/new_relic/agent/instrumentation/view_component/instrumentation.rb +4 -1
 - data/lib/new_relic/agent/javascript_instrumentor.rb +2 -3
 - data/lib/new_relic/agent/messaging.rb +11 -5
 - data/lib/new_relic/agent/transaction/request_attributes.rb +13 -1
 - data/lib/new_relic/agent.rb +93 -0
 - data/lib/new_relic/control/frameworks/rails4.rb +1 -1
 - data/lib/new_relic/environment_report.rb +1 -1
 - data/lib/new_relic/language_support.rb +1 -1
 - data/lib/new_relic/version.rb +1 -1
 - data/newrelic.yml +55 -0
 - metadata +11 -3
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: b0ade9f1a1a36e6382100a271c5e54a2c426c27b95884a15eac8d6740dcee29b
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 18f728d4289bfda058bd54d7d7798a33c3a43d45de83f543b86dd573ff76283e
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: a463e150f83291e4ef1c55e23b155621694dc5cf0a709d78bf7ebd10aee7b801afaa1e76a4fd6d12858fba7806368bad7e6b5ca53bd21273f68e1f995b524edd
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 9d0faa058f7810ce4edff5c91a57e584e1efaea99e6d4e533b2128727b0ccc7bb61dfa87ab0a82e134bce05010c7aec5ccef9b7960f72c502e68473885492434
         
     | 
    
        data/CHANGELOG.md
    CHANGED
    
    | 
         @@ -1,16 +1,98 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # New Relic Ruby Agent Release Notes
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
      
 3 
     | 
    
         
            +
            ## v9.14.0
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Version 9.14.0 adds Apache Kafka instrumentation for the rdkafka and ruby-kafka gems, introduces a configuration-based, automatic way to add custom instrumentation method tracers, correctly captures MIME type for AcionDispatch 7.0+ requests, properly handles Boolean coercion for `newrelic.yml` configuration, fixes a JRuby bug in the configuration manager, fixes a bug related to `Bundler.rubygems.installed_specs`, and fixes a bug to make the agent compatible with ViewComponent v3.15.0+.
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            - **Feature: Add Apache Kafka instrumentation for the rdkafka and ruby-kafka gems**
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              The agent now has instrumentation for both the rdkafka and ruby-kafka gems. The agent will record transactions and message broker segments for produce and consume calls made using these gems. [PR#2824](https://github.com/newrelic/newrelic-ruby-agent/pull/2824) [PR#2842](https://github.com/newrelic/newrelic-ruby-agent/pull/2842)
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            - **Feature: Add a configuration option to permit custom method tracers to be defined automatically**
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              A new `:automatic_custom_instrumentation_method_list` configuration parameter has been added to permit the user to define a list of fully qualified (namespaced) Ruby methods for the agent to automatically add custom instrumentation for without requiring any code modifications to be made to the classes that define the methods.
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              The list should be an array of `CLASS#METHOD` (for instance methods) and/or `CLASS.METHOD` (for class methods) strings.
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
              Use fully qualified class names (using the `::` delimiter) that include any module or class namespacing.
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              Here is some Ruby source code that defines a `render_png` instance method for an `Image` class and a `notify` class method for a `User` class, both within a `MyCompany` module namespace:
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              ```
         
     | 
| 
      
 22 
     | 
    
         
            +
              module MyCompany
         
     | 
| 
      
 23 
     | 
    
         
            +
                class Image
         
     | 
| 
      
 24 
     | 
    
         
            +
                  def render_png
         
     | 
| 
      
 25 
     | 
    
         
            +
                    # code to render a PNG
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                class User
         
     | 
| 
      
 30 
     | 
    
         
            +
                  def self.notify
         
     | 
| 
      
 31 
     | 
    
         
            +
                    # code to notify users
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
              end
         
     | 
| 
      
 35 
     | 
    
         
            +
              ```
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
              Given that source code, the `newrelic.yml` config file might request instrumentation for both of these methods like so:
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              ```
         
     | 
| 
      
 40 
     | 
    
         
            +
              automatic_custom_instrumentation_method_list:
         
     | 
| 
      
 41 
     | 
    
         
            +
                - MyCompany::Image#render_png
         
     | 
| 
      
 42 
     | 
    
         
            +
                - MyCompany::User.notify
         
     | 
| 
      
 43 
     | 
    
         
            +
              ```
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
              That configuration example uses YAML array syntax to specify both methods. Alternatively, a comma-delimited string can be used instead:
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
              ```
         
     | 
| 
      
 48 
     | 
    
         
            +
              automatic_custom_instrumentation_method_list: 'MyCompany::Image#render_png, MyCompany::User.notify'
         
     | 
| 
      
 49 
     | 
    
         
            +
              ```
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
              Whitespace around the comma(s) in the list is optional. When configuring the agent with a list of methods via the `NEW_RELIC_AUTOMATIC_CUSTOM_INSTRUMENTATION_METHOD_LIST` environment variable, this comma-delimited string format should be used:
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
              ```
         
     | 
| 
      
 54 
     | 
    
         
            +
              export NEW_RELIC_AUTOMATIC_CUSTOM_INSTRUMENTATION_METHOD_LIST='MyCompany::Image#render_png, MyCompany::User.notify'
         
     | 
| 
      
 55 
     | 
    
         
            +
              ```
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
              [PR#2851](https://github.com/newrelic/newrelic-ruby-agent/pull/2851)
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
            - **Feature: Collect just MIME type for AcionDispatch 7.0+ requests**
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
              Rails 7.0 [introduced changes](https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#actiondispatch-request-content-type-now-returns-content-type-header-as-it-is) to the behavior of `ActionDispatch::Request#content_type`, adding extra request-related details the agent wasn't expecting to collect. Additionally, the agent's use of `content_type ` was triggering deprecation warnings. The agent now uses `ActionDispatch::Request#media_type` to capture the MIME type. Thanks to [@internethostage](https://github.com/internethostage) for letting us know about this change. [Issue#2500](https://github.com/newrelic/newrelic-ruby-agent/issues/2500) [PR#2855](https://github.com/newrelic/newrelic-ruby-agent/pull/2855)
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
            - **Bugfix: Corrected Boolean coercion for `newrelic.yml` configuration**
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
              Previously, any String assigned to New Relic configurations expecting a Boolean value were evaluated as `true`. This could lead to unexpected behavior. For example, setting `application_logging.enabled: 'false'` in `newrelic.yml` would incorrectly evaluate to `application_logging.enabled: true` due to the truthy nature of Strings.
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
              Now, the agent strictly interprets Boolean configuration values. It recognizes both actual Boolean values and certain Strings/Symbols:
         
     | 
| 
      
 68 
     | 
    
         
            +
              - `'true'`, `'yes'`, or `'on'` (evaluates to `true`)
         
     | 
| 
      
 69 
     | 
    
         
            +
              - `'false'`, `'no'`, or `'off'` (evaluates to `false`)
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
              Any other inputs will revert to the setting's default configuration value. [PR#2847](https://github.com/newrelic/newrelic-ruby-agent/pull/2847)
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
            - **Bugfix: JRuby not saving configuration values correctly in configuration manager**
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
              Previously, a change made to fix a different JRuby bug caused the agent to not save configuration values correctly in the configuration manager when running on JRuby. This has been fixed. [PR#2848](https://github.com/newrelic/newrelic-ruby-agent/pull/2848)
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
            - **Bugfix: Update condition to verify Bundler.rubygems.installed_specs is available**
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
              To address a recent Bundler deprecation warning, we started using `Bundler.rubygems.installed_specs` instead of `Bundler.rubygems.all_specs` in environments that seemed appropriate. We discovered the version constraint we used was too low. Now, rather than check the version, we check for the method using `respond_to?`. [PR#2853](https://github.com/newrelic/newrelic-ruby-agent/pull/2853)
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
            - **Bugfix: Support view_component v3.15.0+**
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
              Previously the agent had been making use of a private API to obtain a component identifier value. This private API was dropped in v3.15.0 of view_component, resulting in errors from the New Relic Ruby agent's continued attempts to use it. Many thanks to community member [@navidemad](https://github.com/navidemad) for bringing this issue to our attention and supplying a bugfix with [PR#2870](https://github.com/newrelic/newrelic-ruby-agent/pull/2870).
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
       3 
85 
     | 
    
         
             
            ## v9.13.0
         
     | 
| 
       4 
86 
     | 
    
         | 
| 
       5 
87 
     | 
    
         
             
            Version 9.13.0 enhances support for AWS Lambda functions, adds experimental OpenSearch instrumentation, updates framework detection, silences a Bundler deprecation warning, fixes Falcon dispatcher detection, fixes a bug with Redis instrumentation installation, and addresses a JRuby-specific concurrency issue.
         
     | 
| 
       6 
88 
     | 
    
         | 
| 
       7 
89 
     | 
    
         
             
            - **Feature: Enhance AWS Lambda function instrumentation**
         
     | 
| 
       8 
90 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
            When utilized via the latest [New Relic Ruby layer for AWS Lambda](https://layers.newrelic-external.com/), the agent now offers enhanced support for AWS Lambda function instrumentation. 
     | 
| 
       10 
     | 
    
         
            -
            * The agent's instrumentation for AWS Lambda functions now supports distributed tracing. 
     | 
| 
       11 
     | 
    
         
            -
            * Web-triggered invocations are now identified as being "web"-based when an API Gateway call is involved, with support for both API Gateway versions 1.0 and 2.0. 
     | 
| 
       12 
     | 
    
         
            -
            * Web-based calls have the HTTP method, URI, and status code recorded. 
     | 
| 
       13 
     | 
    
         
            -
            * The agent now recognizes and reports on 12 separate AWS resources that are capable of triggering a Lambda function invocation: ALB, API Gateway V1, API Gateway V2, CloudFront, CloudWatch Scheduler, DynamoStreams, Firehose, Kinesis, S3, SES, SNS, and SQS. 
     | 
| 
      
 91 
     | 
    
         
            +
            When utilized via the latest [New Relic Ruby layer for AWS Lambda](https://layers.newrelic-external.com/), the agent now offers enhanced support for AWS Lambda function instrumentation.
         
     | 
| 
      
 92 
     | 
    
         
            +
            * The agent's instrumentation for AWS Lambda functions now supports distributed tracing.
         
     | 
| 
      
 93 
     | 
    
         
            +
            * Web-triggered invocations are now identified as being "web"-based when an API Gateway call is involved, with support for both API Gateway versions 1.0 and 2.0.
         
     | 
| 
      
 94 
     | 
    
         
            +
            * Web-based calls have the HTTP method, URI, and status code recorded.
         
     | 
| 
      
 95 
     | 
    
         
            +
            * The agent now recognizes and reports on 12 separate AWS resources that are capable of triggering a Lambda function invocation: ALB, API Gateway V1, API Gateway V2, CloudFront, CloudWatch Scheduler, DynamoStreams, Firehose, Kinesis, S3, SES, SNS, and SQS.
         
     | 
| 
       14 
96 
     | 
    
         
             
            * The type of the triggering resource and its ARN will be recorded for each resource, and for many of them, extra resource-specific attributes will be recorded as well. For example, Lambda function invocations triggered by S3 bucket activity will now result in the S3 bucket name being recorded.
         
     | 
| 
       15 
97 
     | 
    
         
             
            [PR#2811](https://github.com/newrelic/newrelic-ruby-agent/pull/2811)
         
     | 
| 
       16 
98 
     | 
    
         | 
| 
         @@ -35,6 +35,15 @@ module NewRelic 
     | 
|
| 
       35 
35 
     | 
    
         
             
                  end
         
     | 
| 
       36 
36 
     | 
    
         | 
| 
       37 
37 
     | 
    
         
             
                  class DefaultSource
         
     | 
| 
      
 38 
     | 
    
         
            +
                    BOOLEAN_MAP = {
         
     | 
| 
      
 39 
     | 
    
         
            +
                      'true' => true,
         
     | 
| 
      
 40 
     | 
    
         
            +
                      'yes' => true,
         
     | 
| 
      
 41 
     | 
    
         
            +
                      'on' => true,
         
     | 
| 
      
 42 
     | 
    
         
            +
                      'false' => false,
         
     | 
| 
      
 43 
     | 
    
         
            +
                      'no' => false,
         
     | 
| 
      
 44 
     | 
    
         
            +
                      'off' => false
         
     | 
| 
      
 45 
     | 
    
         
            +
                    }.freeze
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
       38 
47 
     | 
    
         
             
                    attr_reader :defaults
         
     | 
| 
       39 
48 
     | 
    
         | 
| 
       40 
49 
     | 
    
         
             
                    extend Forwardable
         
     | 
| 
         @@ -64,6 +73,12 @@ module NewRelic 
     | 
|
| 
       64 
73 
     | 
    
         
             
                      value_from_defaults(key, :allowlist)
         
     | 
| 
       65 
74 
     | 
    
         
             
                    end
         
     | 
| 
       66 
75 
     | 
    
         | 
| 
      
 76 
     | 
    
         
            +
                    def self.boolean_for(key, value)
         
     | 
| 
      
 77 
     | 
    
         
            +
                      string_value = (value.respond_to?(:call) ? value.call : value).to_s
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                      BOOLEAN_MAP.fetch(string_value, nil)
         
     | 
| 
      
 80 
     | 
    
         
            +
                    end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
       67 
82 
     | 
    
         
             
                    def self.default_for(key)
         
     | 
| 
       68 
83 
     | 
    
         
             
                      value_from_defaults(key, :default)
         
     | 
| 
       69 
84 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -1137,6 +1152,56 @@ module NewRelic 
     | 
|
| 
       1137 
1152 
     | 
    
         
             
                      :allowed_from_server => false,
         
     | 
| 
       1138 
1153 
     | 
    
         
             
                      :description => 'If `false`, custom attributes will not be sent on events.'
         
     | 
| 
       1139 
1154 
     | 
    
         
             
                    },
         
     | 
| 
      
 1155 
     | 
    
         
            +
                    :automatic_custom_instrumentation_method_list => {
         
     | 
| 
      
 1156 
     | 
    
         
            +
                      :default => NewRelic::EMPTY_ARRAY,
         
     | 
| 
      
 1157 
     | 
    
         
            +
                      :public => true,
         
     | 
| 
      
 1158 
     | 
    
         
            +
                      :type => Array,
         
     | 
| 
      
 1159 
     | 
    
         
            +
                      :allowed_from_server => false,
         
     | 
| 
      
 1160 
     | 
    
         
            +
                      :transform => proc { |arr| NewRelic::Agent.add_automatic_method_tracers(arr) },
         
     | 
| 
      
 1161 
     | 
    
         
            +
                      :description => <<~DESCRIPTION
         
     | 
| 
      
 1162 
     | 
    
         
            +
                        An array of `CLASS#METHOD` (for instance methods) and/or `CLASS.METHOD` (for class methods) strings representing Ruby methods for the agent to automatically add custom instrumentation to without the need for altering any of the source code that defines the methods.
         
     | 
| 
      
 1163 
     | 
    
         
            +
             
     | 
| 
      
 1164 
     | 
    
         
            +
                        Use fully qualified class names (using the `::` delimiter) that include any module or class namespacing.
         
     | 
| 
      
 1165 
     | 
    
         
            +
             
     | 
| 
      
 1166 
     | 
    
         
            +
                        Here is some Ruby source code that defines a `render_png` instance method for an `Image` class and a `notify` class method for a `User` class, both within a `MyCompany` module namespace:
         
     | 
| 
      
 1167 
     | 
    
         
            +
             
     | 
| 
      
 1168 
     | 
    
         
            +
                        ```
         
     | 
| 
      
 1169 
     | 
    
         
            +
                        module MyCompany
         
     | 
| 
      
 1170 
     | 
    
         
            +
                          class Image
         
     | 
| 
      
 1171 
     | 
    
         
            +
                            def render_png
         
     | 
| 
      
 1172 
     | 
    
         
            +
                              # code to render a PNG
         
     | 
| 
      
 1173 
     | 
    
         
            +
                            end
         
     | 
| 
      
 1174 
     | 
    
         
            +
                          end
         
     | 
| 
      
 1175 
     | 
    
         
            +
             
     | 
| 
      
 1176 
     | 
    
         
            +
                          class User
         
     | 
| 
      
 1177 
     | 
    
         
            +
                            def self.notify
         
     | 
| 
      
 1178 
     | 
    
         
            +
                              # code to notify users
         
     | 
| 
      
 1179 
     | 
    
         
            +
                            end
         
     | 
| 
      
 1180 
     | 
    
         
            +
                          end
         
     | 
| 
      
 1181 
     | 
    
         
            +
                        end
         
     | 
| 
      
 1182 
     | 
    
         
            +
                        ```
         
     | 
| 
      
 1183 
     | 
    
         
            +
             
     | 
| 
      
 1184 
     | 
    
         
            +
                        Given that source code, the `newrelic.yml` config file might request instrumentation for both of these methods like so:
         
     | 
| 
      
 1185 
     | 
    
         
            +
             
     | 
| 
      
 1186 
     | 
    
         
            +
                        ```
         
     | 
| 
      
 1187 
     | 
    
         
            +
                        automatic_custom_instrumentation_method_list:
         
     | 
| 
      
 1188 
     | 
    
         
            +
                          - MyCompany::Image#render_png
         
     | 
| 
      
 1189 
     | 
    
         
            +
                          - MyCompany::User.notify
         
     | 
| 
      
 1190 
     | 
    
         
            +
                        ```
         
     | 
| 
      
 1191 
     | 
    
         
            +
             
     | 
| 
      
 1192 
     | 
    
         
            +
                        That configuration example uses YAML array syntax to specify both methods. Alternatively, a comma-delimited string can be used instead:
         
     | 
| 
      
 1193 
     | 
    
         
            +
             
     | 
| 
      
 1194 
     | 
    
         
            +
                        ```
         
     | 
| 
      
 1195 
     | 
    
         
            +
                        automatic_custom_instrumentation_method_list: 'MyCompany::Image#render_png, MyCompany::User.notify'
         
     | 
| 
      
 1196 
     | 
    
         
            +
                        ```
         
     | 
| 
      
 1197 
     | 
    
         
            +
             
     | 
| 
      
 1198 
     | 
    
         
            +
                        Whitespace around the comma(s) in the list is optional. When configuring the agent with a list of methods via the `NEW_RELIC_AUTOMATIC_CUSTOM_INSTRUMENTATION_METHOD_LIST` environment variable, this comma-delimited string format should be used:
         
     | 
| 
      
 1199 
     | 
    
         
            +
             
     | 
| 
      
 1200 
     | 
    
         
            +
                        ```
         
     | 
| 
      
 1201 
     | 
    
         
            +
                        export NEW_RELIC_AUTOMATIC_CUSTOM_INSTRUMENTATION_METHOD_LIST='MyCompany::Image#render_png, MyCompany::User.notify'
         
     | 
| 
      
 1202 
     | 
    
         
            +
                        ```
         
     | 
| 
      
 1203 
     | 
    
         
            +
                      DESCRIPTION
         
     | 
| 
      
 1204 
     | 
    
         
            +
                    },
         
     | 
| 
       1140 
1205 
     | 
    
         
             
                    # Custom events
         
     | 
| 
       1141 
1206 
     | 
    
         
             
                    :'custom_insights_events.enabled' => {
         
     | 
| 
       1142 
1207 
     | 
    
         
             
                      :default => true,
         
     | 
| 
         @@ -1463,6 +1528,14 @@ module NewRelic 
     | 
|
| 
       1463 
1528 
     | 
    
         
             
                      :allowed_from_server => false,
         
     | 
| 
       1464 
1529 
     | 
    
         
             
                      :description => 'Controls auto-instrumentation of bunny at start-up. May be one of: `auto`, `prepend`, `chain`, `disabled`.'
         
     | 
| 
       1465 
1530 
     | 
    
         
             
                    },
         
     | 
| 
      
 1531 
     | 
    
         
            +
                    :'instrumentation.ruby_kafka' => {
         
     | 
| 
      
 1532 
     | 
    
         
            +
                      :default => 'auto',
         
     | 
| 
      
 1533 
     | 
    
         
            +
                      :public => true,
         
     | 
| 
      
 1534 
     | 
    
         
            +
                      :type => String,
         
     | 
| 
      
 1535 
     | 
    
         
            +
                      :dynamic_name => true,
         
     | 
| 
      
 1536 
     | 
    
         
            +
                      :allowed_from_server => false,
         
     | 
| 
      
 1537 
     | 
    
         
            +
                      :description => 'Controls auto-instrumentation of the ruby-kafka library at start-up. May be one of `auto`, `prepend`, `chain`, `disabled`.'
         
     | 
| 
      
 1538 
     | 
    
         
            +
                    },
         
     | 
| 
       1466 
1539 
     | 
    
         
             
                    :'instrumentation.opensearch' => {
         
     | 
| 
       1467 
1540 
     | 
    
         
             
                      :default => 'auto',
         
     | 
| 
       1468 
1541 
     | 
    
         
             
                      :documentation_default => 'auto',
         
     | 
| 
         @@ -1472,6 +1545,14 @@ module NewRelic 
     | 
|
| 
       1472 
1545 
     | 
    
         
             
                      :allowed_from_server => false,
         
     | 
| 
       1473 
1546 
     | 
    
         
             
                      :description => 'Controls auto-instrumentation of the opensearch-ruby library at start-up. May be one of `auto`, `prepend`, `chain`, `disabled`.'
         
     | 
| 
       1474 
1547 
     | 
    
         
             
                    },
         
     | 
| 
      
 1548 
     | 
    
         
            +
                    :'instrumentation.rdkafka' => {
         
     | 
| 
      
 1549 
     | 
    
         
            +
                      :default => 'auto',
         
     | 
| 
      
 1550 
     | 
    
         
            +
                      :public => true,
         
     | 
| 
      
 1551 
     | 
    
         
            +
                      :type => String,
         
     | 
| 
      
 1552 
     | 
    
         
            +
                      :dynamic_name => true,
         
     | 
| 
      
 1553 
     | 
    
         
            +
                      :allowed_from_server => false,
         
     | 
| 
      
 1554 
     | 
    
         
            +
                      :description => 'Controls auto-instrumentation of the rdkafka library at start-up. May be one of `auto`, `prepend`, `chain`, `disabled`.'
         
     | 
| 
      
 1555 
     | 
    
         
            +
                    },
         
     | 
| 
       1475 
1556 
     | 
    
         
             
                    :'instrumentation.aws_sqs' => {
         
     | 
| 
       1476 
1557 
     | 
    
         
             
                      :default => 'auto',
         
     | 
| 
       1477 
1558 
     | 
    
         
             
                      :public => true,
         
     | 
| 
         @@ -2202,7 +2283,7 @@ module NewRelic 
     | 
|
| 
       2202 
2283 
     | 
    
         
             
                      :description => 'Enable or disable debugging version of JavaScript agent loader for browser monitoring instrumentation.'
         
     | 
| 
       2203 
2284 
     | 
    
         
             
                    },
         
     | 
| 
       2204 
2285 
     | 
    
         
             
                    :'browser_monitoring.ssl_for_http' => {
         
     | 
| 
       2205 
     | 
    
         
            -
                      :default =>  
     | 
| 
      
 2286 
     | 
    
         
            +
                      :default => false,
         
     | 
| 
       2206 
2287 
     | 
    
         
             
                      :allow_nil => true,
         
     | 
| 
       2207 
2288 
     | 
    
         
             
                      :public => false,
         
     | 
| 
       2208 
2289 
     | 
    
         
             
                      :type => Boolean,
         
     | 
| 
         @@ -92,7 +92,11 @@ module NewRelic 
     | 
|
| 
       92 
92 
     | 
    
         
             
                      elsif type == Symbol
         
     | 
| 
       93 
93 
     | 
    
         
             
                        self[config_key] = value.to_sym
         
     | 
| 
       94 
94 
     | 
    
         
             
                      elsif type == Array
         
     | 
| 
       95 
     | 
    
         
            -
                        self[config_key] =  
     | 
| 
      
 95 
     | 
    
         
            +
                        self[config_key] = if DEFAULTS[config_key].key?(:transform)
         
     | 
| 
      
 96 
     | 
    
         
            +
                          DEFAULTS[config_key][:transform].call(value)
         
     | 
| 
      
 97 
     | 
    
         
            +
                        else
         
     | 
| 
      
 98 
     | 
    
         
            +
                          value.split(/\s*,\s*/)
         
     | 
| 
      
 99 
     | 
    
         
            +
                        end
         
     | 
| 
       96 
100 
     | 
    
         
             
                      elsif type == NewRelic::Agent::Configuration::Boolean
         
     | 
| 
       97 
101 
     | 
    
         
             
                        if /false|off|no/i.match?(value)
         
     | 
| 
       98 
102 
     | 
    
         
             
                          self[config_key] = false
         
     | 
| 
         @@ -142,6 +142,9 @@ module NewRelic 
     | 
|
| 
       142 
142 
     | 
    
         
             
                      default = enforce_allowlist(key, evaluated)
         
     | 
| 
       143 
143 
     | 
    
         
             
                      return default if default
         
     | 
| 
       144 
144 
     | 
    
         | 
| 
      
 145 
     | 
    
         
            +
                      boolean = enforce_boolean(key, value)
         
     | 
| 
      
 146 
     | 
    
         
            +
                      return boolean if [true, false].include?(boolean)
         
     | 
| 
      
 147 
     | 
    
         
            +
             
     | 
| 
       145 
148 
     | 
    
         
             
                      apply_transformations(key, evaluated)
         
     | 
| 
       146 
149 
     | 
    
         
             
                    end
         
     | 
| 
       147 
150 
     | 
    
         | 
| 
         @@ -167,6 +170,18 @@ module NewRelic 
     | 
|
| 
       167 
170 
     | 
    
         
             
                      default
         
     | 
| 
       168 
171 
     | 
    
         
             
                    end
         
     | 
| 
       169 
172 
     | 
    
         | 
| 
      
 173 
     | 
    
         
            +
                    def enforce_boolean(key, value)
         
     | 
| 
      
 174 
     | 
    
         
            +
                      type = default_source.value_from_defaults(key, :type)
         
     | 
| 
      
 175 
     | 
    
         
            +
                      return unless type == Boolean
         
     | 
| 
      
 176 
     | 
    
         
            +
             
     | 
| 
      
 177 
     | 
    
         
            +
                      bool_value = default_source.boolean_for(key, value)
         
     | 
| 
      
 178 
     | 
    
         
            +
                      return bool_value unless bool_value.nil?
         
     | 
| 
      
 179 
     | 
    
         
            +
             
     | 
| 
      
 180 
     | 
    
         
            +
                      default = default_source.default_for(key)
         
     | 
| 
      
 181 
     | 
    
         
            +
                      NewRelic::Agent.logger.warn "Invalid value '#{value}' for #{key}, applying default value of '#{default}'"
         
     | 
| 
      
 182 
     | 
    
         
            +
                      default
         
     | 
| 
      
 183 
     | 
    
         
            +
                    end
         
     | 
| 
      
 184 
     | 
    
         
            +
             
     | 
| 
       170 
185 
     | 
    
         
             
                    def transform_from_default(key)
         
     | 
| 
       171 
186 
     | 
    
         
             
                      default_source.transform_for(key)
         
     | 
| 
       172 
187 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -388,7 +403,7 @@ module NewRelic 
     | 
|
| 
       388 
403 
     | 
    
         
             
                      # modified. The hash really only needs to be modified for the benefit
         
     | 
| 
       389 
404 
     | 
    
         
             
                      # of the security agent, so if JRuby is in play and the security agent
         
     | 
| 
       390 
405 
     | 
    
         
             
                      # is not, don't attempt to modify the hash at all and return early.
         
     | 
| 
       391 
     | 
    
         
            -
                      return  
     | 
| 
      
 406 
     | 
    
         
            +
                      return new_cache if NewRelic::LanguageSupport.jruby? && !Agent.config[:'security.agent.enabled']
         
     | 
| 
       392 
407 
     | 
    
         | 
| 
       393 
408 
     | 
    
         
             
                      @lock.synchronize do
         
     | 
| 
       394 
409 
     | 
    
         
             
                        preserved = @cache.dup.select { |_k, v| DEPENDENCY_DETECTION_VALUES.include?(v) }
         
     | 
| 
         @@ -7,17 +7,17 @@ module NewRelic 
     | 
|
| 
       7 
7 
     | 
    
         
             
                module Database
         
     | 
| 
       8 
8 
     | 
    
         
             
                  module ObfuscationHelpers
         
     | 
| 
       9 
9 
     | 
    
         
             
                    COMPONENTS_REGEX_MAP = {
         
     | 
| 
       10 
     | 
    
         
            -
                      : 
     | 
| 
       11 
     | 
    
         
            -
                      : 
     | 
| 
       12 
     | 
    
         
            -
                      : 
     | 
| 
       13 
     | 
    
         
            -
                      : 
     | 
| 
       14 
     | 
    
         
            -
                      : 
     | 
| 
       15 
     | 
    
         
            -
                      : 
     | 
| 
       16 
     | 
    
         
            -
                      : 
     | 
| 
       17 
     | 
    
         
            -
                      : 
     | 
| 
       18 
     | 
    
         
            -
                      : 
     | 
| 
       19 
     | 
    
         
            -
                      : 
     | 
| 
       20 
     | 
    
         
            -
                    }
         
     | 
| 
      
 10 
     | 
    
         
            +
                      single_quotes: /'(?:[^']|'')*?(?:\\'.*|'(?!'))/,
         
     | 
| 
      
 11 
     | 
    
         
            +
                      double_quotes: /"(?:[^"]|"")*?(?:\\".*|"(?!"))/,
         
     | 
| 
      
 12 
     | 
    
         
            +
                      dollar_quotes: /(\$(?!\d)[^$]*?\$).*?(?:\1|$)/,
         
     | 
| 
      
 13 
     | 
    
         
            +
                      uuids: /\{?(?:[0-9a-fA-F]-*){32}\}?/,
         
     | 
| 
      
 14 
     | 
    
         
            +
                      numeric_literals: /-?\b(?:[0-9]+\.)?[0-9]+([eE][+-]?[0-9]+)?\b/,
         
     | 
| 
      
 15 
     | 
    
         
            +
                      boolean_literals: /\b(?:true|false|null)\b/i,
         
     | 
| 
      
 16 
     | 
    
         
            +
                      hexadecimal_literals: /0x[0-9a-fA-F]+/,
         
     | 
| 
      
 17 
     | 
    
         
            +
                      comments: /(?:#|--).*?(?=\r|\n|$)/i,
         
     | 
| 
      
 18 
     | 
    
         
            +
                      multi_line_comments: %r{/\*.*?\*/}m,
         
     | 
| 
      
 19 
     | 
    
         
            +
                      oracle_quoted_strings: /q'\[.*?(?:\]'|$)|q'\{.*?(?:\}'|$)|q'<.*?(?:>'|$)|q'\(.*?(?:\)'|$)/
         
     | 
| 
      
 20 
     | 
    
         
            +
                    }.freeze
         
     | 
| 
       21 
21 
     | 
    
         | 
| 
       22 
22 
     | 
    
         
             
                    DIALECT_COMPONENTS = {
         
     | 
| 
       23 
23 
     | 
    
         
             
                      :fallback => COMPONENTS_REGEX_MAP.keys,
         
     | 
| 
         @@ -31,8 +31,9 @@ module NewRelic::Agent::Instrumentation 
     | 
|
| 
       31 
31 
     | 
    
         
             
                    collection: args[0][:table_name]
         
     | 
| 
       32 
32 
     | 
    
         
             
                  )
         
     | 
| 
       33 
33 
     | 
    
         | 
| 
       34 
     | 
    
         
            -
                   
     | 
| 
       35 
     | 
    
         
            -
                   
     | 
| 
      
 34 
     | 
    
         
            +
                  # TODO: Update this when it has been decided how to handle account id for ARN
         
     | 
| 
      
 35 
     | 
    
         
            +
                  # arn = get_arn(args[0])
         
     | 
| 
      
 36 
     | 
    
         
            +
                  # segment&.add_agent_attribute('cloud.resource_id', arn) if arn
         
     | 
| 
       36 
37 
     | 
    
         | 
| 
       37 
38 
     | 
    
         
             
                  @nr_captured_request = nil # clear request just in case
         
     | 
| 
       38 
39 
     | 
    
         
             
                  begin
         
     | 
| 
         @@ -20,7 +20,7 @@ DependencyDetection.defer do 
     | 
|
| 
       20 
20 
     | 
    
         
             
              depends_on do
         
     | 
| 
       21 
21 
     | 
    
         
             
                begin
         
     | 
| 
       22 
22 
     | 
    
         
             
                  if defined?(Bundler) &&
         
     | 
| 
       23 
     | 
    
         
            -
                      (( 
     | 
| 
      
 23 
     | 
    
         
            +
                      ((Bundler.rubygems.respond_to?(:installed_specs) && Bundler.rubygems.installed_specs.map(&:name).include?('newrelic-grape')) ||
         
     | 
| 
       24 
24 
     | 
    
         
             
                        Bundler.rubygems.all_specs.map(&:name).include?('newrelic-grape'))
         
     | 
| 
       25 
25 
     | 
    
         
             
                    NewRelic::Agent.logger.info('Not installing New Relic supported Grape instrumentation because the third party newrelic-grape gem is present')
         
     | 
| 
       26 
26 
     | 
    
         
             
                    false
         
     | 
| 
         @@ -0,0 +1,71 @@ 
     | 
|
| 
      
 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 'instrumentation'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            module NewRelic::Agent::Instrumentation
         
     | 
| 
      
 8 
     | 
    
         
            +
              module Rdkafka::Chain
         
     | 
| 
      
 9 
     | 
    
         
            +
                def self.instrument!
         
     | 
| 
      
 10 
     | 
    
         
            +
                  ::Rdkafka::Producer.class_eval do
         
     | 
| 
      
 11 
     | 
    
         
            +
                    include NewRelic::Agent::Instrumentation::Rdkafka
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                    alias_method(:produce_without_new_relic, :produce)
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                    def produce(**kwargs)
         
     | 
| 
      
 16 
     | 
    
         
            +
                      produce_with_new_relic(kwargs) do |headers|
         
     | 
| 
      
 17 
     | 
    
         
            +
                        kwargs[:headers] = headers
         
     | 
| 
      
 18 
     | 
    
         
            +
                        produce_without_new_relic(**kwargs)
         
     | 
| 
      
 19 
     | 
    
         
            +
                      end
         
     | 
| 
      
 20 
     | 
    
         
            +
                    end
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  ::Rdkafka::Consumer.class_eval do
         
     | 
| 
      
 24 
     | 
    
         
            +
                    include NewRelic::Agent::Instrumentation::Rdkafka
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                    alias_method(:each_without_new_relic, :each)
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                    def each(**kwargs)
         
     | 
| 
      
 29 
     | 
    
         
            +
                      each_without_new_relic(**kwargs) do |message|
         
     | 
| 
      
 30 
     | 
    
         
            +
                        each_with_new_relic(message) do
         
     | 
| 
      
 31 
     | 
    
         
            +
                          yield(message)
         
     | 
| 
      
 32 
     | 
    
         
            +
                        end
         
     | 
| 
      
 33 
     | 
    
         
            +
                      end
         
     | 
| 
      
 34 
     | 
    
         
            +
                    end
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  ::Rdkafka::Config.class_eval do
         
     | 
| 
      
 38 
     | 
    
         
            +
                    include NewRelic::Agent::Instrumentation::RdkafkaConfig
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                    alias_method(:producer_without_new_relic, :producer)
         
     | 
| 
      
 41 
     | 
    
         
            +
                    alias_method(:consumer_without_new_relic, :consumer)
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                    if Gem::Version.new(::Rdkafka::VERSION) >= Gem::Version.new('0.16.0')
         
     | 
| 
      
 44 
     | 
    
         
            +
                      def producer(**kwargs)
         
     | 
| 
      
 45 
     | 
    
         
            +
                        producer_without_new_relic(**kwargs).tap do |producer|
         
     | 
| 
      
 46 
     | 
    
         
            +
                          set_nr_config(producer)
         
     | 
| 
      
 47 
     | 
    
         
            +
                        end
         
     | 
| 
      
 48 
     | 
    
         
            +
                      end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                      def consumer(**kwargs)
         
     | 
| 
      
 51 
     | 
    
         
            +
                        consumer_without_new_relic(**kwargs).tap do |consumer|
         
     | 
| 
      
 52 
     | 
    
         
            +
                          set_nr_config(consumer)
         
     | 
| 
      
 53 
     | 
    
         
            +
                        end
         
     | 
| 
      
 54 
     | 
    
         
            +
                      end
         
     | 
| 
      
 55 
     | 
    
         
            +
                    else
         
     | 
| 
      
 56 
     | 
    
         
            +
                      def producer
         
     | 
| 
      
 57 
     | 
    
         
            +
                        producer_without_new_relic.tap do |producer|
         
     | 
| 
      
 58 
     | 
    
         
            +
                          set_nr_config(producer)
         
     | 
| 
      
 59 
     | 
    
         
            +
                        end
         
     | 
| 
      
 60 
     | 
    
         
            +
                      end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                      def consumer
         
     | 
| 
      
 63 
     | 
    
         
            +
                        consumer_without_new_relic.tap do |consumer|
         
     | 
| 
      
 64 
     | 
    
         
            +
                          set_nr_config(consumer)
         
     | 
| 
      
 65 
     | 
    
         
            +
                        end
         
     | 
| 
      
 66 
     | 
    
         
            +
                      end
         
     | 
| 
      
 67 
     | 
    
         
            +
                    end
         
     | 
| 
      
 68 
     | 
    
         
            +
                  end
         
     | 
| 
      
 69 
     | 
    
         
            +
                end
         
     | 
| 
      
 70 
     | 
    
         
            +
              end
         
     | 
| 
      
 71 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,70 @@ 
     | 
|
| 
      
 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/messaging'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            module NewRelic::Agent::Instrumentation
         
     | 
| 
      
 8 
     | 
    
         
            +
              module Rdkafka
         
     | 
| 
      
 9 
     | 
    
         
            +
                MESSAGING_LIBRARY = 'Kafka'
         
     | 
| 
      
 10 
     | 
    
         
            +
                PRODUCE = 'Produce'
         
     | 
| 
      
 11 
     | 
    
         
            +
                CONSUME = 'Consume'
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                INSTRUMENTATION_NAME = 'Rdkafka'
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def produce_with_new_relic(*args)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  topic_name = args[0][:topic]
         
     | 
| 
      
 19 
     | 
    
         
            +
                  segment = NewRelic::Agent::Tracer.start_message_broker_segment(
         
     | 
| 
      
 20 
     | 
    
         
            +
                    action: :produce,
         
     | 
| 
      
 21 
     | 
    
         
            +
                    library: MESSAGING_LIBRARY,
         
     | 
| 
      
 22 
     | 
    
         
            +
                    destination_type: :topic,
         
     | 
| 
      
 23 
     | 
    
         
            +
                    destination_name: topic_name
         
     | 
| 
      
 24 
     | 
    
         
            +
                  )
         
     | 
| 
      
 25 
     | 
    
         
            +
                  create_kafka_metrics(action: PRODUCE, topic: topic_name)
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  headers = args[0][:headers] || {}
         
     | 
| 
      
 28 
     | 
    
         
            +
                  ::NewRelic::Agent::DistributedTracing.insert_distributed_trace_headers(headers)
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  NewRelic::Agent::Tracer.capture_segment_error(segment) { yield(headers) }
         
     | 
| 
      
 31 
     | 
    
         
            +
                ensure
         
     | 
| 
      
 32 
     | 
    
         
            +
                  segment&.finish
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                def each_with_new_relic(message)
         
     | 
| 
      
 36 
     | 
    
         
            +
                  NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                  headers = message&.headers || {}
         
     | 
| 
      
 39 
     | 
    
         
            +
                  topic_name = message&.topic
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  NewRelic::Agent::Messaging.wrap_message_broker_consume_transaction(
         
     | 
| 
      
 42 
     | 
    
         
            +
                    library: MESSAGING_LIBRARY,
         
     | 
| 
      
 43 
     | 
    
         
            +
                    destination_type: :topic,
         
     | 
| 
      
 44 
     | 
    
         
            +
                    destination_name: topic_name,
         
     | 
| 
      
 45 
     | 
    
         
            +
                    headers: headers,
         
     | 
| 
      
 46 
     | 
    
         
            +
                    action: :consume
         
     | 
| 
      
 47 
     | 
    
         
            +
                  ) do
         
     | 
| 
      
 48 
     | 
    
         
            +
                    create_kafka_metrics(action: CONSUME, topic: topic_name)
         
     | 
| 
      
 49 
     | 
    
         
            +
                    yield
         
     | 
| 
      
 50 
     | 
    
         
            +
                  end
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                def create_kafka_metrics(action:, topic:)
         
     | 
| 
      
 54 
     | 
    
         
            +
                  hosts = []
         
     | 
| 
      
 55 
     | 
    
         
            +
                  # both 'bootstrap.servers' and 'metadata.broker.list' are valid ways to specify the Kafka server
         
     | 
| 
      
 56 
     | 
    
         
            +
                  hosts << @nr_config[:'bootstrap.servers'] if @nr_config[:'bootstrap.servers']
         
     | 
| 
      
 57 
     | 
    
         
            +
                  hosts << @nr_config[:'metadata.broker.list'] if @nr_config[:'metadata.broker.list']
         
     | 
| 
      
 58 
     | 
    
         
            +
                  hosts.each do |host|
         
     | 
| 
      
 59 
     | 
    
         
            +
                    NewRelic::Agent.record_metric("MessageBroker/Kafka/Nodes/#{host}/#{action}/#{topic}", 1)
         
     | 
| 
      
 60 
     | 
    
         
            +
                    NewRelic::Agent.record_metric("MessageBroker/Kafka/Nodes/#{host}", 1)
         
     | 
| 
      
 61 
     | 
    
         
            +
                  end
         
     | 
| 
      
 62 
     | 
    
         
            +
                end
         
     | 
| 
      
 63 
     | 
    
         
            +
              end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
              module RdkafkaConfig
         
     | 
| 
      
 66 
     | 
    
         
            +
                def set_nr_config(producer_or_consumer)
         
     | 
| 
      
 67 
     | 
    
         
            +
                  producer_or_consumer.instance_variable_set(:@nr_config, self)
         
     | 
| 
      
 68 
     | 
    
         
            +
                end
         
     | 
| 
      
 69 
     | 
    
         
            +
              end
         
     | 
| 
      
 70 
     | 
    
         
            +
            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 'instrumentation'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            module NewRelic::Agent::Instrumentation
         
     | 
| 
      
 8 
     | 
    
         
            +
              module RdkafkaProducer
         
     | 
| 
      
 9 
     | 
    
         
            +
                module Prepend
         
     | 
| 
      
 10 
     | 
    
         
            +
                  include NewRelic::Agent::Instrumentation::Rdkafka
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  def produce(**kwargs)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    produce_with_new_relic(kwargs) do |headers|
         
     | 
| 
      
 14 
     | 
    
         
            +
                      kwargs[:headers] = headers
         
     | 
| 
      
 15 
     | 
    
         
            +
                      super
         
     | 
| 
      
 16 
     | 
    
         
            +
                    end
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              module RdkafkaConsumer
         
     | 
| 
      
 22 
     | 
    
         
            +
                module Prepend
         
     | 
| 
      
 23 
     | 
    
         
            +
                  include NewRelic::Agent::Instrumentation::Rdkafka
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  def each
         
     | 
| 
      
 26 
     | 
    
         
            +
                    super do |message|
         
     | 
| 
      
 27 
     | 
    
         
            +
                      each_with_new_relic(message) do
         
     | 
| 
      
 28 
     | 
    
         
            +
                        yield(message)
         
     | 
| 
      
 29 
     | 
    
         
            +
                      end
         
     | 
| 
      
 30 
     | 
    
         
            +
                    end
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
              module RdkafkaConfig
         
     | 
| 
      
 36 
     | 
    
         
            +
                module Prepend
         
     | 
| 
      
 37 
     | 
    
         
            +
                  include NewRelic::Agent::Instrumentation::RdkafkaConfig
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  if defined?(::Rdkafka) && Gem::Version.new(::Rdkafka::VERSION) >= Gem::Version.new('0.16.0')
         
     | 
| 
      
 40 
     | 
    
         
            +
                    def producer(**kwargs)
         
     | 
| 
      
 41 
     | 
    
         
            +
                      super.tap do |producer|
         
     | 
| 
      
 42 
     | 
    
         
            +
                        set_nr_config(producer)
         
     | 
| 
      
 43 
     | 
    
         
            +
                      end
         
     | 
| 
      
 44 
     | 
    
         
            +
                    end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                    def consumer(**kwargs)
         
     | 
| 
      
 47 
     | 
    
         
            +
                      super.tap do |consumer|
         
     | 
| 
      
 48 
     | 
    
         
            +
                        set_nr_config(consumer)
         
     | 
| 
      
 49 
     | 
    
         
            +
                      end
         
     | 
| 
      
 50 
     | 
    
         
            +
                    end
         
     | 
| 
      
 51 
     | 
    
         
            +
                  else # older versions
         
     | 
| 
      
 52 
     | 
    
         
            +
                    def producer
         
     | 
| 
      
 53 
     | 
    
         
            +
                      super.tap do |producer|
         
     | 
| 
      
 54 
     | 
    
         
            +
                        set_nr_config(producer)
         
     | 
| 
      
 55 
     | 
    
         
            +
                      end
         
     | 
| 
      
 56 
     | 
    
         
            +
                    end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                    def consumer
         
     | 
| 
      
 59 
     | 
    
         
            +
                      super.tap do |consumer|
         
     | 
| 
      
 60 
     | 
    
         
            +
                        set_nr_config(consumer)
         
     | 
| 
      
 61 
     | 
    
         
            +
                      end
         
     | 
| 
      
 62 
     | 
    
         
            +
                    end
         
     | 
| 
      
 63 
     | 
    
         
            +
                  end
         
     | 
| 
      
 64 
     | 
    
         
            +
                end
         
     | 
| 
      
 65 
     | 
    
         
            +
              end
         
     | 
| 
      
 66 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,27 @@ 
     | 
|
| 
      
 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 
     | 
    
         
            +
            DependencyDetection.defer do
         
     | 
| 
      
 6 
     | 
    
         
            +
              named :rdkafka
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              depends_on do
         
     | 
| 
      
 9 
     | 
    
         
            +
                defined?(Rdkafka)
         
     | 
| 
      
 10 
     | 
    
         
            +
              end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              executes do
         
     | 
| 
      
 13 
     | 
    
         
            +
                NewRelic::Agent.logger.info('Installing rdkafka instrumentation')
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                require_relative 'rdkafka/instrumentation'
         
     | 
| 
      
 16 
     | 
    
         
            +
                require_relative 'rdkafka/chain'
         
     | 
| 
      
 17 
     | 
    
         
            +
                require_relative 'rdkafka/prepend'
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                if use_prepend?
         
     | 
| 
      
 20 
     | 
    
         
            +
                  prepend_instrument Rdkafka::Config, NewRelic::Agent::Instrumentation::RdkafkaConfig::Prepend
         
     | 
| 
      
 21 
     | 
    
         
            +
                  prepend_instrument Rdkafka::Producer, NewRelic::Agent::Instrumentation::RdkafkaProducer::Prepend
         
     | 
| 
      
 22 
     | 
    
         
            +
                  prepend_instrument Rdkafka::Consumer, NewRelic::Agent::Instrumentation::RdkafkaConsumer::Prepend
         
     | 
| 
      
 23 
     | 
    
         
            +
                else
         
     | 
| 
      
 24 
     | 
    
         
            +
                  chain_instrument NewRelic::Agent::Instrumentation::Rdkafka::Chain
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,55 @@ 
     | 
|
| 
      
 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 RubyKafka::Chain
         
     | 
| 
      
 7 
     | 
    
         
            +
                def self.instrument!
         
     | 
| 
      
 8 
     | 
    
         
            +
                  ::Kafka::Producer.class_eval do
         
     | 
| 
      
 9 
     | 
    
         
            +
                    include NewRelic::Agent::Instrumentation::RubyKafka
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                    alias_method(:produce_without_new_relic, :produce)
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                    def produce(value, **kwargs)
         
     | 
| 
      
 14 
     | 
    
         
            +
                      produce_with_new_relic(value, **kwargs) do |headers|
         
     | 
| 
      
 15 
     | 
    
         
            +
                        kwargs[:headers] = headers
         
     | 
| 
      
 16 
     | 
    
         
            +
                        produce_without_new_relic(value, **kwargs)
         
     | 
| 
      
 17 
     | 
    
         
            +
                      end
         
     | 
| 
      
 18 
     | 
    
         
            +
                    end
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  ::Kafka::Consumer.class_eval do
         
     | 
| 
      
 22 
     | 
    
         
            +
                    include NewRelic::Agent::Instrumentation::RubyKafka
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                    alias_method(:each_message_without_new_relic, :each_message)
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                    def each_message(*args)
         
     | 
| 
      
 27 
     | 
    
         
            +
                      each_message_without_new_relic(*args) do |message|
         
     | 
| 
      
 28 
     | 
    
         
            +
                        each_message_with_new_relic(message) do
         
     | 
| 
      
 29 
     | 
    
         
            +
                          yield(message)
         
     | 
| 
      
 30 
     | 
    
         
            +
                        end
         
     | 
| 
      
 31 
     | 
    
         
            +
                      end
         
     | 
| 
      
 32 
     | 
    
         
            +
                    end
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  ::Kafka::Client.class_eval do
         
     | 
| 
      
 36 
     | 
    
         
            +
                    include NewRelic::Agent::Instrumentation::RubyKafkaConfig
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                    alias_method(:producer_without_new_relic, :producer)
         
     | 
| 
      
 39 
     | 
    
         
            +
                    alias_method(:consumer_without_new_relic, :consumer)
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                    def producer(**kwargs)
         
     | 
| 
      
 42 
     | 
    
         
            +
                      producer_without_new_relic(**kwargs).tap do |producer|
         
     | 
| 
      
 43 
     | 
    
         
            +
                        set_nr_config(producer)
         
     | 
| 
      
 44 
     | 
    
         
            +
                      end
         
     | 
| 
      
 45 
     | 
    
         
            +
                    end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                    def consumer(**kwargs)
         
     | 
| 
      
 48 
     | 
    
         
            +
                      consumer_without_new_relic(**kwargs).tap do |consumer|
         
     | 
| 
      
 49 
     | 
    
         
            +
                        set_nr_config(consumer)
         
     | 
| 
      
 50 
     | 
    
         
            +
                      end
         
     | 
| 
      
 51 
     | 
    
         
            +
                    end
         
     | 
| 
      
 52 
     | 
    
         
            +
                  end
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
              end
         
     | 
| 
      
 55 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,67 @@ 
     | 
|
| 
      
 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/messaging'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            module NewRelic::Agent::Instrumentation
         
     | 
| 
      
 8 
     | 
    
         
            +
              module RubyKafka
         
     | 
| 
      
 9 
     | 
    
         
            +
                MESSAGING_LIBRARY = 'Kafka'
         
     | 
| 
      
 10 
     | 
    
         
            +
                PRODUCE = 'Produce'
         
     | 
| 
      
 11 
     | 
    
         
            +
                CONSUME = 'Consume'
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                INSTRUMENTATION_NAME = 'ruby-kafka'
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def produce_with_new_relic(value, **kwargs)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  topic_name = kwargs[:topic]
         
     | 
| 
      
 19 
     | 
    
         
            +
                  segment = NewRelic::Agent::Tracer.start_message_broker_segment(
         
     | 
| 
      
 20 
     | 
    
         
            +
                    action: :produce,
         
     | 
| 
      
 21 
     | 
    
         
            +
                    library: MESSAGING_LIBRARY,
         
     | 
| 
      
 22 
     | 
    
         
            +
                    destination_type: :topic,
         
     | 
| 
      
 23 
     | 
    
         
            +
                    destination_name: topic_name
         
     | 
| 
      
 24 
     | 
    
         
            +
                  )
         
     | 
| 
      
 25 
     | 
    
         
            +
                  create_kafka_metrics(action: PRODUCE, topic: topic_name)
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  headers = kwargs[:headers] || {}
         
     | 
| 
      
 28 
     | 
    
         
            +
                  ::NewRelic::Agent::DistributedTracing.insert_distributed_trace_headers(headers)
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  NewRelic::Agent::Tracer.capture_segment_error(segment) { yield(headers) }
         
     | 
| 
      
 31 
     | 
    
         
            +
                ensure
         
     | 
| 
      
 32 
     | 
    
         
            +
                  segment&.finish
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                def each_message_with_new_relic(message)
         
     | 
| 
      
 36 
     | 
    
         
            +
                  NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                  headers = message&.headers || {}
         
     | 
| 
      
 39 
     | 
    
         
            +
                  topic_name = message&.topic
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  NewRelic::Agent::Messaging.wrap_message_broker_consume_transaction(
         
     | 
| 
      
 42 
     | 
    
         
            +
                    library: MESSAGING_LIBRARY,
         
     | 
| 
      
 43 
     | 
    
         
            +
                    destination_type: :topic,
         
     | 
| 
      
 44 
     | 
    
         
            +
                    destination_name: topic_name,
         
     | 
| 
      
 45 
     | 
    
         
            +
                    headers: headers,
         
     | 
| 
      
 46 
     | 
    
         
            +
                    action: :consume
         
     | 
| 
      
 47 
     | 
    
         
            +
                  ) do
         
     | 
| 
      
 48 
     | 
    
         
            +
                    create_kafka_metrics(action: CONSUME, topic: topic_name)
         
     | 
| 
      
 49 
     | 
    
         
            +
                    yield
         
     | 
| 
      
 50 
     | 
    
         
            +
                  end
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                def create_kafka_metrics(action:, topic:)
         
     | 
| 
      
 54 
     | 
    
         
            +
                  @nr_config.each do |seed_broker|
         
     | 
| 
      
 55 
     | 
    
         
            +
                    host = "#{seed_broker&.host}:#{seed_broker&.port}"
         
     | 
| 
      
 56 
     | 
    
         
            +
                    NewRelic::Agent.record_metric("MessageBroker/Kafka/Nodes/#{host}/#{action}/#{topic}", 1)
         
     | 
| 
      
 57 
     | 
    
         
            +
                    NewRelic::Agent.record_metric("MessageBroker/Kafka/Nodes/#{host}", 1)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  end
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
              end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
              module RubyKafkaConfig
         
     | 
| 
      
 63 
     | 
    
         
            +
                def set_nr_config(producer_or_consumer)
         
     | 
| 
      
 64 
     | 
    
         
            +
                  producer_or_consumer.instance_variable_set(:@nr_config, @seed_brokers)
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
              end
         
     | 
| 
      
 67 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,50 @@ 
     | 
|
| 
      
 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 RubyKafkaProducer
         
     | 
| 
      
 7 
     | 
    
         
            +
                module Prepend
         
     | 
| 
      
 8 
     | 
    
         
            +
                  include NewRelic::Agent::Instrumentation::RubyKafka
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def produce(value, **kwargs)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    produce_with_new_relic(value, **kwargs) do |headers|
         
     | 
| 
      
 12 
     | 
    
         
            +
                      kwargs[:headers] = headers
         
     | 
| 
      
 13 
     | 
    
         
            +
                      super
         
     | 
| 
      
 14 
     | 
    
         
            +
                    end
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              module RubyKafkaConsumer
         
     | 
| 
      
 20 
     | 
    
         
            +
                module Prepend
         
     | 
| 
      
 21 
     | 
    
         
            +
                  include NewRelic::Agent::Instrumentation::RubyKafka
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  def each_message(*args)
         
     | 
| 
      
 24 
     | 
    
         
            +
                    super do |message|
         
     | 
| 
      
 25 
     | 
    
         
            +
                      each_message_with_new_relic(message) do
         
     | 
| 
      
 26 
     | 
    
         
            +
                        yield(message)
         
     | 
| 
      
 27 
     | 
    
         
            +
                      end
         
     | 
| 
      
 28 
     | 
    
         
            +
                    end
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
              end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
              module RubyKafkaClient
         
     | 
| 
      
 34 
     | 
    
         
            +
                module Prepend
         
     | 
| 
      
 35 
     | 
    
         
            +
                  include NewRelic::Agent::Instrumentation::RubyKafkaConfig
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  def producer(**kwargs)
         
     | 
| 
      
 38 
     | 
    
         
            +
                    super.tap do |producer|
         
     | 
| 
      
 39 
     | 
    
         
            +
                      set_nr_config(producer)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    end
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  def consumer(**kwargs)
         
     | 
| 
      
 44 
     | 
    
         
            +
                    super.tap do |consumer|
         
     | 
| 
      
 45 
     | 
    
         
            +
                      set_nr_config(consumer)
         
     | 
| 
      
 46 
     | 
    
         
            +
                    end
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
              end
         
     | 
| 
      
 50 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,27 @@ 
     | 
|
| 
      
 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_kafka/instrumentation'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require_relative 'ruby_kafka/chain'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require_relative 'ruby_kafka/prepend'
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            DependencyDetection.defer do
         
     | 
| 
      
 10 
     | 
    
         
            +
              named :'ruby_kafka'
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              depends_on do
         
     | 
| 
      
 13 
     | 
    
         
            +
                defined?(Kafka)
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              executes do
         
     | 
| 
      
 17 
     | 
    
         
            +
                NewRelic::Agent.logger.info('Installing ruby-kafka instrumentation')
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                if use_prepend?
         
     | 
| 
      
 20 
     | 
    
         
            +
                  prepend_instrument Kafka::Producer, NewRelic::Agent::Instrumentation::RubyKafkaProducer::Prepend
         
     | 
| 
      
 21 
     | 
    
         
            +
                  prepend_instrument Kafka::Consumer, NewRelic::Agent::Instrumentation::RubyKafkaConsumer::Prepend
         
     | 
| 
      
 22 
     | 
    
         
            +
                  prepend_instrument Kafka::Client, NewRelic::Agent::Instrumentation::RubyKafkaClient::Prepend
         
     | 
| 
      
 23 
     | 
    
         
            +
                else
         
     | 
| 
      
 24 
     | 
    
         
            +
                  chain_instrument NewRelic::Agent::Instrumentation::RubyKafka::Chain
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -11,7 +11,10 @@ module NewRelic::Agent::Instrumentation 
     | 
|
| 
       11 
11 
     | 
    
         | 
| 
       12 
12 
     | 
    
         
             
                  begin
         
     | 
| 
       13 
13 
     | 
    
         
             
                    segment = NewRelic::Agent::Tracer.start_segment(
         
     | 
| 
       14 
     | 
    
         
            -
                      name: metric_name( 
     | 
| 
      
 14 
     | 
    
         
            +
                      name: metric_name(
         
     | 
| 
      
 15 
     | 
    
         
            +
                        self.class.respond_to?(:identifier) ? self.class.identifier : nil,
         
     | 
| 
      
 16 
     | 
    
         
            +
                        self.class.name
         
     | 
| 
      
 17 
     | 
    
         
            +
                      )
         
     | 
| 
       15 
18 
     | 
    
         
             
                    )
         
     | 
| 
       16 
19 
     | 
    
         
             
                    yield
         
     | 
| 
       17 
20 
     | 
    
         
             
                  rescue => e
         
     | 
| 
         @@ -164,9 +164,8 @@ module NewRelic 
     | 
|
| 
       164 
164 
     | 
    
         | 
| 
       165 
165 
     | 
    
         
             
                  def add_ssl_for_http(data)
         
     | 
| 
       166 
166 
     | 
    
         
             
                    ssl_for_http = NewRelic::Agent.config[:'browser_monitoring.ssl_for_http']
         
     | 
| 
       167 
     | 
    
         
            -
             
     | 
| 
       168 
     | 
    
         
            -
             
     | 
| 
       169 
     | 
    
         
            -
                    end
         
     | 
| 
      
 167 
     | 
    
         
            +
             
     | 
| 
      
 168 
     | 
    
         
            +
                    data[SSL_FOR_HTTP_KEY] = ssl_for_http if ssl_for_http
         
     | 
| 
       170 
169 
     | 
    
         
             
                  end
         
     | 
| 
       171 
170 
     | 
    
         | 
| 
       172 
171 
     | 
    
         
             
                  def add_attributes(data, txn)
         
     | 
| 
         @@ -117,7 +117,8 @@ module NewRelic 
     | 
|
| 
       117 
117 
     | 
    
         
             
                    queue_name: nil,
         
     | 
| 
       118 
118 
     | 
    
         
             
                    exchange_type: nil,
         
     | 
| 
       119 
119 
     | 
    
         
             
                    reply_to: nil,
         
     | 
| 
       120 
     | 
    
         
            -
                    correlation_id: nil 
     | 
| 
      
 120 
     | 
    
         
            +
                    correlation_id: nil,
         
     | 
| 
      
 121 
     | 
    
         
            +
                    action: nil)
         
     | 
| 
       121 
122 
     | 
    
         | 
| 
       122 
123 
     | 
    
         
             
                    state = Tracer.state
         
     | 
| 
       123 
124 
     | 
    
         
             
                    return yield if state.current_transaction
         
     | 
| 
         @@ -125,12 +126,12 @@ module NewRelic 
     | 
|
| 
       125 
126 
     | 
    
         
             
                    txn = nil
         
     | 
| 
       126 
127 
     | 
    
         | 
| 
       127 
128 
     | 
    
         
             
                    begin
         
     | 
| 
       128 
     | 
    
         
            -
                      txn_name = transaction_name(library, destination_type, destination_name)
         
     | 
| 
      
 129 
     | 
    
         
            +
                      txn_name = transaction_name(library, destination_type, destination_name, action)
         
     | 
| 
       129 
130 
     | 
    
         | 
| 
       130 
131 
     | 
    
         
             
                      txn = Tracer.start_transaction(name: txn_name, category: :message)
         
     | 
| 
       131 
     | 
    
         
            -
             
     | 
| 
       132 
132 
     | 
    
         
             
                      if headers
         
     | 
| 
       133 
     | 
    
         
            -
                         
     | 
| 
      
 133 
     | 
    
         
            +
                        NewRelic::Agent::DistributedTracing::accept_distributed_trace_headers(headers, library) # to handle the new w3c headers
         
     | 
| 
      
 134 
     | 
    
         
            +
                        txn.distributed_tracer.consume_message_headers(headers, state, library) # to do the expected old things
         
     | 
| 
       134 
135 
     | 
    
         
             
                        CrossAppTracing.reject_messaging_cat_headers(headers).each do |k, v|
         
     | 
| 
       135 
136 
     | 
    
         
             
                          txn.add_agent_attribute(:"message.headers.#{k}", v, AttributeFilter::DST_NONE) unless v.nil?
         
     | 
| 
       136 
137 
     | 
    
         
             
                        end
         
     | 
| 
         @@ -327,12 +328,17 @@ module NewRelic 
     | 
|
| 
       327 
328 
     | 
    
         
             
                    NewRelic::Agent.config[:'message_tracer.segment_parameters.enabled']
         
     | 
| 
       328 
329 
     | 
    
         
             
                  end
         
     | 
| 
       329 
330 
     | 
    
         | 
| 
       330 
     | 
    
         
            -
                  def transaction_name(library, destination_type, destination_name)
         
     | 
| 
      
 331 
     | 
    
         
            +
                  def transaction_name(library, destination_type, destination_name, action = nil)
         
     | 
| 
       331 
332 
     | 
    
         
             
                    transaction_name = Transaction::MESSAGE_PREFIX + library
         
     | 
| 
       332 
333 
     | 
    
         
             
                    transaction_name << NewRelic::SLASH
         
     | 
| 
       333 
334 
     | 
    
         
             
                    transaction_name << Transaction::MessageBrokerSegment::TYPES[destination_type]
         
     | 
| 
       334 
335 
     | 
    
         
             
                    transaction_name << NewRelic::SLASH
         
     | 
| 
       335 
336 
     | 
    
         | 
| 
      
 337 
     | 
    
         
            +
                    if action == :consume
         
     | 
| 
      
 338 
     | 
    
         
            +
                      transaction_name << 'Consume'
         
     | 
| 
      
 339 
     | 
    
         
            +
                      transaction_name << NewRelic::SLASH
         
     | 
| 
      
 340 
     | 
    
         
            +
                    end
         
     | 
| 
      
 341 
     | 
    
         
            +
             
     | 
| 
       336 
342 
     | 
    
         
             
                    case destination_type
         
     | 
| 
       337 
343 
     | 
    
         
             
                    when :queue
         
     | 
| 
       338 
344 
     | 
    
         
             
                      transaction_name << Transaction::MessageBrokerSegment::NAMED
         
     | 
| 
         @@ -24,7 +24,7 @@ module NewRelic 
     | 
|
| 
       24 
24 
     | 
    
         
             
                      @referer = referer_from_request(request)
         
     | 
| 
       25 
25 
     | 
    
         
             
                      @accept = attribute_from_env(request, HTTP_ACCEPT_HEADER_KEY)
         
     | 
| 
       26 
26 
     | 
    
         
             
                      @content_length = content_length_from_request(request)
         
     | 
| 
       27 
     | 
    
         
            -
                      @content_type =  
     | 
| 
      
 27 
     | 
    
         
            +
                      @content_type = content_type_attribute_from_request(request)
         
     | 
| 
       28 
28 
     | 
    
         
             
                      @host = attribute_from_request(request, :host)
         
     | 
| 
       29 
29 
     | 
    
         
             
                      @port = port_from_request(request)
         
     | 
| 
       30 
30 
     | 
    
         
             
                      @user_agent = attribute_from_request(request, :user_agent)
         
     | 
| 
         @@ -127,6 +127,18 @@ module NewRelic 
     | 
|
| 
       127 
127 
     | 
    
         
             
                      end
         
     | 
| 
       128 
128 
     | 
    
         
             
                    end
         
     | 
| 
       129 
129 
     | 
    
         | 
| 
      
 130 
     | 
    
         
            +
                    def content_type_attribute_from_request(request)
         
     | 
| 
      
 131 
     | 
    
         
            +
                      # Rails 7.0 changed the behavior of `content_type`. We want just the MIME type, so use `media_type` if available.
         
     | 
| 
      
 132 
     | 
    
         
            +
                      # https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#actiondispatch-request-content-type-now-returns-content-type-header-as-it-is
         
     | 
| 
      
 133 
     | 
    
         
            +
                      content_type = if request.respond_to?(:media_type)
         
     | 
| 
      
 134 
     | 
    
         
            +
                        :media_type
         
     | 
| 
      
 135 
     | 
    
         
            +
                      elsif request.respond_to?(:content_type)
         
     | 
| 
      
 136 
     | 
    
         
            +
                        :content_type
         
     | 
| 
      
 137 
     | 
    
         
            +
                      end
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
                      request.send(content_type) if content_type
         
     | 
| 
      
 140 
     | 
    
         
            +
                    end
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
       130 
142 
     | 
    
         
             
                    def attribute_from_env(request, key)
         
     | 
| 
       131 
143 
     | 
    
         
             
                      if env = attribute_from_request(request, :env)
         
     | 
| 
       132 
144 
     | 
    
         
             
                        env[key]
         
     | 
    
        data/lib/new_relic/agent.rb
    CHANGED
    
    | 
         @@ -85,6 +85,10 @@ module NewRelic 
     | 
|
| 
       85 
85 
     | 
    
         
             
                # An exception that forces an agent to stop reporting until its mongrel is restarted.
         
     | 
| 
       86 
86 
     | 
    
         
             
                class ForceDisconnectException < StandardError; end
         
     | 
| 
       87 
87 
     | 
    
         | 
| 
      
 88 
     | 
    
         
            +
                # Error handling for the automated custom instrumentation tracer logic
         
     | 
| 
      
 89 
     | 
    
         
            +
                class AutomaticTracerParseException < StandardError; end
         
     | 
| 
      
 90 
     | 
    
         
            +
                class AutomaticTracerTraceException < StandardError; end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
       88 
92 
     | 
    
         
             
                # An exception that forces an agent to restart.
         
     | 
| 
       89 
93 
     | 
    
         
             
                class ForceRestartException < StandardError
         
     | 
| 
       90 
94 
     | 
    
         
             
                  def message
         
     | 
| 
         @@ -109,6 +113,9 @@ module NewRelic 
     | 
|
| 
       109 
113 
     | 
    
         
             
                # placeholder name used when we cannot determine a transaction's name
         
     | 
| 
       110 
114 
     | 
    
         
             
                UNKNOWN_METRIC = '(unknown)'.freeze
         
     | 
| 
       111 
115 
     | 
    
         
             
                LLM_FEEDBACK_MESSAGE = 'LlmFeedbackMessage'
         
     | 
| 
      
 116 
     | 
    
         
            +
                # give the observed app time to load the code that automatic tracers have
         
     | 
| 
      
 117 
     | 
    
         
            +
                # been configured for
         
     | 
| 
      
 118 
     | 
    
         
            +
                AUTOMATIC_TRACER_MAX_ATTEMPTS = 60 # 60 = try about twice a second for 30 seconds
         
     | 
| 
       112 
119 
     | 
    
         | 
| 
       113 
120 
     | 
    
         
             
                attr_reader :error_group_callback
         
     | 
| 
       114 
121 
     | 
    
         
             
                attr_reader :llm_token_count_callback
         
     | 
| 
         @@ -163,6 +170,92 @@ module NewRelic 
     | 
|
| 
       163 
170 
     | 
    
         
             
                  end
         
     | 
| 
       164 
171 
     | 
    
         
             
                end
         
     | 
| 
       165 
172 
     | 
    
         | 
| 
      
 173 
     | 
    
         
            +
                # @api private
         
     | 
| 
      
 174 
     | 
    
         
            +
                def self.add_automatic_method_tracers(arr)
         
     | 
| 
      
 175 
     | 
    
         
            +
                  return unless arr
         
     | 
| 
      
 176 
     | 
    
         
            +
                  return arr if arr.respond_to?(:empty?) && arr.empty?
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
                  arr = arr.split(/\s*,\s*/) if arr.is_a?(String)
         
     | 
| 
      
 179 
     | 
    
         
            +
             
     | 
| 
      
 180 
     | 
    
         
            +
                  add_tracers_once_methods_are_defined(arr.dup)
         
     | 
| 
      
 181 
     | 
    
         
            +
             
     | 
| 
      
 182 
     | 
    
         
            +
                  arr
         
     | 
| 
      
 183 
     | 
    
         
            +
                end
         
     | 
| 
      
 184 
     | 
    
         
            +
             
     | 
| 
      
 185 
     | 
    
         
            +
                # spawn a thread that will attempt to establish a tracer for each of the
         
     | 
| 
      
 186 
     | 
    
         
            +
                # configured methods. the thread will continue to keep trying with each
         
     | 
| 
      
 187 
     | 
    
         
            +
                # tracer until one of the following happens:
         
     | 
| 
      
 188 
     | 
    
         
            +
                #   - the tracer is successfully established
         
     | 
| 
      
 189 
     | 
    
         
            +
                #   - the configured method string couldn't be parsed
         
     | 
| 
      
 190 
     | 
    
         
            +
                #   - establishing a tracer for a successfully parsed string failed
         
     | 
| 
      
 191 
     | 
    
         
            +
                #   - the maximum number of attempts has been reached
         
     | 
| 
      
 192 
     | 
    
         
            +
                # the thread will only be spawned once per agent initialization, to account
         
     | 
| 
      
 193 
     | 
    
         
            +
                # for configuration reloading scenarios.
         
     | 
| 
      
 194 
     | 
    
         
            +
                #
         
     | 
| 
      
 195 
     | 
    
         
            +
                # @api private
         
     | 
| 
      
 196 
     | 
    
         
            +
                def self.add_tracers_once_methods_are_defined(notations)
         
     | 
| 
      
 197 
     | 
    
         
            +
                  # this class method can be invoked multiple times at agent startup, so
         
     | 
| 
      
 198 
     | 
    
         
            +
                  # we return asap here instead of using a traditional memoization of
         
     | 
| 
      
 199 
     | 
    
         
            +
                  # waiting for the method's body to finish being executed
         
     | 
| 
      
 200 
     | 
    
         
            +
                  if defined?(@add_tracers_once_methods_are_defined)
         
     | 
| 
      
 201 
     | 
    
         
            +
                    return
         
     | 
| 
      
 202 
     | 
    
         
            +
                  else
         
     | 
| 
      
 203 
     | 
    
         
            +
                    @add_tracers_once_methods_are_defined = true
         
     | 
| 
      
 204 
     | 
    
         
            +
                  end
         
     | 
| 
      
 205 
     | 
    
         
            +
             
     | 
| 
      
 206 
     | 
    
         
            +
                  Thread.new do
         
     | 
| 
      
 207 
     | 
    
         
            +
                    AUTOMATIC_TRACER_MAX_ATTEMPTS.times do
         
     | 
| 
      
 208 
     | 
    
         
            +
                      notations.delete_if { |notation| prep_tracer_for(notation) }
         
     | 
| 
      
 209 
     | 
    
         
            +
             
     | 
| 
      
 210 
     | 
    
         
            +
                      break if notations.empty?
         
     | 
| 
      
 211 
     | 
    
         
            +
             
     | 
| 
      
 212 
     | 
    
         
            +
                      sleep 0.5
         
     | 
| 
      
 213 
     | 
    
         
            +
                    end
         
     | 
| 
      
 214 
     | 
    
         
            +
                  end
         
     | 
| 
      
 215 
     | 
    
         
            +
                end
         
     | 
| 
      
 216 
     | 
    
         
            +
             
     | 
| 
      
 217 
     | 
    
         
            +
                # returns `true` if the notation string has either been successfully
         
     | 
| 
      
 218 
     | 
    
         
            +
                # processed or raised an error during processing. returns `false` if the
         
     | 
| 
      
 219 
     | 
    
         
            +
                # string seems good but the (customer) code to be traced has not yet been
         
     | 
| 
      
 220 
     | 
    
         
            +
                # loaded into the Ruby VM
         
     | 
| 
      
 221 
     | 
    
         
            +
                #
         
     | 
| 
      
 222 
     | 
    
         
            +
                # @api private
         
     | 
| 
      
 223 
     | 
    
         
            +
                def self.prep_tracer_for(fully_qualified_method_notation)
         
     | 
| 
      
 224 
     | 
    
         
            +
                  delimiters = fully_qualified_method_notation.scan(/\.|#/)
         
     | 
| 
      
 225 
     | 
    
         
            +
                  raise AutomaticTracerParseException.new("Expected exactly one '.' or '#' delimiter.") unless delimiters.size == 1
         
     | 
| 
      
 226 
     | 
    
         
            +
             
     | 
| 
      
 227 
     | 
    
         
            +
                  delimiter = delimiters.first
         
     | 
| 
      
 228 
     | 
    
         
            +
                  namespace, method_name = fully_qualified_method_notation.split(delimiter)
         
     | 
| 
      
 229 
     | 
    
         
            +
                  unless namespace && !namespace.empty?
         
     | 
| 
      
 230 
     | 
    
         
            +
                    raise AutomaticTracerParseException.new("Nothing found to the left of the #{delimiter} delimiter.")
         
     | 
| 
      
 231 
     | 
    
         
            +
                  end
         
     | 
| 
      
 232 
     | 
    
         
            +
                  unless method_name && !method_name.empty?
         
     | 
| 
      
 233 
     | 
    
         
            +
                    raise AutomaticTracerParseException.new("Nothing found to the right of the #{delimiter} delimiter.")
         
     | 
| 
      
 234 
     | 
    
         
            +
                  end
         
     | 
| 
      
 235 
     | 
    
         
            +
             
     | 
| 
      
 236 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 237 
     | 
    
         
            +
                    klass = ::NewRelic::LanguageSupport.constantize(namespace)
         
     | 
| 
      
 238 
     | 
    
         
            +
                    return false unless klass
         
     | 
| 
      
 239 
     | 
    
         
            +
             
     | 
| 
      
 240 
     | 
    
         
            +
                    klass_to_trace = delimiter.eql?('.') ? klass.singleton_class : klass
         
     | 
| 
      
 241 
     | 
    
         
            +
                    add_or_defer_method_tracer(klass_to_trace, method_name, nil, {})
         
     | 
| 
      
 242 
     | 
    
         
            +
                  rescue StandardError => e
         
     | 
| 
      
 243 
     | 
    
         
            +
                    raise AutomaticTracerTraceException.new("#{e.class} - #{e.message}")
         
     | 
| 
      
 244 
     | 
    
         
            +
                  end
         
     | 
| 
      
 245 
     | 
    
         
            +
             
     | 
| 
      
 246 
     | 
    
         
            +
                  true
         
     | 
| 
      
 247 
     | 
    
         
            +
                rescue AutomaticTracerParseException => e
         
     | 
| 
      
 248 
     | 
    
         
            +
                  NewRelic::Agent.logger.error('Unable to parse out a usable method name to trace. Expected a valid, fully ' \
         
     | 
| 
      
 249 
     | 
    
         
            +
                                               "qualified method notation. Got: '#{fully_qualified_method_notation}'. " \
         
     | 
| 
      
 250 
     | 
    
         
            +
                                               "Error: #{e.message}")
         
     | 
| 
      
 251 
     | 
    
         
            +
                  true
         
     | 
| 
      
 252 
     | 
    
         
            +
                rescue AutomaticTracerTraceException => e
         
     | 
| 
      
 253 
     | 
    
         
            +
                  NewRelic::Agent.logger.error('Unable to automatically apply a tracer to method ' \
         
     | 
| 
      
 254 
     | 
    
         
            +
                                               "'#{fully_qualified_method_notation}'. Error: #{e.message}")
         
     | 
| 
      
 255 
     | 
    
         
            +
                  true
         
     | 
| 
      
 256 
     | 
    
         
            +
                end
         
     | 
| 
      
 257 
     | 
    
         
            +
             
     | 
| 
      
 258 
     | 
    
         
            +
                # @api private
         
     | 
| 
       166 
259 
     | 
    
         
             
                def add_deferred_method_tracers_now
         
     | 
| 
       167 
260 
     | 
    
         
             
                  @tracer_lock.synchronize do
         
     | 
| 
       168 
261 
     | 
    
         
             
                    @tracer_queue.each do |receiver, method_name, metric_name, options|
         
     | 
| 
         @@ -9,7 +9,7 @@ module NewRelic 
     | 
|
| 
       9 
9 
     | 
    
         
             
                module Frameworks
         
     | 
| 
       10 
10 
     | 
    
         
             
                  class Rails4 < NewRelic::Control::Frameworks::Rails3
         
     | 
| 
       11 
11 
     | 
    
         
             
                    def rails_gem_list
         
     | 
| 
       12 
     | 
    
         
            -
                      if  
     | 
| 
      
 12 
     | 
    
         
            +
                      if Bundler.rubygems.respond_to?(:installed_specs)
         
     | 
| 
       13 
13 
     | 
    
         
             
                        Bundler.rubygems.installed_specs.map { |gem| "#{gem.name} (#{gem.version})" }
         
     | 
| 
       14 
14 
     | 
    
         
             
                      else
         
     | 
| 
       15 
15 
     | 
    
         
             
                        Bundler.rubygems.all_specs.map { |gem| "#{gem.name} (#{gem.version})" }
         
     | 
| 
         @@ -44,7 +44,7 @@ module NewRelic 
     | 
|
| 
       44 
44 
     | 
    
         
             
                ####################################
         
     | 
| 
       45 
45 
     | 
    
         
             
                report_on('Gems') do
         
     | 
| 
       46 
46 
     | 
    
         
             
                  begin
         
     | 
| 
       47 
     | 
    
         
            -
                    if  
     | 
| 
      
 47 
     | 
    
         
            +
                    if Bundler.rubygems.respond_to?(:installed_specs)
         
     | 
| 
       48 
48 
     | 
    
         
             
                      Bundler.rubygems.installed_specs.map { |gem| "#{gem.name}(#{gem.version})" }
         
     | 
| 
       49 
49 
     | 
    
         
             
                    else
         
     | 
| 
       50 
50 
     | 
    
         
             
                      Bundler.rubygems.all_specs.map { |gem| "#{gem.name}(#{gem.version})" }
         
     | 
| 
         @@ -90,7 +90,7 @@ module NewRelic 
     | 
|
| 
       90 
90 
     | 
    
         
             
                def bundled_gem?(gem_name)
         
     | 
| 
       91 
91 
     | 
    
         
             
                  return false unless defined?(Bundler)
         
     | 
| 
       92 
92 
     | 
    
         | 
| 
       93 
     | 
    
         
            -
                  if  
     | 
| 
      
 93 
     | 
    
         
            +
                  if Bundler.rubygems.respond_to?(:installed_specs)
         
     | 
| 
       94 
94 
     | 
    
         
             
                    Bundler.rubygems.installed_specs.map(&:name).include?(gem_name)
         
     | 
| 
       95 
95 
     | 
    
         
             
                  else
         
     | 
| 
       96 
96 
     | 
    
         
             
                    Bundler.rubygems.all_specs.map(&:name).include?(gem_name)
         
     | 
    
        data/lib/new_relic/version.rb
    CHANGED
    
    
    
        data/newrelic.yml
    CHANGED
    
    | 
         @@ -113,6 +113,53 @@ common: &default_settings 
     | 
|
| 
       113 
113 
     | 
    
         
             
              # Specifies a path to the audit log file (including the filename).
         
     | 
| 
       114 
114 
     | 
    
         
             
              # audit_log.path: log/newrelic_audit.log
         
     | 
| 
       115 
115 
     | 
    
         | 
| 
      
 116 
     | 
    
         
            +
              # An array of CLASS#METHOD (for instance methods) and/or CLASS.METHOD (for class
         
     | 
| 
      
 117 
     | 
    
         
            +
              # methods) strings representing Ruby methods for the agent to automatically add
         
     | 
| 
      
 118 
     | 
    
         
            +
              # custom instrumentation to without the need for altering any of the source code
         
     | 
| 
      
 119 
     | 
    
         
            +
              # that defines the methods.
         
     | 
| 
      
 120 
     | 
    
         
            +
              #
         
     | 
| 
      
 121 
     | 
    
         
            +
              # Use fully qualified class names (using the :: delimiter) that include any
         
     | 
| 
      
 122 
     | 
    
         
            +
              # module or class namespacing.
         
     | 
| 
      
 123 
     | 
    
         
            +
              #
         
     | 
| 
      
 124 
     | 
    
         
            +
              # Here is some Ruby source code that defines a render_png instance method for an
         
     | 
| 
      
 125 
     | 
    
         
            +
              # Image class and a notify class method for a User class, both within a
         
     | 
| 
      
 126 
     | 
    
         
            +
              # MyCompany module namespace:
         
     | 
| 
      
 127 
     | 
    
         
            +
              # 
         
     | 
| 
      
 128 
     | 
    
         
            +
              # module MyCompany
         
     | 
| 
      
 129 
     | 
    
         
            +
              #   class Image
         
     | 
| 
      
 130 
     | 
    
         
            +
              #     def render_png
         
     | 
| 
      
 131 
     | 
    
         
            +
              #       # code to render a PNG
         
     | 
| 
      
 132 
     | 
    
         
            +
              #     end
         
     | 
| 
      
 133 
     | 
    
         
            +
              #   end
         
     | 
| 
      
 134 
     | 
    
         
            +
              #
         
     | 
| 
      
 135 
     | 
    
         
            +
              #   class User
         
     | 
| 
      
 136 
     | 
    
         
            +
              #     def self.notify
         
     | 
| 
      
 137 
     | 
    
         
            +
              #       # code to notify users
         
     | 
| 
      
 138 
     | 
    
         
            +
              #     end
         
     | 
| 
      
 139 
     | 
    
         
            +
              #   end
         
     | 
| 
      
 140 
     | 
    
         
            +
              # end
         
     | 
| 
      
 141 
     | 
    
         
            +
              # 
         
     | 
| 
      
 142 
     | 
    
         
            +
              # Given that source code, the newrelic.yml config file might request
         
     | 
| 
      
 143 
     | 
    
         
            +
              # instrumentation for both of these methods like so:
         
     | 
| 
      
 144 
     | 
    
         
            +
              # 
         
     | 
| 
      
 145 
     | 
    
         
            +
              # automatic_custom_instrumentation_method_list:
         
     | 
| 
      
 146 
     | 
    
         
            +
              # - MyCompany::Image#render_png
         
     | 
| 
      
 147 
     | 
    
         
            +
              # - MyCompany::User.notify
         
     | 
| 
      
 148 
     | 
    
         
            +
              #
         
     | 
| 
      
 149 
     | 
    
         
            +
              # That configuration example uses YAML array syntax to specify both methods.
         
     | 
| 
      
 150 
     | 
    
         
            +
              # Alternatively, a comma-delimited string can be used instead:
         
     | 
| 
      
 151 
     | 
    
         
            +
              # 
         
     | 
| 
      
 152 
     | 
    
         
            +
              # automatic_custom_instrumentation_method_list: 'MyCompany::Image#render_png, MyCompany::User.notify'
         
     | 
| 
      
 153 
     | 
    
         
            +
              # 
         
     | 
| 
      
 154 
     | 
    
         
            +
              # Whitespace around the comma(s) in the list is optional. When configuring the
         
     | 
| 
      
 155 
     | 
    
         
            +
              # agent with a list of methods via the
         
     | 
| 
      
 156 
     | 
    
         
            +
              # NEW_RELIC_AUTOMATIC_CUSTOM_INSTRUMENTATION_METHOD_LIST environment variable,
         
     | 
| 
      
 157 
     | 
    
         
            +
              # this comma-delimited string format should be used:
         
     | 
| 
      
 158 
     | 
    
         
            +
              # 
         
     | 
| 
      
 159 
     | 
    
         
            +
              # export NEW_RELIC_AUTOMATIC_CUSTOM_INSTRUMENTATION_METHOD_LIST='MyCompany::Image#render_png, MyCompany::User.notify'
         
     | 
| 
      
 160 
     | 
    
         
            +
              # 
         
     | 
| 
      
 161 
     | 
    
         
            +
              # automatic_custom_instrumentation_method_list: []
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
       116 
163 
     | 
    
         
             
              # Specify a list of constants that should prevent the agent from starting
         
     | 
| 
       117 
164 
     | 
    
         
             
              # automatically. Separate individual constants with a comma ,. For example,
         
     | 
| 
       118 
165 
     | 
    
         
             
              # "Rails::Console,UninstrumentedBackgroundJob".
         
     | 
| 
         @@ -535,6 +582,10 @@ common: &default_settings 
     | 
|
| 
       535 
582 
     | 
    
         
             
              # prepend, chain, disabled.
         
     | 
| 
       536 
583 
     | 
    
         
             
              # instrumentation.rake: auto
         
     | 
| 
       537 
584 
     | 
    
         | 
| 
      
 585 
     | 
    
         
            +
              # Controls auto-instrumentation of the rdkafka library at start-up. May be one
         
     | 
| 
      
 586 
     | 
    
         
            +
              # of auto, prepend, chain, disabled.
         
     | 
| 
      
 587 
     | 
    
         
            +
              # instrumentation.rdkafka: auto
         
     | 
| 
      
 588 
     | 
    
         
            +
             
     | 
| 
       538 
589 
     | 
    
         
             
              # Controls auto-instrumentation of Redis at start-up. May be one of: auto,
         
     | 
| 
       539 
590 
     | 
    
         
             
              # prepend, chain, disabled.
         
     | 
| 
       540 
591 
     | 
    
         
             
              # instrumentation.redis: auto
         
     | 
| 
         @@ -547,6 +598,10 @@ common: &default_settings 
     | 
|
| 
       547 
598 
     | 
    
         
             
              # prepend, chain, disabled.
         
     | 
| 
       548 
599 
     | 
    
         
             
              # instrumentation.roda: auto
         
     | 
| 
       549 
600 
     | 
    
         | 
| 
      
 601 
     | 
    
         
            +
              # Controls auto-instrumentation of the ruby-kafka library at start-up. May be
         
     | 
| 
      
 602 
     | 
    
         
            +
              # one of auto, prepend, chain, disabled.
         
     | 
| 
      
 603 
     | 
    
         
            +
              # instrumentation.ruby_kafka: auto
         
     | 
| 
      
 604 
     | 
    
         
            +
             
     | 
| 
       550 
605 
     | 
    
         
             
              # Controls auto-instrumentation of the ruby-openai gem at start-up. May be one
         
     | 
| 
       551 
606 
     | 
    
         
             
              # of: auto, prepend, chain, disabled. Defaults to disabled in high security
         
     | 
| 
       552 
607 
     | 
    
         
             
              # mode.
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: newrelic_rpm
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 9. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 9.14.0
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Tanna McClure
         
     | 
| 
         @@ -11,7 +11,7 @@ authors: 
     | 
|
| 
       11 
11 
     | 
    
         
             
            autorequire: 
         
     | 
| 
       12 
12 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       13 
13 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       14 
     | 
    
         
            -
            date: 2024- 
     | 
| 
      
 14 
     | 
    
         
            +
            date: 2024-09-30 00:00:00.000000000 Z
         
     | 
| 
       15 
15 
     | 
    
         
             
            dependencies:
         
     | 
| 
       16 
16 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       17 
17 
     | 
    
         
             
              name: bundler
         
     | 
| 
         @@ -509,6 +509,10 @@ files: 
     | 
|
| 
       509 
509 
     | 
    
         
             
            - lib/new_relic/agent/instrumentation/rake/chain.rb
         
     | 
| 
       510 
510 
     | 
    
         
             
            - lib/new_relic/agent/instrumentation/rake/instrumentation.rb
         
     | 
| 
       511 
511 
     | 
    
         
             
            - lib/new_relic/agent/instrumentation/rake/prepend.rb
         
     | 
| 
      
 512 
     | 
    
         
            +
            - lib/new_relic/agent/instrumentation/rdkafka.rb
         
     | 
| 
      
 513 
     | 
    
         
            +
            - lib/new_relic/agent/instrumentation/rdkafka/chain.rb
         
     | 
| 
      
 514 
     | 
    
         
            +
            - lib/new_relic/agent/instrumentation/rdkafka/instrumentation.rb
         
     | 
| 
      
 515 
     | 
    
         
            +
            - lib/new_relic/agent/instrumentation/rdkafka/prepend.rb
         
     | 
| 
       512 
516 
     | 
    
         
             
            - lib/new_relic/agent/instrumentation/redis.rb
         
     | 
| 
       513 
517 
     | 
    
         
             
            - lib/new_relic/agent/instrumentation/redis/chain.rb
         
     | 
| 
       514 
518 
     | 
    
         
             
            - lib/new_relic/agent/instrumentation/redis/cluster_middleware.rb
         
     | 
| 
         @@ -527,6 +531,10 @@ files: 
     | 
|
| 
       527 
531 
     | 
    
         
             
            - lib/new_relic/agent/instrumentation/roda/instrumentation.rb
         
     | 
| 
       528 
532 
     | 
    
         
             
            - lib/new_relic/agent/instrumentation/roda/prepend.rb
         
     | 
| 
       529 
533 
     | 
    
         
             
            - lib/new_relic/agent/instrumentation/roda/roda_transaction_namer.rb
         
     | 
| 
      
 534 
     | 
    
         
            +
            - lib/new_relic/agent/instrumentation/ruby_kafka.rb
         
     | 
| 
      
 535 
     | 
    
         
            +
            - lib/new_relic/agent/instrumentation/ruby_kafka/chain.rb
         
     | 
| 
      
 536 
     | 
    
         
            +
            - lib/new_relic/agent/instrumentation/ruby_kafka/instrumentation.rb
         
     | 
| 
      
 537 
     | 
    
         
            +
            - lib/new_relic/agent/instrumentation/ruby_kafka/prepend.rb
         
     | 
| 
       530 
538 
     | 
    
         
             
            - lib/new_relic/agent/instrumentation/ruby_openai.rb
         
     | 
| 
       531 
539 
     | 
    
         
             
            - lib/new_relic/agent/instrumentation/ruby_openai/chain.rb
         
     | 
| 
       532 
540 
     | 
    
         
             
            - lib/new_relic/agent/instrumentation/ruby_openai/instrumentation.rb
         
     | 
| 
         @@ -770,7 +778,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement 
     | 
|
| 
       770 
778 
     | 
    
         
             
                - !ruby/object:Gem::Version
         
     | 
| 
       771 
779 
     | 
    
         
             
                  version: 1.3.1
         
     | 
| 
       772 
780 
     | 
    
         
             
            requirements: []
         
     | 
| 
       773 
     | 
    
         
            -
            rubygems_version: 3.5. 
     | 
| 
      
 781 
     | 
    
         
            +
            rubygems_version: 3.5.16
         
     | 
| 
       774 
782 
     | 
    
         
             
            signing_key: 
         
     | 
| 
       775 
783 
     | 
    
         
             
            specification_version: 4
         
     | 
| 
       776 
784 
     | 
    
         
             
            summary: New Relic Ruby Agent
         
     |