datadog 2.17.0 → 2.18.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 (90) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -1
  3. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +12 -46
  4. data/ext/datadog_profiling_native_extension/collectors_stack.c +227 -49
  5. data/ext/datadog_profiling_native_extension/collectors_stack.h +19 -3
  6. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +63 -12
  7. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +1 -0
  8. data/ext/datadog_profiling_native_extension/extconf.rb +7 -0
  9. data/ext/datadog_profiling_native_extension/heap_recorder.c +239 -363
  10. data/ext/datadog_profiling_native_extension/heap_recorder.h +4 -6
  11. data/ext/datadog_profiling_native_extension/libdatadog_helpers.c +22 -0
  12. data/ext/datadog_profiling_native_extension/libdatadog_helpers.h +8 -5
  13. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +1 -0
  14. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +6 -3
  15. data/ext/datadog_profiling_native_extension/ruby_helpers.c +1 -13
  16. data/ext/datadog_profiling_native_extension/ruby_helpers.h +2 -10
  17. data/ext/datadog_profiling_native_extension/stack_recorder.c +154 -57
  18. data/ext/libdatadog_api/extconf.rb +2 -2
  19. data/ext/libdatadog_api/library_config.c +54 -12
  20. data/ext/libdatadog_api/library_config.h +6 -0
  21. data/ext/libdatadog_api/process_discovery.c +2 -7
  22. data/ext/libdatadog_extconf_helpers.rb +1 -1
  23. data/lib/datadog/appsec/api_security/lru_cache.rb +9 -2
  24. data/lib/datadog/appsec/api_security/route_extractor.rb +65 -0
  25. data/lib/datadog/appsec/api_security/sampler.rb +59 -0
  26. data/lib/datadog/appsec/api_security.rb +14 -0
  27. data/lib/datadog/appsec/assets/waf_rules/recommended.json +257 -85
  28. data/lib/datadog/appsec/assets/waf_rules/strict.json +10 -78
  29. data/lib/datadog/appsec/component.rb +30 -54
  30. data/lib/datadog/appsec/configuration/settings.rb +60 -2
  31. data/lib/datadog/appsec/context.rb +6 -6
  32. data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +1 -1
  33. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +27 -16
  34. data/lib/datadog/appsec/processor/rule_loader.rb +5 -6
  35. data/lib/datadog/appsec/remote.rb +15 -55
  36. data/lib/datadog/appsec/security_engine/engine.rb +194 -0
  37. data/lib/datadog/appsec/security_engine/runner.rb +10 -11
  38. data/lib/datadog/appsec.rb +4 -7
  39. data/lib/datadog/core/configuration/agent_settings.rb +52 -0
  40. data/lib/datadog/core/configuration/agent_settings_resolver.rb +1 -43
  41. data/lib/datadog/core/configuration/components.rb +2 -4
  42. data/lib/datadog/core/configuration/option.rb +9 -9
  43. data/lib/datadog/core/configuration/settings.rb +22 -10
  44. data/lib/datadog/core/configuration/stable_config.rb +1 -2
  45. data/lib/datadog/core/crashtracking/tag_builder.rb +4 -22
  46. data/lib/datadog/core/process_discovery/tracer_memfd.rb +15 -0
  47. data/lib/datadog/core/process_discovery.rb +5 -1
  48. data/lib/datadog/core/remote/configuration/repository.rb +12 -0
  49. data/lib/datadog/core/tag_builder.rb +56 -0
  50. data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +1 -0
  51. data/lib/datadog/core/telemetry/event/app_started.rb +129 -39
  52. data/lib/datadog/core/telemetry/logger.rb +5 -4
  53. data/lib/datadog/core/telemetry/logging.rb +11 -5
  54. data/lib/datadog/core/transport/http/adapters/net.rb +17 -2
  55. data/lib/datadog/core/transport/http/builder.rb +2 -2
  56. data/lib/datadog/core/transport/http/env.rb +8 -0
  57. data/lib/datadog/core/utils.rb +7 -0
  58. data/lib/datadog/di/instrumenter.rb +52 -2
  59. data/lib/datadog/di/probe_notification_builder.rb +31 -41
  60. data/lib/datadog/di/probe_notifier_worker.rb +9 -1
  61. data/lib/datadog/di/serializer.rb +6 -2
  62. data/lib/datadog/di/transport/http/input.rb +10 -0
  63. data/lib/datadog/di/transport/input.rb +10 -2
  64. data/lib/datadog/profiling/collectors/code_provenance.rb +17 -8
  65. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +4 -0
  66. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -0
  67. data/lib/datadog/profiling/collectors/thread_context.rb +16 -1
  68. data/lib/datadog/profiling/component.rb +7 -9
  69. data/lib/datadog/profiling/ext.rb +0 -12
  70. data/lib/datadog/profiling/http_transport.rb +2 -2
  71. data/lib/datadog/profiling/profiler.rb +2 -0
  72. data/lib/datadog/profiling/scheduler.rb +2 -1
  73. data/lib/datadog/profiling/stack_recorder.rb +5 -5
  74. data/lib/datadog/profiling/tag_builder.rb +5 -37
  75. data/lib/datadog/profiling/tasks/setup.rb +2 -0
  76. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +15 -0
  77. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +19 -12
  78. data/lib/datadog/tracing/contrib/action_pack/ext.rb +2 -0
  79. data/lib/datadog/tracing/contrib/lograge/patcher.rb +4 -2
  80. data/lib/datadog/tracing/contrib/sidekiq/ext.rb +1 -0
  81. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +5 -2
  82. data/lib/datadog/tracing/sync_writer.rb +1 -1
  83. data/lib/datadog/tracing/trace_operation.rb +12 -4
  84. data/lib/datadog/tracing/tracer.rb +6 -2
  85. data/lib/datadog/version.rb +1 -1
  86. metadata +12 -10
  87. data/lib/datadog/appsec/assets/waf_rules/processors.json +0 -321
  88. data/lib/datadog/appsec/assets/waf_rules/scanners.json +0 -1023
  89. data/lib/datadog/appsec/processor/rule_merger.rb +0 -171
  90. data/lib/datadog/appsec/processor.rb +0 -107
