datadog 2.1.0 → 2.2.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 +53 -2
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +19 -1
- data/ext/datadog_profiling_native_extension/collectors_stack.c +41 -0
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +1 -1
- data/ext/datadog_profiling_native_extension/crashtracker.c +1 -1
- data/ext/datadog_profiling_native_extension/extconf.rb +6 -4
- data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +47 -1
- data/ext/datadog_profiling_native_extension/setup_signal_handler.c +1 -1
- data/ext/datadog_profiling_native_extension/stack_recorder.c +13 -6
- data/ext/datadog_profiling_native_extension/stack_recorder.h +1 -0
- data/lib/datadog/appsec/contrib/sinatra/patcher.rb +1 -1
- data/lib/datadog/appsec/extensions.rb +1 -0
- data/lib/datadog/core/configuration/components.rb +6 -3
- data/lib/datadog/core/configuration/settings.rb +39 -0
- data/lib/datadog/core/configuration.rb +3 -17
- data/lib/datadog/core/deprecations.rb +58 -0
- data/lib/datadog/core/environment/yjit.rb +5 -0
- data/lib/datadog/core/runtime/ext.rb +1 -0
- data/lib/datadog/core/runtime/metrics.rb +6 -0
- data/lib/datadog/core/telemetry/component.rb +107 -0
- data/lib/datadog/core/telemetry/event.rb +100 -25
- data/lib/datadog/core/telemetry/ext.rb +2 -0
- data/lib/datadog/core/telemetry/http/adapters/net.rb +1 -1
- data/lib/datadog/core/telemetry/metric.rb +167 -0
- data/lib/datadog/core/telemetry/metrics_collection.rb +81 -0
- data/lib/datadog/core/telemetry/metrics_manager.rb +81 -0
- data/lib/datadog/core/telemetry/request.rb +1 -1
- data/lib/datadog/core/telemetry/worker.rb +173 -0
- data/lib/datadog/core/utils/only_once_successful.rb +76 -0
- data/lib/datadog/core.rb +2 -19
- data/lib/datadog/opentelemetry/sdk/propagator.rb +5 -10
- data/lib/datadog/opentelemetry/sdk/span_processor.rb +5 -2
- data/lib/datadog/profiling/collectors/code_provenance.rb +18 -5
- data/lib/datadog/profiling/component.rb +18 -1
- data/lib/datadog/profiling/ext/dir_monkey_patches.rb +410 -0
- data/lib/datadog/profiling.rb +1 -0
- data/lib/datadog/tracing/contrib/action_cable/event.rb +1 -1
- data/lib/datadog/tracing/contrib/action_cable/events/broadcast.rb +1 -1
- data/lib/datadog/tracing/contrib/action_cable/events/perform_action.rb +1 -1
- data/lib/datadog/tracing/contrib/action_cable/events/transmit.rb +1 -1
- data/lib/datadog/tracing/contrib/action_mailer/event.rb +4 -6
- data/lib/datadog/tracing/contrib/action_mailer/events/deliver.rb +9 -4
- data/lib/datadog/tracing/contrib/action_mailer/events/process.rb +3 -2
- data/lib/datadog/tracing/contrib/action_view/events/render_partial.rb +1 -5
- data/lib/datadog/tracing/contrib/action_view/events/render_template.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/discard.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/enqueue.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/enqueue_at.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/enqueue_retry.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/perform.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/retry_stopped.rb +1 -1
- data/lib/datadog/tracing/contrib/active_model_serializers/events/render.rb +1 -1
- data/lib/datadog/tracing/contrib/active_model_serializers/events/serialize.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/events/sql.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/cache/event.rb +32 -0
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +156 -0
- data/lib/datadog/tracing/contrib/active_support/cache/events.rb +34 -0
- data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +45 -41
- data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +17 -40
- data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +4 -1
- data/lib/datadog/tracing/contrib/active_support/notifications/event.rb +29 -6
- data/lib/datadog/tracing/contrib/active_support/notifications/subscriber.rb +16 -4
- data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +33 -29
- data/lib/datadog/tracing/contrib/analytics.rb +5 -0
- data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +5 -0
- data/lib/datadog/tracing/contrib/graphql/patcher.rb +8 -2
- data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +166 -0
- data/lib/datadog/tracing/contrib/graphql/unified_trace_patcher.rb +25 -0
- data/lib/datadog/tracing/contrib/kafka/consumer_event.rb +1 -1
- data/lib/datadog/tracing/contrib/kafka/consumer_group_event.rb +1 -1
- data/lib/datadog/tracing/contrib/kafka/event.rb +1 -1
- data/lib/datadog/tracing/contrib/kafka/events/connection/request.rb +3 -3
- data/lib/datadog/tracing/contrib/kafka/events/consumer/process_batch.rb +3 -3
- data/lib/datadog/tracing/contrib/kafka/events/consumer/process_message.rb +3 -3
- data/lib/datadog/tracing/contrib/kafka/events/consumer_group/heartbeat.rb +3 -3
- data/lib/datadog/tracing/contrib/kafka/events/produce_operation/send_messages.rb +3 -3
- data/lib/datadog/tracing/contrib/kafka/events/producer/deliver_messages.rb +3 -3
- data/lib/datadog/tracing/contrib/racecar/event.rb +2 -2
- data/lib/datadog/tracing/contrib/rails/ext.rb +9 -0
- data/lib/datadog/tracing/contrib/rails/patcher.rb +7 -0
- data/lib/datadog/tracing/contrib/rails/runner.rb +95 -0
- data/lib/datadog/tracing/distributed/b3_multi.rb +1 -1
- data/lib/datadog/tracing/distributed/b3_single.rb +3 -1
- data/lib/datadog/tracing/distributed/datadog.rb +2 -2
- data/lib/datadog/tracing/distributed/propagation.rb +9 -2
- data/lib/datadog/tracing/distributed/trace_context.rb +3 -2
- data/lib/datadog/tracing/span_operation.rb +3 -2
- data/lib/datadog/tracing/trace_operation.rb +7 -3
- data/lib/datadog/tracing/trace_segment.rb +4 -1
- data/lib/datadog/tracing/tracer.rb +9 -2
- data/lib/datadog/tracing.rb +5 -1
- data/lib/datadog/version.rb +2 -2
- metadata +22 -9
- data/lib/datadog/core/telemetry/client.rb +0 -95
- data/lib/datadog/core/telemetry/heartbeat.rb +0 -33
| @@ -4,6 +4,7 @@ require_relative '../analytics' | |
| 4 4 | 
             
            require_relative '../patcher'
         | 
