datadog 2.8.0 → 2.9.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 +36 -1
- data/ext/datadog_profiling_native_extension/clock_id.h +2 -2
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +64 -54
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -1
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +1 -1
- data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +16 -16
- data/ext/datadog_profiling_native_extension/collectors_stack.c +7 -7
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +219 -122
- data/ext/datadog_profiling_native_extension/heap_recorder.h +1 -1
- data/ext/datadog_profiling_native_extension/http_transport.c +4 -4
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +3 -0
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +3 -1
- data/ext/datadog_profiling_native_extension/profiling.c +10 -8
- data/ext/datadog_profiling_native_extension/ruby_helpers.c +8 -8
- data/ext/datadog_profiling_native_extension/stack_recorder.c +54 -54
- data/ext/datadog_profiling_native_extension/stack_recorder.h +1 -1
- data/ext/datadog_profiling_native_extension/time_helpers.h +1 -1
- data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.c +47 -0
- data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h +31 -0
- data/ext/libdatadog_api/crashtracker.c +3 -0
- data/lib/datadog/appsec/assets/waf_rules/recommended.json +355 -157
- data/lib/datadog/appsec/assets/waf_rules/strict.json +62 -32
- data/lib/datadog/appsec/context.rb +54 -0
- data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +7 -7
- data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +6 -6
- data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +4 -4
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +19 -28
- data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +5 -5
- data/lib/datadog/appsec/contrib/rack/gateway/response.rb +3 -3
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +64 -96
- data/lib/datadog/appsec/contrib/rack/reactive/request.rb +10 -10
- data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +5 -5
- data/lib/datadog/appsec/contrib/rack/reactive/response.rb +6 -6
- data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +10 -11
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +43 -49
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +21 -32
- data/lib/datadog/appsec/contrib/rails/patcher.rb +1 -1
- data/lib/datadog/appsec/contrib/rails/reactive/action.rb +6 -6
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +41 -63
- data/lib/datadog/appsec/contrib/sinatra/patcher.rb +2 -2
- data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +5 -5
- data/lib/datadog/appsec/event.rb +6 -6
- data/lib/datadog/appsec/ext.rb +3 -1
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +22 -32
- data/lib/datadog/appsec/monitor/reactive/set_user.rb +5 -5
- data/lib/datadog/appsec/processor/rule_loader.rb +0 -3
- data/lib/datadog/appsec.rb +3 -3
- data/lib/datadog/auto_instrument.rb +3 -0
- data/lib/datadog/core/configuration/agent_settings_resolver.rb +39 -11
- data/lib/datadog/core/configuration/components.rb +4 -2
- data/lib/datadog/core/configuration.rb +1 -1
- data/lib/datadog/{tracing → core}/contrib/rails/utils.rb +1 -3
- data/lib/datadog/core/crashtracking/component.rb +1 -3
- data/lib/datadog/core/telemetry/event.rb +87 -3
- data/lib/datadog/core/telemetry/logging.rb +2 -2
- data/lib/datadog/core/telemetry/metric.rb +22 -0
- data/lib/datadog/core/telemetry/worker.rb +33 -0
- data/lib/datadog/di/base.rb +115 -0
- data/lib/datadog/di/code_tracker.rb +7 -4
- data/lib/datadog/di/component.rb +17 -11
- data/lib/datadog/di/configuration/settings.rb +11 -1
- data/lib/datadog/di/contrib/railtie.rb +15 -0
- data/lib/datadog/di/contrib.rb +26 -0
- data/lib/datadog/di/error.rb +5 -0
- data/lib/datadog/di/instrumenter.rb +39 -18
- data/lib/datadog/di/{init.rb → preload.rb} +2 -4
- data/lib/datadog/di/probe_manager.rb +4 -4
- data/lib/datadog/di/probe_notification_builder.rb +16 -2
- data/lib/datadog/di/probe_notifier_worker.rb +5 -6
- data/lib/datadog/di/remote.rb +4 -4
- data/lib/datadog/di/transport.rb +2 -4
- data/lib/datadog/di.rb +5 -108
- data/lib/datadog/kit/appsec/events.rb +3 -3
- data/lib/datadog/kit/identity.rb +4 -4
- data/lib/datadog/profiling/component.rb +55 -53
- data/lib/datadog/profiling/http_transport.rb +1 -26
- data/lib/datadog/tracing/contrib/action_cable/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/action_mailer/integration.rb +6 -2
- data/lib/datadog/tracing/contrib/action_pack/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/action_view/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/active_job/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/active_record/integration.rb +6 -2
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +3 -1
- data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +3 -1
- data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +10 -0
- data/lib/datadog/tracing/contrib/active_support/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/auto_instrument.rb +2 -2
- data/lib/datadog/tracing/contrib/aws/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/httprb/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/kafka/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/mongodb/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/opensearch/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/presto/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/rack/integration.rb +2 -2
- data/lib/datadog/tracing/contrib/rails/framework.rb +2 -2
- data/lib/datadog/tracing/contrib/rails/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/rest_client/integration.rb +3 -0
- data/lib/datadog/tracing/span.rb +12 -4
- data/lib/datadog/tracing/span_event.rb +123 -3
- data/lib/datadog/tracing/span_operation.rb +6 -0
- data/lib/datadog/tracing/transport/serializable_trace.rb +24 -6
- data/lib/datadog/version.rb +1 -1
- metadata +19 -10
- data/lib/datadog/appsec/reactive/operation.rb +0 -68
- data/lib/datadog/appsec/scope.rb +0 -58
- data/lib/datadog/core/crashtracking/agent_base_url.rb +0 -21
| @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            require_relative '../../../instrumentation/gateway'
         | 