@@ -0,0 +1,194 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module AppSec
5
+ module SecurityEngine
6
+ # SecurityEngine::Engine creates WAF builder and manages its configuration.
7
+ # It also rebuilds WAF handle from the WAF builder when configuration changes.
8
+ class Engine
9
+ DEFAULT_RULES_CONFIG_PATH = 'ASM_DD/default'
10
+ TELEMETRY_ACTIONS = %w[init update].freeze
11
+ DIAGNOSTICS_CONFIG_KEYS = %w[
12
+ rules
13
+ custom_rules
14
+ exclusions
15
+ actions
16
+ processors
17
+ scanners
18
+ rules_override
19
+ rules_data
20
+ exclusion_data
21
+ ].freeze
22
+
23
+ attr_reader :waf_addresses, :ruleset_version
24
+
25
+ def initialize(appsec_settings:, telemetry:)
26
+ @default_ruleset = appsec_settings.ruleset
27
+
28
+ # NOTE: replace appsec_settings argument with default_ruleset when removing these deprecated settings
29
+ @default_ip_denylist = appsec_settings.ip_denylist
30
+ @default_user_id_denylist = appsec_settings.user_id_denylist
31
+ @default_ip_passlist = appsec_settings.ip_passlist
32
+
33
+ @waf_builder = WAF::HandleBuilder.new(
34
+ obfuscator: {
35
+ key_regex: appsec_settings.obfuscator_key_regex,
36
+ value_regex: appsec_settings.obfuscator_value_regex
37
+ }
38
+ )
39
+
40
+ diagnostics = load_default_config(telemetry: telemetry)
41
+ report_configuration_diagnostics(diagnostics, action: 'init', telemetry: telemetry)
42
+
43
+ @waf_handle = @waf_builder.build_handle
44
+ @waf_addresses = @waf_handle.known_addresses
45
+ rescue WAF::Error => e
46
+ error_message = "AppSec security engine failed to initialize"
47
+
48
+ Datadog.logger.error("#{error_message}, error #{e.inspect}")
49
+ telemetry.report(e, description: error_message)
50
+
51
+ raise e
52
+ end
53
+
54
+ def finalize!
55
+ @waf_handle&.finalize!
56
+ @waf_builder&.finalize!
57
+
58
+ @waf_addresses = []
59
+ @ruleset_version = nil
60
+ end
61
+
62
+ def new_runner
63
+ SecurityEngine::Runner.new(@waf_handle.build_context)
64
+ end
65
+
66
+ def add_or_update_config(config, path:)
67
+ @is_ruleset_update = path.include?('ASM_DD')
68
+
69
+ # default config has to be removed when adding an ASM_DD config
70
+ remove_config_at_path(DEFAULT_RULES_CONFIG_PATH) if @is_ruleset_update
71
+
72
+ diagnostics = @waf_builder.add_or_update_config(config, path: path)
73
+ @ruleset_version = diagnostics['ruleset_version'] if diagnostics.key?('ruleset_version')
74
+ report_configuration_diagnostics(diagnostics, action: 'update', telemetry: AppSec.telemetry)
75
+
76
+ # we need to load default config if diagnostics contains top-level error for rules or processors
77
+ if @is_ruleset_update &&
78
+ (diagnostics.key?('error') ||
79
+ diagnostics.dig('rules', 'error') ||
80
+ diagnostics.dig('processors', 'errors'))
81
+ diagnostics = load_default_config(telemetry: AppSec.telemetry)
82
+ report_configuration_diagnostics(diagnostics, action: 'update', telemetry: AppSec.telemetry)
83
+ end
84
+
85
+ diagnostics
86
+ rescue WAF::Error => e
87
+ error_message = "libddwaf builder failed to add or update config at path: #{path}"
88
+
89
+ Datadog.logger.debug("#{error_message}, error: #{e.inspect}")
90
+ AppSec.telemetry.report(e, description: error_message)
91
+ end
92
+
93
+ def remove_config_at_path(path)
94
+ result = @waf_builder.remove_config_at_path(path)
95
+
96
+ if result && path != DEFAULT_RULES_CONFIG_PATH && path.include?('ASM_DD')
97
+ diagnostics = load_default_config(telemetry: AppSec.telemetry)
98
+ report_configuration_diagnostics(diagnostics, action: 'update', telemetry: AppSec.telemetry)
99
+ end
100
+
101
+ result
102
+ rescue WAF::Error => e
103
+ error_message = "libddwaf handle builder failed to remove config at path: #{path}"
104
+
105
+ Datadog.logger.error("#{error_message}, error: #{e.inspect}")
106
+ AppSec.telemetry.report(e, description: error_message)
107
+ end
108
+
109
+ def reconfigure!
110
+ old_waf_handle = @waf_handle
111
+
112
+ @waf_handle = @waf_builder.build_handle
113
+ @waf_addresses = @waf_handle.known_addresses
114
+
115
+ old_waf_handle&.finalize!
116
+ rescue WAF::Error => e
117
+ error_message = "AppSec security engine failed to reconfigure"
118
+
119
+ Datadog.logger.error("#{error_message}, error #{e.inspect}")
120
+ AppSec.telemetry.report(e, description: error_message)
121
+
122
+ if old_waf_handle
123
+ Datadog.logger.warn("Reverting to the previous configuration")
124
+
125
+ @waf_handle = old_waf_handle
126
+ @waf_addresses = old_waf_handle.known_addresses
127
+ end
128
+ end
129
+
130
+ private
131
+
132
+ def load_default_config(telemetry:)
133
+ config = AppSec::Processor::RuleLoader.load_rules(telemetry: telemetry, ruleset: @default_ruleset)
134
+
135
+ # deprecated - ip and user id denylists should be configured via RC
136
+ config['rules_data'] ||= AppSec::Processor::RuleLoader.load_data(
137
+ ip_denylist: @default_ip_denylist,
138
+ user_id_denylist: @default_user_id_denylist
139
+ )
140
+
141
+ # deprecated - ip passlist should be configured via RC
142
+ config['exclusions'] ||= AppSec::Processor::RuleLoader.load_exclusions(ip_passlist: @default_ip_passlist)
143
+
144
+ diagnostics = @waf_builder.add_or_update_config(config, path: DEFAULT_RULES_CONFIG_PATH)
145
+ @ruleset_version = diagnostics['ruleset_version']
146
+
147
+ diagnostics
148
+ end
149
+
150
+ def report_configuration_diagnostics(diagnostics, action:, telemetry:)
151
+ raise ArgumentError, 'action must be one of TELEMETRY_ACTIONS' unless TELEMETRY_ACTIONS.include?(action)
152
+
153
+ common_tags = {
154
+ waf_version: Datadog::AppSec::WAF::VERSION::BASE_STRING,
155
+ event_rules_version: diagnostics.fetch('ruleset_version', @ruleset_version).to_s,
156
+ action: action
157
+ }
158
+
159
+ if diagnostics['error']
160
+ telemetry.inc(
161
+ Ext::TELEMETRY_METRICS_NAMESPACE, 'waf.config_errors', 1,
162
+ tags: common_tags.merge(scope: 'top-level')
163
+ )
164
+
165
+ telemetry.error(diagnostics['error'])
166
+ end
167
+
168
+ diagnostics.each do |config_key, config_diagnostics|
169
+ next unless DIAGNOSTICS_CONFIG_KEYS.include?(config_key)
170
+ next if !config_diagnostics.key?('error') && config_diagnostics.fetch('errors', []).empty?
171
+
172
+ if config_diagnostics['error']
173
+ telemetry.error(config_diagnostics['error'])
174
+
175
+ telemetry.inc(
176
+ Ext::TELEMETRY_METRICS_NAMESPACE, 'waf.config_errors', 1,
177
+ tags: common_tags.merge(config_key: config_key, scope: 'top-level')
178
+ )
179
+ elsif config_diagnostics['errors']
180
+ config_diagnostics['errors'].each do |error, config_ids|
181
+ telemetry.error("#{error}: [#{config_ids.join(",")}]")
182
+ end
183
+
184
+ telemetry.inc(
185
+ Ext::TELEMETRY_METRICS_NAMESPACE, 'waf.config_errors', config_diagnostics['errors'].count,
186
+ tags: common_tags.merge(config_key: config_key, scope: 'item')
187
+ )
188
+ end
189
+ end
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end
@@ -9,10 +9,9 @@ module Datadog
9
9
  class Runner