| 5 5 | 
             
            require_relative 'tracing_patcher'
         | 
| 6 6 | 
             
            require_relative 'trace_patcher'
         | 
| 7 | 
            +
            require_relative 'unified_trace_patcher'
         | 
| 7 8 |  | 
| 8 9 | 
             
            module Datadog
         | 
| 9 10 | 
             
              module Tracing
         | 
| @@ -23,10 +24,15 @@ module Datadog | |
| 23 24 | 
             
                        if configuration[:with_deprecated_tracer]
         | 
| 24 25 | 
             
                          TracingPatcher.patch!(schemas, trace_options)
         | 
| 25 26 | 
             
                        elsif Integration.trace_supported?
         | 
| 26 | 
            -
                           | 
| 27 | 
            +
                          if configuration[:with_unified_tracer]
         | 
| 28 | 
            +
                            UnifiedTracePatcher.patch!(schemas, trace_options)
         | 
| 29 | 
            +
                          else
         | 
| 30 | 
            +
                            TracePatcher.patch!(schemas, trace_options)
         | 
| 31 | 
            +
                          end
         | 
| 27 32 | 
             
                        else
         | 
| 28 33 | 
             
                          Datadog.logger.warn(
         | 
| 29 | 
            -
                            "GraphQL version (#{target_version}) does not support GraphQL::Tracing::DataDogTrace | 
| 34 | 
            +
                            "GraphQL version (#{target_version}) does not support GraphQL::Tracing::DataDogTrace"\
         | 
| 35 | 
            +
                            'or Datadog::Tracing::Contrib::GraphQL::UnifiedTrace.'\
         | 
| 30 36 | 
             
                            'Falling back to GraphQL::Tracing::DataDogTracing.'
         | 
| 31 37 | 
             
                          )
         | 
| 32 38 | 
             
                          TracingPatcher.patch!(schemas, trace_options)
         | 
| @@ -0,0 +1,166 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'graphql/tracing'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Datadog
         | 
| 6 | 
            +
              module Tracing
         | 
| 7 | 
            +
                module Contrib
         | 
| 8 | 
            +
                  module GraphQL
         | 
| 9 | 
            +
                    # These methods will be called by the GraphQL runtime to trace the execution of queries.
         | 
| 10 | 
            +
                    # This tracer differs from the upstream one as it follows the unified naming convention specification,
         | 
| 11 | 
            +
                    # which is required to use features such as API Catalog.
         | 
| 12 | 
            +
                    # DEV-3.0: This tracer should be the default one in the next major version.
         | 
| 13 | 
            +
                    module UnifiedTrace
         | 
| 14 | 
            +
                      # @param analytics_enabled [Boolean] Deprecated
         | 
| 15 | 
            +
                      # @param analytics_sample_rate [Float] Deprecated
         | 
| 16 | 
            +
                      # @param service [String|nil] The service name to be set on the spans
         | 
| 17 | 
            +
                      def initialize(*args, analytics_enabled: false, analytics_sample_rate: 1.0, service: nil, **kwargs)
         | 
| 18 | 
            +
                        @analytics_enabled = analytics_enabled
         | 
| 19 | 
            +
                        @analytics_sample_rate = analytics_sample_rate
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                        @service_name = service
         | 
| 22 | 
            +
                        @has_prepare_span = respond_to?(:prepare_span)
         | 
| 23 | 
            +
                        super
         | 
| 24 | 
            +
                      end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                      def lex(*args, query_string:, **kwargs)
         | 
| 27 | 
            +
                        trace(proc { super }, 'lex', query_string, query_string: query_string)
         | 
| 28 | 
            +
                      end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                      def parse(*args, query_string:, **kwargs)
         | 
| 31 | 
            +
                        trace(proc { super }, 'parse', query_string, query_string: query_string) do |span|
         | 
| 32 | 
            +
                          span.set_tag('graphql.source', query_string)
         | 
| 33 | 
            +
                        end
         | 
| 34 | 
            +
                      end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                      def validate(*args, query:, validate:, **kwargs)
         | 
| 37 | 
            +
                        trace(proc { super }, 'validate', query.selected_operation_name, query: query, validate: validate) do |span|
         | 
| 38 | 
            +
                          span.set_tag('graphql.source', query.query_string)
         | 
| 39 | 
            +
                        end
         | 
| 40 | 
            +
                      end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                      def analyze_multiplex(*args, multiplex:, **kwargs)
         | 
| 43 | 
            +
                        trace(proc { super }, 'analyze_multiplex', multiplex_resource(multiplex), multiplex: multiplex)
         | 
| 44 | 
            +
                      end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                      def analyze_query(*args, query:, **kwargs)
         | 
| 47 | 
            +
                        trace(proc { super }, 'analyze', query.query_string, query: query)
         | 
