datadog 2.7.0 → 2.8.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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +43 -1
  3. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +47 -17
  4. data/ext/datadog_profiling_native_extension/extconf.rb +3 -8
  5. data/ext/datadog_profiling_native_extension/heap_recorder.c +11 -89
  6. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +3 -9
  7. data/ext/datadog_profiling_native_extension/profiling.c +6 -0
  8. data/ext/datadog_profiling_native_extension/ruby_helpers.c +14 -4
  9. data/ext/datadog_profiling_native_extension/ruby_helpers.h +4 -0
  10. data/ext/datadog_profiling_native_extension/stack_recorder.c +0 -34
  11. data/ext/libdatadog_extconf_helpers.rb +1 -1
  12. data/lib/datadog/appsec/component.rb +1 -8
  13. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +73 -0
  14. data/lib/datadog/appsec/contrib/active_record/integration.rb +41 -0
  15. data/lib/datadog/appsec/contrib/active_record/patcher.rb +53 -0
  16. data/lib/datadog/appsec/event.rb +1 -1
  17. data/lib/datadog/appsec/processor/context.rb +2 -2
  18. data/lib/datadog/appsec/remote.rb +1 -3
  19. data/lib/datadog/appsec/response.rb +7 -11
  20. data/lib/datadog/appsec.rb +3 -2
  21. data/lib/datadog/core/configuration/components.rb +17 -1
  22. data/lib/datadog/core/configuration/settings.rb +10 -0
  23. data/lib/datadog/core/configuration.rb +9 -1
  24. data/lib/datadog/core/remote/client/capabilities.rb +6 -0
  25. data/lib/datadog/core/remote/client.rb +65 -59
  26. data/lib/datadog/core/telemetry/component.rb +9 -3
  27. data/lib/datadog/core/telemetry/ext.rb +1 -0
  28. data/lib/datadog/di/code_tracker.rb +5 -4
  29. data/lib/datadog/di/component.rb +5 -1
  30. data/lib/datadog/di/contrib/active_record.rb +1 -0
  31. data/lib/datadog/di/init.rb +20 -0
  32. data/lib/datadog/di/instrumenter.rb +81 -11
  33. data/lib/datadog/di/probe.rb +11 -1
  34. data/lib/datadog/di/probe_builder.rb +1 -0
  35. data/lib/datadog/di/probe_manager.rb +4 -1
  36. data/lib/datadog/di/probe_notification_builder.rb +13 -7
  37. data/lib/datadog/di/remote.rb +124 -0
  38. data/lib/datadog/di/serializer.rb +14 -7
  39. data/lib/datadog/di/transport.rb +2 -1
  40. data/lib/datadog/di/utils.rb +7 -0
  41. data/lib/datadog/di.rb +84 -20
  42. data/lib/datadog/profiling/component.rb +4 -16
  43. data/lib/datadog/tracing/configuration/settings.rb +4 -8
  44. data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +16 -4
  45. data/lib/datadog/tracing/contrib/elasticsearch/configuration/settings.rb +4 -0
  46. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +6 -1
  47. data/lib/datadog/tracing/tracer.rb +1 -1
  48. data/lib/datadog/version.rb +1 -1
  49. data/lib/datadog.rb +3 -0
  50. metadata +17 -13
  51. data/lib/datadog/appsec/processor/actions.rb +0 -49
data/lib/datadog/di.rb CHANGED
@@ -12,6 +12,7 @@ require_relative 'di/probe_manager'
12
12
  require_relative 'di/probe_notification_builder'
13
13
  require_relative 'di/probe_notifier_worker'
14
14
  require_relative 'di/redactor'
15
+ require_relative 'di/remote'
15
16
  require_relative 'di/serializer'
16
17
  require_relative 'di/transport'
17
18
  require_relative 'di/utils'
@@ -25,6 +26,9 @@ if defined?(ActiveRecord::Base)
25
26
  # and AR should be loaded before any application code is loaded, being
26
27
  # part of Rails, therefore for now we should be OK to just require the
27
28
  # AR integration from here.
29
+ #
30
+ # TODO this require might need to be delayed via Rails post-initialization
31
+ # logic?
28
32
  require_relative 'di/contrib/active_record'
29
33
  end
30
34
 
@@ -42,6 +46,8 @@ module Datadog
42
46
  # Expose DI to global shared objects
43
47
  Extensions.activate!
44
48
 
49
+ LOCK = Mutex.new
50
+
45
51
  class << self
46
52
  attr_reader :code_tracker
47
53
 
@@ -58,6 +64,32 @@ module Datadog
58
64
  (@code_tracker ||= CodeTracker.new).start
