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.
- 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 +412 -25
- data/lib/datadog/core/cloudwise/component.rb +195 -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 +90 -4
- 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 +43 -0
- data/lib/datadog/core/configuration/supported_configurations.rb +6 -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 +73 -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,36 @@ 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, api_prefix_mode: 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 路径前缀
|
|
33
|
+
@api_prefix_mode = api_prefix_mode # API 前缀模式(简化配置)
|
|
26
34
|
@host_id = nil
|
|
27
35
|
@account_id = nil
|
|
28
36
|
@is_first_heartbeat = true
|
|
37
|
+
|
|
38
|
+
# Parse token if provided
|
|
39
|
+
parse_token if @token && !@token.empty?
|
|
40
|
+
|
|
41
|
+
# Generate agent instance ID for DOCC
|
|
42
|
+
@agent_instance_id = generate_agent_id(get_local_ip) if use_integrated_mode?
|
|
29
43
|
end
|
|
30
44
|
|
|
31
45
|
# 工厂方法:从 Datadog settings 创建 Client
|
|
@@ -47,7 +61,11 @@ module Datadog
|
|
|
47
61
|
base_url: base_url,
|
|
48
62
|
server_name: settings.service || 'unknown-service',
|
|
49
63
|
license_key: settings.cloudwise.license_key,
|
|
50
|
-
logger: logger
|
|
64
|
+
logger: logger,
|
|
65
|
+
integrated_mode: settings.cloudwise.integrated_mode,
|
|
66
|
+
token: settings.cloudwise.token,
|
|
67
|
+
api_prefix: settings.cloudwise.api_prefix,
|
|
68
|
+
api_prefix_mode: settings.cloudwise.api_prefix_mode
|
|
51
69
|
)
|
|
52
70
|
end
|
|
53
71
|
|
|
@@ -181,6 +199,22 @@ module Datadog
|
|
|
181
199
|
})
|
|
182
200
|
end
|
|
183
201
|
|
|
202
|
+
# 熔断状态上报接口
|
|
203
|
+
# @param fuse_state [Integer] 熔断状态码
|
|
204
|
+
# @param fuse_describe [String] 熔断描述
|
|
205
|
+
def report_fuse_state(fuse_state:, fuse_describe:)
|
|
206
|
+
host_ip = get_local_ip
|
|
207
|
+
|
|
208
|
+
post('/api/v1/agent/fuseHeart', {
|
|
209
|
+
version: Datadog::VERSION::STRING,
|
|
210
|
+
accountId: @account_id,
|
|
211
|
+
agentId: generate_agent_id(host_ip),
|
|
212
|
+
fuseState: fuse_state,
|
|
213
|
+
fuseDescribe: fuse_describe,
|
|
214
|
+
appId: generate_app_id(server_name)
|
|
215
|
+
})
|
|
216
|
+
end
|
|
217
|
+
|
|
184
218
|
# 应用注册接口
|
|
185
219
|
def register_application
|
|
186
220
|
host_ip = get_local_ip
|
|
@@ -210,11 +244,94 @@ module Datadog
|
|
|
210
244
|
})
|
|
211
245
|
end
|
|
212
246
|
|
|
247
|
+
# Check if should use integrated mode (DOCC interfaces)
|
|
248
|
+
# 判断是否需要使用融合模式
|
|
249
|
+
# token不为空且integrated_mode=true时启用
|
|
250
|
+
def use_integrated_mode?
|
|
251
|
+
@integrated_mode && @token && !@token.empty? && @token_account_id && @token_user_id
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
# ====================================================================
|
|
255
|
+
# DOCC Interface Methods (Integrated Mode)
|
|
256
|
+
# ====================================================================
|
|
257
|
+
|
|
258
|
+
# DOCC 注册纳管接口
|
|
259
|
+
# 接口路径: api/ext/gaia/daemon/registExt
|
|
260
|
+
# 调用频率: 每10分钟一次
|
|
261
|
+
def docc_register_ext
|
|
262
|
+
host_ip = get_local_ip
|
|
263
|
+
|
|
264
|
+
data = {
|
|
265
|
+
agent_instance_id: generate_agent_id(host_ip),
|
|
266
|
+
agent_id: 'rubyagent',
|
|
267
|
+
version: 'v' + Datadog::VERSION::STRING,
|
|
268
|
+
agent_pid: Process.pid,
|
|
269
|
+
agent_run_user: get_run_user,
|
|
270
|
+
log_path: get_log_path,
|
|
271
|
+
ip_address: host_ip,
|
|
272
|
+
host_name: Socket.gethostname,
|
|
273
|
+
system_uuid: get_system_uuid,
|
|
274
|
+
os: get_os_name,
|
|
275
|
+
arch: get_architecture,
|
|
276
|
+
meta_info: {
|
|
277
|
+
app_name: @server_name,
|
|
278
|
+
service_path: get_process_path,
|
|
279
|
+
sample: calculate_sample_rate,
|
|
280
|
+
physical_ip: detect_container? ? get_host_real_ip : '',
|
|
281
|
+
container_id: detect_container? ? get_container_id : '',
|
|
282
|
+
sys: ENV['CW_SYS'] || 'default',
|
|
283
|
+
env_tag: Datadog.configuration.env || 'default'
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
post_docc('/api/ext/gaia/daemon/registExt', data)
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
# DOCC 心跳纳管接口
|
|
291
|
+
# 接口路径: api/ext/gaia/daemon/heartbeatExt
|
|
292
|
+
# 调用频率: 每30秒一次
|
|
293
|
+
def docc_heartbeat_ext(fusing: false, fusing_condition: nil, fusing_start_time: nil, fusing_end_time: nil)
|
|
294
|
+
host_ip = get_local_ip
|
|
295
|
+
|
|
296
|
+
data = {
|
|
297
|
+
agent_id: 'rubyagent',
|
|
298
|
+
agent_instance_id: generate_agent_id(host_ip),
|
|
299
|
+
agent_pid: Process.pid,
|
|
300
|
+
agent_run_user: get_run_user,
|
|
301
|
+
fusing: fusing,
|
|
302
|
+
fusing_condition: fusing_condition,
|
|
303
|
+
fusing_start_time: fusing_start_time,
|
|
304
|
+
fusing_end_time: fusing_end_time
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
post_docc('/api/ext/gaia/daemon/heartbeatExt', data)
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
# DOCC 操作拉取接口
|
|
311
|
+
# 接口路径: api/ext/gaia/daemon/fetchExt/${agentInstanceId}
|
|
312
|
+
# 调用频率: 每30秒一次
|
|
313
|
+
def docc_fetch_operation
|
|
314
|
+
post_docc("/api/ext/gaia/daemon/fetchExt/#{@agent_instance_id}", {})
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
# DOCC 操作结果上报接口
|
|
318
|
+
# 接口路径: api/ext/gaia/daemon/report/${agentInstanceId}
|
|
319
|
+
# 上报操作结果(支持批量上报)
|
|
320
|
+
# @param results [Array<Hash>, Hash] 单个结果或结果数组
|
|
321
|
+
def docc_report_operation(results)
|
|
322
|
+
# 如果传入的是数组,直接使用;否则包装成数组
|
|
323
|
+
data = results.is_a?(Array) ? results : [results]
|
|
324
|
+
|
|
325
|
+
post_docc("/api/ext/gaia/daemon/report/#{@agent_instance_id}", data)
|
|
326
|
+
end
|
|
327
|
+
|
|
213
328
|
private
|
|
214
329
|
|
|
215
330
|
def post(path, data)
|
|
216
|
-
|
|
331
|
+
# 统一处理 API 路径前缀
|
|
332
|
+
path = apply_api_prefix(path)
|
|
217
333
|
|
|
334
|
+
uri = URI.join(base_url, path)
|
|
218
335
|
http = Net::HTTP.new(uri.host, uri.port)
|
|
219
336
|
http.use_ssl = (uri.scheme == 'https')
|
|
220
337
|
http.open_timeout = 5
|
|
@@ -248,7 +365,7 @@ module Datadog
|
|
|
248
365
|
success: true,
|
|
249
366
|
data: body['data'] || body,
|
|
250
367
|
code: code,
|
|
251
|
-
message: body['
|
|
368
|
+
message: body['msg']
|
|
252
369
|
}
|
|
253
370
|
when 400..499
|
|
254
371
|
Cloudwise.log_warn { "Cloudwise API client error for #{path}: #{response.code} #{response.body}" }
|
|
@@ -262,17 +379,6 @@ module Datadog
|
|
|
262
379
|
end
|
|
263
380
|
end
|
|
264
381
|
|
|
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
382
|
|
|
277
383
|
# 获取本机 IP 地址
|
|
278
384
|
# 优先获取外网 IP(通过创建 UDP 连接,不实际发送数据)
|
|
@@ -287,7 +393,6 @@ module Datadog
|
|
|
287
393
|
udp_socket.connect('8.8.8.8', 1)
|
|
288
394
|
local_ip = udp_socket.addr.last
|
|
289
395
|
udp_socket.close
|
|
290
|
-
|
|
291
396
|
return local_ip
|
|
292
397
|
rescue => e
|
|
293
398
|
Cloudwise.log_debug { "Cloudwise: Failed to get IP via UDP: #{e.message}" }
|
|
@@ -416,16 +521,34 @@ module Datadog
|
|
|
416
521
|
''
|
|
417
522
|
end
|
|
418
523
|
|
|
419
|
-
#
|
|
524
|
+
# 计算采样率(读取 Datadog 配置或环境变量)
|
|
525
|
+
# 返回 0-100 的整数值
|
|
420
526
|
def calculate_sample_rate
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
527
|
+
rate = nil
|
|
528
|
+
|
|
529
|
+
# 1. 尝试从 Datadog 配置读取(0.0-1.0 的浮点数)
|
|
530
|
+
if defined?(Datadog.configuration) &&
|
|
531
|
+
Datadog.configuration.respond_to?(:tracing) &&
|
|
532
|
+
Datadog.configuration.tracing.respond_to?(:sampling) &&
|
|
533
|
+
Datadog.configuration.tracing.sampling.respond_to?(:default_rate)
|
|
534
|
+
configured_rate = Datadog.configuration.tracing.sampling.default_rate
|
|
535
|
+
rate = configured_rate if configured_rate && configured_rate >= 0.0 && configured_rate <= 1.0
|
|
536
|
+
end
|
|
425
537
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
538
|
+
# 2. 尝试从环境变量读取(DD_TRACE_SAMPLE_RATE,0.0-1.0 的浮点数)
|
|
539
|
+
if rate.nil? && ENV['DD_TRACE_SAMPLE_RATE']
|
|
540
|
+
env_rate = ENV['DD_TRACE_SAMPLE_RATE'].to_f
|
|
541
|
+
rate = env_rate if env_rate >= 0.0 && env_rate <= 1.0
|
|
542
|
+
end
|
|
543
|
+
|
|
544
|
+
# 3. 如果没有配置,默认使用 100%
|
|
545
|
+
rate = 1.0 if rate.nil?
|
|
546
|
+
|
|
547
|
+
# 转换为 0-100 的整数
|
|
548
|
+
(rate * 100).to_i
|
|
549
|
+
rescue => e
|
|
550
|
+
Cloudwise.log_debug { "Failed to calculate sample rate: #{e.message}" }
|
|
551
|
+
100 # 出错时默认 100%
|
|
429
552
|
end
|
|
430
553
|
|
|
431
554
|
# 生成标识(基于多个因素的唯一标识)
|
|
@@ -484,6 +607,270 @@ module Datadog
|
|
|
484
607
|
url.chomp('/')
|
|
485
608
|
end
|
|
486
609
|
|
|
610
|
+
# 统一处理 API 路径前缀
|
|
611
|
+
# 优先级:api_prefix_mode > api_prefix > integrated_mode (/apm) > 无前缀
|
|
612
|
+
# @param path [String] 原始路径
|
|
613
|
+
# @return [String] 处理后的路径
|
|
614
|
+
def apply_api_prefix(path)
|
|
615
|
+
# DOCC 接口不需要添加前缀(它们有自己的路径)
|
|
616
|
+
return path if path.start_with?('/api/ext/gaia/daemon/')
|
|
617
|
+
|
|
618
|
+
# 获取需要应用前缀的路径
|
|
619
|
+
# 这些路径是 Cloudwise 特定的API,不是 DOCC 接口
|
|
620
|
+
cloudwise_api_paths = [
|
|
621
|
+
'/v2/app/generateHostId',
|
|
622
|
+
'/v2/app/registerHost',
|
|
623
|
+
'/api/v1/agent/heartbeat',
|
|
624
|
+
'/api/v1/agent/fuseHeart',
|
|
625
|
+
'/v2/app/create',
|
|
626
|
+
'/v2/licence/verification'
|
|
627
|
+
]
|
|
628
|
+
|
|
629
|
+
# 检查是否是需要添加前缀的路径
|
|
630
|
+
needs_prefix = cloudwise_api_paths.any? { |p| path.start_with?(p) }
|
|
631
|
+
return path unless needs_prefix
|
|
632
|
+
|
|
633
|
+
# 优先级 1: api_prefix_mode 模式配置(最高优先级,简化配置)
|
|
634
|
+
if @api_prefix_mode && !@api_prefix_mode.empty?
|
|
635
|
+
prefix = get_prefix_by_mode(@api_prefix_mode)
|
|
636
|
+
return "#{prefix}#{path}" if prefix
|
|
637
|
+
end
|
|
638
|
+
|
|
639
|
+
# 优先级 2: 显式配置的 api_prefix(自定义前缀)
|
|
640
|
+
if @api_prefix && !@api_prefix.empty?
|
|
641
|
+
prefix = @api_prefix.start_with?('/') ? @api_prefix : "/#{@api_prefix}"
|
|
642
|
+
return "#{prefix}#{path}"
|
|
643
|
+
end
|
|
644
|
+
|
|
645
|
+
# 优先级 3: integrated_mode 使用 /apm 前缀
|
|
646
|
+
if use_integrated_mode?
|
|
647
|
+
return "/apm#{path}"
|
|
648
|
+
end
|
|
649
|
+
|
|
650
|
+
# 优先级 4: 无前缀(默认)
|
|
651
|
+
path
|
|
652
|
+
end
|
|
653
|
+
|
|
654
|
+
# 根据模式获取前缀
|
|
655
|
+
# @param mode [String] 前缀模式:'doop', 'apm', 'custom'
|
|
656
|
+
# @return [String, nil] 前缀字符串,如果模式无效返回 nil
|
|
657
|
+
def get_prefix_by_mode(mode)
|
|
658
|
+
case mode.to_s.downcase
|
|
659
|
+
when 'doop'
|
|
660
|
+
'/doop-agent-api'
|
|
661
|
+
when 'apm'
|
|
662
|
+
'/apm'
|
|
663
|
+
when 'custom'
|
|
664
|
+
# 使用 api_prefix 配置的自定义前缀
|
|
665
|
+
if @api_prefix && !@api_prefix.empty?
|
|
666
|
+
@api_prefix.start_with?('/') ? @api_prefix : "/#{@api_prefix}"
|
|
667
|
+
else
|
|
668
|
+
Cloudwise.log_warn { "Cloudwise: api_prefix_mode='custom' but api_prefix is not set" }
|
|
669
|
+
nil
|
|
670
|
+
end
|
|
671
|
+
else
|
|
672
|
+
Cloudwise.log_warn { "Cloudwise: Unknown api_prefix_mode '#{mode}', ignoring" }
|
|
673
|
+
nil
|
|
674
|
+
end
|
|
675
|
+
end
|
|
676
|
+
|
|
677
|
+
# Parse token to extract account_id and user_id
|
|
678
|
+
# Token format: base64("account_id@user_id")
|
|
679
|
+
def parse_token
|
|
680
|
+
require 'base64'
|
|
681
|
+
|
|
682
|
+
begin
|
|
683
|
+
decoded = Base64.decode64(@token)
|
|
684
|
+
parts = decoded.split('@')
|
|
685
|
+
|
|
686
|
+
if parts.length == 2 && !parts[0].empty? && !parts[1].empty?
|
|
687
|
+
@token_account_id = parts[0]
|
|
688
|
+
@token_user_id = parts[1]
|
|
689
|
+
@account_id = @token_account_id
|
|
690
|
+
Cloudwise.log_debug { "Cloudwise: Token parsed - account_id: #{@token_account_id}, user_id: #{@token_user_id}" }
|
|
691
|
+
|
|
692
|
+
#account_id
|
|
693
|
+
ENV['CLOUDWISE_ACCOUNT_ID'] = @token_account_id.to_s
|
|
694
|
+
else
|
|
695
|
+
Cloudwise.log_warn { 'Cloudwise: Invalid token format (expected base64 of account_id@user_id)' }
|
|
696
|
+
@token_account_id = nil
|
|
697
|
+
@token_user_id = nil
|
|
698
|
+
end
|
|
699
|
+
rescue => e
|
|
700
|
+
Cloudwise.log_error { "Cloudwise: Failed to parse token: #{e.message}" }
|
|
701
|
+
@token_account_id = nil
|
|
702
|
+
@token_user_id = nil
|
|
703
|
+
end
|
|
704
|
+
end
|
|
705
|
+
|
|
706
|
+
|
|
707
|
+
# Get current run user
|
|
708
|
+
def get_run_user
|
|
709
|
+
ENV['USER'] || ENV['USERNAME'] || 'cloudwise'
|
|
710
|
+
rescue
|
|
711
|
+
'cloudwise'
|
|
712
|
+
end
|
|
713
|
+
|
|
714
|
+
# Get log path
|
|
715
|
+
def get_log_path
|
|
716
|
+
if defined?(Datadog.logger) && Datadog.logger.respond_to?(:logdev)
|
|
717
|
+
logdev = Datadog.logger.logdev
|
|
718
|
+
return logdev.filename if logdev.respond_to?(:filename) && logdev.filename
|
|
719
|
+
end
|
|
720
|
+
''
|
|
721
|
+
rescue
|
|
722
|
+
''
|
|
723
|
+
end
|
|
724
|
+
|
|
725
|
+
|
|
726
|
+
# Get system UUID
|
|
727
|
+
# Try multiple methods to get a unique system identifier
|
|
728
|
+
def get_system_uuid
|
|
729
|
+
# Method 1: Try to read from /etc/machine-id (Linux)
|
|
730
|
+
if File.exist?('/etc/machine-id')
|
|
731
|
+
uuid = File.read('/etc/machine-id').strip
|
|
732
|
+
return uuid unless uuid.empty?
|
|
733
|
+
end
|
|
734
|
+
|
|
735
|
+
# Method 2: Try to read from /var/lib/dbus/machine-id (Linux)
|
|
736
|
+
if File.exist?('/var/lib/dbus/machine-id')
|
|
737
|
+
uuid = File.read('/var/lib/dbus/machine-id').strip
|
|
738
|
+
return uuid unless uuid.empty?
|
|
739
|
+
end
|
|
740
|
+
|
|
741
|
+
# Method 3: Try macOS system_profiler
|
|
742
|
+
if RUBY_PLATFORM =~ /darwin/
|
|
743
|
+
uuid = `system_profiler SPHardwareDataType 2>/dev/null | awk '/UUID/ { print $3; }'`.strip
|
|
744
|
+
return uuid unless uuid.empty?
|
|
745
|
+
end
|
|
746
|
+
|
|
747
|
+
# Method 4: Generate a persistent UUID based on hostname and mac address
|
|
748
|
+
generate_uuid_from_system_info
|
|
749
|
+
rescue => e
|
|
750
|
+
Cloudwise.log_debug { "Failed to get system UUID: #{e.message}" }
|
|
751
|
+
# Fallback: generate a UUID from hostname
|
|
752
|
+
generate_fallback_uuid
|
|
753
|
+
end
|
|
754
|
+
|
|
755
|
+
# Generate UUID from system information
|
|
756
|
+
def generate_uuid_from_system_info
|
|
757
|
+
require 'digest/md5'
|
|
758
|
+
hostname = get_safe_hostname
|
|
759
|
+
mac = get_mac_address
|
|
760
|
+
combined = "#{hostname}-#{mac}"
|
|
761
|
+
Digest::MD5.hexdigest(combined)
|
|
762
|
+
end
|
|
763
|
+
|
|
764
|
+
# Generate fallback UUID
|
|
765
|
+
def generate_fallback_uuid
|
|
766
|
+
require 'digest/md5'
|
|
767
|
+
hostname = get_safe_hostname
|
|
768
|
+
Digest::MD5.hexdigest(hostname)
|
|
769
|
+
end
|
|
770
|
+
|
|
771
|
+
# Get hostname safely
|
|
772
|
+
def get_safe_hostname
|
|
773
|
+
Socket.gethostname
|
|
774
|
+
rescue
|
|
775
|
+
'unknown'
|
|
776
|
+
end
|
|
777
|
+
|
|
778
|
+
# Get MAC address
|
|
779
|
+
def get_mac_address
|
|
780
|
+
# Try to get MAC address from network interfaces
|
|
781
|
+
if File.exist?('/sys/class/net')
|
|
782
|
+
Dir.glob('/sys/class/net/*/address').each do |addr_file|
|
|
783
|
+
next if addr_file.include?('lo') # Skip loopback
|
|
784
|
+
mac = File.read(addr_file).strip
|
|
785
|
+
return mac unless mac.empty? || mac == '00:00:00:00:00:00'
|
|
786
|
+
end
|
|
787
|
+
end
|
|
788
|
+
|
|
789
|
+
# Fallback: try ifconfig/ip command
|
|
790
|
+
output = `ifconfig 2>/dev/null || ip link show 2>/dev/null`.strip
|
|
791
|
+
match = output.match(/(?:[0-9a-f]{2}:){5}[0-9a-f]{2}/i)
|
|
792
|
+
return match[0] if match
|
|
793
|
+
|
|
794
|
+
''
|
|
795
|
+
rescue
|
|
796
|
+
''
|
|
797
|
+
end
|
|
798
|
+
|
|
799
|
+
# Get OS name
|
|
800
|
+
def get_os_name
|
|
801
|
+
case RUBY_PLATFORM
|
|
802
|
+
when /linux/
|
|
803
|
+
'Linux'
|
|
804
|
+
when /darwin/
|
|
805
|
+
'Darwin'
|
|
806
|
+
when /freebsd/
|
|
807
|
+
'FreeBSD'
|
|
808
|
+
when /netbsd/
|
|
809
|
+
'NetBSD'
|
|
810
|
+
when /openbsd/
|
|
811
|
+
'OpenBSD'
|
|
812
|
+
when /sunos|solaris/
|
|
813
|
+
'Solaris'
|
|
814
|
+
when /aix/
|
|
815
|
+
'AIX'
|
|
816
|
+
when /win|mingw|mswin/
|
|
817
|
+
'Windows'
|
|
818
|
+
else
|
|
819
|
+
RUBY_PLATFORM
|
|
820
|
+
end
|
|
821
|
+
rescue
|
|
822
|
+
'Unknown'
|
|
823
|
+
end
|
|
824
|
+
|
|
825
|
+
# Get system architecture
|
|
826
|
+
def get_architecture
|
|
827
|
+
case RbConfig::CONFIG['host_cpu']
|
|
828
|
+
when /x86_64|amd64/
|
|
829
|
+
'x86_64'
|
|
830
|
+
when /i[3-6]86|x86/
|
|
831
|
+
'x86'
|
|
832
|
+
when /aarch64|arm64/
|
|
833
|
+
'aarch_64'
|
|
834
|
+
when /arm/
|
|
835
|
+
'arm'
|
|
836
|
+
when /ppc64le/
|
|
837
|
+
'ppc64le'
|
|
838
|
+
when /ppc64/
|
|
839
|
+
'ppc64'
|
|
840
|
+
when /s390x/
|
|
841
|
+
's390x'
|
|
842
|
+
else
|
|
843
|
+
RbConfig::CONFIG['host_cpu']
|
|
844
|
+
end
|
|
845
|
+
rescue
|
|
846
|
+
'unknown'
|
|
847
|
+
end
|
|
848
|
+
|
|
849
|
+
# POST request for DOCC interfaces with token authentication
|
|
850
|
+
def post_docc(path, data)
|
|
851
|
+
uri = URI.join(base_url, path)
|
|
852
|
+
|
|
853
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
854
|
+
http.use_ssl = (uri.scheme == 'https')
|
|
855
|
+
http.open_timeout = 5
|
|
856
|
+
http.read_timeout = 5
|
|
857
|
+
|
|
858
|
+
request = Net::HTTP::Post.new(uri.path)
|
|
859
|
+
request['Content-Type'] = 'application/json'
|
|
860
|
+
request['token'] = @token
|
|
861
|
+
request['User-Agent'] = "Datadog-Ruby-Agent/#{Datadog::VERSION::STRING}"
|
|
862
|
+
request['DD-Internal-Untraced-Request'] = '1'
|
|
863
|
+
request.body = data.to_json
|
|
864
|
+
|
|
865
|
+
Cloudwise.log_debug { "Cloudwise DOCC API request: #{request.method} #{uri} with data: #{data.inspect}" }
|
|
866
|
+
|
|
867
|
+
response = http.request(request)
|
|
868
|
+
handle_response(response, path)
|
|
869
|
+
rescue => e
|
|
870
|
+
Cloudwise.log_error { "Cloudwise DOCC API error for #{path}: #{e.class.name} #{e.message}" }
|
|
871
|
+
{ success: false, error: e.message, code: nil }
|
|
872
|
+
end
|
|
873
|
+
|
|
487
874
|
end
|
|
488
875
|
end
|
|
489
876
|
end
|