| 48 | 
            +
                      end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                      def execute_multiplex(*args, multiplex:, **kwargs)
         | 
| 51 | 
            +
                        trace(proc { super }, 'execute_multiplex', multiplex_resource(multiplex), multiplex: multiplex) do |span|
         | 
| 52 | 
            +
                          span.set_tag('graphql.source', "Multiplex[#{multiplex.queries.map(&:query_string).join(', ')}]")
         | 
| 53 | 
            +
                        end
         | 
| 54 | 
            +
                      end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                      def execute_query(*args, query:, **kwargs)
         | 
| 57 | 
            +
                        trace(proc { super }, 'execute', query.selected_operation_name, query: query) do |span|
         | 
| 58 | 
            +
                          span.set_tag('graphql.source', query.query_string)
         | 
| 59 | 
            +
                          span.set_tag('graphql.operation.type', query.selected_operation.operation_type)
         | 
| 60 | 
            +
                          span.set_tag('graphql.operation.name', query.selected_operation_name) if query.selected_operation_name
         | 
| 61 | 
            +
                          query.variables.instance_variable_get(:@storage).each do |key, value|
         | 
| 62 | 
            +
                            span.set_tag("graphql.variables.#{key}", value)
         | 
| 63 | 
            +
                          end
         | 
| 64 | 
            +
                        end
         | 
| 65 | 
            +
                      end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                      def execute_query_lazy(*args, query:, multiplex:, **kwargs)
         | 
| 68 | 
            +
                        resource = if query
         | 
| 69 | 
            +
                                     query.selected_operation_name || fallback_transaction_name(query.context)
         | 
| 70 | 
            +
                                   else
         | 
| 71 | 
            +
                                     multiplex_resource(multiplex)
         | 
| 72 | 
            +
                                   end
         | 
| 73 | 
            +
                        trace(proc { super }, 'execute_lazy', resource, query: query, multiplex: multiplex)
         | 
| 74 | 
            +
                      end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                      def execute_field_span(callable, span_key, **kwargs)
         | 
| 77 | 
            +
                        # @platform_key_cache is initialized upstream, in ::GraphQL::Tracing::PlatformTrace
         | 
| 78 | 
            +
                        platform_key = @platform_key_cache[UnifiedTrace].platform_field_key_cache[kwargs[:field]]
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                        if platform_key
         | 
| 81 | 
            +
                          trace(callable, span_key, platform_key, **kwargs) do |span|
         | 
| 82 | 
            +
                            kwargs[:arguments].each do |key, value|
         | 
| 83 | 
            +
                              span.set_tag("graphql.variables.#{key}", value)
         | 
| 84 | 
            +
                            end
         | 
| 85 | 
            +
                          end
         | 
| 86 | 
            +
                        else
         | 
| 87 | 
            +
                          callable.call
         | 
| 88 | 
            +
                        end
         | 
| 89 | 
            +
                      end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                      def execute_field(*args, **kwargs)
         | 
| 92 | 
            +
                        execute_field_span(proc { super }, 'resolve', **kwargs)
         | 
| 93 | 
            +
                      end
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                      def execute_field_lazy(*args, **kwargs)
         | 
| 96 | 
            +
                        execute_field_span(proc { super }, 'resolve_lazy', **kwargs)
         | 
| 97 | 
            +
                      end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                      def authorized_span(callable, span_key, **kwargs)
         | 
| 100 | 
            +
                        platform_key = @platform_key_cache[UnifiedTrace].platform_authorized_key_cache[kwargs[:type]]
         | 
| 101 | 
            +
                        trace(callable, span_key, platform_key, **kwargs)
         | 
| 102 | 
            +
                      end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                      def authorized(*args, **kwargs)
         | 
| 105 | 
            +
                        authorized_span(proc { super }, 'authorized', **kwargs)
         | 
| 106 | 
            +
                      end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                      def authorized_lazy(*args, **kwargs)
         | 
| 109 | 
            +
                        authorized_span(proc { super }, 'authorized_lazy', **kwargs)
         | 
| 110 | 
            +
                      end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                      def resolve_type_span(callable, span_key, **kwargs)
         | 
| 113 | 
            +
                        platform_key = @platform_key_cache[UnifiedTrace].platform_resolve_type_key_cache[kwargs[:type]]
         | 
| 114 | 
            +
                        trace(callable, span_key, platform_key, **kwargs)
         | 
| 115 | 
            +
                      end
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                      def resolve_type(*args, **kwargs)
         | 
| 118 | 
            +
                        resolve_type_span(proc { super }, 'resolve_type', **kwargs)
         | 
| 119 | 
            +
                      end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                      def resolve_type_lazy(*args, **kwargs)
         | 
| 122 | 
            +
                        resolve_type_span(proc { super }, 'resolve_type_lazy', **kwargs)
         | 
| 123 | 
            +
                      end
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                      include ::GraphQL::Tracing::PlatformTrace
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                      def platform_field_key(field, *args, **kwargs)
         | 
| 128 | 
            +
                        field.path
         | 
| 129 | 
            +
                      end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                      def platform_authorized_key(type, *args, **kwargs)
         | 
| 132 | 
            +
                        "#{type.graphql_name}.authorized"
         | 
| 133 | 
            +
                      end
         | 
| 134 | 
            +
             | 
| 135 | 
            +
                      def platform_resolve_type_key(type, *args, **kwargs)
         | 
| 136 | 
            +
                        "#{type.graphql_name}.resolve_type"
         | 
| 137 | 
            +
                      end
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                      private
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                      def trace(callable, trace_key, resource, **kwargs)
         | 
| 142 | 
            +
                        Tracing.trace("graphql.#{trace_key}", resource: resource, service: @service_name, type: 'graphql') do |span|
         | 
