cw-datadog 2.23.0.2 → 2.23.0.4

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 (93) hide show
  1. checksums.yaml +4 -4
  2. data/ext/datadog_profiling_native_extension/extconf.rb +4 -2
  3. data/ext/libdatadog_api/library_config.c +12 -11
  4. data/ext/libdatadog_extconf_helpers.rb +1 -1
  5. data/lib/datadog/appsec/api_security/route_extractor.rb +20 -5
  6. data/lib/datadog/appsec/api_security/sampler.rb +3 -1
  7. data/lib/datadog/appsec/assets/blocked.html +8 -0
  8. data/lib/datadog/appsec/assets/blocked.json +1 -1
  9. data/lib/datadog/appsec/assets/blocked.text +3 -1
  10. data/lib/datadog/appsec/assets.rb +1 -1
  11. data/lib/datadog/appsec/remote.rb +4 -0
  12. data/lib/datadog/appsec/response.rb +18 -4
  13. data/lib/datadog/core/cloudwise/client.rb +412 -25
  14. data/lib/datadog/core/cloudwise/component.rb +195 -52
  15. data/lib/datadog/core/cloudwise/docc_heartbeat_worker.rb +105 -0
  16. data/lib/datadog/core/cloudwise/docc_operation_worker.rb +191 -0
  17. data/lib/datadog/core/cloudwise/docc_registration_worker.rb +89 -0
  18. data/lib/datadog/core/cloudwise/license_worker.rb +90 -4
  19. data/lib/datadog/core/cloudwise/probe_state.rb +134 -12
  20. data/lib/datadog/core/configuration/components.rb +10 -9
  21. data/lib/datadog/core/configuration/settings.rb +43 -0
  22. data/lib/datadog/core/configuration/supported_configurations.rb +6 -2
  23. data/lib/datadog/core/remote/client/capabilities.rb +7 -0
  24. data/lib/datadog/core/remote/component.rb +2 -2
  25. data/lib/datadog/core/remote/transport/config.rb +2 -10
  26. data/lib/datadog/core/remote/transport/http/config.rb +9 -9
  27. data/lib/datadog/core/remote/transport/http/negotiation.rb +17 -8
  28. data/lib/datadog/core/remote/transport/http.rb +2 -0
  29. data/lib/datadog/core/remote/transport/negotiation.rb +2 -18
  30. data/lib/datadog/core/remote/worker.rb +23 -35
  31. data/lib/datadog/core/telemetry/component.rb +26 -13
  32. data/lib/datadog/core/telemetry/event/app_started.rb +67 -49
  33. data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +27 -4
  34. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +5 -6
  35. data/lib/datadog/core/telemetry/transport/telemetry.rb +1 -2
  36. data/lib/datadog/core/telemetry/worker.rb +51 -6
  37. data/lib/datadog/core/transport/http/adapters/net.rb +2 -0
  38. data/lib/datadog/core/transport/http/client.rb +69 -0
  39. data/lib/datadog/core/utils/only_once_successful.rb +6 -2
  40. data/lib/datadog/data_streams/transport/http/client.rb +4 -32
  41. data/lib/datadog/data_streams/transport/stats.rb +1 -1
  42. data/lib/datadog/di/probe_notification_builder.rb +35 -13
  43. data/lib/datadog/di/transport/diagnostics.rb +2 -2
  44. data/lib/datadog/di/transport/http/diagnostics.rb +2 -4
  45. data/lib/datadog/di/transport/http/input.rb +2 -4
  46. data/lib/datadog/di/transport/input.rb +2 -2
  47. data/lib/datadog/open_feature/component.rb +60 -0
  48. data/lib/datadog/open_feature/configuration.rb +27 -0
  49. data/lib/datadog/open_feature/evaluation_engine.rb +59 -0
  50. data/lib/datadog/open_feature/exposures/batch_builder.rb +32 -0
  51. data/lib/datadog/open_feature/exposures/buffer.rb +43 -0
  52. data/lib/datadog/open_feature/exposures/deduplicator.rb +30 -0
  53. data/lib/datadog/open_feature/exposures/event.rb +60 -0
  54. data/lib/datadog/open_feature/exposures/reporter.rb +40 -0
  55. data/lib/datadog/open_feature/exposures/worker.rb +116 -0
  56. data/lib/datadog/open_feature/ext.rb +13 -0
  57. data/lib/datadog/open_feature/noop_evaluator.rb +26 -0
  58. data/lib/datadog/open_feature/provider.rb +134 -0
  59. data/lib/datadog/open_feature/remote.rb +74 -0
  60. data/lib/datadog/open_feature/resolution_details.rb +35 -0
  61. data/lib/datadog/open_feature/transport.rb +72 -0
  62. data/lib/datadog/open_feature.rb +19 -0
  63. data/lib/datadog/profiling/component.rb +6 -0
  64. data/lib/datadog/profiling/profiler.rb +4 -0
  65. data/lib/datadog/profiling.rb +1 -2
  66. data/lib/datadog/single_step_instrument.rb +1 -1
  67. data/lib/datadog/tracing/contrib/cloudwise/propagation.rb +164 -7
  68. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +22 -17
  69. data/lib/datadog/tracing/contrib/karafka/framework.rb +30 -0
  70. data/lib/datadog/tracing/contrib/karafka/patcher.rb +14 -0
  71. data/lib/datadog/tracing/contrib/rack/middlewares.rb +6 -2
  72. data/lib/datadog/tracing/contrib/waterdrop/configuration/settings.rb +27 -0
  73. data/lib/datadog/tracing/contrib/waterdrop/distributed/propagation.rb +48 -0
  74. data/lib/datadog/tracing/contrib/waterdrop/ext.rb +17 -0
  75. data/lib/datadog/tracing/contrib/waterdrop/integration.rb +43 -0
  76. data/lib/datadog/tracing/contrib/waterdrop/middleware.rb +46 -0
  77. data/lib/datadog/tracing/contrib/waterdrop/patcher.rb +46 -0
  78. data/lib/datadog/tracing/contrib/waterdrop/producer.rb +50 -0
  79. data/lib/datadog/tracing/contrib/waterdrop.rb +37 -0
  80. data/lib/datadog/tracing/contrib.rb +1 -0
  81. data/lib/datadog/tracing/transport/http/api.rb +73 -1
  82. data/lib/datadog/tracing/transport/http/client.rb +12 -26
  83. data/lib/datadog/tracing/transport/http/traces.rb +4 -2
  84. data/lib/datadog/tracing/transport/trace_formatter.rb +16 -0
  85. data/lib/datadog/version.rb +2 -2
  86. data/lib/datadog.rb +1 -0
  87. metadata +38 -15
  88. data/lib/datadog/core/cloudwise/IMPLEMENTATION_V2.md +0 -517
  89. data/lib/datadog/core/cloudwise/QUICKSTART.md +0 -398
  90. data/lib/datadog/core/cloudwise/README.md +0 -722
  91. data/lib/datadog/core/remote/transport/http/client.rb +0 -49
  92. data/lib/datadog/core/telemetry/transport/http/client.rb +0 -49
  93. data/lib/datadog/di/transport/http/client.rb +0 -47