10
10
  SUCCESSFUL_EXECUTION_CODES = [:ok, :match].freeze
11
11
 
12
- def initialize(handle, telemetry:)
12
+ def initialize(waf_context)
13
13
  @mutex = Mutex.new
14
- @context = WAF::Context.new(handle)
15
- @telemetry = telemetry
14
+ @waf_context = waf_context
16
15
 
17
16
  @debug_tag = "libddwaf:#{WAF::VERSION::STRING} method:ddwaf_run"
18
17
  end
@@ -33,7 +32,7 @@ module Datadog
33
32
  v.nil? || v.empty?
34
33
  end
35
34
 
36
- _code, result = try_run(persistent_data, ephemeral_data, timeout)
35
+ result = try_run(persistent_data, ephemeral_data, timeout)
37
36
  stop_ns = Core::Utils::Time.get_time(:nanosecond)
38
37
 
39
38
  report_execution(result)
@@ -55,19 +54,19 @@ module Datadog
55
54
  @mutex.unlock
56
55
  end
57
56
 
58
- def finalize
59
- @context.finalize
57
+ def finalize!
58
+ @waf_context.finalize!
60
59
  end
61
60
 
62
61
  private
63
62
 
64
63
  def try_run(persistent_data, ephemeral_data, timeout)
65
- @context.run(persistent_data, ephemeral_data, timeout)
66
- rescue WAF::LibDDWAF::Error => e
64
+ @waf_context.run(persistent_data, ephemeral_data, timeout)
65
+ rescue WAF::LibDDWAFError => e
67
66
  Datadog.logger.debug { "#{@debug_tag} execution error: #{e} backtrace: #{e.backtrace&.first(3)}" }