| 143 | 
            +
                          yield(span) if block_given?
         | 
| 144 | 
            +
             | 
| 145 | 
            +
                          prepare_span(trace_key, kwargs, span) if @has_prepare_span
         | 
| 146 | 
            +
             | 
| 147 | 
            +
                          callable.call
         | 
| 148 | 
            +
                        end
         | 
| 149 | 
            +
                      end
         | 
| 150 | 
            +
             | 
| 151 | 
            +
                      def multiplex_resource(multiplex)
         | 
| 152 | 
            +
                        return nil unless multiplex
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                        operations = multiplex.queries.map(&:selected_operation_name).compact.join(', ')
         | 
| 155 | 
            +
                        if operations.empty?
         | 
| 156 | 
            +
                          first_query = multiplex.queries.first
         | 
| 157 | 
            +
                          fallback_transaction_name(first_query && first_query.context)
         | 
| 158 | 
            +
                        else
         | 
| 159 | 
            +
                          operations
         | 
| 160 | 
            +
                        end
         | 
| 161 | 
            +
                      end
         | 
| 162 | 
            +
                    end
         | 
| 163 | 
            +
                  end
         | 
| 164 | 
            +
                end
         | 
| 165 | 
            +
              end
         | 
| 166 | 
            +
            end
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Datadog
         | 
| 4 | 
            +
              module Tracing
         | 
| 5 | 
            +
                module Contrib
         | 
| 6 | 
            +
                  module GraphQL
         | 
| 7 | 
            +
                    # Provides instrumentation for `graphql` through the GraphQL's tracing with methods defined in UnifiedTrace
         | 
| 8 | 
            +
                    module UnifiedTracePatcher
         | 
| 9 | 
            +
                      module_function
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                      def patch!(schemas, options)
         | 
| 12 | 
            +
                        require_relative 'unified_trace'
         | 
| 13 | 
            +
                        if schemas.empty?
         | 
| 14 | 
            +
                          ::GraphQL::Schema.trace_with(UnifiedTrace, **options)
         | 
| 15 | 
            +
                        else
         | 
| 16 | 
            +
                          schemas.each do |schema|
         | 
| 17 | 
            +
                            schema.trace_with(UnifiedTrace, **options)
         | 
| 18 | 
            +
                          end
         | 
| 19 | 
            +
                        end
         | 
| 20 | 
            +
                      end
         | 
| 21 | 
            +
                    end
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
            end
         | 
| @@ -29,7 +29,7 @@ module Datadog | |
| 29 29 | 
             
                          Datadog.configuration.tracing[:kafka]
         | 
| 30 30 | 
             
                        end
         | 
| 31 31 |  | 
| 32 | 
            -
                        def  | 
| 32 | 
            +
                        def on_start(span, _event, _id, payload)
         | 
| 33 33 | 
             
                          span.set_tag(Tracing::Metadata::Ext::TAG_COMPONENT, Ext::TAG_COMPONENT)
         | 
| 34 34 | 
             
                          span.set_tag(Contrib::Ext::Messaging::TAG_SYSTEM, Ext::TAG_MESSAGING_SYSTEM)
         | 
| 35 35 |  | 
| @@ -15,7 +15,9 @@ module Datadog | |
| 15 15 |  | 
| 16 16 | 
             
                          EVENT_NAME = 'request.connection.kafka'
         | 
| 17 17 |  | 
| 18 | 
            -
                           | 
| 18 | 
            +
                          module_function
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                          def on_start(span, _event, _id, payload)
         | 
| 19 21 | 
             
                            super
         | 
| 20 22 |  | 
| 21 23 | 
             
                            span.resource = payload[:api]
         | 
| @@ -24,8 +26,6 @@ module Datadog | |
| 24 26 | 
             
                            span.set_tag(Ext::TAG_RESPONSE_SIZE, payload[:response_size]) if payload.key?(:response_size)
         | 
| 25 27 | 
             
                          end
         | 
| 26 28 |  | 
| 27 | 
            -
                          module_function
         | 
| 28 | 
            -
             | 
| 29 29 | 
             
                          def span_name
         | 
| 30 30 | 
             
                            Ext::SPAN_CONNECTION_REQUEST
         | 
| 31 31 | 
             
                          end
         | 
| @@ -17,7 +17,9 @@ module Datadog | |
| 17 17 |  | 
| 18 18 | 
             
                          EVENT_NAME = 'process_batch.consumer.kafka'
         | 
| 19 19 |  | 
| 20 | 
            -
                           | 
| 20 | 
            +
                          module_function
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                          def on_start(span, _event, _id, payload)
         | 
| 21 23 | 
             
                            super
         | 
| 22 24 |  | 
| 23 25 | 
             
                            span.resource = payload[:topic]
         | 
| @@ -31,8 +33,6 @@ module Datadog | |
| 31 33 | 
             
                            span.set_tag(Ext::TAG_OFFSET_LAG, payload[:offset_lag]) if payload.key?(:offset_lag)
         | 
| 32 34 | 
             
                          end
         | 
| 33 35 |  | 
| 34 | 
            -
                          module_function
         | 
| 35 | 
            -
             | 
| 36 36 | 
             
                          def span_name
         | 
| 37 37 | 
             
                            Ext::SPAN_PROCESS_BATCH
         | 
| 38 38 | 
             
                          end
         | 
| @@ -17,7 +17,9 @@ module Datadog | |
| 17 17 |  | 
| 18 18 | 
             
                          EVENT_NAME = 'process_message.consumer.kafka'
         | 
| 19 19 |  | 
| 20 | 
            -
                           | 
| 20 | 
            +
                          module_function
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                          def on_start(span, _event, _id, payload)
         | 