@@ -19,6 +19,22 @@ module Datadog
19
19
  # 成功的状态码
20
20
  CODE_SUCCESS = 1000
21
21
 
22
+ # 熔断状态定义
23
+ FUSE_STATE_NORMAL = 0 # 正常
24
+ FUSE_STATE_FUSING = 1 # 熔断
25
+
26
+ # 熔断描述定义
27
+ FUSE_DESCRIBE_LICENSE_EXPIRED = 7 # License过期熔断
28
+ FUSE_DESCRIBE_AGENT_SUSPENDED = 8 # Agent暂停熔断
29
+ FUSE_DESCRIBE_LICENSE_OVER_QUOTA = 9 # License超配额熔断
30
+ FUSE_DESCRIBE_LICENSE_INTERFACE_ERROR = 10 # License接口异常熔断
31
+
32
+ # License 响应码定义
33
+ LICENSE_CODE_AGENT_SUSPENDED = 4113 # Agent暂停
34
+ LICENSE_CODE_OVER_QUOTA = 4114 # License超配额
35
+ LICENSE_CODE_EXPIRED = 4116 # License过期
36
+ LICENSE_CODE_INTERFACE_ERROR = 4120 # License接口异常
37
+
22
38
  attr_reader :client
23
39
 
24
40
  def initialize(client:, logger:, probe_state:, **options)
@@ -26,6 +42,8 @@ module Datadog
26
42
  @logger = logger
27
43
  @probe_state = probe_state
28
44
  @failure_count = 0
45
+ @last_fuse_state = nil # 记录最后一次的熔断状态
46
+ @last_fuse_describe = nil # 记录最后一次的熔断描述
29
47
 
30
48
  # Workers::Async::Thread settings
31
49
  self.fork_policy = options.fetch(:fork_policy, Workers::Async::Thread::FORK_POLICY_STOP)
@@ -76,20 +94,37 @@ module Datadog
76
94
  end
77
95
 
78
96
  code = result[:code]
97
+ # msg 字段在响应的顶层(result[:message]),是字符串 "true" 或 "false"
98
+ msg = result[:message]
79
99
 
80
- # License 校验成功 (code == 1000)
81
- if code == CODE_SUCCESS
100
+ # License 校验成功 (code == 1000 且 msg == 'true')
101
+ if code == CODE_SUCCESS && msg == 'true'
82
102
  Cloudwise.log_debug { 'Cloudwise: License valid' }