| 4 | 
            -
            require_relative '../../../reactive/ | 
| 4 | 
            +
            require_relative '../../../reactive/engine'
         | 
| 5 5 | 
             
            require_relative '../../rack/reactive/request_body'
         | 
| 6 6 | 
             
            require_relative '../reactive/routed'
         | 
| 7 7 | 
             
            require_relative '../../../event'
         | 
| @@ -23,85 +23,63 @@ module Datadog | |
| 23 23 |  | 
| 24 24 | 
             
                          def watch_request_dispatch(gateway = Instrumentation.gateway)
         | 
| 25 25 | 
             
                            gateway.watch('sinatra.request.dispatch', :appsec) do |stack, gateway_request|
         | 
| 26 | 
            -
                              block = false
         | 
| 27 | 
            -
             | 
| 28 26 | 
             
                              event = nil
         | 
| 29 | 
            -
                               | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 45 | 
            -
             | 
| 46 | 
            -
             | 
| 47 | 
            -
                                  end
         | 
| 27 | 
            +
                              context = gateway_request.env[Datadog::AppSec::Ext::CONTEXT_KEY]
         | 
| 28 | 
            +
                              engine = AppSec::Reactive::Engine.new
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                              Rack::Reactive::RequestBody.subscribe(engine, context) do |result|
         | 
| 31 | 
            +
                                if result.status == :match
         | 
| 32 | 
            +
                                  # TODO: should this hash be an Event instance instead?
         | 
| 33 | 
            +
                                  event = {
         | 
| 34 | 
            +
                                    waf_result: result,
         | 
| 35 | 
            +
                                    trace: context.trace,
         | 
| 36 | 
            +
                                    span: context.span,
         | 
| 37 | 
            +
                                    request: gateway_request,
         | 
| 38 | 
            +
                                    actions: result.actions
         | 
| 39 | 
            +
                                  }
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                                  # We want to keep the trace in case of security event
         | 
| 42 | 
            +
                                  context.trace.keep! if context.trace
         | 
| 43 | 
            +
                                  Datadog::AppSec::Event.tag_and_keep!(context, result)
         | 
| 44 | 
            +
                                  context.waf_runner.events << event
         | 
| 48 45 | 
             
                                end
         | 
| 49 | 
            -
             | 
| 50 | 
            -
                                block = Rack::Reactive::RequestBody.publish(op, gateway_request)
         | 
| 51 46 | 
             
                              end
         | 
| 52 47 |  | 
| 48 | 
            +
                              block = Rack::Reactive::RequestBody.publish(engine, gateway_request)
         | 
| 53 49 | 
             
                              next [nil, [[:block, event]]] if block
         | 
| 54 50 |  | 
| 55 | 
            -
                               | 
| 56 | 
            -
             | 
| 57 | 
            -
                              if event
         | 
| 58 | 
            -
                                res ||= []
         | 
| 59 | 
            -
                                res << [:monitor, event]
         | 
| 60 | 
            -
                              end
         | 
| 61 | 
            -
             | 
| 62 | 
            -
                              [ret, res]
         | 
| 51 | 
            +
                              stack.call(gateway_request.request)
         | 
| 63 52 | 
             
                            end
         | 
| 64 53 | 
             
                          end
         | 
| 65 54 |  | 
| 66 55 | 
             
                          def watch_request_routed(gateway = Instrumentation.gateway)
         | 
| 67 56 | 
             
                            gateway.watch('sinatra.request.routed', :appsec) do |stack, (gateway_request, gateway_route_params)|
         | 
| 68 | 
            -
                              block = false
         | 
| 69 | 
            -
             | 
| 70 57 | 
             
                              event = nil
         | 
| 71 | 
            -
                               | 
| 72 | 
            -
             | 
| 73 | 
            -
             | 
| 74 | 
            -
             | 
| 75 | 
            -
             | 
| 76 | 
            -
             | 
| 77 | 
            -
             | 
| 78 | 
            -
             | 
| 79 | 
            -
             | 
| 80 | 
            -
             | 
| 81 | 
            -
             | 
| 82 | 
            -
             | 
| 83 | 
            -
             | 
| 84 | 
            -
             | 
| 85 | 
            -
             | 
| 86 | 
            -
             | 
| 87 | 
            -
             | 
| 88 | 
            -
             | 
| 89 | 
            -
                                  end
         | 
| 58 | 
            +
                              context = gateway_request.env[Datadog::AppSec::Ext::CONTEXT_KEY]
         | 
| 59 | 
            +
                              engine = AppSec::Reactive::Engine.new
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                              Sinatra::Reactive::Routed.subscribe(engine, context) do |result|
         | 
| 62 | 
            +
                                if result.status == :match
         | 
| 63 | 
            +
                                  # TODO: should this hash be an Event instance instead?
         | 