68
- @telemetry.report(e, description: 'libddwaf-rb internal low-level error')
67
+ AppSec.telemetry.report(e, description: 'libddwaf-rb internal low-level error')
69
68
 
70
- [:err_internal, WAF::Result.new(:err_internal, [], 0, false, [], [])]
69
+ WAF::Result.new(:err_internal, [], 0, false, [], [])
71
70
  end
72
71
 
73
72
  def report_execution(result)
@@ -79,7 +78,7 @@ module Datadog
79
78
  message = "#{@debug_tag} execution error: #{result.status.inspect}"
80
79
 
81
80
  Datadog.logger.debug { message }
82
- @telemetry.error(message)
81
+ AppSec.telemetry.error(message)
83
82
  end
84
83
  end
85
84
  end
@@ -26,15 +26,12 @@ module Datadog
26
26
  components.appsec&.telemetry
27
27
  end
28
28
 
29
- def processor
30
- components.appsec&.processor
29
+ def security_engine
30
+ components.appsec&.security_engine
31
31
  end
32
32
 
33
- def reconfigure(ruleset:, telemetry:)
34
- appsec_component = components.appsec
35
- return unless appsec_component
36
-
37
- appsec_component.reconfigure(ruleset: ruleset, telemetry: telemetry)
33
+ def reconfigure!
34
+ components.appsec&.reconfigure!
38
35
  end