83
103
  probe_state.mark_license_valid!
84
104
  @failure_count = 0 # 重置失败计数
105
+ # 上报正常状态(如果状态发生变化)
106
+ report_fuse_state_if_changed(FUSE_STATE_NORMAL, nil)
107
+ return
108
+ end
109
+
110
+ # 特殊情况:code == 1000 但 msg == 'false',视为 License 过期
111
+ if code == CODE_SUCCESS && msg == 'false'
112
+ Cloudwise.log_error { "Cloudwise: License verification failed - code #{code} with msg false (License expired)" }
113
+ probe_state.mark_license_invalid!
114
+ @failure_count = 0 # 重置失败计数(因为接口成功返回了)
115
+ # 上报为License过期熔断状态
116
+ report_fuse_state_if_changed(FUSE_STATE_FUSING, FUSE_DESCRIBE_LICENSE_EXPIRED)
85
117
  return
86
118
  end
87
119
 
88
- # License 校验失败 (code != 1000)
120
+ # 其他 License 校验失败情况 (code != 1000)
89
121
  Cloudwise.log_error { "Cloudwise: License verification failed with code #{code}" }
90
- Cloudwise.log_error { "Cloudwise: Data collection suspended due to invalid license" }
91
122
  probe_state.mark_license_invalid!
92
123
  @failure_count = 0 # 重置失败计数(因为接口成功返回了)
124
+
125
+ # 根据错误码上报相应的熔断状态
126
+ fuse_describe = map_license_code_to_fuse_describe(code)
127
+ report_fuse_state_if_changed(FUSE_STATE_FUSING, fuse_describe)
93
128
  end
94
129
 
95
130
  def handle_license_failure
@@ -100,8 +135,59 @@ module Datadog
100
135
  if @failure_count >= MAX_RETRIES
101
136
  Cloudwise.log_error { "Cloudwise: License verification failed #{@failure_count} times, marking as invalid" }
102
137
  probe_state.mark_license_invalid!
138
+
139
+ # 上报License接口异常熔断状态
140
+ report_fuse_state_if_changed(FUSE_STATE_FUSING, FUSE_DESCRIBE_LICENSE_INTERFACE_ERROR)
141
+ end
142
+ end
143
+
144
+ # 将License错误码映射为熔断描述
145
+ def map_license_code_to_fuse_describe(license_code)
146
+ case license_code
147
+ when LICENSE_CODE_AGENT_SUSPENDED
148
+ FUSE_DESCRIBE_AGENT_SUSPENDED
149
+ when LICENSE_CODE_OVER_QUOTA
150
+ FUSE_DESCRIBE_LICENSE_OVER_QUOTA
151
+ when LICENSE_CODE_EXPIRED
152
+ FUSE_DESCRIBE_LICENSE_EXPIRED
153
+ when LICENSE_CODE_INTERFACE_ERROR
154
+ FUSE_DESCRIBE_LICENSE_INTERFACE_ERROR
155
+ else
156
+ # 其他未知的License错误码,统一按接口异常处理
157
+ FUSE_DESCRIBE_LICENSE_INTERFACE_ERROR
103
158
  end
104
159
  end
160
+
161
+ # 仅在状态发生变化时上报熔断状态
162
+ # @param fuse_state [Integer] 熔断状态: 0-正常, 1-熔断
163
+ # @param fuse_describe [Integer, nil] 熔断描述: 7/8/9/10,正常状态时为nil
164
+ def report_fuse_state_if_changed(fuse_state, fuse_describe)
165
+ # 检查状态是否发生变化
166
+ if @last_fuse_state == fuse_state && @last_fuse_describe == fuse_describe
167
+ Cloudwise.log_debug { "Cloudwise: Fuse state unchanged (state: #{fuse_state}, describe: #{fuse_describe}), skip reporting" }
168
+ return
169
+ end
170
+
171
+ # 状态发生变化,进行上报
172
+ Cloudwise.log_info { "Cloudwise: Fuse state changed from (#{@last_fuse_state}, #{@last_fuse_describe}) to (#{fuse_state}, #{fuse_describe})" }
173
+
174
+ # 构造上报参数
175
+ fuse_describe_str = fuse_describe ? fuse_describe.to_s : fuse_state.to_s
176
+
177
+ # 调用Client的上报接口
178
+ result = client.report_fuse_state(fuse_state: fuse_state, fuse_describe: fuse_describe_str)
179
+
180
+ if result[:success]
181
+ Cloudwise.log_debug { "Cloudwise: Fuse state reported successfully (state: #{fuse_state}, describe: #{fuse_describe})" }
182
+ # 更新最后一次的状态
183
+ @last_fuse_state = fuse_state
184
+ @last_fuse_describe = fuse_describe
185
+ else
186
+ Cloudwise.log_error { "Cloudwise: Failed to report fuse state: #{result[:error]}" }
187
+ end
188
+ rescue => e
189
+ Cloudwise.log_error { "Cloudwise: Error reporting fuse state: #{e.class.name} #{e.message}" }
190
+ end
105
191
  end
