cw-datadog 2.23.0.2 → 2.23.0.3
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/datadog_profiling_native_extension/extconf.rb +4 -2
- data/ext/libdatadog_api/library_config.c +12 -11
- data/ext/libdatadog_extconf_helpers.rb +1 -1
- data/lib/datadog/appsec/api_security/route_extractor.rb +20 -5
- data/lib/datadog/appsec/api_security/sampler.rb +3 -1
- data/lib/datadog/appsec/assets/blocked.html +8 -0
- data/lib/datadog/appsec/assets/blocked.json +1 -1
- data/lib/datadog/appsec/assets/blocked.text +3 -1
- data/lib/datadog/appsec/assets.rb +1 -1
- data/lib/datadog/appsec/remote.rb +4 -0
- data/lib/datadog/appsec/response.rb +18 -4
- data/lib/datadog/core/cloudwise/client.rb +364 -25
- data/lib/datadog/core/cloudwise/component.rb +197 -52
- data/lib/datadog/core/cloudwise/docc_heartbeat_worker.rb +105 -0
- data/lib/datadog/core/cloudwise/docc_operation_worker.rb +191 -0
- data/lib/datadog/core/cloudwise/docc_registration_worker.rb +89 -0
- data/lib/datadog/core/cloudwise/license_worker.rb +3 -1
- data/lib/datadog/core/cloudwise/probe_state.rb +134 -12
- data/lib/datadog/core/configuration/components.rb +10 -9
- data/lib/datadog/core/configuration/settings.rb +28 -0
- data/lib/datadog/core/configuration/supported_configurations.rb +5 -2
- data/lib/datadog/core/remote/client/capabilities.rb +7 -0
- data/lib/datadog/core/remote/component.rb +2 -2
- data/lib/datadog/core/remote/transport/config.rb +2 -10
- data/lib/datadog/core/remote/transport/http/config.rb +9 -9
- data/lib/datadog/core/remote/transport/http/negotiation.rb +17 -8
- data/lib/datadog/core/remote/transport/http.rb +2 -0
- data/lib/datadog/core/remote/transport/negotiation.rb +2 -18
- data/lib/datadog/core/remote/worker.rb +23 -35
- data/lib/datadog/core/telemetry/component.rb +26 -13
- data/lib/datadog/core/telemetry/event/app_started.rb +67 -49
- data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +27 -4
- data/lib/datadog/core/telemetry/transport/http/telemetry.rb +5 -6
- data/lib/datadog/core/telemetry/transport/telemetry.rb +1 -2
- data/lib/datadog/core/telemetry/worker.rb +51 -6
- data/lib/datadog/core/transport/http/adapters/net.rb +2 -0
- data/lib/datadog/core/transport/http/client.rb +69 -0
- data/lib/datadog/core/utils/only_once_successful.rb +6 -2
- data/lib/datadog/data_streams/transport/http/client.rb +4 -32
- data/lib/datadog/data_streams/transport/stats.rb +1 -1
- data/lib/datadog/di/probe_notification_builder.rb +35 -13
- data/lib/datadog/di/transport/diagnostics.rb +2 -2
- data/lib/datadog/di/transport/http/diagnostics.rb +2 -4
- data/lib/datadog/di/transport/http/input.rb +2 -4
- data/lib/datadog/di/transport/input.rb +2 -2
- data/lib/datadog/open_feature/component.rb +60 -0
- data/lib/datadog/open_feature/configuration.rb +27 -0
- data/lib/datadog/open_feature/evaluation_engine.rb +59 -0
- data/lib/datadog/open_feature/exposures/batch_builder.rb +32 -0
- data/lib/datadog/open_feature/exposures/buffer.rb +43 -0
- data/lib/datadog/open_feature/exposures/deduplicator.rb +30 -0
- data/lib/datadog/open_feature/exposures/event.rb +60 -0
- data/lib/datadog/open_feature/exposures/reporter.rb +40 -0
- data/lib/datadog/open_feature/exposures/worker.rb +116 -0
- data/lib/datadog/open_feature/ext.rb +13 -0
- data/lib/datadog/open_feature/noop_evaluator.rb +26 -0
- data/lib/datadog/open_feature/provider.rb +134 -0
- data/lib/datadog/open_feature/remote.rb +74 -0
- data/lib/datadog/open_feature/resolution_details.rb +35 -0
- data/lib/datadog/open_feature/transport.rb +72 -0
- data/lib/datadog/open_feature.rb +19 -0
- data/lib/datadog/profiling/component.rb +6 -0
- data/lib/datadog/profiling/profiler.rb +4 -0
- data/lib/datadog/profiling.rb +1 -2
- data/lib/datadog/single_step_instrument.rb +1 -1
- data/lib/datadog/tracing/contrib/cloudwise/propagation.rb +164 -7
- data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +22 -17
- data/lib/datadog/tracing/contrib/karafka/framework.rb +30 -0
- data/lib/datadog/tracing/contrib/karafka/patcher.rb +14 -0
- data/lib/datadog/tracing/contrib/rack/middlewares.rb +6 -2
- data/lib/datadog/tracing/contrib/waterdrop/configuration/settings.rb +27 -0
- data/lib/datadog/tracing/contrib/waterdrop/distributed/propagation.rb +48 -0
- data/lib/datadog/tracing/contrib/waterdrop/ext.rb +17 -0
- data/lib/datadog/tracing/contrib/waterdrop/integration.rb +43 -0
- data/lib/datadog/tracing/contrib/waterdrop/middleware.rb +46 -0
- data/lib/datadog/tracing/contrib/waterdrop/patcher.rb +46 -0
- data/lib/datadog/tracing/contrib/waterdrop/producer.rb +50 -0
- data/lib/datadog/tracing/contrib/waterdrop.rb +37 -0
- data/lib/datadog/tracing/contrib.rb +1 -0
- data/lib/datadog/tracing/transport/http/api.rb +40 -1
- data/lib/datadog/tracing/transport/http/client.rb +12 -26
- data/lib/datadog/tracing/transport/http/traces.rb +4 -2
- data/lib/datadog/tracing/transport/trace_formatter.rb +16 -0
- data/lib/datadog/version.rb +2 -2
- data/lib/datadog.rb +1 -0
- metadata +38 -15
- data/lib/datadog/core/cloudwise/IMPLEMENTATION_V2.md +0 -517
- data/lib/datadog/core/cloudwise/QUICKSTART.md +0 -398
- data/lib/datadog/core/cloudwise/README.md +0 -722
- data/lib/datadog/core/remote/transport/http/client.rb +0 -49
- data/lib/datadog/core/telemetry/transport/http/client.rb +0 -49
- data/lib/datadog/di/transport/http/client.rb +0 -47
|
@@ -10,22 +10,35 @@ module Datadog
|
|
|
10
10
|
module Cloudwise
|
|
11
11
|
# HTTP client for Cloudwise API calls
|
|
12
12
|
class Client
|
|
13
|
-
attr_reader :base_url, :server_name, :license_key, :logger, :account_id
|
|
13
|
+
attr_reader :base_url, :server_name, :license_key, :logger, :account_id,
|
|
14
|
+
:integrated_mode, :token, :token_account_id, :token_user_id,
|
|
15
|
+
:agent_instance_id
|
|
14
16
|
|
|
15
17
|
# Response codes
|
|
16
18
|
CODE_SUCCESS = 1000
|
|
17
19
|
CODE_PROBE_SUSPENDED = 1001 # 探针熔断
|
|
18
20
|
CODE_PROBE_ACTIVE = 1002 # 探针活跃/恢复
|
|
19
21
|
CODE_LICENSE_INVALID = 2001 # License 校验失败
|
|
22
|
+
# DOCC response codes
|
|
23
|
+
DOCC_CODE_SUCCESS = 100000
|
|
20
24
|
|
|
21
|
-
def initialize(base_url:, server_name:, license_key:, logger:)
|
|
25
|
+
def initialize(base_url:, server_name:, license_key:, logger:, integrated_mode: true, token: nil, api_prefix: nil)
|
|
22
26
|
@base_url = normalize_url(base_url)
|
|
23
27
|
@server_name = server_name
|
|
24
28
|
@license_key = license_key
|
|
25
29
|
@logger = logger
|
|
30
|
+
@integrated_mode = integrated_mode
|
|
31
|
+
@token = token
|
|
32
|
+
@api_prefix = api_prefix # 统一的 API 路径前缀
|
|
26
33
|
@host_id = nil
|
|
27
34
|
@account_id = nil
|
|
28
35
|
@is_first_heartbeat = true
|
|
36
|
+
|
|
37
|
+
# Parse token if provided
|
|
38
|
+
parse_token if @token && !@token.empty?
|
|
39
|
+
|
|
40
|
+
# Generate agent instance ID for DOCC
|
|
41
|
+
@agent_instance_id = generate_agent_id(get_local_ip) if use_integrated_mode?
|
|
29
42
|
end
|
|
30
43
|
|
|
31
44
|
# 工厂方法:从 Datadog settings 创建 Client
|
|
@@ -47,7 +60,10 @@ module Datadog
|
|
|
47
60
|
base_url: base_url,
|
|
48
61
|
server_name: settings.service || 'unknown-service',
|
|
49
62
|
license_key: settings.cloudwise.license_key,
|
|
50
|
-
logger: logger
|
|
63
|
+
logger: logger,
|
|
64
|
+
integrated_mode: settings.cloudwise.integrated_mode,
|
|
65
|
+
token: settings.cloudwise.token,
|
|
66
|
+
api_prefix: settings.cloudwise.api_prefix
|
|
51
67
|
)
|
|
52
68
|
end
|
|
53
69
|
|
|
@@ -210,11 +226,94 @@ module Datadog
|
|
|
210
226
|
})
|
|
211
227
|
end
|
|
212
228
|
|
|
229
|
+
# Check if should use integrated mode (DOCC interfaces)
|
|
230
|
+
# 判断是否需要使用融合模式
|
|
231
|
+
# token不为空且integrated_mode=true时启用
|
|
232
|
+
def use_integrated_mode?
|
|
233
|
+
@integrated_mode && @token && !@token.empty? && @token_account_id && @token_user_id
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# ====================================================================
|
|
237
|
+
# DOCC Interface Methods (Integrated Mode)
|
|
238
|
+
# ====================================================================
|
|
239
|
+
|
|
240
|
+
# DOCC 注册纳管接口
|
|
241
|
+
# 接口路径: api/ext/gaia/daemon/registExt
|
|
242
|
+
# 调用频率: 每10分钟一次
|
|
243
|
+
def docc_register_ext
|
|
244
|
+
host_ip = get_local_ip
|
|
245
|
+
|
|
246
|
+
data = {
|
|
247
|
+
agent_instance_id: generate_agent_id(host_ip),
|
|
248
|
+
agent_id: 'rubyagent',
|
|
249
|
+
version: 'v' + Datadog::VERSION::STRING,
|
|
250
|
+
agent_pid: Process.pid,
|
|
251
|
+
agent_run_user: get_run_user,
|
|
252
|
+
log_path: get_log_path,
|
|
253
|
+
ip_address: host_ip,
|
|
254
|
+
host_name: Socket.gethostname,
|
|
255
|
+
system_uuid: get_system_uuid,
|
|
256
|
+
os: get_os_name,
|
|
257
|
+
arch: get_architecture,
|
|
258
|
+
meta_info: {
|
|
259
|
+
app_name: @server_name,
|
|
260
|
+
service_path: get_process_path,
|
|
261
|
+
sample: calculate_sample_rate,
|
|
262
|
+
physical_ip: detect_container? ? get_host_real_ip : '',
|
|
263
|
+
container_id: detect_container? ? get_container_id : '',
|
|
264
|
+
sys: ENV['CW_SYS'] || '',
|
|
265
|
+
env_tag: Datadog.configuration.env || 'default'
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
post_docc('/api/ext/gaia/daemon/registExt', data)
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# DOCC 心跳纳管接口
|
|
273
|
+
# 接口路径: api/ext/gaia/daemon/heartbeatExt
|
|
274
|
+
# 调用频率: 每30秒一次
|
|
275
|
+
def docc_heartbeat_ext(fusing: false, fusing_condition: nil, fusing_start_time: nil, fusing_end_time: nil)
|
|
276
|
+
host_ip = get_local_ip
|
|
277
|
+
|
|
278
|
+
data = {
|
|
279
|
+
agent_id: 'rubyagent',
|
|
280
|
+
agent_instance_id: generate_agent_id(host_ip),
|
|
281
|
+
agent_pid: Process.pid,
|
|
282
|
+
agent_run_user: get_run_user,
|
|
283
|
+
fusing: fusing,
|
|
284
|
+
fusing_condition: fusing_condition,
|
|
285
|
+
fusing_start_time: fusing_start_time,
|
|
286
|
+
fusing_end_time: fusing_end_time
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
post_docc('/api/ext/gaia/daemon/heartbeatExt', data)
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
# DOCC 操作拉取接口
|
|
293
|
+
# 接口路径: api/ext/gaia/daemon/fetchExt/${agentInstanceId}
|
|
294
|
+
# 调用频率: 每30秒一次
|
|
295
|
+
def docc_fetch_operation
|
|
296
|
+
post_docc("/api/ext/gaia/daemon/fetchExt/#{@agent_instance_id}", {})
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
# DOCC 操作结果上报接口
|
|
300
|
+
# 接口路径: api/ext/gaia/daemon/report/${agentInstanceId}
|
|
301
|
+
# 上报操作结果(支持批量上报)
|
|
302
|
+
# @param results [Array<Hash>, Hash] 单个结果或结果数组
|
|
303
|
+
def docc_report_operation(results)
|
|
304
|
+
# 如果传入的是数组,直接使用;否则包装成数组
|
|
305
|
+
data = results.is_a?(Array) ? results : [results]
|
|
306
|
+
|
|
307
|
+
post_docc("/api/ext/gaia/daemon/report/#{@agent_instance_id}", data)
|
|
308
|
+
end
|
|
309
|
+
|
|
213
310
|
private
|
|
214
311
|
|
|
215
312
|
def post(path, data)
|
|
216
|
-
|
|
313
|
+
# 统一处理 API 路径前缀
|
|
314
|
+
path = apply_api_prefix(path)
|
|
217
315
|
|
|
316
|
+
uri = URI.join(base_url, path)
|
|
218
317
|
http = Net::HTTP.new(uri.host, uri.port)
|
|
219
318
|
http.use_ssl = (uri.scheme == 'https')
|
|
220
319
|
http.open_timeout = 5
|
|
@@ -248,7 +347,7 @@ module Datadog
|
|
|
248
347
|
success: true,
|
|
249
348
|
data: body['data'] || body,
|
|
250
349
|
code: code,
|
|
251
|
-
message: body['
|
|
350
|
+
message: body['msg']
|
|
252
351
|
}
|
|
253
352
|
when 400..499
|
|
254
353
|
Cloudwise.log_warn { "Cloudwise API client error for #{path}: #{response.code} #{response.body}" }
|
|
@@ -262,17 +361,6 @@ module Datadog
|
|
|
262
361
|
end
|
|
263
362
|
end
|
|
264
363
|
|
|
265
|
-
def detect_framework
|
|
266
|
-
if defined?(::Rails)
|
|
267
|
-
'rails'
|
|
268
|
-
elsif defined?(::Sinatra)
|
|
269
|
-
'sinatra'
|
|
270
|
-
elsif defined?(::Rack)
|
|
271
|
-
'rack'
|
|
272
|
-
else
|
|
273
|
-
'unknown'
|
|
274
|
-
end
|
|
275
|
-
end
|
|
276
364
|
|
|
277
365
|
# 获取本机 IP 地址
|
|
278
366
|
# 优先获取外网 IP(通过创建 UDP 连接,不实际发送数据)
|
|
@@ -287,7 +375,6 @@ module Datadog
|
|
|
287
375
|
udp_socket.connect('8.8.8.8', 1)
|
|
288
376
|
local_ip = udp_socket.addr.last
|
|
289
377
|
udp_socket.close
|
|
290
|
-
|
|
291
378
|
return local_ip
|
|
292
379
|
rescue => e
|
|
293
380
|
Cloudwise.log_debug { "Cloudwise: Failed to get IP via UDP: #{e.message}" }
|
|
@@ -416,16 +503,34 @@ module Datadog
|
|
|
416
503
|
''
|
|
417
504
|
end
|
|
418
505
|
|
|
419
|
-
#
|
|
506
|
+
# 计算采样率(读取 Datadog 配置或环境变量)
|
|
507
|
+
# 返回 0-100 的整数值
|
|
420
508
|
def calculate_sample_rate
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
509
|
+
rate = nil
|
|
510
|
+
|
|
511
|
+
# 1. 尝试从 Datadog 配置读取(0.0-1.0 的浮点数)
|
|
512
|
+
if defined?(Datadog.configuration) &&
|
|
513
|
+
Datadog.configuration.respond_to?(:tracing) &&
|
|
514
|
+
Datadog.configuration.tracing.respond_to?(:sampling) &&
|
|
515
|
+
Datadog.configuration.tracing.sampling.respond_to?(:default_rate)
|
|
516
|
+
configured_rate = Datadog.configuration.tracing.sampling.default_rate
|
|
517
|
+
rate = configured_rate if configured_rate && configured_rate >= 0.0 && configured_rate <= 1.0
|
|
518
|
+
end
|
|
425
519
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
520
|
+
# 2. 尝试从环境变量读取(DD_TRACE_SAMPLE_RATE,0.0-1.0 的浮点数)
|
|
521
|
+
if rate.nil? && ENV['DD_TRACE_SAMPLE_RATE']
|
|
522
|
+
env_rate = ENV['DD_TRACE_SAMPLE_RATE'].to_f
|
|
523
|
+
rate = env_rate if env_rate >= 0.0 && env_rate <= 1.0
|
|
524
|
+
end
|
|
525
|
+
|
|
526
|
+
# 3. 如果没有配置,默认使用 100%
|
|
527
|
+
rate = 1.0 if rate.nil?
|
|
528
|
+
|
|
529
|
+
# 转换为 0-100 的整数
|
|
530
|
+
(rate * 100).to_i
|
|
531
|
+
rescue => e
|
|
532
|
+
Cloudwise.log_debug { "Failed to calculate sample rate: #{e.message}" }
|
|
533
|
+
100 # 出错时默认 100%
|
|
429
534
|
end
|
|
430
535
|
|
|
431
536
|
# 生成标识(基于多个因素的唯一标识)
|
|
@@ -484,6 +589,240 @@ module Datadog
|
|
|
484
589
|
url.chomp('/')
|
|
485
590
|
end
|
|
486
591
|
|
|
592
|
+
# 统一处理 API 路径前缀
|
|
593
|
+
# 优先级:DD_CLOUDWISE_API_PREFIX > integrated_mode (/apm) > 无前缀
|
|
594
|
+
# @param path [String] 原始路径
|
|
595
|
+
# @return [String] 处理后的路径
|
|
596
|
+
def apply_api_prefix(path)
|
|
597
|
+
# DOCC 接口不需要添加前缀(它们有自己的路径)
|
|
598
|
+
return path if path.start_with?('/api/ext/gaia/daemon/')
|
|
599
|
+
|
|
600
|
+
# 获取需要应用前缀的路径
|
|
601
|
+
# 这些路径是 Cloudwise 特定的API,不是 DOCC 接口
|
|
602
|
+
cloudwise_api_paths = [
|
|
603
|
+
'/v2/app/generateHostId',
|
|
604
|
+
'/v2/app/registerHost',
|
|
605
|
+
'/api/v1/agent/heartbeat',
|
|
606
|
+
'/v2/app/create',
|
|
607
|
+
'/v2/licence/verification'
|
|
608
|
+
]
|
|
609
|
+
|
|
610
|
+
# 检查是否是需要添加前缀的路径
|
|
611
|
+
needs_prefix = cloudwise_api_paths.any? { |p| path.start_with?(p) }
|
|
612
|
+
return path unless needs_prefix
|
|
613
|
+
|
|
614
|
+
# 优先级 1: 显式配置的 api_prefix(最高优先级)
|
|
615
|
+
if @api_prefix && !@api_prefix.empty?
|
|
616
|
+
prefix = @api_prefix.start_with?('/') ? @api_prefix : "/#{@api_prefix}"
|
|
617
|
+
return "#{prefix}#{path}"
|
|
618
|
+
end
|
|
619
|
+
|
|
620
|
+
# 优先级 2: integrated_mode 使用 /apm 前缀
|
|
621
|
+
if use_integrated_mode?
|
|
622
|
+
return "/apm#{path}"
|
|
623
|
+
end
|
|
624
|
+
|
|
625
|
+
# 优先级 3: 无前缀(默认)
|
|
626
|
+
path
|
|
627
|
+
end
|
|
628
|
+
|
|
629
|
+
# Parse token to extract account_id and user_id
|
|
630
|
+
# Token format: base64("account_id@user_id")
|
|
631
|
+
def parse_token
|
|
632
|
+
require 'base64'
|
|
633
|
+
|
|
634
|
+
begin
|
|
635
|
+
decoded = Base64.decode64(@token)
|
|
636
|
+
parts = decoded.split('@')
|
|
637
|
+
|
|
638
|
+
if parts.length == 2 && !parts[0].empty? && !parts[1].empty?
|
|
639
|
+
@token_account_id = parts[0]
|
|
640
|
+
@token_user_id = parts[1]
|
|
641
|
+
@account_id = @token_account_id
|
|
642
|
+
Cloudwise.log_debug { "Cloudwise: Token parsed - account_id: #{@token_account_id}, user_id: #{@token_user_id}" }
|
|
643
|
+
|
|
644
|
+
#account_id
|
|
645
|
+
ENV['CLOUDWISE_ACCOUNT_ID'] = @token_account_id.to_s
|
|
646
|
+
else
|
|
647
|
+
Cloudwise.log_warn { 'Cloudwise: Invalid token format (expected base64 of account_id@user_id)' }
|
|
648
|
+
@token_account_id = nil
|
|
649
|
+
@token_user_id = nil
|
|
650
|
+
end
|
|
651
|
+
rescue => e
|
|
652
|
+
Cloudwise.log_error { "Cloudwise: Failed to parse token: #{e.message}" }
|
|
653
|
+
@token_account_id = nil
|
|
654
|
+
@token_user_id = nil
|
|
655
|
+
end
|
|
656
|
+
end
|
|
657
|
+
|
|
658
|
+
|
|
659
|
+
# Get current run user
|
|
660
|
+
def get_run_user
|
|
661
|
+
ENV['USER'] || ENV['USERNAME'] || 'cloudwise'
|
|
662
|
+
rescue
|
|
663
|
+
'cloudwise'
|
|
664
|
+
end
|
|
665
|
+
|
|
666
|
+
# Get log path
|
|
667
|
+
def get_log_path
|
|
668
|
+
if defined?(Datadog.logger) && Datadog.logger.respond_to?(:logdev)
|
|
669
|
+
logdev = Datadog.logger.logdev
|
|
670
|
+
return logdev.filename if logdev.respond_to?(:filename) && logdev.filename
|
|
671
|
+
end
|
|
672
|
+
''
|
|
673
|
+
rescue
|
|
674
|
+
''
|
|
675
|
+
end
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
# Get system UUID
|
|
679
|
+
# Try multiple methods to get a unique system identifier
|
|
680
|
+
def get_system_uuid
|
|
681
|
+
# Method 1: Try to read from /etc/machine-id (Linux)
|
|
682
|
+
if File.exist?('/etc/machine-id')
|
|
683
|
+
uuid = File.read('/etc/machine-id').strip
|
|
684
|
+
return uuid unless uuid.empty?
|
|
685
|
+
end
|
|
686
|
+
|
|
687
|
+
# Method 2: Try to read from /var/lib/dbus/machine-id (Linux)
|
|
688
|
+
if File.exist?('/var/lib/dbus/machine-id')
|
|
689
|
+
uuid = File.read('/var/lib/dbus/machine-id').strip
|
|
690
|
+
return uuid unless uuid.empty?
|
|
691
|
+
end
|
|
692
|
+
|
|
693
|
+
# Method 3: Try macOS system_profiler
|
|
694
|
+
if RUBY_PLATFORM =~ /darwin/
|
|
695
|
+
uuid = `system_profiler SPHardwareDataType 2>/dev/null | awk '/UUID/ { print $3; }'`.strip
|
|
696
|
+
return uuid unless uuid.empty?
|
|
697
|
+
end
|
|
698
|
+
|
|
699
|
+
# Method 4: Generate a persistent UUID based on hostname and mac address
|
|
700
|
+
generate_uuid_from_system_info
|
|
701
|
+
rescue => e
|
|
702
|
+
Cloudwise.log_debug { "Failed to get system UUID: #{e.message}" }
|
|
703
|
+
# Fallback: generate a UUID from hostname
|
|
704
|
+
generate_fallback_uuid
|
|
705
|
+
end
|
|
706
|
+
|
|
707
|
+
# Generate UUID from system information
|
|
708
|
+
def generate_uuid_from_system_info
|
|
709
|
+
require 'digest/md5'
|
|
710
|
+
hostname = get_safe_hostname
|
|
711
|
+
mac = get_mac_address
|
|
712
|
+
combined = "#{hostname}-#{mac}"
|
|
713
|
+
Digest::MD5.hexdigest(combined)
|
|
714
|
+
end
|
|
715
|
+
|
|
716
|
+
# Generate fallback UUID
|
|
717
|
+
def generate_fallback_uuid
|
|
718
|
+
require 'digest/md5'
|
|
719
|
+
hostname = get_safe_hostname
|
|
720
|
+
Digest::MD5.hexdigest(hostname)
|
|
721
|
+
end
|
|
722
|
+
|
|
723
|
+
# Get hostname safely
|
|
724
|
+
def get_safe_hostname
|
|
725
|
+
Socket.gethostname
|
|
726
|
+
rescue
|
|
727
|
+
'unknown'
|
|
728
|
+
end
|
|
729
|
+
|
|
730
|
+
# Get MAC address
|
|
731
|
+
def get_mac_address
|
|
732
|
+
# Try to get MAC address from network interfaces
|
|
733
|
+
if File.exist?('/sys/class/net')
|
|
734
|
+
Dir.glob('/sys/class/net/*/address').each do |addr_file|
|
|
735
|
+
next if addr_file.include?('lo') # Skip loopback
|
|
736
|
+
mac = File.read(addr_file).strip
|
|
737
|
+
return mac unless mac.empty? || mac == '00:00:00:00:00:00'
|
|
738
|
+
end
|
|
739
|
+
end
|
|
740
|
+
|
|
741
|
+
# Fallback: try ifconfig/ip command
|
|
742
|
+
output = `ifconfig 2>/dev/null || ip link show 2>/dev/null`.strip
|
|
743
|
+
match = output.match(/(?:[0-9a-f]{2}:){5}[0-9a-f]{2}/i)
|
|
744
|
+
return match[0] if match
|
|
745
|
+
|
|
746
|
+
''
|
|
747
|
+
rescue
|
|
748
|
+
''
|
|
749
|
+
end
|
|
750
|
+
|
|
751
|
+
# Get OS name
|
|
752
|
+
def get_os_name
|
|
753
|
+
case RUBY_PLATFORM
|
|
754
|
+
when /linux/
|
|
755
|
+
'Linux'
|
|
756
|
+
when /darwin/
|
|
757
|
+
'Darwin'
|
|
758
|
+
when /freebsd/
|
|
759
|
+
'FreeBSD'
|
|
760
|
+
when /netbsd/
|
|
761
|
+
'NetBSD'
|
|
762
|
+
when /openbsd/
|
|
763
|
+
'OpenBSD'
|
|
764
|
+
when /sunos|solaris/
|
|
765
|
+
'Solaris'
|
|
766
|
+
when /aix/
|
|
767
|
+
'AIX'
|
|
768
|
+
when /win|mingw|mswin/
|
|
769
|
+
'Windows'
|
|
770
|
+
else
|
|
771
|
+
RUBY_PLATFORM
|
|
772
|
+
end
|
|
773
|
+
rescue
|
|
774
|
+
'Unknown'
|
|
775
|
+
end
|
|
776
|
+
|
|
777
|
+
# Get system architecture
|
|
778
|
+
def get_architecture
|
|
779
|
+
case RbConfig::CONFIG['host_cpu']
|
|
780
|
+
when /x86_64|amd64/
|
|
781
|
+
'x86_64'
|
|
782
|
+
when /i[3-6]86|x86/
|
|
783
|
+
'x86'
|
|
784
|
+
when /aarch64|arm64/
|
|
785
|
+
'aarch_64'
|
|
786
|
+
when /arm/
|
|
787
|
+
'arm'
|
|
788
|
+
when /ppc64le/
|
|
789
|
+
'ppc64le'
|
|
790
|
+
when /ppc64/
|
|
791
|
+
'ppc64'
|
|
792
|
+
when /s390x/
|
|
793
|
+
's390x'
|
|
794
|
+
else
|
|
795
|
+
RbConfig::CONFIG['host_cpu']
|
|
796
|
+
end
|
|
797
|
+
rescue
|
|
798
|
+
'unknown'
|
|
799
|
+
end
|
|
800
|
+
|
|
801
|
+
# POST request for DOCC interfaces with token authentication
|
|
802
|
+
def post_docc(path, data)
|
|
803
|
+
uri = URI.join(base_url, path)
|
|
804
|
+
|
|
805
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
806
|
+
http.use_ssl = (uri.scheme == 'https')
|
|
807
|
+
http.open_timeout = 5
|
|
808
|
+
http.read_timeout = 5
|
|
809
|
+
|
|
810
|
+
request = Net::HTTP::Post.new(uri.path)
|
|
811
|
+
request['Content-Type'] = 'application/json'
|
|
812
|
+
request['token'] = @token
|
|
813
|
+
request['User-Agent'] = "Datadog-Ruby-Agent/#{Datadog::VERSION::STRING}"
|
|
814
|
+
request['DD-Internal-Untraced-Request'] = '1'
|
|
815
|
+
request.body = data.to_json
|
|
816
|
+
|
|
817
|
+
Cloudwise.log_debug { "Cloudwise DOCC API request: #{request.method} #{uri} with data: #{data.inspect}" }
|
|
818
|
+
|
|
819
|
+
response = http.request(request)
|
|
820
|
+
handle_response(response, path)
|
|
821
|
+
rescue => e
|
|
822
|
+
Cloudwise.log_error { "Cloudwise DOCC API error for #{path}: #{e.class.name} #{e.message}" }
|
|
823
|
+
{ success: false, error: e.message, code: nil }
|
|
824
|
+
end
|
|
825
|
+
|
|
487
826
|
end
|
|
488
827
|
end
|
|
489
828
|
end
|