| 21 23 | 
             
                            super
         | 
| 22 24 |  | 
| 23 25 | 
             
                            span.resource = payload[:topic]
         | 
| @@ -29,8 +31,6 @@ module Datadog | |
| 29 31 | 
             
                            span.set_tag(Ext::TAG_OFFSET_LAG, payload[:offset_lag]) if payload.key?(:offset_lag)
         | 
| 30 32 | 
             
                          end
         | 
| 31 33 |  | 
| 32 | 
            -
                          module_function
         | 
| 33 | 
            -
             | 
| 34 34 | 
             
                          def span_name
         | 
| 35 35 | 
             
                            Ext::SPAN_PROCESS_MESSAGE
         | 
| 36 36 | 
             
                          end
         | 
| @@ -19,7 +19,9 @@ module Datadog | |
| 19 19 |  | 
| 20 20 | 
             
                          EVENT_NAME = 'heartbeat.consumer.kafka'
         | 
| 21 21 |  | 
| 22 | 
            -
                           | 
| 22 | 
            +
                          module_function
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                          def on_start(span, _event, _id, payload)
         | 
| 23 25 | 
             
                            super
         | 
| 24 26 |  | 
| 25 27 | 
             
                            if payload.key?(:topic_partitions)
         | 
| @@ -29,8 +31,6 @@ module Datadog | |
| 29 31 | 
             
                            end
         | 
| 30 32 | 
             
                          end
         | 
| 31 33 |  | 
| 32 | 
            -
                          module_function
         | 
| 33 | 
            -
             | 
| 34 34 | 
             
                          def span_name
         | 
| 35 35 | 
             
                            Ext::SPAN_CONSUMER_HEARTBEAT
         | 
| 36 36 | 
             
                          end
         | 
| @@ -15,7 +15,9 @@ module Datadog | |
| 15 15 |  | 
| 16 16 | 
             
                          EVENT_NAME = 'send_messages.producer.kafka'
         | 
| 17 17 |  | 
| 18 | 
            -
                           | 
| 18 | 
            +
                          module_function
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                          def on_start(span, _event, _id, payload)
         | 
| 19 21 | 
             
                            super
         | 
| 20 22 |  | 
| 21 23 | 
             
                            span.set_tag(Ext::TAG_MESSAGE_COUNT, payload[:message_count]) if payload.key?(:message_count)
         | 
| @@ -23,8 +25,6 @@ module Datadog | |
| 23 25 | 
             
                            span.set_tag(Tracing::Metadata::Ext::TAG_KIND, Tracing::Metadata::Ext::SpanKind::TAG_PRODUCER)
         | 
| 24 26 | 
             
                          end
         | 
| 25 27 |  | 
| 26 | 
            -
                          module_function
         | 
| 27 | 
            -
             | 
| 28 28 | 
             
                          def span_name
         | 
| 29 29 | 
             
                            Ext::SPAN_SEND_MESSAGES
         | 
| 30 30 | 
             
                          end
         | 
| @@ -15,7 +15,9 @@ module Datadog | |
| 15 15 |  | 
| 16 16 | 
             
                          EVENT_NAME = 'deliver_messages.producer.kafka'
         | 
| 17 17 |  | 
| 18 | 
            -
                           | 
| 18 | 
            +
                          module_function
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                          def on_start(span, _event, _id, payload)
         | 
| 19 21 | 
             
                            super
         | 
| 20 22 |  | 
| 21 23 | 
             
                            span.set_tag(Ext::TAG_ATTEMPTS, payload[:attempts]) if payload.key?(:attempts)
         | 
| @@ -26,8 +28,6 @@ module Datadog | |
| 26 28 | 
             
                            span.set_tag(Tracing::Metadata::Ext::TAG_KIND, Tracing::Metadata::Ext::SpanKind::TAG_PRODUCER)
         | 
| 27 29 | 
             
                          end
         | 
| 28 30 |  | 
| 29 | 
            -
                          module_function
         | 
| 30 | 
            -
             | 
| 31 31 | 
             
                          def span_name
         | 
| 32 32 | 
             
                            Ext::SPAN_DELIVER_MESSAGES
         | 
| 33 33 | 
             
                          end
         | 
| @@ -19,7 +19,7 @@ module Datadog | |
| 19 19 | 
             
                      # Class methods for Racecar events.
         | 
| 20 20 | 
             
                      # Note, they share the same process method and before_trace method.
         | 
| 21 21 | 
             
                      module ClassMethods
         | 
| 22 | 
            -
                        def subscription(*args)
         | 
| 22 | 
            +
                        def subscription(*args, **kwargs)
         | 
| 23 23 | 
             
                          super.tap do |subscription|
         | 
| 24 24 | 
             
                            subscription.before_trace { ensure_clean_context! }
         | 
| 25 25 | 
             
                          end
         | 
| @@ -33,7 +33,7 @@ module Datadog | |
| 33 33 | 
             
                          Datadog.configuration.tracing[:racecar]
         | 
| 34 34 | 
             
                        end
         | 
| 35 35 |  | 
| 36 | 
            -
                        def  | 
| 36 | 
            +
                        def on_start(span, event, _id, payload)
         | 
| 37 37 | 
             
                          span.service = configuration[:service_name]
         | 
| 38 38 | 
             
                          span.resource = payload[:consumer_class]
         | 
| 39 39 |  | 
| @@ -14,6 +14,15 @@ module Datadog | |
| 14 14 | 
             
                      ENV_ANALYTICS_SAMPLE_RATE = 'DD_TRACE_RAILS_ANALYTICS_SAMPLE_RATE'
         | 
| 15 15 | 
             
                      ENV_DISABLE = 'DISABLE_DATADOG_RAILS'
         | 