106
192
  end
107
193
  end
@@ -15,6 +15,12 @@ module Datadog
15
15
  @heartbeat_active = false # 心跳是否正常
16
16
  @license_valid = false # License 是否校验通过
17
17
  @app_registered = false # 应用是否已注册(注册失败不影响采集)
18
+
19
+ # 融合模式状态
20
+ @docc_registered = false # 注册是否成功
21
+ @docc_heartbeat_active = false # 心跳是否正常
22
+ @docc_operation_active = true # 操作状态(默认为 true,agent_stop 时为 false)
23
+ @use_docc_mode = false # 是否使用 模式
18
24
  end
19
25
 
20
26
  # Host ID 相关
@@ -91,10 +97,81 @@ module Datadog
91
97
  end
92
98
  end
93
99
 
94
- # 探针是否可以采集数据:需要 Host ID + 心跳 + License 都正常
100
+ # DOCC 注册相关
101
+ def mark_docc_registered!
102
+ @mutex.synchronize do
103
+ return if @docc_registered
104
+ @docc_registered = true
105
+ Cloudwise.log_debug { 'Cloudwise DOCC: Extension registered' }
106
+ log_status_change
107
+ end
108
+ end
109
+
110
+ def mark_docc_unregistered!
111
+ @mutex.synchronize do
112
+ return unless @docc_registered
113
+ @docc_registered = false
114
+ Cloudwise.log_warn { 'Cloudwise DOCC: Extension not registered' }
115
+ log_status_change
116
+ end
117
+ end
118
+
119
+ # DOCC 心跳相关
120
+ def mark_docc_heartbeat_active!
121
+ @mutex.synchronize do
122
+ return if @docc_heartbeat_active
123
+ @docc_heartbeat_active = true
124
+ Cloudwise.log_debug { 'Cloudwise DOCC: Heartbeat active' }
125
+ log_status_change
126
+ end
127
+ end
128
+
129
+ def mark_docc_heartbeat_inactive!
130
+ @mutex.synchronize do
131
+ return unless @docc_heartbeat_active
132
+ @docc_heartbeat_active = false
133
+ Cloudwise.log_warn { 'Cloudwise DOCC: Heartbeat inactive' }
134
+ log_status_change
135
+ end
136
+ end
137
+
138
+ # DOCC 操作相关
139
+ def mark_docc_operation_active!
140
+ @mutex.synchronize do
141
+ return if @docc_operation_active
142
+ @docc_operation_active = true
143
+ Cloudwise.log_info { 'Cloudwise DOCC: Agent started - data collection enabled' }
144
+ log_status_change
145
+ end
146
+ end
147
+
148
+ def mark_docc_operation_inactive!
149
+ @mutex.synchronize do
150
+ return unless @docc_operation_active
151
+ @docc_operation_active = false
152
+ Cloudwise.log_info { 'Cloudwise DOCC: Agent stopped - data collection disabled' }
153
+ log_status_change
154
+ end
155
+ end
156
+
157
+ # 设置使用 DOCC 模式
158
+ def enable_docc_mode!
159
+ @mutex.synchronize do
160
+ @use_docc_mode = true
161
+ Cloudwise.log_debug { 'Cloudwise: Using DOCC integrated mode' }
162
+ end
163
+ end
164
+
165
+ # 探针是否可以采集数据
166
+ # 如果使用 DOCC 模式:需要 DOCC 心跳 + License + Operation 都正常
167
+ # 如果使用传统模式:需要 Host ID + 心跳 + License 都正常
95
168
  def can_collect_data?
96
169
  @mutex.synchronize do
97
- @host_id_ready && @heartbeat_active && @license_valid
170
+ if @use_docc_mode
171
+ @docc_heartbeat_active && @license_valid && @docc_operation_active
172
+ else
173
+ @host_id_ready && @heartbeat_active && @license_valid
174
+ end
98
175
  end
99
176
  end
100
177
 
@@ -115,6 +192,22 @@ module Datadog
115
192
  @mutex.synchronize { @app_registered }
116
193
  end
117
194
 
