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.
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 +364 -25
  14. data/lib/datadog/core/cloudwise/component.rb +197 -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 +3 -1
  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 +28 -0
  22. data/lib/datadog/core/configuration/supported_configurations.rb +5 -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 +40 -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
@@ -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
- uri = URI.join(base_url, path)
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['message']
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
- # 计算采样率(借鉴 Propagation 的规则,不引用 tracing 组件)
506
+ # 计算采样率(读取 Datadog 配置或环境变量)
507
+ # 返回 0-100 的整数值
420
508
  def calculate_sample_rate
421
- # 默认采样率为 1(100% 采样)
422
- # 可以从环境变量读取自定义采样率
423
- rate = ENV['CLOUDWISE_SAMPLE_RATE']&.to_i
424
- return rate if rate && rate >= 0 && rate <= 100
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
- 1 # 默认值
427
- rescue
428
- 1
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