| 64 | 
            +
                                  event = {
         | 
| 65 | 
            +
                                    waf_result: result,
         | 
| 66 | 
            +
                                    trace: context.trace,
         | 
| 67 | 
            +
                                    span: context.span,
         | 
| 68 | 
            +
                                    request: gateway_request,
         | 
| 69 | 
            +
                                    actions: result.actions
         | 
| 70 | 
            +
                                  }
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                                  # We want to keep the trace in case of security event
         | 
| 73 | 
            +
                                  context.trace.keep! if context.trace
         | 
| 74 | 
            +
                                  Datadog::AppSec::Event.tag_and_keep!(context, result)
         | 
| 75 | 
            +
                                  context.waf_runner.events << event
         | 
| 90 76 | 
             
                                end
         | 
| 91 | 
            -
             | 
| 92 | 
            -
                                block = Sinatra::Reactive::Routed.publish(op, [gateway_request, gateway_route_params])
         | 
| 93 77 | 
             
                              end
         | 
| 94 78 |  | 
| 79 | 
            +
                              block = Sinatra::Reactive::Routed.publish(engine, [gateway_request, gateway_route_params])
         | 
| 95 80 | 
             
                              next [nil, [[:block, event]]] if block
         | 
| 96 81 |  | 
| 97 | 
            -
                               | 
| 98 | 
            -
             | 
| 99 | 
            -
                              if event
         | 
| 100 | 
            -
                                res ||= []
         | 
| 101 | 
            -
                                res << [:monitor, event]
         | 
| 102 | 
            -
                              end
         | 
| 103 | 
            -
             | 
| 104 | 
            -
                              [ret, res]
         | 
| 82 | 
            +
                              stack.call(gateway_request.request)
         | 
| 105 83 | 
             
                            end
         | 
| 106 84 | 
             
                          end
         | 
| 107 85 | 
             
                        end
         | 
| @@ -54,7 +54,7 @@ module Datadog | |
| 54 54 | 
             
                      def dispatch!
         | 
| 55 55 | 
             
                        env = @request.env
         | 