| 16 16 |  | 
| 17 | 
            +
                      SPAN_RUNNER_FILE = 'rails.runner.file'
         | 
| 18 | 
            +
                      SPAN_RUNNER_INLINE = 'rails.runner.inline'
         | 
| 19 | 
            +
                      SPAN_RUNNER_STDIN = 'rails.runner.stdin'
         | 
| 20 | 
            +
                      TAG_COMPONENT = 'rails'
         | 
| 21 | 
            +
                      TAG_OPERATION_FILE = 'runner.file'
         | 
| 22 | 
            +
                      TAG_OPERATION_INLINE = 'runner.inline'
         | 
| 23 | 
            +
                      TAG_OPERATION_STDIN = 'runner.stdin'
         | 
| 24 | 
            +
                      TAG_RUNNER_SOURCE = 'source'
         | 
| 25 | 
            +
             | 
| 17 26 | 
             
                      # @!visibility private
         | 
| 18 27 | 
             
                      MINIMUM_VERSION = Gem::Version.new('4')
         | 
| 19 28 | 
             
                    end
         | 
| @@ -5,6 +5,7 @@ require_relative '../rack/middlewares' | |
| 5 5 | 
             
            require_relative 'framework'
         | 
| 6 6 | 
             
            require_relative 'log_injection'
         | 
| 7 7 | 
             
            require_relative 'middlewares'
         | 
| 8 | 
            +
            require_relative 'runner'
         | 
| 8 9 | 
             
            require_relative 'utils'
         | 
| 9 10 | 
             
            require_relative '../semantic_logger/patcher'
         | 
| 10 11 |  | 
| @@ -28,6 +29,7 @@ module Datadog | |
| 28 29 | 
             
                      def patch
         | 
| 29 30 | 
             
                        patch_before_initialize
         | 
| 30 31 | 
             
                        patch_after_initialize
         | 
| 32 | 
            +
                        patch_rails_runner
         | 
| 31 33 | 
             
                      end
         | 
| 32 34 |  | 
| 33 35 | 
             
                      def patch_before_initialize
         | 
| @@ -81,6 +83,11 @@ module Datadog | |
| 81 83 | 
             
                      def setup_tracer
         | 
| 82 84 | 
             
                        Contrib::Rails::Framework.setup
         | 
| 83 85 | 
             
                      end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                      # Instruments the `bin/rails runner` command.
         | 
| 88 | 
            +
                      def patch_rails_runner
         | 
| 89 | 
            +
                        ::Rails::Command.singleton_class.prepend(Command) if defined?(::Rails::Command)
         | 
| 90 | 
            +
                      end
         | 
| 84 91 | 
             
                    end
         | 
| 85 92 | 
             
                  end
         | 
| 86 93 | 
             
                end
         | 
| @@ -0,0 +1,95 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Datadog
         | 
| 4 | 
            +
              module Tracing
         | 
| 5 | 
            +
                module Contrib
         | 
| 6 | 
            +
                  module Rails
         | 
| 7 | 
            +
                    # Instruments the `bin/rails runner` command.
         | 
| 8 | 
            +
                    # This command executes the provided code with the host Rails application loaded.
         | 
| 9 | 
            +
                    # The command can be either:
         | 
| 10 | 
            +
                    # * `-`: for code provided through the STDIN.
         | 
| 11 | 
            +
                    # * File path: for code provided through a local file.
         | 
| 12 | 
            +
                    # * `inline code`: for code provided directly as a command line argument.
         | 
| 13 | 
            +
                    # @see https://guides.rubyonrails.org/v6.1/command_line.html#bin-rails-runner
         | 
| 14 | 
            +
                    module Runner
         | 
| 15 | 
            +
                      # Limit the maximum size of the source code captured in the source tag.
         | 
| 16 | 
            +
                      MAX_TAG_VALUE_SIZE = 4096
         | 
| 17 | 
            +
                      private_constant :MAX_TAG_VALUE_SIZE
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                      def runner(code_or_file = nil, *_command_argv)
         | 
| 20 | 
            +
                        if code_or_file == '-'
         | 
| 21 | 
            +
                          name = Ext::SPAN_RUNNER_STDIN
         | 
| 22 | 
            +
                          resource = nil
         | 
| 23 | 
            +
                          operation = Ext::TAG_OPERATION_STDIN
         | 
| 24 | 
            +
                          # The source is not yet available for STDIN, but it will be captured in `eval`.
         | 
| 25 | 
            +
                        elsif File.exist?(code_or_file)
         | 
| 26 | 
            +
                          name = Ext::SPAN_RUNNER_FILE
         | 
| 27 | 
            +
                          resource = code_or_file
         | 
| 28 | 
            +
                          operation = Ext::TAG_OPERATION_FILE
         | 
| 29 | 
            +
                          source = File.read(code_or_file)
         | 
| 30 | 
            +
                        else
         | 
| 31 | 
            +
                          name = Ext::SPAN_RUNNER_INLINE
         | 
| 32 | 
            +
                          resource = nil
         | 
| 33 | 
            +
                          operation = Ext::TAG_OPERATION_INLINE
         | 
| 34 | 
            +
                          source = code_or_file
         | 
| 35 | 
            +
                        end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                        Tracing.trace(
         | 
| 38 | 
            +
                          name,
         | 
| 39 | 
            +
                          service: Datadog.configuration.tracing[:rails][:service_name],
         | 
| 40 | 
            +
                          resource: resource,
         | 
| 41 | 
            +
                          tags: {
         | 
| 42 | 
            +
                            Tracing::Metadata::Ext::TAG_COMPONENT => Ext::TAG_COMPONENT,
         | 
| 43 | 
            +
                            Tracing::Metadata::Ext::TAG_OPERATION => operation,
         | 
| 44 | 
            +
                          }
         | 
| 45 | 
            +
                        ) do |span|
         | 