59
65
  end
60
66
 
67
+ # Activates code tracking if possible.
68
+ #
69
+ # This method does nothing if invoked in an environment that does not
70
+ # implement required trace points for code tracking (MRI Ruby < 2.6,
71
+ # JRuby) and rescues any exceptions that may be raised by downstream
72
+ # DI code.
73
+ def activate_tracking
74
+ # :script_compiled trace point was added in Ruby 2.6.
75
+ return unless RUBY_VERSION >= '2.6'
76
+
77
+ begin
78
+ # Activate code tracking by default because line trace points will not work
79
+ # without it.
80
+ Datadog::DI.activate_tracking!
81
+ rescue => exc
82
+ if defined?(Datadog.logger)
83
+ Datadog.logger.warn("Failed to activate code tracking for DI: #{exc.class}: #{exc}")
84
+ else
85
+ # We do not have Datadog logger potentially because DI code tracker is
86
+ # being loaded early in application boot process and the rest of datadog
87
+ # wasn't loaded yet. Output to standard error.
88
+ warn("Failed to activate code tracking for DI: #{exc.class}: #{exc}")
89
+ end
90
+ end
91
+ end
92
+
61
93
  # Deactivates code tracking. In normal usage of DI this method should
62
94
  # never be called, however it is used by DI's test suite to reset
63
95
  # state for individual tests.
@@ -76,30 +108,62 @@ module Datadog
76
108
  code_tracker&.active? || false
77
109
  end
78
110
 
111
+ # This method is called from DI Remote handler to issue DI operations
112
+ # to the probe manager (add or remove probes).
113
+ #
114
+ # When DI Remote is executing, Datadog.components should be initialized
115
+ # and we should be able to reference it to get to the DI component.
116
+ #
117
+ # Given that we need the current_component anyway for code tracker,
118
+ # perhaps we should delete the +component+ method and just use
119
+ # +current_component+ in all cases.
79
120
  def component
80
- # TODO uncomment when remote is merged
81
- #Datadog.send(:components).dynamic_instrumentation
121
+ Datadog.send(:components).dynamic_instrumentation
122
+ end
123
+
124
+ # DI code tracker is instantiated globally before the regular set of
125
+ # components is created, but the code tracker needs to call out to the
126
+ # "current" DI component to perform instrumentation when application
127
+ # code is loaded. Because this call may happen prior to Datadog
128
+ # components having been initialized, we maintain the "current component"
129
+ # which contains a reference to the most recently instantiated
130
+ # DI::Component. This way, if a DI component hasn't been instantiated,
131
+ # we do not try to reference Datadog.components.
132
+ def current_component
133
+ LOCK.synchronize do
134
+ @current_components&.last
135
+ end
136
+ end
137
+
138
+ # To avoid potential races with DI::Component being added and removed,
139
+ # we maintain a list of the components. Normally the list should contain
140
+ # either zero or one component depending on whether DI is enabled in
141
+ # Datadog configuration. However, if a new instance of DI::Component
142
+ # is created while the previous instance is still running, we are
143
+ # guaranteed to not end up with no component when one is running.
144
+ def add_current_component(component)
145
+ LOCK.synchronize do
146
+ @current_components ||= []
147
+ @current_components << component
148
+ end
149
+ end
150
+
151
+ def remove_current_component(component)
152
+ LOCK.synchronize do
153
+ @current_components&.delete(component)
154
+ end
82
155
  end
83
156
  end
84
157
  end
85
158
  end
86
159
 
87
- =begin not yet enabled
88
- # :script_compiled trace point was added in Ruby 2.6.
89
- if RUBY_VERSION >= '2.6'
90
- begin
91
- # Activate code tracking by default because line trace points will not work
92
- # without it.
93
- Datadog::DI.activate_tracking!
94
- rescue => exc
95
- if defined?(Datadog.logger)
96
- Datadog.logger.warn("Failed to activate code tracking for DI: #{exc.class}: #{exc}")
97
- else
98
- # We do not have Datadog logger potentially because DI code tracker is
99
- # being loaded early in application boot process and the rest of datadog
100
- # wasn't loaded yet. Output to standard error.
101
- warn("Failed to activate code tracking for DI: #{exc.class}: #{exc}")
102
- end
103
- end
160
+ if %w(1 true).include?(ENV['DD_DYNAMIC_INSTRUMENTATION_ENABLED']) # steep:ignore
161
+ # For initial release of Dynamic Instrumentation, activate code tracking
162
+ # only if DI is explicitly requested in the environment.
163
+ # Code tracking is required for line probes to work; see the comments
164
+ # above for the implementation of the method.
165
+ #
166
+ # If DI is enabled programmatically, the application can (and must,
167
+ # for line probes to work) activate tracking in an initializer.
168
+ Datadog::DI.activate_tracking
104
169
  end