39
36
 
40
37
  def reconfigure_lock(&block)
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'ext'
4
+
5
+ module Datadog
6
+ module Core
7
+ module Configuration
8
+ # Immutable container for the resulting settings
9
+ class AgentSettings
10
+ # IPv6 regular expression from
11
+ # https://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses
12
+ # Does not match IPv4 addresses.
13
+ 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
14
+
15
+ attr_reader :adapter, :ssl, :hostname, :port, :uds_path, :timeout_seconds
16
+
17
+ def initialize(adapter: nil, ssl: nil, hostname: nil, port: nil, uds_path: nil, timeout_seconds: nil)
18
+ @adapter = adapter
19
+ @ssl = ssl
20
+ @hostname = hostname
21
+ @port = port
22
+ @uds_path = uds_path
23
+ @timeout_seconds = timeout_seconds
24
+ freeze
25
+ end
26
+
27
+ def url
28
+ case adapter
29
+ when Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER
30
+ hostname = self.hostname
31
+ hostname = "[#{hostname}]" if IPV6_REGEXP.match?(hostname)
32
+ "#{ssl ? "https" : "http"}://#{hostname}:#{port}/"
33
+ when Datadog::Core::Configuration::Ext::Agent::UnixSocket::ADAPTER
34
+ "unix://#{uds_path}"
35
+ else
36
+ raise ArgumentError, "Unexpected adapter: #{adapter}"
37
+ end
38
+ end
39
+
40
+ def ==(other)
41
+ self.class == other.class &&
42
+ adapter == other.adapter &&
43
+ ssl == other.ssl &&
44
+ hostname == other.hostname &&
45
+ port == other.port &&
46
+ uds_path == other.uds_path &&
47
+ timeout_seconds == other.timeout_seconds
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -4,6 +4,7 @@ require 'uri'
4
4
 
5
5
  require_relative 'settings'
6
6
  require_relative 'ext'
7
+ require_relative 'agent_settings'
7
8
  require_relative '../transport/ext'
8
9
 
9
10
  module Datadog
@@ -19,49 +20,6 @@ module Datadog
19
20
  # Whenever there is a conflict (different configurations are provided in different orders), it MUST warn the users
20
21
  # about it and pick a value based on the following priority: code > environment variable > defaults.
21
22
  class AgentSettingsResolver
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
- freeze
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 IPV6_REGEXP.match?(hostname)
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
58
- end
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
-
65
23
  def self.call(settings, logger: Datadog.logger)
66
24
  new(settings, logger: logger).send(:call)
67
25
  end
@@ -126,8 +126,7 @@ module Datadog
126
126
  @dynamic_instrumentation = Datadog::DI::Component.build(settings, agent_settings, @logger, telemetry: telemetry)