195
+ def docc_registered?
196
+ @mutex.synchronize { @docc_registered }
197
+ end
198
+
199
+ def docc_heartbeat_active?
200
+ @mutex.synchronize { @docc_heartbeat_active }
201
+ end
202
+
203
+ def docc_operation_active?
204
+ @mutex.synchronize { @docc_operation_active }
205
+ end
206
+
207
+ def using_docc_mode?
208
+ @mutex.synchronize { @use_docc_mode }
209
+ end
210
+
118
211
  # 兼容旧接口
119
212
  def suspended?
120
213
  !can_collect_data?
@@ -127,13 +220,27 @@ module Datadog
127
220
  # 获取当前状态摘要
128
221
  def status
129
222
  @mutex.synchronize do
130
- {
223
+ base_status = {
131
224
  host_id_ready: @host_id_ready,
132
225
  heartbeat_active: @heartbeat_active,
133
226
  license_valid: @license_valid,
134
- app_registered: @app_registered,
135
- can_collect_data: @host_id_ready && @heartbeat_active && @license_valid
227
+ app_registered: @app_registered
136
228
  }
229
+
230
+ if @use_docc_mode
231
+ base_status.merge(
232
+ use_docc_mode: true,
233
+ docc_registered: @docc_registered,
234
+ docc_heartbeat_active: @docc_heartbeat_active,
235
+ docc_operation_active: @docc_operation_active,
236
+ can_collect_data: @docc_heartbeat_active && @license_valid && @docc_operation_active
237
+ )
238
+ else
239
+ base_status.merge(
240
+ use_docc_mode: false,
241
+ can_collect_data: @host_id_ready && @heartbeat_active && @license_valid
242
+ )
243
+ end
137
244
  end
138
245
  end
139
246
 
@@ -143,15 +250,30 @@ module Datadog
143
250
  # 它不能再次获取锁,所以直接读取实例变量
144
251
  def log_status_change
145
252
  # 直接读取实例变量,避免递归锁定(不调用 can_collect_data? 方法)
146
- if @host_id_ready && @heartbeat_active && @license_valid
147
- Cloudwise.log_debug { 'Cloudwise: Probe ACTIVE - data collection enabled' }
253
+ if @use_docc_mode
254
+ # DOCC 模式状态日志
255
+ if @docc_heartbeat_active && @license_valid && @docc_operation_active
256
+ Cloudwise.log_debug { 'Cloudwise DOCC: Probe ACTIVE - data collection enabled' }
257
+ else
258
+ reasons = []
259
+ reasons << 'DOCC Heartbeat inactive' unless @docc_heartbeat_active
260
+ reasons << 'License invalid' unless @license_valid
261
+ reasons << 'Agent stopped by operation' unless @docc_operation_active
262
+
263
+ Cloudwise.log_debug { "Cloudwise DOCC: Probe SUSPENDED - data collection disabled (#{reasons.join(', ')})" }
264
+ end
148
265
  else
149
- reasons = []
150
- reasons << 'Host ID not ready' unless @host_id_ready
151
- reasons << 'Heartbeat inactive' unless @heartbeat_active
152
- reasons << 'License invalid' unless @license_valid
266
+ # 传统模式状态日志
267
+ if @host_id_ready && @heartbeat_active && @license_valid
268
+ Cloudwise.log_debug { 'Cloudwise: Probe ACTIVE - data collection enabled' }
269
+ else
270
+ reasons = []
271
+ reasons << 'Host ID not ready' unless @host_id_ready
272
+ reasons << 'Heartbeat inactive' unless @heartbeat_active
273
+ reasons << 'License invalid' unless @license_valid
153
274
 
154
- Cloudwise.log_debug { "Cloudwise: Probe SUSPENDED - data collection disabled (#{reasons.join(', ')})" }
275
+ Cloudwise.log_debug { "Cloudwise: Probe SUSPENDED - data collection disabled (#{reasons.join(', ')})" }
276
+ end
155
277
  end
156
278
  end
157
279
  end
@@ -15,6 +15,7 @@ require_relative '../../tracing/component'
15
15
  require_relative '../../profiling/component'
16
16
  require_relative '../../appsec/component'
17
17
  require_relative '../../di/component'
18
+ require_relative '../../open_feature/component'
18
19
  require_relative '../../error_tracking/component'
19
20
  require_relative '../crashtracking/component'
20
21
  require_relative '../environment/agent_info'
@@ -151,6 +152,7 @@ module Datadog
151
152
  attr_reader \
152
153
  :health_metrics,
153
154
  :settings,
155
+ :agent_settings,
154
156
  :logger,
155
157
  :remote,
156
158
  :profiler,
@@ -163,7 +165,8 @@ module Datadog
163
165
  :appsec,
164
166
  :agent_info,
165
167
  :data_streams,
166
- :cloudwise
168
+ :cloudwise,
169
+ :open_feature
167
170
 
168
171
  def initialize(settings)
169
172
  @settings = settings
@@ -207,7 +210,7 @@ module Datadog
207
210
  # This agent_settings is intended for use within Core. If you require
208
211
  # agent_settings within a product outside of core you should extend
209
212
  # the Core resolver from within your product/component's namespace.
210
- agent_settings = AgentSettingsResolver.call(settings, logger: @logger)
213
+ @agent_settings = AgentSettingsResolver.call(settings, logger: @logger)
211
214
 
212
215
  # Exposes agent capability information for detection by any components
213
216
  @agent_info = Core::Environment::AgentInfo.new(agent_settings, logger: @logger)
@@ -233,6 +236,7 @@ module Datadog
233
236
  @runtime_metrics = self.class.build_runtime_metrics_worker(settings, @logger, telemetry)
234
237
  @health_metrics = self.class.build_health_metrics(settings, @logger, telemetry)
235
238
  @appsec = Datadog::AppSec::Component.build_appsec_component(settings, telemetry: telemetry)
239
+ @open_feature = OpenFeature::Component.build(settings, agent_settings, logger: @logger, telemetry: telemetry)
236
240
  @dynamic_instrumentation = Datadog::DI::Component.build(settings, agent_settings, @logger, telemetry: telemetry)
237
241
  @error_tracking = Datadog::ErrorTracking::Component.build(settings, @tracer, @logger)
238
242
  @data_streams = self.class.build_data_streams(settings, agent_settings, @logger)
@@ -268,14 +272,8 @@ module Datadog
268
272
 
269
273
  # Starts up components
270
274
  def startup!(settings, old_state: nil)
271
- # If Datadog components are not initialized yet (waiting for Cloudwise),
272
- # skip startup - it will be called after Datadog components are initialized
273
- unless datadog_components_initialized?
274
- @pending_startup = { settings: settings, old_state: old_state }
275
- return
276
- end
277
275
 
278
- telemetry.start(old_state&.telemetry_enabled?)
276
+ telemetry.start(old_state&.telemetry_enabled?, components: self)
279
277
 
280
278
  if settings.profiling.enabled
281
279
  if profiler
@@ -321,6 +319,9 @@ module Datadog
321
319
  # Shutdown DI after remote, since remote config triggers DI operations.
322
320
  dynamic_instrumentation&.shutdown!
323
321
 
322
+ # Shutdown OpenFeature component
323
+ open_feature&.shutdown!
324
+
324
325
  # Decommission AppSec
325
326
  appsec&.shutdown!
326
327
 
@@ -1025,6 +1025,49 @@ module Datadog
1025
1025
  o.default nil
1026
1026
  end
1027
1027
 
1028
+ # Integrated mode - whether agent handles integrated environment
1029
+ # @default `DD_CLOUDWISE_INTEGRATED_MODE` environment variable, otherwise `true`
1030
+ # @return [Boolean]
1031
+ option :integrated_mode do |o|
1032
+ o.type :bool
1033
+ o.env 'DD_CLOUDWISE_INTEGRATED_MODE'
1034
+ o.default true
1035
+ end
1036
+
1037
+ # Token for integrated mode (DOCC interface authentication)
1038
+ # Format: base64 encoded "account_id@user_id"
1039
+ # @default `DD_CLOUDWISE_TOKEN` environment variable
1040
+ # @return [String,nil]
1041
+ option :token do |o|
1042
+ o.type :string, nilable: true
1043
+ o.env 'DD_CLOUDWISE_TOKEN'
1044
+ o.default nil
1045
+ end
1046
+
1047
+ # API 路径前缀模式(简化配置)
1048
+ # 可选值: 'doop', 'apm', 'custom'
1049
+ # 优先级: api_prefix_mode > api_prefix > integrated_mode > 无前缀
1050
+ option :api_prefix_mode do |o|
1051
+ o.type :string, nilable: true
1052
+ o.env 'DD_CLOUDWISE_API_PREFIX_MODE'
1053
+ o.default nil
1054
+ end
1055
+
1056
+ # API 路径前缀(自定义配置)
1057
+ # 优先级: api_prefix_mode > api_prefix > integrated_mode ('/apm') > 无前缀
1058
+ option :api_prefix do |o|
1059
+ o.type :string, nilable: true
1060
+ o.env 'DD_CLOUDWISE_API_PREFIX'
1061
+ o.default nil
1062
+ end
1063
+
1064
+ # SYS
1065
+ option :sys do |o|
1066
+ o.type :string, nilable: true
1067
+ o.env 'CW_SYS'
1068
+ o.default 'default'
1069
+ end
1070
+
1028
1071
  # Heartbeat interval in seconds
1029
1072
  # @default `DD_CLOUDWISE_HEARTBEAT_INTERVAL` environment variable, otherwise `30`
1030
1073
  # @return [Integer]
@@ -34,9 +34,11 @@ module Datadog
34
34
  "DD_APPSEC_WAF_TIMEOUT" => {version: ["A"]},
35
35
  "DD_CLOUDWISE_APP_REGISTRATION_INTERVAL" => {version: ["A"]},
36
36
  "DD_CLOUDWISE_ENABLED" => {version: ["A"]},
37
- "DD_CLOUDWISE_HEARTBEAT_INTERVAL" => {version: ["A"]},
38
- "DD_CLOUDWISE_LICENSE_CHECK_INTERVAL" => {version: ["A"]},
39
37
  "DD_CLOUDWISE_LICENSE_KEY" => {version: ["A"]},
38
+ "DD_CLOUDWISE_TOKEN" => {version: ["A"]},
39
+ "CW_SYS" => {version: ["A"]},
40
+ "DD_CLOUDWISE_API_PREFIX_MODE" => {version: ["A"]},
41
+ "DD_CLOUDWISE_API_PREFIX" => {version: ["A"]},
40
42
  "DD_CRASHTRACKING_ENABLED" => {version: ["A"]},
41
43
  "DD_DATA_STREAMS_ENABLED" => {version: ["A"]},
42
44
  "DD_DBM_PROPAGATION_MODE" => {version: ["A"]},
@@ -48,6 +50,7 @@ module Datadog
48
50
  "DD_ENV" => {version: ["A"]},
49
51
  "DD_ERROR_TRACKING_HANDLED_ERRORS" => {version: ["A"]},
50
52
  "DD_ERROR_TRACKING_HANDLED_ERRORS_INCLUDE" => {version: ["A"]},
53
+ "DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED" => {version: ["A"]},
51
54
  "DD_GIT_COMMIT_SHA" => {version: ["A"]},
52
55
  "DD_GIT_REPOSITORY_URL" => {version: ["A"]},
53
56
  "DD_HEALTH_METRICS_ENABLED" => {version: ["A"]},
@@ -314,6 +317,7 @@ module Datadog
314
317
  "DD_TRACE_TRILOGY_ENABLED" => {version: ["A"]},
315
318
  "DD_TRACE_TRILOGY_PEER_SERVICE" => {version: ["A"]},
316
319
  "DD_TRACE_TRILOGY_SERVICE_NAME" => {version: ["A"]},
320
+ "DD_TRACE_WATERDROP_ENABLED" => {version: ["A"]},
317
321
  "DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH" => {version: ["A"]},
318
322
  "DD_VERSION" => {version: ["A"]},
319
323
  "OTEL_TRACES_SAMPLER_ARG" => {version: ["A"]}}.freeze
