cw-datadog 2.23.0.4 → 2.23.0.5
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/ext/libdatadog_api/feature_flags.c +554 -0
- data/ext/libdatadog_api/feature_flags.h +5 -0
- data/ext/libdatadog_api/init.c +2 -0
- data/lib/datadog/core/cloudwise/client.rb +99 -4
- data/lib/datadog/core/cloudwise/component.rb +55 -13
- data/lib/datadog/core/cloudwise/docc_operation_worker.rb +11 -1
- data/lib/datadog/core/cloudwise/license_worker.rb +7 -0
- data/lib/datadog/core/cloudwise/time_sync_worker.rb +200 -0
- data/lib/datadog/core/configuration/settings.rb +12 -0
- data/lib/datadog/core/configuration/supported_configurations.rb +14 -0
- data/lib/datadog/core/environment/ext.rb +6 -0
- data/lib/datadog/core/environment/process.rb +79 -0
- data/lib/datadog/core/feature_flags.rb +61 -0
- data/lib/datadog/core/tag_normalizer.rb +84 -0
- data/lib/datadog/core/transport/http/adapters/net.rb +8 -0
- data/lib/datadog/core/utils/array.rb +29 -0
- data/lib/datadog/core/utils.rb +2 -0
- data/lib/datadog/data_streams/processor.rb +1 -1
- data/lib/datadog/di/transport/http.rb +6 -2
- data/lib/datadog/di/transport/input.rb +62 -2
- data/lib/datadog/open_feature/evaluation_engine.rb +19 -9
- data/lib/datadog/open_feature/ext.rb +1 -0
- data/lib/datadog/open_feature/native_evaluator.rb +38 -0
- data/lib/datadog/open_feature/noop_evaluator.rb +3 -3
- data/lib/datadog/open_feature/provider.rb +15 -8
- data/lib/datadog/open_feature/remote.rb +1 -1
- data/lib/datadog/opentelemetry/configuration/settings.rb +159 -0
- data/lib/datadog/opentelemetry/metrics.rb +110 -0
- data/lib/datadog/opentelemetry/sdk/configurator.rb +25 -1
- data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +38 -0
- data/lib/datadog/opentelemetry.rb +3 -0
- data/lib/datadog/tracing/configuration/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/cloudwise/propagation.rb +143 -17
- data/lib/datadog/tracing/contrib/grape/endpoint.rb +141 -0
- data/lib/datadog/tracing/contrib/kafka/events/consumer/process_batch.rb +26 -0
- data/lib/datadog/tracing/contrib/kafka/events/consumer/process_message.rb +26 -0
- data/lib/datadog/tracing/contrib/kafka/instrumentation/consumer.rb +79 -9
- data/lib/datadog/tracing/contrib/kafka/instrumentation/producer.rb +29 -6
- data/lib/datadog/tracing/contrib/rack/middlewares.rb +6 -54
- data/lib/datadog/tracing/diagnostics/environment_logger.rb +1 -1
- data/lib/datadog/tracing/transport/serializable_trace.rb +8 -1
- data/lib/datadog/tracing/transport/trace_formatter.rb +11 -0
- data/lib/datadog/tracing/transport/traces.rb +3 -5
- data/lib/datadog/version.rb +1 -1
- metadata +29 -4
|
@@ -157,7 +157,7 @@ module Datadog
|
|
|
157
157
|
imagePath: get_agent_path,
|
|
158
158
|
ip: host_ip,
|
|
159
159
|
agentId: generate_agent_id(host_ip),
|
|
160
|
-
timestamp:
|
|
160
|
+
timestamp: get_adjusted_timestamp_seconds,
|
|
161
161
|
routingKey: 'HeartBeat',
|
|
162
162
|
classPath: '',
|
|
163
163
|
isFirst: @is_first_heartbeat ? 1 : 0,
|
|
@@ -279,7 +279,7 @@ module Datadog
|
|
|
279
279
|
sample: calculate_sample_rate,
|
|
280
280
|
physical_ip: detect_container? ? get_host_real_ip : '',
|
|
281
281
|
container_id: detect_container? ? get_container_id : '',
|
|
282
|
-
sys:
|
|
282
|
+
sys: get_cloudwise_sys,
|
|
283
283
|
env_tag: Datadog.configuration.env || 'default'
|
|
284
284
|
}
|
|
285
285
|
}
|
|
@@ -325,8 +325,61 @@ module Datadog
|
|
|
325
325
|
post_docc("/api/ext/gaia/daemon/report/#{@agent_instance_id}", data)
|
|
326
326
|
end
|
|
327
327
|
|
|
328
|
-
|
|
328
|
+
# 获取服务器时间戳接口
|
|
329
|
+
# @return [Hash] { success: true/false, server_timestamp: Integer (毫秒), offset_ms: Integer }
|
|
330
|
+
def fetch_server_timestamp
|
|
331
|
+
path = apply_api_prefix('/api/v70/timestamp')
|
|
332
|
+
uri = URI.join(base_url, path)
|
|
333
|
+
|
|
334
|
+
Cloudwise.log_debug { "Cloudwise: Fetching server timestamp from #{uri}" }
|
|
335
|
+
|
|
336
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
337
|
+
http.use_ssl = (uri.scheme == 'https')
|
|
338
|
+
http.open_timeout = 5
|
|
339
|
+
http.read_timeout = 5
|
|
340
|
+
|
|
341
|
+
request = Net::HTTP::Get.new(uri.path)
|
|
342
|
+
request['User-Agent'] = "Datadog-Ruby-Agent/#{Datadog::VERSION::STRING}"
|
|
343
|
+
request['DD-Internal-Untraced-Request'] = '1'
|
|
344
|
+
|
|
345
|
+
# 记录请求前的本地时间
|
|
346
|
+
local_before = (Time.now.to_f * 1000).to_i
|
|
347
|
+
|
|
348
|
+
response = http.request(request)
|
|
349
|
+
|
|
350
|
+
# 记录请求后的本地时间
|
|
351
|
+
local_after = (Time.now.to_f * 1000).to_i
|
|
352
|
+
|
|
353
|
+
if response.code.to_i == 200
|
|
354
|
+
server_timestamp = response.body.to_s.strip.to_i
|
|
355
|
+
|
|
356
|
+
# 使用请求前后的中间时间作为本地参考时间
|
|
357
|
+
local_timestamp = (local_before + local_after) / 2
|
|
358
|
+
|
|
359
|
+
# 计算时间偏移(服务器时间 - 本地时间)
|
|
360
|
+
# 正值表示服务器时间比本地快,负值表示服务器时间比本地慢
|
|
361
|
+
offset_ms = server_timestamp - local_timestamp
|
|
362
|
+
|
|
363
|
+
Cloudwise.log_debug do
|
|
364
|
+
"Cloudwise: Server timestamp sync - server=#{server_timestamp}, local=#{local_timestamp}, offset=#{offset_ms}ms"
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
{
|
|
368
|
+
success: true,
|
|
369
|
+
server_timestamp: server_timestamp,
|
|
370
|
+
local_timestamp: local_timestamp,
|
|
371
|
+
offset_ms: offset_ms
|
|
372
|
+
}
|
|
373
|
+
else
|
|
374
|
+
Cloudwise.log_warn { "Cloudwise: path: #{path} Failed to fetch server timestamp: #{response.code}" }
|
|
375
|
+
{ success: false, error: "HTTP #{response.code}" }
|
|
376
|
+
end
|
|
377
|
+
rescue => e
|
|
378
|
+
Cloudwise.log_error { "Cloudwise: Error fetching server timestamp: #{e.message}" }
|
|
379
|
+
{ success: false, error: e.message }
|
|
380
|
+
end
|
|
329
381
|
|
|
382
|
+
private
|
|
330
383
|
def post(path, data)
|
|
331
384
|
# 统一处理 API 路径前缀
|
|
332
385
|
path = apply_api_prefix(path)
|
|
@@ -380,6 +433,31 @@ module Datadog
|
|
|
380
433
|
end
|
|
381
434
|
|
|
382
435
|
|
|
436
|
+
# 获取校正后的秒级时间戳
|
|
437
|
+
# 如果启用了时间同步,会应用偏移量校正
|
|
438
|
+
# @return [Integer] 校正后的秒级时间戳
|
|
439
|
+
def get_adjusted_timestamp_seconds
|
|
440
|
+
local_time_s = Time.now.to_i
|
|
441
|
+
if defined?(TimeSyncWorker) && TimeSyncWorker.sync_enabled?
|
|
442
|
+
# offset_ms 是毫秒,转换为秒
|
|
443
|
+
local_time_s + (TimeSyncWorker.offset_ms / 1000)
|
|
444
|
+
else
|
|
445
|
+
local_time_s
|
|
446
|
+
end
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
# 获取校正后的毫秒级时间戳
|
|
450
|
+
# 如果启用了时间同步,会应用偏移量校正
|
|
451
|
+
# @return [Integer] 校正后的毫秒级时间戳
|
|
452
|
+
def get_adjusted_timestamp_ms
|
|
453
|
+
local_time_ms = (Time.now.to_f * 1000).to_i
|
|
454
|
+
if defined?(TimeSyncWorker) && TimeSyncWorker.sync_enabled?
|
|
455
|
+
local_time_ms + TimeSyncWorker.offset_ms
|
|
456
|
+
else
|
|
457
|
+
local_time_ms
|
|
458
|
+
end
|
|
459
|
+
end
|
|
460
|
+
|
|
383
461
|
# 获取本机 IP 地址
|
|
384
462
|
# 优先获取外网 IP(通过创建 UDP 连接,不实际发送数据)
|
|
385
463
|
# 如果失败,尝试获取局域网 IP
|
|
@@ -623,7 +701,8 @@ module Datadog
|
|
|
623
701
|
'/api/v1/agent/heartbeat',
|
|
624
702
|
'/api/v1/agent/fuseHeart',
|
|
625
703
|
'/v2/app/create',
|
|
626
|
-
'/v2/licence/verification'
|
|
704
|
+
'/v2/licence/verification',
|
|
705
|
+
'/api/v70/timestamp'
|
|
627
706
|
]
|
|
628
707
|
|
|
629
708
|
# 检查是否是需要添加前缀的路径
|
|
@@ -704,6 +783,22 @@ module Datadog
|
|
|
704
783
|
end
|
|
705
784
|
|
|
706
785
|
|
|
786
|
+
# 获取 Cloudwise sys 配置值
|
|
787
|
+
# 优先级: Datadog.configuration.cloudwise.sys > CW_SYS 环境变量 > 默认值 'default'
|
|
788
|
+
# @return [String] sys 值
|
|
789
|
+
def get_cloudwise_sys
|
|
790
|
+
# 优先从配置读取
|
|
791
|
+
if defined?(Datadog.configuration) &&
|
|
792
|
+
Datadog.configuration.respond_to?(:cloudwise) &&
|
|
793
|
+
Datadog.configuration.cloudwise.respond_to?(:sys)
|
|
794
|
+
sys = Datadog.configuration.cloudwise.sys
|
|
795
|
+
return sys if sys && !sys.empty? && sys != 'default'
|
|
796
|
+
end
|
|
797
|
+
|
|
798
|
+
# 其次从环境变量读取
|
|
799
|
+
ENV['CW_SYS'] || 'default'
|
|
800
|
+
end
|
|
801
|
+
|
|
707
802
|
# Get current run user
|
|
708
803
|
def get_run_user
|
|
709
804
|
ENV['USER'] || ENV['USERNAME'] || 'cloudwise'
|
|
@@ -9,6 +9,7 @@ require_relative 'app_registration_worker'
|
|
|
9
9
|
require_relative 'docc_registration_worker'
|
|
10
10
|
require_relative 'docc_heartbeat_worker'
|
|
11
11
|
require_relative 'docc_operation_worker'
|
|
12
|
+
require_relative 'time_sync_worker'
|
|
12
13
|
|
|
13
14
|
module Datadog
|
|
14
15
|
module Core
|
|
@@ -46,7 +47,8 @@ module Datadog
|
|
|
46
47
|
class Component
|
|
47
48
|
attr_reader :client, :probe_state, :host_id_worker, :heartbeat_worker,
|
|
48
49
|
:license_worker, :app_registration_worker, :logger,
|
|
49
|
-
:docc_registration_worker, :docc_heartbeat_worker, :docc_operation_worker
|
|
50
|
+
:docc_registration_worker, :docc_heartbeat_worker, :docc_operation_worker,
|
|
51
|
+
:time_sync_worker
|
|
50
52
|
|
|
51
53
|
# 类级别的单例锁,确保全局只初始化一次
|
|
52
54
|
@initialization_mutex = Mutex.new
|
|
@@ -185,6 +187,9 @@ module Datadog
|
|
|
185
187
|
def stop
|
|
186
188
|
return unless @enabled
|
|
187
189
|
|
|
190
|
+
# 停止时间同步 worker(两种模式都需要)
|
|
191
|
+
@time_sync_worker&.stop(true)
|
|
192
|
+
|
|
188
193
|
if @client.use_integrated_mode?
|
|
189
194
|
@docc_heartbeat_worker&.stop(true)
|
|
190
195
|
@docc_registration_worker&.stop(true)
|
|
@@ -216,6 +221,13 @@ module Datadog
|
|
|
216
221
|
return { enabled: false } unless @enabled
|
|
217
222
|
|
|
218
223
|
probe_status = probe_state.status
|
|
224
|
+
# 获取时间同步状态
|
|
225
|
+
time_sync_status = if defined?(Datadog::Core::Cloudwise::TimeSyncWorker)
|
|
226
|
+
Datadog::Core::Cloudwise::TimeSyncWorker.status
|
|
227
|
+
else
|
|
228
|
+
{ enabled: false }
|
|
229
|
+
end
|
|
230
|
+
|
|
219
231
|
base_status = {
|
|
220
232
|
enabled: true,
|
|
221
233
|
integrated_mode: @client.use_integrated_mode?,
|
|
@@ -223,7 +235,10 @@ module Datadog
|
|
|
223
235
|
probe_active: probe_state.active?,
|
|
224
236
|
probe_suspended: probe_state.suspended?,
|
|
225
237
|
license_valid: probe_status[:license_valid],
|
|
226
|
-
license_running: license_worker&.running
|
|
238
|
+
license_running: license_worker&.running?,
|
|
239
|
+
time_sync_enabled: time_sync_status[:enabled],
|
|
240
|
+
time_sync_offset_ms: time_sync_status[:offset_ms],
|
|
241
|
+
time_sync_running: time_sync_worker&.running?
|
|
227
242
|
}
|
|
228
243
|
|
|
229
244
|
if @client.use_integrated_mode?
|
|
@@ -282,6 +297,13 @@ module Datadog
|
|
|
282
297
|
probe_state: probe_state,
|
|
283
298
|
interval: settings.cloudwise.license_check_interval
|
|
284
299
|
)
|
|
300
|
+
|
|
301
|
+
# 5. Time Sync Worker (3 min interval, depends on License)
|
|
302
|
+
@time_sync_worker = TimeSyncWorker.new(
|
|
303
|
+
client: client,
|
|
304
|
+
logger: logger,
|
|
305
|
+
probe_state: probe_state
|
|
306
|
+
)
|
|
285
307
|
end
|
|
286
308
|
|
|
287
309
|
# 初始化 DOCC 模式的 workers
|
|
@@ -315,6 +337,13 @@ module Datadog
|
|
|
315
337
|
probe_state: probe_state,
|
|
316
338
|
interval: settings.cloudwise.license_check_interval
|
|
317
339
|
)
|
|
340
|
+
|
|
341
|
+
# 5. Time Sync Worker (3 min interval, depends on License)
|
|
342
|
+
@time_sync_worker = TimeSyncWorker.new(
|
|
343
|
+
client: client,
|
|
344
|
+
logger: logger,
|
|
345
|
+
probe_state: probe_state
|
|
346
|
+
)
|
|
318
347
|
end
|
|
319
348
|
|
|
320
349
|
# 检查实例是否已经启动
|
|
@@ -335,7 +364,8 @@ module Datadog
|
|
|
335
364
|
# 3. Start Heartbeat worker
|
|
336
365
|
# 4. Start App Registration worker (non-blocking)
|
|
337
366
|
# 5. Start License worker
|
|
338
|
-
# 6.
|
|
367
|
+
# 6. Start Time Sync worker (3 min interval)
|
|
368
|
+
# 7. ProbeState controls whether data collection is active
|
|
339
369
|
def start_cloudwise_workers_when_ready
|
|
340
370
|
Thread.new do
|
|
341
371
|
Thread.current.name = 'Cloudwise-Initializer'
|
|
@@ -368,7 +398,6 @@ module Datadog
|
|
|
368
398
|
# ============================================================
|
|
369
399
|
# STEP 4: Start License worker
|
|
370
400
|
# ============================================================
|
|
371
|
-
#
|
|
372
401
|
@license_worker.start
|
|
373
402
|
|
|
374
403
|
# Wait for first successful license validation
|
|
@@ -376,6 +405,12 @@ module Datadog
|
|
|
376
405
|
sleep(1)
|
|
377
406
|
end
|
|
378
407
|
|
|
408
|
+
# ============================================================
|
|
409
|
+
# STEP 5: Start Time Sync worker (3 min interval)
|
|
410
|
+
# ============================================================
|
|
411
|
+
Cloudwise.log_debug { 'Cloudwise: Starting Time Sync worker (3 min interval)...' }
|
|
412
|
+
@time_sync_worker.start
|
|
413
|
+
|
|
379
414
|
# ============================================================
|
|
380
415
|
# All validations passed - Probe is now ACTIVE
|
|
381
416
|
# ============================================================
|
|
@@ -392,7 +427,8 @@ module Datadog
|
|
|
392
427
|
# 2. 等待第一次心跳成功
|
|
393
428
|
# 3. 启动 DOCC 注册 worker
|
|
394
429
|
# 4. 启动 License worker
|
|
395
|
-
# 5. 启动
|
|
430
|
+
# 5. 启动 Time Sync worker (3 min interval)
|
|
431
|
+
# 6. 启动 DOCC 操作 worker
|
|
396
432
|
def start_docc_workers_when_ready
|
|
397
433
|
Thread.new do
|
|
398
434
|
Thread.current.name = 'Cloudwise-DOCC-Initializer'
|
|
@@ -400,11 +436,11 @@ module Datadog
|
|
|
400
436
|
# ============================================================
|
|
401
437
|
# STEP 1: Start DOCC Heartbeat worker
|
|
402
438
|
# ============================================================
|
|
403
|
-
Cloudwise.log_debug { 'Cloudwise
|
|
439
|
+
Cloudwise.log_debug { 'Cloudwise docc: Starting heartbeat worker...' }
|
|
404
440
|
@docc_heartbeat_worker.start
|
|
405
441
|
|
|
406
442
|
# Wait for first successful heartbeat
|
|
407
|
-
Cloudwise.log_debug { 'Cloudwise
|
|
443
|
+
Cloudwise.log_debug { 'Cloudwise docc: Waiting for first successful heartbeat...' }
|
|
408
444
|
until probe_state.docc_heartbeat_active?
|
|
409
445
|
sleep(1)
|
|
410
446
|
end
|
|
@@ -412,13 +448,13 @@ module Datadog
|
|
|
412
448
|
# ============================================================
|
|
413
449
|
# STEP 2: Start DOCC Registration worker
|
|
414
450
|
# ============================================================
|
|
415
|
-
Cloudwise.log_debug { 'Cloudwise
|
|
451
|
+
Cloudwise.log_debug { 'Cloudwise docc: Starting registration worker...' }
|
|
416
452
|
@docc_registration_worker.start
|
|
417
453
|
|
|
418
454
|
# ============================================================
|
|
419
455
|
# STEP 3: Start License worker
|
|
420
456
|
# ============================================================
|
|
421
|
-
Cloudwise.log_debug { 'Cloudwise
|
|
457
|
+
Cloudwise.log_debug { 'Cloudwise docc: Starting license worker...' }
|
|
422
458
|
@license_worker.start
|
|
423
459
|
|
|
424
460
|
# Wait for first successful license validation
|
|
@@ -427,17 +463,23 @@ module Datadog
|
|
|
427
463
|
end
|
|
428
464
|
|
|
429
465
|
# ============================================================
|
|
430
|
-
# STEP 4: Start
|
|
466
|
+
# STEP 4: Start Time Sync worker (3 min interval)
|
|
467
|
+
# ============================================================
|
|
468
|
+
Cloudwise.log_debug { 'Cloudwise docc: Starting Time Sync worker (3 min interval)...' }
|
|
469
|
+
@time_sync_worker.start
|
|
470
|
+
|
|
471
|
+
# ============================================================
|
|
472
|
+
# STEP 5: Start DOCC Operation worker
|
|
431
473
|
# ============================================================
|
|
432
|
-
Cloudwise.log_debug { 'Cloudwise
|
|
474
|
+
Cloudwise.log_debug { 'Cloudwise docc: Starting operation worker...' }
|
|
433
475
|
@docc_operation_worker.start
|
|
434
476
|
|
|
435
477
|
# ============================================================
|
|
436
478
|
# All validations passed - Probe is now ACTIVE
|
|
437
479
|
# ============================================================
|
|
438
|
-
Cloudwise.log_debug { 'Cloudwise
|
|
480
|
+
Cloudwise.log_debug { 'Cloudwise docc: Data collection and reporting now enabled.' }
|
|
439
481
|
rescue => e
|
|
440
|
-
Cloudwise.log_error { "Cloudwise
|
|
482
|
+
Cloudwise.log_error { "Cloudwise docc: Error in background initializer: #{e.class.name} #{e.message}" }
|
|
441
483
|
Cloudwise.log_error { e.backtrace.join("\n") }
|
|
442
484
|
end
|
|
443
485
|
end
|
|
@@ -170,10 +170,20 @@ module Datadog
|
|
|
170
170
|
agent_id: 'rubyagent'
|
|
171
171
|
},
|
|
172
172
|
status: status,
|
|
173
|
-
timestamp:
|
|
173
|
+
timestamp: get_adjusted_timestamp_ms
|
|
174
174
|
}
|
|
175
175
|
end
|
|
176
176
|
|
|
177
|
+
# 获取校正后的毫秒时间戳
|
|
178
|
+
def get_adjusted_timestamp_ms
|
|
179
|
+
local_time_ms = (Time.now.to_f * 1000).to_i
|
|
180
|
+
if defined?(TimeSyncWorker) && TimeSyncWorker.sync_enabled?
|
|
181
|
+
local_time_ms + TimeSyncWorker.offset_ms
|
|
182
|
+
else
|
|
183
|
+
local_time_ms
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
177
187
|
# 批量上报操作结果
|
|
178
188
|
def report_operation_results(results)
|
|
179
189
|
result = client.docc_report_operation(results)
|
|
@@ -159,9 +159,16 @@ module Datadog
|
|
|
159
159
|
end
|
|
160
160
|
|
|
161
161
|
# 仅在状态发生变化时上报熔断状态
|
|
162
|
+
# 注意:融合模式(use_integrated_mode)下不进行上报
|
|
162
163
|
# @param fuse_state [Integer] 熔断状态: 0-正常, 1-熔断
|
|
163
164
|
# @param fuse_describe [Integer, nil] 熔断描述: 7/8/9/10,正常状态时为nil
|
|
164
165
|
def report_fuse_state_if_changed(fuse_state, fuse_describe)
|
|
166
|
+
# 融合模式下不上报熔断状态
|
|
167
|
+
if client.use_integrated_mode?
|
|
168
|
+
Cloudwise.log_debug { 'Cloudwise: Integrated mode enabled, skip fuse state reporting' }
|
|
169
|
+
return
|
|
170
|
+
end
|
|
171
|
+
|
|
165
172
|
# 检查状态是否发生变化
|
|
166
173
|
if @last_fuse_state == fuse_state && @last_fuse_describe == fuse_describe
|
|
167
174
|
Cloudwise.log_debug { "Cloudwise: Fuse state unchanged (state: #{fuse_state}, describe: #{fuse_describe}), skip reporting" }
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../worker'
|
|
4
|
+
require_relative '../workers/async'
|
|
5
|
+
require_relative '../workers/polling'
|
|
6
|
+
|
|
7
|
+
module Datadog
|
|
8
|
+
module Core
|
|
9
|
+
module Cloudwise
|
|
10
|
+
# Worker that synchronizes time with server every 3 minutes
|
|
11
|
+
# 时间同步 Worker,每 3 分钟执行一次
|
|
12
|
+
# 整合了时间偏移量管理和定时同步功能
|
|
13
|
+
class TimeSyncWorker < Worker
|
|
14
|
+
include Workers::Polling
|
|
15
|
+
|
|
16
|
+
# 3 minutes interval (180 seconds)
|
|
17
|
+
DEFAULT_INTERVAL = 180
|
|
18
|
+
|
|
19
|
+
# 最大偏移量阈值(毫秒)- 超过此值才进行校正
|
|
20
|
+
# 小于 100ms 的偏移可以忽略
|
|
21
|
+
OFFSET_THRESHOLD_MS = 100
|
|
22
|
+
|
|
23
|
+
# 类级别的时间偏移量状态(全局共享)
|
|
24
|
+
@offset_ms = 0
|
|
25
|
+
@sync_enabled = false
|
|
26
|
+
@last_sync_time = nil
|
|
27
|
+
@state_mutex = Mutex.new
|
|
28
|
+
|
|
29
|
+
class << self
|
|
30
|
+
attr_reader :state_mutex
|
|
31
|
+
|
|
32
|
+
# 获取当前时间偏移量(毫秒)
|
|
33
|
+
# @return [Integer] 时间偏移量,正值表示服务器时间比本地快
|
|
34
|
+
def offset_ms
|
|
35
|
+
@offset_ms ||= 0
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# 设置时间偏移量
|
|
39
|
+
# @param value [Integer] 偏移量(毫秒)
|
|
40
|
+
def offset_ms=(value)
|
|
41
|
+
@offset_ms = value.to_i
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# 获取时间偏移量(纳秒)
|
|
45
|
+
# @return [Integer] 时间偏移量(纳秒)
|
|
46
|
+
def offset_ns
|
|
47
|
+
offset_ms * 1_000_000
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# 检查是否启用时间同步
|
|
51
|
+
# @return [Boolean]
|
|
52
|
+
def sync_enabled?
|
|
53
|
+
@sync_enabled ||= false
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# 启用时间同步
|
|
57
|
+
def enable_sync!
|
|
58
|
+
@sync_enabled = true
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# 禁用时间同步
|
|
62
|
+
def disable_sync!
|
|
63
|
+
@sync_enabled = false
|
|
64
|
+
@offset_ms = 0
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# 上次同步时间
|
|
68
|
+
# @return [Integer, nil] 毫秒时间戳
|
|
69
|
+
def last_sync_time
|
|
70
|
+
@last_sync_time
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# 设置上次同步时间
|
|
74
|
+
def last_sync_time=(value)
|
|
75
|
+
@last_sync_time = value
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# 校正时间戳(纳秒)
|
|
79
|
+
# 将本地时间戳转换为服务器时间戳
|
|
80
|
+
# @param local_time_ns [Integer] 本地时间戳(纳秒)
|
|
81
|
+
# @return [Integer] 校正后的时间戳(纳秒)
|
|
82
|
+
def adjust_timestamp_ns(local_time_ns)
|
|
83
|
+
return local_time_ns unless sync_enabled?
|
|
84
|
+
return local_time_ns if offset_ms.abs < OFFSET_THRESHOLD_MS
|
|
85
|
+
|
|
86
|
+
local_time_ns + offset_ns
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# 校正 Time 对象
|
|
90
|
+
# @param time [Time] 本地时间
|
|
91
|
+
# @return [Time] 校正后的时间
|
|
92
|
+
def adjust_time(time)
|
|
93
|
+
return time unless sync_enabled?
|
|
94
|
+
return time if offset_ms.abs < OFFSET_THRESHOLD_MS
|
|
95
|
+
|
|
96
|
+
time + (offset_ms / 1000.0)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# 重置状态(用于测试)
|
|
100
|
+
def reset!
|
|
101
|
+
@offset_ms = 0
|
|
102
|
+
@sync_enabled = false
|
|
103
|
+
@last_sync_time = nil
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# 获取同步状态信息
|
|
107
|
+
# @return [Hash]
|
|
108
|
+
def status
|
|
109
|
+
{
|
|
110
|
+
enabled: sync_enabled?,
|
|
111
|
+
offset_ms: offset_ms,
|
|
112
|
+
offset_ns: offset_ns,
|
|
113
|
+
last_sync_time: last_sync_time
|
|
114
|
+
}
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
attr_reader :client
|
|
119
|
+
|
|
120
|
+
def initialize(client:, logger:, probe_state:, **options)
|
|
121
|
+
@client = client
|
|
122
|
+
@logger = logger
|
|
123
|
+
@probe_state = probe_state
|
|
124
|
+
|
|
125
|
+
# Workers::Async::Thread settings
|
|
126
|
+
self.fork_policy = options.fetch(:fork_policy, Workers::Async::Thread::FORK_POLICY_STOP)
|
|
127
|
+
|
|
128
|
+
# Workers::IntervalLoop settings
|
|
129
|
+
self.loop_base_interval = options.fetch(:interval, DEFAULT_INTERVAL)
|
|
130
|
+
|
|
131
|
+
self.enabled = options.fetch(:enabled, true)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def perform
|
|
135
|
+
# 只有在 License 校验通过后才执行时间同步
|
|
136
|
+
unless probe_state.license_valid?
|
|
137
|
+
Cloudwise.log_debug { 'Cloudwise: Waiting for license validation before time sync' }
|
|
138
|
+
return true
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
Cloudwise.log_debug { 'Cloudwise: Performing server time synchronization' }
|
|
142
|
+
|
|
143
|
+
if sync_time!
|
|
144
|
+
Cloudwise.log_debug { "Cloudwise: Time sync completed, offset=#{self.class.offset_ms}ms" }
|
|
145
|
+
else
|
|
146
|
+
Cloudwise.log_warn { 'Cloudwise: Time sync failed' }
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
true
|
|
150
|
+
rescue => e
|
|
151
|
+
Cloudwise.log_error { "Cloudwise: Time sync worker error: #{e.class.name} #{e.message}" }
|
|
152
|
+
true # Continue running
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Public method to start the worker
|
|
156
|
+
def start
|
|
157
|
+
return false if !enabled? || started?
|
|
158
|
+
|
|
159
|
+
# Start the async worker thread
|
|
160
|
+
perform
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
private
|
|
164
|
+
|
|
165
|
+
attr_reader :logger, :probe_state
|
|
166
|
+
|
|
167
|
+
# 执行时间同步
|
|
168
|
+
# @return [Boolean] 是否同步成功
|
|
169
|
+
def sync_time!
|
|
170
|
+
return false unless client
|
|
171
|
+
|
|
172
|
+
result = client.fetch_server_timestamp
|
|
173
|
+
if result[:success]
|
|
174
|
+
self.class.state_mutex.synchronize do
|
|
175
|
+
self.class.offset_ms = result[:offset_ms]
|
|
176
|
+
self.class.last_sync_time = (Time.now.to_f * 1000).to_i
|
|
177
|
+
self.class.enable_sync!
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
Cloudwise.log_info do
|
|
181
|
+
"Cloudwise TimeSync: Synchronized with server, offset=#{self.class.offset_ms}ms"
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
true
|
|
185
|
+
else
|
|
186
|
+
Cloudwise.log_warn do
|
|
187
|
+
"Cloudwise TimeSync: Failed to sync - #{result[:error]}"
|
|
188
|
+
end
|
|
189
|
+
false
|
|
190
|
+
end
|
|
191
|
+
rescue => e
|
|
192
|
+
Cloudwise.log_error do
|
|
193
|
+
"Cloudwise TimeSync: Error during sync - #{e.message}"
|
|
194
|
+
end
|
|
195
|
+
false
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
@@ -12,6 +12,7 @@ require_relative '../remote/ext'
|
|
|
12
12
|
require_relative '../../profiling/ext'
|
|
13
13
|
|
|
14
14
|
require_relative '../../tracing/configuration/settings'
|
|
15
|
+
require_relative '../../opentelemetry/configuration/settings'
|
|
15
16
|
|
|
16
17
|
module Datadog
|
|
17
18
|
module Core
|
|
@@ -1095,6 +1096,15 @@ module Datadog
|
|
|
1095
1096
|
o.default 180
|
|
1096
1097
|
end
|
|
1097
1098
|
end
|
|
1099
|
+
# Enable experimental process tags propagation such that payloads like spans contain the process tag.
|
|
1100
|
+
#
|
|
1101
|
+
# @default `DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED` environment variable, otherwise `false`
|
|
1102
|
+
# @return [Boolean]
|
|
1103
|
+
option :experimental_propagate_process_tags_enabled do |o|
|
|
1104
|
+
o.env 'DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED'
|
|
1105
|
+
o.default false
|
|
1106
|
+
o.type :bool
|
|
1107
|
+
end
|
|
1098
1108
|
|
|
1099
1109
|
# Tracer specific configuration starting with APM (e.g. DD_APM_TRACING_ENABLED).
|
|
1100
1110
|
# @public_api
|
|
@@ -1123,6 +1133,8 @@ module Datadog
|
|
|
1123
1133
|
# TODO: Tracing should manage its own settings.
|
|
1124
1134
|
# Keep this extension here for now to keep things working.
|
|
1125
1135
|
extend Datadog::Tracing::Configuration::Settings
|
|
1136
|
+
|
|
1137
|
+
extend Datadog::OpenTelemetry::Configuration::Settings
|
|
1126
1138
|
end
|
|
1127
1139
|
# standard:enable Metrics/BlockLength
|
|
1128
1140
|
end
|
|
@@ -51,6 +51,7 @@ module Datadog
|
|
|
51
51
|
"DD_ERROR_TRACKING_HANDLED_ERRORS" => {version: ["A"]},
|
|
52
52
|
"DD_ERROR_TRACKING_HANDLED_ERRORS_INCLUDE" => {version: ["A"]},
|
|
53
53
|
"DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED" => {version: ["A"]},
|
|
54
|
+
"DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED" => {version: ["A"]},
|
|
54
55
|
"DD_GIT_COMMIT_SHA" => {version: ["A"]},
|
|
55
56
|
"DD_GIT_REPOSITORY_URL" => {version: ["A"]},
|
|
56
57
|
"DD_HEALTH_METRICS_ENABLED" => {version: ["A"]},
|
|
@@ -63,6 +64,7 @@ module Datadog
|
|
|
63
64
|
"DD_INTEGRATION_SERVICE" => {version: ["A"]},
|
|
64
65
|
"DD_LOGS_INJECTION" => {version: ["A"]},
|
|
65
66
|
"DD_METRIC_AGENT_PORT" => {version: ["A"]},
|
|
67
|
+
"DD_METRICS_OTEL_ENABLED" => {version: ["A"]},
|
|
66
68
|
"DD_PROFILING_ALLOCATION_ENABLED" => {version: ["A"]},
|
|
67
69
|
"DD_PROFILING_DIR_INTERRUPTION_WORKAROUND_ENABLED" => {version: ["A"]},
|
|
68
70
|
"DD_PROFILING_ENABLED" => {version: ["A"]},
|
|
@@ -320,6 +322,18 @@ module Datadog
|
|
|
320
322
|
"DD_TRACE_WATERDROP_ENABLED" => {version: ["A"]},
|
|
321
323
|
"DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH" => {version: ["A"]},
|
|
322
324
|
"DD_VERSION" => {version: ["A"]},
|
|
325
|
+
"OTEL_EXPORTER_OTLP_ENDPOINT" => {version: ["A"]},
|
|
326
|
+
"OTEL_EXPORTER_OTLP_HEADERS" => {version: ["A"]},
|
|
327
|
+
"OTEL_EXPORTER_OTLP_METRICS_ENDPOINT" => {version: ["A"]},
|
|
328
|
+
"OTEL_EXPORTER_OTLP_METRICS_HEADERS" => {version: ["A"]},
|
|
329
|
+
"OTEL_EXPORTER_OTLP_METRICS_PROTOCOL" => {version: ["A"]},
|
|
330
|
+
"OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE" => {version: ["A"]},
|
|
331
|
+
"OTEL_EXPORTER_OTLP_METRICS_TIMEOUT" => {version: ["A"]},
|
|
332
|
+
"OTEL_EXPORTER_OTLP_PROTOCOL" => {version: ["A"]},
|
|
333
|
+
"OTEL_EXPORTER_OTLP_TIMEOUT" => {version: ["A"]},
|
|
334
|
+
"OTEL_METRIC_EXPORT_INTERVAL" => {version: ["A"]},
|
|
335
|
+
"OTEL_METRIC_EXPORT_TIMEOUT" => {version: ["A"]},
|
|
336
|
+
"OTEL_METRICS_EXPORTER" => {version: ["A"]},
|
|
323
337
|
"OTEL_TRACES_SAMPLER_ARG" => {version: ["A"]}}.freeze
|
|
324
338
|
|
|
325
339
|
ALIASES =
|
|
@@ -33,8 +33,14 @@ module Datadog
|
|
|
33
33
|
LANG_INTERPRETER = "#{RUBY_ENGINE}-#{RUBY_PLATFORM}"
|
|
34
34
|
LANG_PLATFORM = RUBY_PLATFORM
|
|
35
35
|
LANG_VERSION = RUBY_VERSION
|
|
36
|
+
PROCESS_TYPE = 'script' # Out of the options [jar, script, class, executable], we consider Ruby to always be a script
|
|
36
37
|
RUBY_ENGINE = ::RUBY_ENGINE # e.g. 'ruby', 'jruby', 'truffleruby'
|
|
37
38
|
TAG_ENV = 'env'
|
|
39
|
+
TAG_ENTRYPOINT_BASEDIR = "entrypoint.basedir"
|
|
40
|
+
TAG_ENTRYPOINT_NAME = "entrypoint.name"
|
|
41
|
+
TAG_ENTRYPOINT_WORKDIR = "entrypoint.workdir"
|
|
42
|
+
TAG_ENTRYPOINT_TYPE = "entrypoint.type"
|
|
43
|
+
TAG_PROCESS_TAGS = "_dd.tags.process"
|
|
38
44
|
TAG_SERVICE = 'service'
|
|
39
45
|
TAG_VERSION = 'version'
|
|
40
46
|
|