127
127
  @error_tracking = Datadog::ErrorTracking::Component.build(settings, @tracer, @logger)
128
128
  @environment_logger_extra[:dynamic_instrumentation_enabled] = !!@dynamic_instrumentation
129
- # TODO: Re-enable this once we have updated libdatadog to 17.1
130
- # @process_discovery_fd = Core::ProcessDiscovery.get_and_store_metadata(settings, @logger)
129
+ @process_discovery_fd = Core::ProcessDiscovery.get_and_store_metadata(settings, @logger)
131
130
 
132
131
  self.class.configure_tracing(settings)
133
132
  end
@@ -211,8 +210,7 @@ module Datadog
211
210
  telemetry.emit_closing! unless replacement&.telemetry&.enabled
212
211
  telemetry.shutdown!
213
212
 
214
- # TODO: Re-enable this once we have updated libdatadog to 17.1
215
- # Core::ProcessDiscovery._native_close_tracer_memfd(@process_discovery_fd, @logger) if @process_discovery_fd
213
+ @process_discovery_fd&.shutdown!
216
214
  end
217
215
 
218
216
  # Returns the current state of various components.
@@ -22,7 +22,7 @@ module Datadog
22
22
  # Represents an Option precedence level.
23
23
  # Each precedence has a `numeric` value; higher values means higher precedence.
24
24
  # `name` is for inspection purposes only.
25
- Value = Struct.new(:numeric, :name) do
25
+ Value = Struct.new(:numeric, :name, :origin) do
26
26
  include Comparable
27
27
 
28
28
  def <=>(other)
@@ -33,22 +33,22 @@ module Datadog
33
33
  end
34
34
 
35
35
  # Remote configuration provided through the Datadog app.
36
- REMOTE_CONFIGURATION = Value.new(5, :remote_configuration).freeze
36
+ REMOTE_CONFIGURATION = Value.new(5, :remote_configuration, 'remote_config').freeze
37
37
 
38
38
  # Configuration provided in Ruby code, in this same process
39
- PROGRAMMATIC = Value.new(4, :programmatic).freeze
39
+ PROGRAMMATIC = Value.new(4, :programmatic, 'code').freeze
40
40
 
41
41
  # Configuration provided by fleet managed stable config
42
- FLEET_STABLE = Value.new(3, :fleet_stable).freeze
42
+ FLEET_STABLE = Value.new(3, :fleet_stable, 'fleet_stable_config').freeze
43
43
 
44
44
  # Configuration provided via environment variable
45
- ENVIRONMENT = Value.new(2, :environment).freeze
45
+ ENVIRONMENT = Value.new(2, :environment, 'env_var').freeze
46
46
 
47
47
  # Configuration provided by local stable config file
48
- LOCAL_STABLE = Value.new(1, :local_stable).freeze
48
+ LOCAL_STABLE = Value.new(1, :local_stable, 'local_stable_config').freeze
49
49
 
50
50
  # Configuration that comes from default values
51
- DEFAULT = Value.new(0, :default).freeze
51
+ DEFAULT = Value.new(0, :default, 'default').freeze
52
52
 
53
53
  # All precedences, sorted from highest to lowest
54
54
  LIST = [REMOTE_CONFIGURATION, PROGRAMMATIC, FLEET_STABLE, ENVIRONMENT, LOCAL_STABLE, DEFAULT].sort.reverse.freeze
@@ -309,7 +309,7 @@ module Datadog
309
309
  end
310
310
 
311
311
  def set_customer_stable_config_value
312
- customer_config = StableConfig.configuration[:local]
312
+ customer_config = StableConfig.configuration.dig(:local, :config)
313
313
  return if customer_config.nil?
314
314
 
315
315
  value, resolved_env = get_value_and_resolved_env_from(customer_config, source: 'local stable config')
@@ -317,7 +317,7 @@ module Datadog
317
317
  end
318
318
 
319
319
  def set_fleet_stable_config_value
320
- fleet_config = StableConfig.configuration[:fleet]
320
+ fleet_config = StableConfig.configuration.dig(:fleet, :config)
321
321
  return if fleet_config.nil?
322
322
 