| 46 | 
            +
                          if source
         | 
| 47 | 
            +
                            span.set_tag(
         | 
| 48 | 
            +
                              Ext::TAG_RUNNER_SOURCE,
         | 
| 49 | 
            +
                              Core::Utils.truncate(source, MAX_TAG_VALUE_SIZE)
         | 
| 50 | 
            +
                            )
         | 
| 51 | 
            +
                          end
         | 
| 52 | 
            +
                          Contrib::Analytics.set_rate!(span, Datadog.configuration.tracing[:rails])
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                          super
         | 
| 55 | 
            +
                        end
         | 
| 56 | 
            +
                      end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                      # Capture the executed source code when provided from STDIN.
         | 
| 59 | 
            +
                      def eval(*args)
         | 
| 60 | 
            +
                        span = Datadog::Tracing.active_span
         | 
| 61 | 
            +
                        if span.name == Ext::SPAN_RUNNER_STDIN
         | 
| 62 | 
            +
                          source = args[0]
         | 
| 63 | 
            +
                          span.set_tag(
         | 
| 64 | 
            +
                            Ext::TAG_RUNNER_SOURCE,
         | 
| 65 | 
            +
                            Core::Utils.truncate(source, MAX_TAG_VALUE_SIZE)
         | 
| 66 | 
            +
                          )
         | 
| 67 | 
            +
                        end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                        super
         | 
| 70 | 
            +
                      end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                      ruby2_keywords :eval if respond_to?(:ruby2_keywords, true)
         | 
| 73 | 
            +
                    end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                    # The instrumentation target, {Rails::Command::RunnerCommand} is only loaded
         | 
| 76 | 
            +
                    # right before `bin/rails runner` is executed. This means there's not much
         | 
| 77 | 
            +
                    # opportunity to patch it ahead of time.
         | 
| 78 | 
            +
                    # To ensure we can patch it successfully, we patch it's caller, {Rails::Command}
         | 
| 79 | 
            +
                    # and promptly patch {Rails::Command::RunnerCommand} when it is loaded.
         | 
| 80 | 
            +
                    module Command
         | 
| 81 | 
            +
                      def find_by_namespace(*args)
         | 
| 82 | 
            +
                        ret = super
         | 
| 83 | 
            +
                        # Patch RunnerCommand if it is loaded and not already patched.
         | 
| 84 | 
            +
                        if defined?(::Rails::Command::RunnerCommand) && !(::Rails::Command::RunnerCommand < Runner)
         | 
| 85 | 
            +
                          ::Rails::Command::RunnerCommand.prepend(Runner)
         | 
| 86 | 
            +
                        end
         | 
| 87 | 
            +
                        ret
         | 
| 88 | 
            +
                      end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                      ruby2_keywords :find_by_namespace if respond_to?(:ruby2_keywords, true)
         | 
| 91 | 
            +
                    end
         | 
| 92 | 
            +
                  end
         | 
| 93 | 
            +
                end
         | 
| 94 | 
            +
              end
         | 
| 95 | 
            +
            end
         | 
| @@ -31,7 +31,7 @@ module Datadog | |
| 31 31 |  | 
| 32 32 | 
             
                      # DEV: We need these to be hex encoded
         | 
| 33 33 | 
             
                      data[@trace_id_key] = format('%032x', digest.trace_id)
         | 
| 34 | 
            -
                      data[@span_id_key] = format('%016x', digest.span_id)
         | 
| 34 | 
            +
                      data[@span_id_key] = format('%016x', digest.span_id || 0) # # Fall back to zero (invalid) if not present
         | 
| 35 35 |  | 
| 36 36 | 
             
                      if digest.trace_sampling_priority
         | 