105
- =end
@@ -207,28 +207,16 @@ module Datadog
207
207
 
208
208
  return false unless heap_profiling_enabled
209
209
 
210
- if RUBY_VERSION.start_with?("2.") && RUBY_VERSION < "2.7"
210
+ if RUBY_VERSION < "3.1"
211
211
  Datadog.logger.warn(
212
- "Heap profiling currently relies on features introduced in Ruby 2.7 and will be forcibly disabled. " \
213
- "Please upgrade to Ruby >= 2.7 in order to use this feature."
212
+ "Current Ruby version (#{RUBY_VERSION}) cannot support heap profiling due to VM limitations. " \
213
+ "Please upgrade to Ruby >= 3.1 in order to use this feature. Heap profiling has been disabled."
214
214
  )
215
215
  return false
216
216
  end
217
217
 
218
- if RUBY_VERSION < "3.1"
219
- Datadog.logger.debug(
220
- "Current Ruby version (#{RUBY_VERSION}) supports forced object recycling which has a bug that the " \
221
- "heap profiler is forced to work around to remain accurate. This workaround requires force-setting " \
222
- "the SEEN_OBJ_ID flag on objects that should have it but don't. Full details can be found in " \
223
- "https://github.com/DataDog/dd-trace-rb/pull/3360. This workaround should be safe but can be " \
224
- "bypassed by disabling the heap profiler or upgrading to Ruby >= 3.1 where forced object recycling " \
225
- "was completely removed (https://bugs.ruby-lang.org/issues/18290)."
226
- )
227
- end
228
-
229
218
  unless allocation_profiling_enabled
230
- raise ArgumentError,
231
- "Heap profiling requires allocation profiling to be enabled"
219
+ raise ArgumentError, "Heap profiling requires allocation profiling to be enabled"
232
220
  end
233
221
 