323
323
  value, resolved_env = get_value_and_resolved_env_from(fleet_config, source: 'fleet stable config')
@@ -313,7 +313,7 @@ module Datadog
313
313
 
314
314
  # Can be used to enable/disable the collection of heap profiles.
315
315
  #
316
- # This feature is alpha and disabled by default
316
+ # This feature is in preview and disabled by default. Requires Ruby 3.1+.
317
317
  #
318
318
  # @warn To enable heap profiling you are required to also enable allocation profiling.
319
319
  #
@@ -326,12 +326,12 @@ module Datadog
326
326
 
327
327
  # Can be used to enable/disable the collection of heap size profiles.
328
328
  #
329
- # This feature is alpha and enabled by default when heap profiling is enabled.
329
+ # This feature is in preview and by default is enabled whenever heap profiling is enabled.
330
330
  #
331
- # @warn To enable heap size profiling you are required to also enable allocation and heap profiling.
331
+ # @warn Heap size profiling depends on allocation and heap profiling, so they must be enabled as well.
332
332
  #
333
- # @default `DD_PROFILING_EXPERIMENTAL_HEAP_SIZE_ENABLED` environment variable as a boolean, otherwise
334
- # whatever the value of DD_PROFILING_EXPERIMENTAL_HEAP_ENABLED is.
333
+ # @default `DD_PROFILING_EXPERIMENTAL_HEAP_SIZE_ENABLED` environment variable as a boolean, otherwise it
334
+ # follows the value of `experimental_heap_enabled`.
335
335
  option :experimental_heap_size_enabled do |o|
336
336
  o.type :bool
337
337
  o.env 'DD_PROFILING_EXPERIMENTAL_HEAP_SIZE_ENABLED'
@@ -341,17 +341,19 @@ module Datadog
341
341
  # Can be used to configure the heap sampling rate: a heap sample will be collected for every x allocation
342
342
  # samples.
343
343
  #
344
- # The lower the value, the more accuracy in heap tracking but the bigger the overhead. In particular, a
345
- # value of 1 will track ALL allocations samples for heap profiles.
344
+ # The higher the value, the less accuracy in heap tracking but the smaller the overhead.
345
+ #
346
+ # If you needed to tweak this, please tell us why on <https://github.com/DataDog/dd-trace-rb/issues/new>,
347
+ # so we can fix it!
346
348
  #
347
349
  # The effective heap sampling rate in terms of allocations (not allocation samples) can be calculated via
348
350
  # effective_heap_sample_rate = allocation_sample_rate * heap_sample_rate.
349
351
  #
350
- # @default `DD_PROFILING_EXPERIMENTAL_HEAP_SAMPLE_RATE` environment variable, otherwise `10`.
352
+ # @default `DD_PROFILING_EXPERIMENTAL_HEAP_SAMPLE_RATE` environment variable, otherwise `1`.
351
353
  option :experimental_heap_sample_rate do |o|
352
354
  o.type :int
353
355
  o.env 'DD_PROFILING_EXPERIMENTAL_HEAP_SAMPLE_RATE'
354
- o.default 10
356
+ o.default 1
355
357
  end
356
358
 
357
359
  # Can be used to disable checking which version of `libmysqlclient` is being used by the `mysql2` gem.
@@ -542,6 +544,16 @@ module Datadog
542
544
  o.env 'DD_PROFILING_HEAP_CLEAN_AFTER_GC_ENABLED'
543
545
  o.default true
544
546
  end
547
+
548
+ # Controls if the profiler should use native filenames for frames in stack traces for functions implemented using
549
+ # native code. Setting to `false` will make the profiler fall back to default Ruby stack trace behavior (only show .rb files).
550
+ #
551
+ # @default true
552
+ option :native_filenames_enabled do |o|
553
+ o.type :bool
554
+ o.env 'DD_PROFILING_NATIVE_FILENAMES_ENABLED'
555
+ o.default true
556
+ end
545
557
  end
546
558
 
547
559
  # @public_api
@@ -572,7 +584,7 @@ module Datadog
572
584
 
573
585
  option :experimental_runtime_id_enabled do |o|
574
586
  o.type :bool