@@ -3,6 +3,7 @@
3
3
  require_relative '../../utils/base64'
4
4
  require_relative '../../../appsec/remote'
5
5
  require_relative '../../../tracing/remote'
6
+ require_relative '../../../open_feature/remote'
6
7
 
7
8
  module Datadog
8
9
  module Core
@@ -38,6 +39,12 @@ module Datadog
38
39
  register_receivers(Datadog::DI::Remote.receivers(@telemetry))
39
40
  end
40
41
 
42
+ if settings.respond_to?(:open_feature) && settings.open_feature.enabled
43
+ register_capabilities(Datadog::OpenFeature::Remote.capabilities)
44
+ register_products(Datadog::OpenFeature::Remote.products)
45
+ register_receivers(Datadog::OpenFeature::Remote.receivers(@telemetry))
46
+ end
47
+
41
48
  register_capabilities(Datadog::Tracing::Remote.capabilities)
42
49
  register_products(Datadog::Tracing::Remote.products)
43
50
  register_receivers(Datadog::Tracing::Remote.receivers(@telemetry))
@@ -68,12 +68,12 @@ module Datadog
68
68
 
69
69
  # Starts the Remote Configuration worker without waiting for first run
70
70
  def start
71
- @worker.start
71
+ # @worker.start
72
72
  end