234
222
  Datadog.logger.warn(
@@ -368,22 +368,18 @@ module Datadog
368
368
  end
369
369
  end
370
370
 
371
- # [Continuous Integration Visibility](https://docs.datadoghq.com/continuous_integration/) configuration.
371
+ # This is only for internal Datadog use via https://github.com/DataDog/datadog-ci-rb . It should not be
372
+ # used directly.
373
+ #
374
+ # DEV-3.0: Make this a non-public API in the next release.
372
375
  # @public_api
373
376
  settings :test_mode do
374
- # Enable test mode. This allows the tracer to collect spans from test runs.
375
- #
376
- # It also prevents the tracer from collecting spans in a production environment. Only use in a test environment.
377
- #
378
- # @default `DD_TRACE_TEST_MODE_ENABLED` environment variable, otherwise `false`
379
- # @return [Boolean]
380
377
  option :enabled do |o|
381
378
  o.type :bool
382
379
  o.default false
383
380
  o.env Tracing::Configuration::Ext::Test::ENV_MODE_ENABLED
384
381
  end
385
382
 
386
- # Use async writer in test mode
387
383
  option :async do |o|
388
384
  o.type :bool
389
385
  o.default false
@@ -22,17 +22,29 @@ module Datadog
22
22
  # For Rails >= 5.2 w/o redis-activesupport...
23
23
  # ActiveSupport includes a Redis cache store internally, and does not require these overrides.
24
24
  # https://github.com/rails/rails/blob/master/activesupport/lib/active_support/cache/redis_cache_store.rb
25
- def patch_redis?(meth)
25
+ def patch_redis_store?(meth)
26
26
  !Gem.loaded_specs['redis-activesupport'].nil? \
27
27
  && defined?(::ActiveSupport::Cache::RedisStore) \
28
28
  && ::ActiveSupport::Cache::RedisStore.instance_methods(false).include?(meth)
29
29
  end
30
30
 
31
+ # Patches the Rails built-in Redis cache backend `redis_cache_store`, added in Rails 5.2.
32
+ # We avoid loading the RedisCacheStore class, as it invokes the statement `gem "redis", ">= 4.0.1"` which
33
+ # fails if the application is using an old version of Redis, or not using Redis at all.
34
+ # @see https://github.com/rails/rails/blob/d0dcb8fa6073a0c4d42600c15e82e3bb386b27d3/activesupport/lib/active_support/cache/redis_cache_store.rb#L4
35
+ def patch_redis_cache_store?(meth)
36
+ Gem.loaded_specs['redis'] &&
37
+ # Autoload constants return `constant` for `defined?`, but that doesn't mean they are loaded...
38
+ defined?(::ActiveSupport::Cache::RedisCacheStore) &&
39
+ # ... to check that we need to call `autoload?` and check if it returns `nil`, meaning it's loaded.
40
+ ::ActiveSupport::Cache.autoload?(:RedisCacheStore).nil? &&
41
+ ::ActiveSupport::Cache::RedisCacheStore.instance_methods(false).include?(meth)
42
+ end
43
+
31
44
  def cache_store_class(meth)
32
- if patch_redis?(meth)
45
+ if patch_redis_store?(meth)
33
46
  [::ActiveSupport::Cache::RedisStore, ::ActiveSupport::Cache::Store]
34
- elsif Gem.loaded_specs['redis'] && defined?(::ActiveSupport::Cache::RedisCacheStore) \
35
- && ::ActiveSupport::Cache::RedisCacheStore.instance_methods(false).include?(meth)
47
+ elsif patch_redis_cache_store?(meth)
36
48
  [::ActiveSupport::Cache::RedisCacheStore, ::ActiveSupport::Cache::Store]
37
49
  else
38
50
  super
@@ -49,6 +49,10 @@ module Datadog
49
49
  o.type :string, nilable: true
50
50
  o.env Ext::ENV_PEER_SERVICE
51
51
  end
52
+
53
+ option :on_error do |o|
54
+ o.type :proc, nilable: true
55
+ end
52
56
  end
53
57
  end
54
58
  end
@@ -40,6 +40,7 @@ module Datadog
40
40
  # `Client#transport` is the most convenient object both for this integration and the library
41
41
  # as users have shared access to it across all `elasticsearch` versions.
42
42
  service ||= Datadog.configuration_for(transport, :service_name) || datadog_configuration[:service_name]
43
+ on_error = Datadog.configuration_for(transport, :on_error) || datadog_configuration[:on_error]
43
44
 
44
45
  method = args[0]
45
46
  path = args[1]
@@ -49,7 +50,11 @@ module Datadog
49
50
  url = full_url.path
50
51
  response = nil
51
52
 
52
- Tracing.trace(Datadog::Tracing::Contrib::Elasticsearch::Ext::SPAN_QUERY, service: service) do |span|
53
+ Tracing.trace(
54
+ Datadog::Tracing::Contrib::Elasticsearch::Ext::SPAN_QUERY,
55
+ service: service,
56
+ on_error: on_error
57
+ ) do |span|
53
58
  begin
54
59
  connection = transport.connections.first
55
60
  host = connection.host[:host] if connection
@@ -442,7 +442,7 @@ module Datadog
442
442
  tags || @tags.dup
443
443
  end
444
444
  # Remove version tag if service is not the default service
445
- if merged_tags.key?(Core::Environment::Ext::TAG_VERSION) && service != @default_service
445
+ if merged_tags.key?(Core::Environment::Ext::TAG_VERSION) && service && service != @default_service
446
446
  merged_tags.delete(Core::Environment::Ext::TAG_VERSION)
447
447
  end
448
448
  merged_tags
@@ -3,7 +3,7 @@
3
3
  module Datadog
4
4
  module VERSION
5
5
  MAJOR = 2
6
- MINOR = 7
6
+ MINOR = 8
7
7
  PATCH = 0
8
8
  PRE = nil
9
9
  BUILD = nil
data/lib/datadog.rb CHANGED
@@ -7,4 +7,7 @@ require_relative 'datadog/tracing/contrib'
7
7
  # Load other products (must follow tracing)
8
8
  require_relative 'datadog/profiling'
9
9
  require_relative 'datadog/appsec'
10
+ # Line probes will not work on Ruby < 2.6 because of lack of :script_compiled
11
+ # trace point. Only load DI on supported Ruby versions.
12
+ require_relative 'datadog/di' if RUBY_VERSION >= '2.6'
10
13
  require_relative 'datadog/kit'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: datadog
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.7.0
4
+ version: 2.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Datadog, Inc.
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-11-13 00:00:00.000000000 Z
11
+ date: 2024-12-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: msgpack
@@ -44,28 +44,28 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 1.15.0.0.0
47
+ version: 1.18.0.0.0
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 1.15.0.0.0
54
+ version: 1.18.0.0.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: libdatadog
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 14.1.0.1.0
61
+ version: 14.3.1.1.0
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 14.1.0.1.0
68
+ version: 14.3.1.1.0
69
69
  description: |
70
70
  datadog is Datadog's client library for Ruby. It includes a suite of tools
71
71
  which provide visibility into the performance and security of Ruby applications,
@@ -151,6 +151,9 @@ files:
151
151
  - lib/datadog/appsec/component.rb
152
152
  - lib/datadog/appsec/configuration.rb
153
153
  - lib/datadog/appsec/configuration/settings.rb
154
+ - lib/datadog/appsec/contrib/active_record/instrumentation.rb
155
+ - lib/datadog/appsec/contrib/active_record/integration.rb
156
+ - lib/datadog/appsec/contrib/active_record/patcher.rb
154
157
  - lib/datadog/appsec/contrib/auto_instrument.rb
155
158
  - lib/datadog/appsec/contrib/devise/event.rb
156
159
  - lib/datadog/appsec/contrib/devise/ext.rb
@@ -208,7 +211,6 @@ files:
208
211
  - lib/datadog/appsec/monitor/gateway/watcher.rb
209
212
  - lib/datadog/appsec/monitor/reactive/set_user.rb
210
213
  - lib/datadog/appsec/processor.rb
211
- - lib/datadog/appsec/processor/actions.rb
212
214
  - lib/datadog/appsec/processor/context.rb
213
215
  - lib/datadog/appsec/processor/rule_loader.rb
214
216
  - lib/datadog/appsec/processor/rule_merger.rb
@@ -370,6 +372,7 @@ files:
370
372
  - lib/datadog/di/contrib/active_record.rb
371
373
  - lib/datadog/di/error.rb
372
374
  - lib/datadog/di/extensions.rb
375
+ - lib/datadog/di/init.rb
373
376
  - lib/datadog/di/instrumenter.rb
374
377
  - lib/datadog/di/probe.rb
375
378
  - lib/datadog/di/probe_builder.rb
@@ -377,6 +380,7 @@ files:
377
380
  - lib/datadog/di/probe_notification_builder.rb
378
381
  - lib/datadog/di/probe_notifier_worker.rb
379
382
  - lib/datadog/di/redactor.rb
383
+ - lib/datadog/di/remote.rb
380
384
  - lib/datadog/di/serializer.rb
381
385
  - lib/datadog/di/transport.rb
382
386
  - lib/datadog/di/utils.rb
@@ -898,9 +902,9 @@ licenses:
898
902
  - Apache-2.0
899
903
  metadata:
900
904
  allowed_push_host: https://rubygems.org
901
- changelog_uri: https://github.com/DataDog/dd-trace-rb/blob/v2.7.0/CHANGELOG.md
902
- source_code_uri: https://github.com/DataDog/dd-trace-rb/tree/v2.7.0
903
- post_install_message:
905
+ changelog_uri: https://github.com/DataDog/dd-trace-rb/blob/v2.8.0/CHANGELOG.md
906
+ source_code_uri: https://github.com/DataDog/dd-trace-rb/tree/v2.8.0
907
+ post_install_message:
904
908
  rdoc_options: []
905
909
  require_paths:
906
910
  - lib
@@ -918,8 +922,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
918
922
  - !ruby/object:Gem::Version
919
923
  version: 2.0.0
920
924
  requirements: []
921
- rubygems_version: 3.5.16
922
- signing_key:
925
+ rubygems_version: 3.4.10
926
+ signing_key:
923
927
  specification_version: 4
924
928
  summary: Datadog tracing code for your Ruby applications
925
929
  test_files: []
@@ -1,49 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Datadog
4
- module AppSec
5
- class Processor
6
- # Actions store the actions information in memory
7
- # Also, takes care of merging when RC send new information
8
- module Actions
9
- class << self
10
- def actions
11
- @actions ||= []
12
- end
13
-
14
- def fetch_configuration(action)
15
- actions.find { |action_configuration| action_configuration['id'] == action }
16
- end
17
-
18
- def merge(actions_to_merge)
19
- return if actions_to_merge.empty?
20
-
21
- if actions.empty?
22
- @actions = actions_to_merge
23
- else
24
- merged_actions = []
25
- actions_dup = actions.dup
26
-
27
- actions_to_merge.each do |new_action|
28
- existing_action = actions_dup.find { |action| new_action['id'] == action['id'] }
29
-
30
- # the old action is discard and the new kept
31
- actions_dup.delete(existing_action) if existing_action
32
- merged_actions << new_action
33
- end
34
-
35
- @actions = merged_actions.concat(actions_dup)
36
- end
37
- end
38
-
39
- private
40
-
41
- # Used in tests
42
- def reset
43
- @actions = []
44
- end
45
- end
46
- end
47
- end
48
- end
49
- end