575
- o.env 'DD_TRACE_EXPERIMENTAL_RUNTIME_ID_ENABLED'
587
+ o.env ['DD_TRACE_EXPERIMENTAL_RUNTIME_ID_ENABLED', 'DD_RUNTIME_METRICS_RUNTIME_ID_ENABLED']
576
588
  o.default false
577
589
  end
578
590
 
@@ -14,8 +14,7 @@ module Datadog
14
14
  end
15
15
 
16
16
  def self.configuration
17
- # @configuration ||= StableConfig.extract_configuration # TODO: After libdatadog 17.1 release, uncomment this line
18
- @configuration ||= {} # TODO: After libdatadog 17.1 release, delete this line
17
+ @configuration ||= StableConfig.extract_configuration
19
18
  end
20
19
  end
21
20
  end
@@ -1,9 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative '../tag_builder'
3
4
  require_relative '../utils'
4
- require_relative '../environment/socket'
5
- require_relative '../environment/identity'
6
- require_relative '../environment/git'
7
5
 
8
6
  module Datadog
9
7
  module Core
@@ -11,27 +9,11 @@ module Datadog
11
9
  # This module builds a hash of tags
12
10
  module TagBuilder
13
11
  def self.call(settings)
14
- hash = {
15
- 'host' => Environment::Socket.hostname,
16
- 'process_id' => Process.pid.to_s,
17
- 'runtime_engine' => Environment::Identity.lang_engine,
18
- 'runtime-id' => Environment::Identity.id,
19
- 'runtime_platform' => Environment::Identity.lang_platform,
20
- 'runtime_version' => Environment::Identity.lang_version,
21
- 'env' => settings.env,
22
- 'service' => settings.service,
23
- 'version' => settings.version,
24
- 'git.repository_url' => Environment::Git.git_repository_url,
25
- 'git.commit.sha' => Environment::Git.git_commit_sha,
12
+ hash = Core::TagBuilder.tags(settings).merge(
26
13
  'is_crash' => 'true',
27
- 'language' => 'ruby',
28
- 'library_version' => Core::Environment::Identity.gem_datadog_version,
29
- }.compact
14
+ )
30
15
 
31
- # Make sure everything is an utf-8 string, to avoid encoding issues in downstream
32
- settings.tags.merge(hash).each_with_object({}) do |(key, value), h|
33
- h[Utils.utf8_encode(key)] = Utils.utf8_encode(value)
34
- end
16
+ Utils.encode_tags(hash)
35
17
  end
36
18
  end
37
19
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module Core
5
+ class ProcessDiscovery
6
+ class TracerMemfd
7
+ attr_accessor :logger
8
+
9
+ def shutdown!
10
+ ProcessDiscovery._native_close_tracer_memfd(self, logger)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'datadog/core/process_discovery/tracer_memfd'
4
+
3
5
  module Datadog
4
6
  module Core
5
7
  # Class used to store tracer metadata in a native file descriptor.
@@ -10,7 +12,9 @@ module Datadog
10
12
  return
11
13
  end
12
14
  metadata = get_metadata(settings)
13
- _native_store_tracer_metadata(logger, **metadata)
15
+ memfd = _native_store_tracer_metadata(logger, **metadata)
16
+ memfd.logger = logger if memfd
17
+ memfd
14
18
  end
15
19
 
16
20
  # According to the RFC, runtime_id, service_name, service_env, service_version are optional.
@@ -237,6 +237,10 @@ module Datadog
237
237
  @path = path
238
238
  @previous = previous
239
239
  end
240
+
241
+ def type
242
+ :delete
243
+ end
240
244
  end
241
245
 
242
246
  # Insert change
@@ -247,6 +251,10 @@ module Datadog
247
251
  @path = path
248
252
  @content = content
249
253
  end
254
+
255
+ def type
256
+ :insert
257
+ end
250
258
  end
251
259
 
252
260
  # Update change
@@ -258,6 +266,10 @@ module Datadog
258
266
  @content = content
259
267
  @previous = previous
260
268
  end
269
+
270
+ def type
271
+ :update
272
+ end
261
273
  end
262
274
  end
263
275