73
73
 
74
74
  # Is the Remote Configuration worker running?
75
75
  def started?
76
- @worker.started?
76
+ # @worker.started?
77
77
  end
78
78
 
79
79
  # If the worker is not initialized, initialize it.
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative '../../../core/transport/request'
4
4
  require_relative '../../../core/transport/parcel'
5
+ require_relative 'http/config'
5
6
 
6
7
  module Datadog
7
8
  module Core
@@ -21,15 +22,6 @@ module Datadog
21
22
  class Request < Datadog::Core::Transport::Request
22
23
  end
23
24
 
24
- # Config response
25
- module Response
26
- attr_reader :roots, :targets, :target_files, :client_configs
27
-
28
- def empty?
29
- @empty
30
- end
31
- end
32
-
33
25
  # Config transport
34
26
  class Transport
35
27
  attr_reader :client, :apis, :default_api, :current_api_id, :logger
@@ -38,7 +30,7 @@ module Datadog
38
30
  @apis = apis
39
31
  @logger = logger
40
32
 
41
- @client = HTTP::Client.new(current_api, logger: logger)
33
+ @client = Remote::Transport::HTTP::Config::Client.new(current_api, logger: logger)
42
34
  end
43
35
 
44
36
  ##### there is only one transport! it's negotiation!