| 56 56 |  | 
| 57 | 
            -
                        context = env[Datadog::AppSec::Ext:: | 
| 57 | 
            +
                        context = env[Datadog::AppSec::Ext::CONTEXT_KEY]
         | 
| 58 58 |  | 
| 59 59 | 
             
                        return super unless context
         | 
| 60 60 |  | 
| @@ -86,7 +86,7 @@ module Datadog | |
| 86 86 | 
             
                      def process_route(*)
         | 
| 87 87 | 
             
                        env = @request.env
         | 
| 88 88 |  | 
| 89 | 
            -
                        context = env[Datadog::AppSec::Ext:: | 
| 89 | 
            +
                        context = env[Datadog::AppSec::Ext::CONTEXT_KEY]
         | 
| 90 90 |  | 
| 91 91 | 
             
                        return super unless context
         | 
| 92 92 |  | 
| @@ -12,18 +12,18 @@ module Datadog | |
| 12 12 | 
             
                        ].freeze
         | 
| 13 13 | 
             
                        private_constant :ADDRESSES
         | 
| 14 14 |  | 
| 15 | 
            -
                        def self.publish( | 
| 15 | 
            +
                        def self.publish(engine, data)
         | 
| 16 16 | 
             
                          _request, route_params = data
         | 
| 17 17 |  | 
| 18 18 | 
             
                          catch(:block) do
         | 
| 19 | 
            -
                             | 
| 19 | 
            +
                            engine.publish('sinatra.request.route_params', route_params.params)
         | 
| 20 20 |  | 
| 21 21 | 
             
                            nil
         | 
| 22 22 | 
             
                          end
         | 
| 23 23 | 
             
                        end
         | 
| 24 24 |  | 
| 25 | 
            -
                        def self.subscribe( | 
| 26 | 
            -
                           | 
| 25 | 
            +
                        def self.subscribe(engine, context)
         | 
| 26 | 
            +
                          engine.subscribe(*ADDRESSES) do |*values|
         | 
| 27 27 | 
             
                            Datadog.logger.debug { "reacted to #{ADDRESSES.inspect}: #{values.inspect}" }
         | 
| 28 28 | 
             
                            path_params = values[0]
         | 
| 29 29 |  | 
| @@ -32,7 +32,7 @@ module Datadog | |
| 32 32 | 
             
                            }
         | 
| 33 33 |  | 
| 34 34 | 
             
                            waf_timeout = Datadog.configuration.appsec.waf_timeout
         | 
| 35 | 
            -
                            result =  | 
| 35 | 
            +
                            result = context.run_waf(persistent_data, {}, waf_timeout)
         | 
| 36 36 |  | 
| 37 37 | 
             
                            next if result.status != :match
         | 
| 38 38 |  | 
    
        data/lib/datadog/appsec/event.rb
    CHANGED
    
    | @@ -137,16 +137,16 @@ module Datadog | |
| 137 137 | 
             
                    end
         | 
| 138 138 | 
             
                    # rubocop:enable Metrics/MethodLength
         | 
| 139 139 |  | 
| 140 | 
            -
                    def tag_and_keep!( | 
| 140 | 
            +
                    def tag_and_keep!(context, waf_result)
         | 
| 141 141 | 
             
                      # We want to keep the trace in case of security event
         | 
| 142 | 
            -
                       | 
| 142 | 
            +
                      context.trace.keep! if context.trace
         | 
| 143 143 |  | 
| 144 | 
            -
                      if  | 
| 145 | 
            -
                         | 
| 146 | 
            -
                         | 
| 144 | 
            +
                      if context.span
         | 
| 145 | 
            +
                        context.span.set_tag('appsec.blocked', 'true') if waf_result.actions.key?('block_request')
         | 
| 146 | 
            +
                        context.span.set_tag('appsec.event', 'true')
         | 
| 147 147 | 
             
                      end
         | 
| 148 148 |  | 
| 149 | 
            -
                      add_distributed_tags( | 
| 149 | 
            +
                      add_distributed_tags(context.trace)
         | 
| 150 150 | 
             
                    end
         | 
| 151 151 |  | 
| 152 152 | 
             
                    private
         | 
    
        data/lib/datadog/appsec/ext.rb
    CHANGED
    
    | @@ -3,8 +3,10 @@ | |
| 3 3 | 
             
            module Datadog
         | 
| 4 4 | 
             
              module AppSec
         | 
| 5 5 | 
             
                module Ext
         | 
| 6 | 
            +
                  RASP_SQLI = :sql_injection
         | 
| 6 7 | 
             
                  INTERRUPT = :datadog_appsec_interrupt
         | 
| 7 | 
            -
                   | 
| 8 | 
            +
                  CONTEXT_KEY = 'datadog.appsec.context'
         | 
| 9 | 
            +
                  ACTIVE_CONTEXT_KEY = :datadog_appsec_active_context
         | 
| 8 10 |  | 
| 9 11 | 
             
                  TAG_APPSEC_ENABLED = '_dd.appsec.enabled'
         | 
| 10 12 | 
             
                  TAG_APM_ENABLED = '_dd.apm.enabled'
         | 
| @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            require_relative '../../instrumentation/gateway'
         | 
| 4 | 
            -
            require_relative '../../reactive/ | 
| 4 | 
            +
            require_relative '../../reactive/engine'
         | 
| 5 5 | 
             
            require_relative '../reactive/set_user'
         | 
| 6 6 |  | 
| 7 7 | 
             
            module Datadog
         | 
| @@ -19,42 +19,32 @@ module Datadog | |
| 19 19 |  | 
| 20 20 | 
             
                        def watch_user_id(gateway = Instrumentation.gateway)
         | 
| 21 21 | 
             
                          gateway.watch('identity.set_user', :appsec) do |stack, user|
         | 
| 22 | 
            -
                            block = false
         | 
| 23 22 | 
             
                            event = nil
         | 
| 24 | 
            -
                             | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
                                end
         | 
| 23 | 
            +
                            context = Datadog::AppSec.active_context
         | 
| 24 | 
            +
                            engine = AppSec::Reactive::Engine.new
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                            Monitor::Reactive::SetUser.subscribe(engine, context) do |result|
         | 
| 27 | 
            +
                              if result.status == :match
         | 
| 28 | 
            +
                                # TODO: should this hash be an Event instance instead?
         | 
| 29 | 
            +
                                event = {
         | 
| 30 | 
            +
                                  waf_result: result,
         | 
| 31 | 
            +
                                  trace: context.trace,
         | 
| 32 | 
            +
                                  span: context.span,
         | 
| 33 | 
            +
                                  user: user,
         | 
| 34 | 
            +
                                  actions: result.actions
         | 
| 35 | 
            +
                                }
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                                # We want to keep the trace in case of security event
         | 
| 38 | 
            +
                                context.trace.keep! if context.trace
         | 
| 39 | 
            +
                                Datadog::AppSec::Event.tag_and_keep!(context, result)
         | 
| 40 | 
            +
                                context.waf_runner.events << event
         | 
| 43 41 | 
             
                              end
         | 
| 44 | 
            -
             | 
| 45 | 
            -
                              block = Monitor::Reactive::SetUser.publish(op, user)
         | 
| 46 42 | 
             
                            end
         | 
| 47 43 |  | 
| 48 | 
            -
                             | 
| 49 | 
            -
             | 
| 50 | 
            -
                            ret, res = stack.call(user)
         | 
| 51 | 
            -
             | 
| 52 | 
            -
                            if event
         | 
| 53 | 
            -
                              res ||= []
         | 
| 54 | 
            -
                              res << [:monitor, event]
         | 
| 55 | 
            -
                            end
         | 
| 44 | 
            +
                            block = Monitor::Reactive::SetUser.publish(engine, user)
         | 
| 45 | 
            +
                            throw(Datadog::AppSec::Ext::INTERRUPT, event[:actions]) if block
         | 
| 56 46 |  | 
| 57 | 
            -
                             | 
| 47 | 
            +
                            stack.call(user)
         | 
| 58 48 | 
             
                          end
         | 
| 59 49 | 
             
                        end
         | 
| 60 50 | 
             
                      end
         | 
| @@ -11,16 +11,16 @@ module Datadog | |
| 11 11 | 
             
                      ].freeze
         | 
| 12 12 | 
             
                      private_constant :ADDRESSES
         | 
| 13 13 |  | 
| 14 | 
            -
                      def self.publish( | 
| 14 | 
            +
                      def self.publish(engine, user)
         | 
| 15 15 | 
             
                        catch(:block) do
         | 
| 16 | 
            -
                           | 
| 16 | 
            +
                          engine.publish('usr.id', user.id)
         | 
| 17 17 |  | 
| 18 18 | 
             
                          nil
         | 
| 19 19 | 
             
                        end
         | 
| 20 20 | 
             
                      end
         | 
| 21 21 |  | 
| 22 | 
            -
                      def self.subscribe( | 
| 23 | 
            -
                         | 
| 22 | 
            +
                      def self.subscribe(engine, context)
         | 
| 23 | 
            +
                        engine.subscribe(*ADDRESSES) do |*values|
         | 
| 24 24 | 
             
                          Datadog.logger.debug { "reacted to #{ADDRESSES.inspect}: #{values.inspect}" }
         | 
| 25 25 |  | 
| 26 26 | 
             
                          user_id = values[0]
         | 
| @@ -30,7 +30,7 @@ module Datadog | |
| 30 30 | 
             
                          }
         | 
| 31 31 |  | 
| 32 32 | 
             
                          waf_timeout = Datadog.configuration.appsec.waf_timeout
         | 
| 33 | 
            -
                          result =  | 
| 33 | 
            +
                          result = context.run_waf(persistent_data, {}, waf_timeout)
         | 
| 34 34 |  | 
| 35 35 | 
             
                          next if result.status != :match
         | 
| 36 36 |  | 
    
        data/lib/datadog/appsec.rb
    CHANGED
    
    | @@ -2,7 +2,7 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            require_relative 'appsec/configuration'
         | 
| 4 4 | 
             
            require_relative 'appsec/extensions'
         | 
| 5 | 
            -
            require_relative 'appsec/ | 
| 5 | 
            +
            require_relative 'appsec/context'
         | 
| 6 6 | 
             
            require_relative 'appsec/ext'
         | 
| 7 7 | 
             
            require_relative 'appsec/utils'
         | 
| 8 8 |  | 
| @@ -14,8 +14,8 @@ module Datadog | |
| 14 14 | 
             
                    Datadog.configuration.appsec.enabled
         | 
| 15 15 | 
             
                  end
         | 
| 16 16 |  | 
| 17 | 
            -
                  def  | 
| 18 | 
            -
                    Datadog::AppSec:: | 
| 17 | 
            +
                  def active_context
         | 
| 18 | 
            +
                    Datadog::AppSec::Context.active
         | 
| 19 19 | 
             
                  end
         | 
| 20 20 |  | 
| 21 21 | 
             
                  def processor
         | 
| @@ -6,6 +6,9 @@ | |
| 6 6 | 
             
            require_relative '../datadog'
         | 
| 7 7 | 
             
            require_relative 'tracing/contrib/auto_instrument'
         | 
| 8 8 |  | 
| 9 | 
            +
            # DI is not loaded on Ruby 2.5 and JRuby
         | 
| 10 | 
            +
            Datadog::DI::Contrib.load_now_or_later if defined?(Datadog::DI::Contrib)
         | 
| 11 | 
            +
             | 
| 9 12 | 
             
            Datadog::Profiling.start_if_enabled
         | 
| 10 13 |  | 
| 11 14 | 
             
            module Datadog
         | 
| @@ -19,21 +19,49 @@ module Datadog | |
| 19 19 | 
             
                  # Whenever there is a conflict (different configurations are provided in different orders), it MUST warn the users
         | 
| 20 20 | 
             
                  # about it and pick a value based on the following priority: code > environment variable > defaults.
         | 
| 21 21 | 
             
                  class AgentSettingsResolver
         | 
| 22 | 
            -
                     | 
| 23 | 
            -
             | 
| 24 | 
            -
                      :ssl,
         | 
| 25 | 
            -
             | 
| 26 | 
            -
                      :port,
         | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
                         | 
| 22 | 
            +
                    # Immutable container for the resulting settings
         | 
| 23 | 
            +
                    class AgentSettings
         | 
| 24 | 
            +
                      attr_reader :adapter, :ssl, :hostname, :port, :uds_path, :timeout_seconds
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                      def initialize(adapter: nil, ssl: nil, hostname: nil, port: nil, uds_path: nil, timeout_seconds: nil)
         | 
| 27 | 
            +
                        @adapter = adapter
         | 
| 28 | 
            +
                        @ssl = ssl
         | 
| 29 | 
            +
                        @hostname = hostname
         | 
| 30 | 
            +
                        @port = port
         | 
| 31 | 
            +
                        @uds_path = uds_path
         | 
| 32 | 
            +
                        @timeout_seconds = timeout_seconds
         | 
| 33 33 | 
             
                        freeze
         | 
| 34 34 | 
             
                      end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                      def url
         | 
| 37 | 
            +
                        case adapter
         | 
| 38 | 
            +
                        when Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER
         | 
| 39 | 
            +
                          hostname = self.hostname
         | 
| 40 | 
            +
                          hostname = "[#{hostname}]" if hostname =~ IPV6_REGEXP
         | 
| 41 | 
            +
                          "#{ssl ? 'https' : 'http'}://#{hostname}:#{port}/"
         | 
| 42 | 
            +
                        when Datadog::Core::Configuration::Ext::Agent::UnixSocket::ADAPTER
         | 
| 43 | 
            +
                          "unix://#{uds_path}"
         | 
| 44 | 
            +
                        else
         | 
| 45 | 
            +
                          raise ArgumentError, "Unexpected adapter: #{adapter}"
         | 
| 46 | 
            +
                        end
         | 
| 47 | 
            +
                      end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                      def ==(other)
         | 
| 50 | 
            +
                        self.class == other.class &&
         | 
| 51 | 
            +
                          adapter == other.adapter &&
         | 
| 52 | 
            +
                          ssl == other.ssl &&
         | 
| 53 | 
            +
                          hostname == other.hostname &&
         | 
| 54 | 
            +
                          port == other.port &&
         | 
| 55 | 
            +
                          uds_path == other.uds_path &&
         | 
| 56 | 
            +
                          timeout_seconds == other.timeout_seconds
         | 
| 57 | 
            +
                      end
         | 
| 35 58 | 
             
                    end
         | 
| 36 59 |  | 
| 60 | 
            +
                    # IPv6 regular expression from
         | 
| 61 | 
            +
                    # https://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses
         | 
| 62 | 
            +
                    # Does not match IPv4 addresses.
         | 
| 63 | 
            +
                    IPV6_REGEXP = /\A(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\z)/.freeze # rubocop:disable Layout/LineLength
         | 
| 64 | 
            +
             | 
| 37 65 | 
             
                    def self.call(settings, logger: Datadog.logger)
         | 
| 38 66 | 
             
                      new(settings, logger: logger).send(:call)
         | 
| 39 67 | 
             
                    end
         | 
| @@ -105,14 +105,16 @@ module Datadog | |
| 105 105 | 
             
                      @profiler, profiler_logger_extra = Datadog::Profiling::Component.build_profiler_component(
         | 
| 106 106 | 
             
                        settings: settings,
         | 
| 107 107 | 
             
                        agent_settings: agent_settings,
         | 
| 108 | 
            -
                        optional_tracer: @tracer
         | 
| 108 | 
            +
                        optional_tracer: @tracer,
         | 
| 109 | 
            +
                        logger: @logger,
         | 
| 109 110 | 
             
                      )
         | 
| 110 111 | 
             
                      @environment_logger_extra.merge!(profiler_logger_extra) if profiler_logger_extra
         | 
| 111 112 |  | 
| 112 113 | 
             
                      @runtime_metrics = self.class.build_runtime_metrics_worker(settings)
         | 
| 113 114 | 
             
                      @health_metrics = self.class.build_health_metrics(settings)
         | 
| 114 115 | 
             
                      @appsec = Datadog::AppSec::Component.build_appsec_component(settings, telemetry: telemetry)
         | 
| 115 | 
            -
                      @dynamic_instrumentation = Datadog::DI::Component.build(settings, agent_settings, telemetry: telemetry)
         | 
| 116 | 
            +
                      @dynamic_instrumentation = Datadog::DI::Component.build(settings, agent_settings, @logger, telemetry: telemetry)
         | 
| 117 | 
            +
                      @environment_logger_extra[:dynamic_instrumentation_enabled] = !!@dynamic_instrumentation
         | 
| 116 118 |  | 
| 117 119 | 
             
                      self.class.configure_tracing(settings)
         | 
| 118 120 | 
             
                    end
         | 
| @@ -236,7 +236,7 @@ module Datadog | |
| 236 236 | 
             
                      rescue ThreadError => e
         | 
| 237 237 | 
             
                        logger_without_components.error(
         | 
| 238 238 | 
             
                          'Detected deadlock during datadog initialization. ' \
         | 
| 239 | 
            -
                          'Please report this at https://github.com/ | 
| 239 | 
            +
                          'Please report this at https://github.com/datadog/dd-trace-rb/blob/master/CONTRIBUTING.md#found-a-bug' \
         | 
| 240 240 | 
             
                          "\n\tSource:\n\t#{Array(e.backtrace).join("\n\t")}"
         | 
| 241 241 | 
             
                        )
         | 
| 242 242 | 
             
                        nil
         | 
| @@ -3,7 +3,6 @@ | |
| 3 3 | 
             
            require 'libdatadog'
         | 
| 4 4 |  | 
| 5 5 | 
             
            require_relative 'tag_builder'
         | 
| 6 | 
            -
            require_relative 'agent_base_url'
         | 
| 7 6 | 
             
            require_relative '../utils/only_once'
         | 
| 8 7 | 
             
            require_relative '../utils/at_fork_monkey_patch'
         | 
| 9 8 |  | 
| @@ -31,8 +30,7 @@ module Datadog | |
| 31 30 |  | 
| 32 31 | 
             
                    def self.build(settings, agent_settings, logger:)
         | 
| 33 32 | 
             
                      tags = TagBuilder.call(settings)
         | 
| 34 | 
            -
                      agent_base_url =  | 
| 35 | 
            -
                      logger.warn('Missing agent base URL; cannot enable crash tracking') unless agent_base_url
         | 
| 33 | 
            +
                      agent_base_url = agent_settings.url
         | 
| 36 34 |  | 
| 37 35 | 
             
                      ld_library_path = ::Libdatadog.ld_library_path
         | 
| 38 36 | 
             
                      logger.warn('Missing ld_library_path; cannot enable crash tracking') unless ld_library_path
         | 
| @@ -29,6 +29,22 @@ module Datadog | |
| 29 29 | 
             
                      def payload
         | 
| 30 30 | 
             
                        {}
         | 
| 31 31 | 
             
                      end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                      # Override equality to allow for deduplication
         | 
| 34 | 
            +
                      # The basic implementation is to check if the other object is an instance of the same class.
         | 
| 35 | 
            +
                      # This works for events that have no attributes.
         | 
| 36 | 
            +
                      # For events with attributes, you should override this method to compare the attributes.
         | 
| 37 | 
            +
                      def ==(other)
         | 
| 38 | 
            +
                        other.is_a?(self.class)
         | 
| 39 | 
            +
                      end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                      # @see #==
         | 
| 42 | 
            +
                      alias eql? ==
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                      # @see #==
         | 
| 45 | 
            +
                      def hash
         | 
| 46 | 
            +
                        self.class.hash
         | 
| 47 | 
            +
                      end
         | 
| 32 48 | 
             
                    end
         | 
| 33 49 |  | 
| 34 50 | 
             
                    # Telemetry class for the 'app-started' event
         | 
| @@ -263,6 +279,8 @@ module Datadog | |
| 263 279 |  | 
| 264 280 | 
             
                    # Telemetry class for the 'app-client-configuration-change' event
         | 
| 265 281 | 
             
                    class AppClientConfigurationChange < Base
         | 
| 282 | 
            +
                      attr_reader :changes, :origin
         | 
| 283 | 
            +
             | 
| 266 284 | 
             
                      def type
         | 
| 267 285 | 
             
                        'app-client-configuration-change'
         | 
| 268 286 | 
             
                      end
         | 
| @@ -301,6 +319,16 @@ module Datadog | |
| 301 319 |  | 
| 302 320 | 
             
                        res
         | 
| 303 321 | 
             
                      end
         | 
| 322 | 
            +
             | 
| 323 | 
            +
                      def ==(other)
         | 
| 324 | 
            +
                        other.is_a?(AppClientConfigurationChange) && other.changes == @changes && other.origin == @origin
         | 
| 325 | 
            +
                      end
         | 
| 326 | 
            +
             | 
| 327 | 
            +
                      alias eql? ==
         | 
| 328 | 
            +
             | 
| 329 | 
            +
                      def hash
         | 
| 330 | 
            +
                        [self.class, @changes, @origin].hash
         | 
| 331 | 
            +
                      end
         | 
| 304 332 | 
             
                    end
         | 
| 305 333 |  | 
| 306 334 | 
             
                    # Telemetry class for the 'app-heartbeat' event
         | 
| @@ -319,6 +347,8 @@ module Datadog | |
| 319 347 |  | 
| 320 348 | 
             
                    # Telemetry class for the 'generate-metrics' event
         | 
| 321 349 | 
             
                    class GenerateMetrics < Base
         | 
| 350 | 
            +
                      attr_reader :namespace, :metric_series
         | 
| 351 | 
            +
             | 
| 322 352 | 
             
                      def type
         | 
| 323 353 | 
             
                        'generate-metrics'
         | 
| 324 354 | 
             
                      end
         | 
| @@ -335,24 +365,54 @@ module Datadog | |
| 335 365 | 
             
                          series: @metric_series.map(&:to_h)
         | 
| 336 366 | 
             
                        }
         | 
| 337 367 | 
             
                      end
         | 
| 368 | 
            +
             | 
| 369 | 
            +
                      def ==(other)
         | 
| 370 | 
            +
                        other.is_a?(GenerateMetrics) && other.namespace == @namespace && other.metric_series == @metric_series
         | 
| 371 | 
            +
                      end
         | 
| 372 | 
            +
             | 
| 373 | 
            +
                      alias eql? ==
         | 
| 374 | 
            +
             | 
| 375 | 
            +
                      def hash
         | 
| 376 | 
            +
                        [self.class, @namespace, @metric_series].hash
         | 
| 377 | 
            +
                      end
         | 
| 338 378 | 
             
                    end
         | 
| 339 379 |  | 
| 340 | 
            -
                    # Telemetry class for the 'logs' event
         | 
| 380 | 
            +
                    # Telemetry class for the 'logs' event.
         | 
| 381 | 
            +
                    # Logs with the same content are deduplicated at flush time.
         | 
| 341 382 | 
             
                    class Log < Base
         | 
| 342 383 | 
             
                      LEVELS = {
         | 
| 343 384 | 
             
                        error: 'ERROR',
         | 
| 344 385 | 
             
                        warn: 'WARN',
         | 
| 345 386 | 
             
                      }.freeze
         | 
| 346 387 |  | 
| 388 | 
            +
                      LEVELS_STRING = LEVELS.values.freeze
         | 
| 389 | 
            +
             | 
| 390 | 
            +
                      attr_reader :message, :level, :stack_trace, :count
         | 
| 391 | 
            +
             | 
| 347 392 | 
             
                      def type
         | 
| 348 393 | 
             
                        'logs'
         | 
| 349 394 | 
             
                      end
         | 
| 350 395 |  | 
| 351 | 
            -
                       | 
| 396 | 
            +
                      # @param message [String] the log message
         | 
| 397 | 
            +
                      # @param level [Symbol, String] the log level. Either :error, :warn, 'ERROR', or 'WARN'.
         | 
| 398 | 
            +
                      # @param stack_trace [String, nil] the stack trace
         | 
| 399 | 
            +
                      # @param count [Integer] the number of times the log was emitted. Used for deduplication.
         | 
| 400 | 
            +
                      def initialize(message:, level:, stack_trace: nil, count: 1)
         | 
| 352 401 | 
             
                        super()
         | 
| 353 402 | 
             
                        @message = message
         | 
| 354 403 | 
             
                        @stack_trace = stack_trace
         | 
| 355 | 
            -
             | 
| 404 | 
            +
             | 
| 405 | 
            +
                        if level.is_a?(String) && LEVELS_STRING.include?(level)
         | 
| 406 | 
            +
                          # String level is used during object copy for deduplication
         | 
| 407 | 
            +
                          @level = level
         | 
| 408 | 
            +
                        elsif level.is_a?(Symbol)
         | 
| 409 | 
            +
                          # Symbol level is used by the regular log emitter user
         | 
| 410 | 
            +
                          @level = LEVELS.fetch(level) { |k| raise ArgumentError, "Invalid log level :#{k}" }
         | 
| 411 | 
            +
                        else
         | 
| 412 | 
            +
                          raise ArgumentError, "Invalid log level #{level}"
         | 
| 413 | 
            +
                        end
         | 
| 414 | 
            +
             | 
| 415 | 
            +
                        @count = count
         | 
| 356 416 | 
             
                      end
         | 
| 357 417 |  | 
| 358 418 | 
             
                      def payload
         | 
| @@ -362,10 +422,24 @@ module Datadog | |
| 362 422 | 
             
                              message: @message,
         | 
| 363 423 | 
             
                              level: @level,
         | 
| 364 424 | 
             
                              stack_trace: @stack_trace,
         | 
| 425 | 
            +
                              count: @count,
         | 
| 365 426 | 
             
                            }.compact
         | 
| 366 427 | 
             
                          ]
         | 
| 367 428 | 
             
                        }
         | 