| 37 37 | 
             
                        sampling_priority = Helpers.clamp_sampling_priority(
         | 
| @@ -25,8 +25,10 @@ module Datadog | |
| 25 25 | 
             
                    def inject!(digest, env)
         | 
| 26 26 | 
             
                      return if digest.nil?
         | 
| 27 27 |  | 
| 28 | 
            +
                      span_id = digest.span_id || 0 # Fall back to zero (invalid) if not present
         | 
| 29 | 
            +
             | 
| 28 30 | 
             
                      # DEV: We need these to be hex encoded
         | 
| 29 | 
            -
                      value = "#{format('%032x', digest.trace_id)}-#{format('%016x',  | 
| 31 | 
            +
                      value = "#{format('%032x', digest.trace_id)}-#{format('%016x', span_id)}"
         | 
| 30 32 |  | 
| 31 33 | 
             
                      if digest.trace_sampling_priority
         | 
| 32 34 | 
             
                        sampling_priority = Helpers.clamp_sampling_priority(
         | 
| @@ -42,7 +42,7 @@ module Datadog | |
| 42 42 |  | 
| 43 43 | 
             
                      data[@trace_id_key] = Tracing::Utils::TraceId.to_low_order(digest.trace_id).to_s
         | 
| 44 44 |  | 
| 45 | 
            -
                      data[@parent_id_key] = digest.span_id.to_s
         | 
| 45 | 
            +
                      data[@parent_id_key] = digest.span_id.to_s if digest.span_id
         | 
| 46 46 | 
             
                      data[@sampling_priority_key] = digest.trace_sampling_priority.to_s if digest.trace_sampling_priority
         | 
| 47 47 | 
             
                      data[@origin_key] = digest.trace_origin.to_s if digest.trace_origin
         | 
| 48 48 |  | 
| @@ -109,7 +109,7 @@ module Datadog | |
| 109 109 |  | 
| 110 110 | 
             
                      return tags if high_order == 0
         | 
| 111 111 |  | 
| 112 | 
            -
                      tags.merge(Tracing::Metadata::Ext::Distributed::TAG_TID => high_order | 
| 112 | 
            +
                      tags.merge(Tracing::Metadata::Ext::Distributed::TAG_TID => format('%016x', high_order))
         | 
| 113 113 | 
             
                    end
         | 
| 114 114 |  | 
| 115 115 | 
             
                    # Side effect: Remove high order 64 bit hex-encoded `tid` tag from distributed tags
         | 
| @@ -32,7 +32,9 @@ module Datadog | |
| 32 32 |  | 
| 33 33 | 
             
                    # inject! populates the env with span ID, trace ID and sampling priority
         | 
| 34 34 | 
             
                    #
         | 
| 35 | 
            -
                    # This method will never raise errors | 
| 35 | 
            +
                    # This method will never raise errors.
         | 
| 36 | 
            +
                    # It can propagate partial data, if deemed useful, instead of failing.
         | 
| 37 | 
            +
                    # In case of unrecoverable errors, it will log them to `Datadog.logger`.
         | 
| 36 38 | 
             
                    #
         | 
| 37 39 | 
             
                    # DEV-2.0: inject! should work without arguments, injecting the active_trace's digest
         | 
| 38 40 | 
             
                    # DEV-2.0: and returning a new Hash with the injected data.
         | 
| @@ -45,7 +47,7 @@ module Datadog | |
| 45 47 | 
             
                    # @param digest [TraceDigest]
         | 
| 46 48 | 
             
                    # @param data [Hash]
         | 
| 47 49 | 
             
                    # @return [Boolean] `true` if injected successfully, `false` if no propagation style is configured
         | 
| 48 | 
            -
                    # @return [nil] in case of  | 
| 50 | 
            +
                    # @return [nil] in case of unrecoverable errors, see `Datadog.logger` output for details.
         | 
| 49 51 | 
             
                    def inject!(digest, data)
         | 
| 50 52 | 
             
                      if digest.nil?
         | 
| 51 53 | 
             
                        ::Datadog.logger.debug('Cannot inject distributed trace data: digest is nil.')
         | 
| @@ -54,6 +56,11 @@ module Datadog | |
| 54 56 |  | 
| 55 57 | 
             
                      digest = digest.to_digest if digest.respond_to?(:to_digest)
         | 
| 56 58 |  | 
| 59 | 
            +
                      if digest.trace_id.nil?
         | 
| 60 | 
            +
                        ::Datadog.logger.debug('Cannot inject distributed trace data: digest.trace_id is nil.')
         | 
| 61 | 
            +
                        return nil
         | 
| 62 | 
            +
                      end
         | 
| 63 | 
            +
             | 
| 57 64 | 
             
                      result = false
         | 
| 58 65 |  | 
| 59 66 | 
             
                      # Inject all configured propagation styles
         | 
| @@ -107,7 +107,7 @@ module Datadog | |
| 107 107 | 
             
                    def build_traceparent(digest)
         | 
| 108 108 | 
             
                      build_traceparent_string(
         | 
| 109 109 | 
             
                        digest.trace_id,
         | 
| 110 | 
            -
                        digest.span_id,
         | 
| 110 | 
            +
                        digest.span_id || 0, # Fall back to zero (invalid) if not present
         | 
| 111 111 | 
             
                        build_trace_flags(digest)
         | 
| 112 112 | 
             
                      )
         | 
| 113 113 | 
             
                    end
         | 
| @@ -198,7 +198,8 @@ module Datadog | |
| 198 198 |  | 
| 199 199 | 
             
                    def last_dd_parent_id(digest)
         | 
| 200 200 | 
             
                      if !digest.span_remote
         | 
| 201 | 
            -
                         | 
| 201 | 
            +
                        span_id = digest.span_id || 0 # Fall back to zero (invalid) if not present
         | 
| 202 | 
            +
                        "p:#{format('%016x', span_id)};"
         | 
| 202 203 | 
             
                      elsif digest.trace_distributed_tags&.key?(Tracing::Metadata::Ext::Distributed::TAG_DD_PARENT_ID)
         | 
| 203 204 | 
             
                        "p:#{digest.trace_distributed_tags[Tracing::Metadata::Ext::Distributed::TAG_DD_PARENT_ID]};"
         | 
| 204 205 | 
             
                      else
         | 
| @@ -48,7 +48,8 @@ module Datadog | |
| 48 48 | 
             
                    tags: nil,
         | 
| 49 49 | 
             
                    trace_id: nil,
         | 
| 50 50 | 
             
                    type: nil,
         | 
| 51 | 
            -
                    links: nil
         | 
| 51 | 
            +
                    links: nil,
         | 
| 52 | 
            +
                    id: nil
         | 
| 52 53 | 
             
                  )
         | 
| 53 54 | 
             
                    # Ensure dynamically created strings are UTF-8 encoded.
         | 
| 54 55 | 
             
                    #
         | 
| @@ -60,7 +61,7 @@ module Datadog | |
| 60 61 | 
             
                    self.type = type
         | 
| 61 62 | 
             
                    self.resource = resource
         | 
| 62 63 |  | 
| 63 | 
            -
                    @id = Tracing::Utils.next_id
         | 
| 64 | 
            +
                    @id = id.nil? ? Tracing::Utils.next_id : id
         | 
| 64 65 | 
             
                    @parent_id = parent_id || 0
         | 
| 65 66 | 
             
                    @trace_id = trace_id || Tracing::Utils::TraceId.next_id
         | 
| 66 67 |  |