@@ -2,8 +2,7 @@
2
2
 
3
3
  require 'json'
4
4
 
5
- require_relative '../config'
6
- require_relative 'client'
5
+ require_relative '../../../transport/http/client'
7
6
  require_relative '../../../utils/base64'
8
7
  require_relative '../../../utils/truncation'
9
8
  require_relative '../../../transport/http/response'
@@ -19,7 +18,6 @@ module Datadog
19
18
  # Response from HTTP transport for remote configuration
20
19
  class Response
21
20
  include Datadog::Core::Transport::HTTP::Response
22
- include Core::Remote::Transport::Config::Response
23
21
 
24
22
  def initialize(http_response, options = {}) # standard:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
25
23
  super(http_response)
@@ -114,6 +112,12 @@ module Datadog
114
112
  end.freeze
115
113
  end
116
114
 
115
+ attr_reader :roots, :targets, :target_files, :client_configs
116
+
117
+ def empty?
118
+ @empty
119
+ end
120
+
117
121
  def inspect
118
122
  "#{super}, #{
119
123
  {
@@ -174,8 +178,8 @@ module Datadog
174
178
  end
175
179
  end
176
180
 
177
- # Extensions for HTTP client
178
- module Client
181
+ # Remote transport HTTP client
182
+ class Client < Core::Transport::HTTP::Client
179
183
  def send_config_payload(request)
180
184
  send_request(request) do |api, env|
181
185
  api.send_config(env)
@@ -240,10 +244,6 @@ module Datadog
240
244
  end
241
245
  end
242
246
  end
243
-
244
- # Add remote configuration behavior to transport components
245
- ###### overrides send_payload! which calls send_<endpoint>! kills any other possible endpoint!
246
- HTTP::Client.include(Config::Client)
247
247
  end
248
248
  end
249
249
  end
@@ -2,8 +2,7 @@
2
2
 
3
3
  require 'json'
4
4
 
5
- require_relative '../negotiation'
6
- require_relative 'client'
5
+ require_relative '../../../transport/http/client'
7
6
  require_relative '../../../transport/http/response'
8
7
  require_relative '../../../transport/http/api/endpoint'
9
8
 
@@ -17,7 +16,6 @@ module Datadog
17
16
  # Response from HTTP transport for agent feature negotiation
18
17
  class Response
19
18
  include Datadog::Core::Transport::HTTP::Response
20
- include Core::Remote::Transport::Negotiation::Response
21
19
 
22
20
  def initialize(http_response, options = {})
23
21
  super(http_response)
@@ -29,10 +27,24 @@ module Datadog
29
27
  @config = options[:config]
30
28
  @span_events = options[:span_events]
31
29
  end
30
+
31
+ # @!attribute [r] version
32
+ # The version of the agent.
33
+ # @return [String]
34
+ # @!attribute [r] endpoints
35
+ # The HTTP endpoints the agent supports.
36
+ # @return [Array<String>]
37
+ # @!attribute [r] config
38
+ # The agent configuration. These are configured by the user when starting the agent, as well as any defaults.
39
+ # @return [Hash]
40
+ # @!attribute [r] span_events
41
+ # Whether the agent supports the top-level span events field in flushed spans.
42
+ # @return [Boolean,nil]
43
+ attr_reader :version, :endpoints, :config, :span_events
32
44
  end
33
45
 
34
- # Extensions for HTTP client
35
- module Client
46
+ # Remote negotiation HTTP client
47
+ class Client < Core::Transport::HTTP::Client
36
48
  def send_info_payload(request)
37
49
  send_request(request) do |api, env|
38
50
  api.send_info(env)
@@ -92,9 +104,6 @@ module Datadog
92
104
  end
93
105
  end
94
106
  end
95
-
96
- # Add negotiation behavior to transport components
97
- HTTP::Client.include(Negotiation::Client)
98
107
  end
99
108
  end
100
109
  end
@@ -4,6 +4,8 @@ require_relative '../../environment/container'
4
4
  require_relative '../../environment/ext'
5
5
  require_relative '../../transport/ext'
6
6
  require_relative '../../transport/http'
7
+ require_relative 'config'
8
+ require_relative 'negotiation'
7
9
 
8
10
  # TODO: Improve negotiation to allow per endpoint selection
9
11
  #