| 368 429 | 
             
                      end
         | 
| 430 | 
            +
             | 
| 431 | 
            +
                      # override equality to allow for deduplication
         | 
| 432 | 
            +
                      def ==(other)
         | 
| 433 | 
            +
                        other.is_a?(Log) &&
         | 
| 434 | 
            +
                          other.message == @message &&
         | 
| 435 | 
            +
                          other.level == @level && other.stack_trace == @stack_trace && other.count == @count
         | 
| 436 | 
            +
                      end
         | 
| 437 | 
            +
             | 
| 438 | 
            +
                      alias eql? ==
         | 
| 439 | 
            +
             | 
| 440 | 
            +
                      def hash
         | 
| 441 | 
            +
                        [self.class, @message, @level, @stack_trace, @count].hash
         | 
| 442 | 
            +
                      end
         | 
| 369 443 | 
             
                    end
         | 
| 370 444 |  | 
| 371 445 | 
             
                    # Telemetry class for the 'distributions' event
         | 
| @@ -395,6 +469,16 @@ module Datadog | |
| 395 469 | 
             
                          }
         | 
| 396 470 | 
             
                        end
         | 
| 397 471 | 
             
                      end
         | 
| 472 | 
            +
             | 
| 473 | 
            +
                      def ==(other)
         | 
| 474 | 
            +
                        other.is_a?(MessageBatch) && other.events == @events
         | 
| 475 | 
            +
                      end
         | 
| 476 | 
            +
             | 
| 477 | 
            +
                      alias eql? ==
         | 
| 478 | 
            +
             | 
| 479 | 
            +
                      def hash
         | 
| 480 | 
            +
                        [self.class, @events].hash
         | 
| 481 | 
            +
                      end
         | 
| 398 482 | 
             
                    end
         | 
| 399 483 | 
             
                  end
         | 
| 400 484 | 
             
                end
         | 
| @@ -41,7 +41,7 @@ module Datadog | |
| 41 41 | 
             
                          else
         | 
| 42 42 | 
             
                            'REDACTED'
         | 
| 43 43 | 
             
                          end
         | 
| 44 | 
            -
                        end.join( | 
| 44 | 
            +
                        end.join("\n")
         | 
| 45 45 | 
             
                      end
         | 
| 46 46 | 
             
                    end
         | 
| 47 47 |  | 
| @@ -49,7 +49,7 @@ module Datadog | |
| 49 49 | 
             
                      # Annoymous exceptions to be logged as <Class:0x00007f8b1c0b3b40>
         | 
| 50 50 | 
             
                      message = +''
         | 
| 51 51 | 
             
                      message << (exception.class.name || exception.class.inspect)
         | 
| 52 | 
            -
                      message << ':' << description if description
         | 
| 52 | 
            +
                      message << ': ' << description if description
         | 
| 53 53 |  | 
| 54 54 | 
             
                      event = Event::Log.new(
         | 
| 55 55 | 
             
                        message: message,
         |