cw-datadog 2.23.0.3 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e48258b923a9015853cdfcb2b879dfcf9cc347ca9c8ade2ec013d66c0752ed93
4
- data.tar.gz: '0998633db06aa8661eeb1f75bb6b4a18460109ae6815671cdcc6e10f8def8a30'
3
+ metadata.gz: bd6025da8b149a6b2277f316f7549afc34f428ce4de309db359dfc9addc38986
4
+ data.tar.gz: da6349523059c13f04fb61e415e081926d6d8d16f2946558473765371ad951cd
5
5
  SHA512:
6
- metadata.gz: 216d0de9105aecd55f60d887be3c1779d3fdb51aa120f454a4b8ab7093f6e0e64fe06df5d9ea69677c94a190ed1cd767f67be0fd98c255b137c64495f9208447
7
- data.tar.gz: 126ae7bae30741f6b010cf6e13dd5ff013f0a2e69a82bf2a156043260142781e520f4d87341bebbd4d928e599790094e67af55f505e1f08c138eca515e2ef77e
6
+ metadata.gz: e14911f3d08e21faa4875f030b9889efd3909fc6c30cbd3e01f5cb716014a468f28800307b3535b5d54895a90b14cb1d838b88281f724ef4e872b1f632014085
7
+ data.tar.gz: fbe9e9791dfd7e1b3cad8b0e74eac6ee79c579bc5c3357e231c4a5fc3c44722b58acc7860bd2f3674cf04a6e9deba41cf3729fee4508114568665a12f6c4c494
@@ -22,14 +22,15 @@ module Datadog
22
22
  # DOCC response codes
23
23
  DOCC_CODE_SUCCESS = 100000
24
24
 
25
- def initialize(base_url:, server_name:, license_key:, logger:, integrated_mode: true, token: nil, api_prefix: nil)
25
+ def initialize(base_url:, server_name:, license_key:, logger:, integrated_mode: true, token: nil, api_prefix: nil, api_prefix_mode: nil)
26
26
  @base_url = normalize_url(base_url)
27
27
  @server_name = server_name
28
28
  @license_key = license_key
29
29
  @logger = logger
30
30
  @integrated_mode = integrated_mode
31
31
  @token = token
32
- @api_prefix = api_prefix # 统一的 API 路径前缀
32
+ @api_prefix = api_prefix # 自定义 API 路径前缀
33
+ @api_prefix_mode = api_prefix_mode # API 前缀模式(简化配置)
33
34
  @host_id = nil
34
35
  @account_id = nil
35
36
  @is_first_heartbeat = true
@@ -63,7 +64,8 @@ module Datadog
63
64
  logger: logger,
64
65
  integrated_mode: settings.cloudwise.integrated_mode,
65
66
  token: settings.cloudwise.token,
66
- api_prefix: settings.cloudwise.api_prefix
67
+ api_prefix: settings.cloudwise.api_prefix,
68
+ api_prefix_mode: settings.cloudwise.api_prefix_mode
67
69
  )
68
70
  end
69
71
 
@@ -197,6 +199,22 @@ module Datadog
197
199
  })
198
200
  end
199
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
+
200
218
  # 应用注册接口
201
219
  def register_application
202
220
  host_ip = get_local_ip
@@ -261,7 +279,7 @@ module Datadog
261
279
  sample: calculate_sample_rate,
262
280
  physical_ip: detect_container? ? get_host_real_ip : '',
263
281
  container_id: detect_container? ? get_container_id : '',
264
- sys: ENV['CW_SYS'] || '',
282
+ sys: ENV['CW_SYS'] || 'default',
265
283
  env_tag: Datadog.configuration.env || 'default'
266
284
  }
267
285
  }
@@ -590,7 +608,7 @@ module Datadog
590
608
  end
591
609
 
592
610
  # 统一处理 API 路径前缀
593
- # 优先级:DD_CLOUDWISE_API_PREFIX > integrated_mode (/apm) > 无前缀
611
+ # 优先级:api_prefix_mode > api_prefix > integrated_mode (/apm) > 无前缀
594
612
  # @param path [String] 原始路径
595
613
  # @return [String] 处理后的路径
596
614
  def apply_api_prefix(path)
@@ -603,6 +621,7 @@ module Datadog
603
621
  '/v2/app/generateHostId',
604
622
  '/v2/app/registerHost',
605
623
  '/api/v1/agent/heartbeat',
624
+ '/api/v1/agent/fuseHeart',
606
625
  '/v2/app/create',
607
626
  '/v2/licence/verification'
608
627
  ]
@@ -611,21 +630,50 @@ module Datadog
611
630
  needs_prefix = cloudwise_api_paths.any? { |p| path.start_with?(p) }
612
631
  return path unless needs_prefix
613
632
 
614
- # 优先级 1: 显式配置的 api_prefix(最高优先级)
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(自定义前缀)
615
640
  if @api_prefix && !@api_prefix.empty?
616
641
  prefix = @api_prefix.start_with?('/') ? @api_prefix : "/#{@api_prefix}"
617
642
  return "#{prefix}#{path}"
618
643
  end
619
644
 
620
- # 优先级 2: integrated_mode 使用 /apm 前缀
645
+ # 优先级 3: integrated_mode 使用 /apm 前缀
621
646
  if use_integrated_mode?
622
647
  return "/apm#{path}"
623
648
  end
624
649
 
625
- # 优先级 3: 无前缀(默认)
650
+ # 优先级 4: 无前缀(默认)
626
651
  path
627
652
  end
628
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
+
629
677
  # Parse token to extract account_id and user_id
630
678
  # Token format: base64("account_id@user_id")
631
679
  def parse_token
@@ -290,8 +290,7 @@ module Datadog
290
290
  @docc_registration_worker = DOCCRegistrationWorker.new(
291
291
  client: client,
292
292
  logger: logger,
293
- probe_state: probe_state,
294
- interval: settings.cloudwise.docc_registration_interval
293
+ probe_state: probe_state
295
294
  )
296
295
 
297
296
  # 2. DOCC Heartbeat Worker (30s interval)
@@ -306,8 +305,7 @@ module Datadog
306
305
  @docc_operation_worker = DOCCOperationWorker.new(
307
306
  client: client,
308
307
  logger: logger,
309
- probe_state: probe_state,
310
- interval: settings.cloudwise.docc_operation_interval
308
+ probe_state: probe_state
311
309
  )
312
310
 
313
311
  # 4. License Worker (5 min interval) - License 校验逻辑保持不变
@@ -19,6 +19,22 @@ module Datadog
19
19
  # 成功的状态码
20
20
  CODE_SUCCESS = 1000
21
21
 
22
+ # 熔断状态定义
23
+ FUSE_STATE_NORMAL = 0 # 正常
24
+ FUSE_STATE_FUSING = 1 # 熔断
25
+
26
+ # 熔断描述定义
27
+ FUSE_DESCRIBE_LICENSE_EXPIRED = 7 # License过期熔断
28
+ FUSE_DESCRIBE_AGENT_SUSPENDED = 8 # Agent暂停熔断
29
+ FUSE_DESCRIBE_LICENSE_OVER_QUOTA = 9 # License超配额熔断
30
+ FUSE_DESCRIBE_LICENSE_INTERFACE_ERROR = 10 # License接口异常熔断
31
+
32
+ # License 响应码定义
33
+ LICENSE_CODE_AGENT_SUSPENDED = 4113 # Agent暂停
34
+ LICENSE_CODE_OVER_QUOTA = 4114 # License超配额
35
+ LICENSE_CODE_EXPIRED = 4116 # License过期
36
+ LICENSE_CODE_INTERFACE_ERROR = 4120 # License接口异常
37
+
22
38
  attr_reader :client
23
39
 
24
40
  def initialize(client:, logger:, probe_state:, **options)
@@ -26,6 +42,8 @@ module Datadog
26
42
  @logger = logger
27
43
  @probe_state = probe_state
28
44
  @failure_count = 0
45
+ @last_fuse_state = nil # 记录最后一次的熔断状态
46
+ @last_fuse_describe = nil # 记录最后一次的熔断描述
29
47
 
30
48
  # Workers::Async::Thread settings
31
49
  self.fork_policy = options.fetch(:fork_policy, Workers::Async::Thread::FORK_POLICY_STOP)
@@ -79,19 +97,34 @@ module Datadog
79
97
  # msg 字段在响应的顶层(result[:message]),是字符串 "true" 或 "false"
80
98
  msg = result[:message]
81
99
 
82
- # License 校验成功 (code == 1000)
100
+ # License 校验成功 (code == 1000 且 msg == 'true')
83
101
  if code == CODE_SUCCESS && msg == 'true'
84
102
  Cloudwise.log_debug { 'Cloudwise: License valid' }
85
103
  probe_state.mark_license_valid!
86
104
  @failure_count = 0 # 重置失败计数
105
+ # 上报正常状态(如果状态发生变化)
106
+ report_fuse_state_if_changed(FUSE_STATE_NORMAL, nil)
107
+ return
108
+ end
109
+
110
+ # 特殊情况:code == 1000 但 msg == 'false',视为 License 过期
111
+ if code == CODE_SUCCESS && msg == 'false'
112
+ Cloudwise.log_error { "Cloudwise: License verification failed - code #{code} with msg false (License expired)" }
113
+ probe_state.mark_license_invalid!
114
+ @failure_count = 0 # 重置失败计数(因为接口成功返回了)
115
+ # 上报为License过期熔断状态
116
+ report_fuse_state_if_changed(FUSE_STATE_FUSING, FUSE_DESCRIBE_LICENSE_EXPIRED)
87
117
  return
88
118
  end
89
119
 
90
- # License 校验失败 (code != 1000)
120
+ # 其他 License 校验失败情况 (code != 1000)
91
121
  Cloudwise.log_error { "Cloudwise: License verification failed with code #{code}" }
92
- Cloudwise.log_error { "Cloudwise: Data collection suspended due to invalid license" }
93
122
  probe_state.mark_license_invalid!
94
123
  @failure_count = 0 # 重置失败计数(因为接口成功返回了)
124
+
125
+ # 根据错误码上报相应的熔断状态
126
+ fuse_describe = map_license_code_to_fuse_describe(code)
127
+ report_fuse_state_if_changed(FUSE_STATE_FUSING, fuse_describe)
95
128
  end
96
129
 
97
130
  def handle_license_failure
@@ -102,8 +135,59 @@ module Datadog
102
135
  if @failure_count >= MAX_RETRIES
103
136
  Cloudwise.log_error { "Cloudwise: License verification failed #{@failure_count} times, marking as invalid" }
104
137
  probe_state.mark_license_invalid!
138
+
139
+ # 上报License接口异常熔断状态
140
+ report_fuse_state_if_changed(FUSE_STATE_FUSING, FUSE_DESCRIBE_LICENSE_INTERFACE_ERROR)
141
+ end
142
+ end
143
+
144
+ # 将License错误码映射为熔断描述
145
+ def map_license_code_to_fuse_describe(license_code)
146
+ case license_code
147
+ when LICENSE_CODE_AGENT_SUSPENDED
148
+ FUSE_DESCRIBE_AGENT_SUSPENDED
149
+ when LICENSE_CODE_OVER_QUOTA
150
+ FUSE_DESCRIBE_LICENSE_OVER_QUOTA
151
+ when LICENSE_CODE_EXPIRED
152
+ FUSE_DESCRIBE_LICENSE_EXPIRED
153
+ when LICENSE_CODE_INTERFACE_ERROR
154
+ FUSE_DESCRIBE_LICENSE_INTERFACE_ERROR
155
+ else
156
+ # 其他未知的License错误码,统一按接口异常处理
157
+ FUSE_DESCRIBE_LICENSE_INTERFACE_ERROR
105
158
  end
106
159
  end
160
+
161
+ # 仅在状态发生变化时上报熔断状态
162
+ # @param fuse_state [Integer] 熔断状态: 0-正常, 1-熔断
163
+ # @param fuse_describe [Integer, nil] 熔断描述: 7/8/9/10,正常状态时为nil
164
+ def report_fuse_state_if_changed(fuse_state, fuse_describe)
165
+ # 检查状态是否发生变化
166
+ if @last_fuse_state == fuse_state && @last_fuse_describe == fuse_describe
167
+ Cloudwise.log_debug { "Cloudwise: Fuse state unchanged (state: #{fuse_state}, describe: #{fuse_describe}), skip reporting" }
168
+ return
169
+ end
170
+
171
+ # 状态发生变化,进行上报
172
+ Cloudwise.log_info { "Cloudwise: Fuse state changed from (#{@last_fuse_state}, #{@last_fuse_describe}) to (#{fuse_state}, #{fuse_describe})" }
173
+
174
+ # 构造上报参数
175
+ fuse_describe_str = fuse_describe ? fuse_describe.to_s : fuse_state.to_s
176
+
177
+ # 调用Client的上报接口
178
+ result = client.report_fuse_state(fuse_state: fuse_state, fuse_describe: fuse_describe_str)
179
+
180
+ if result[:success]
181
+ Cloudwise.log_debug { "Cloudwise: Fuse state reported successfully (state: #{fuse_state}, describe: #{fuse_describe})" }
182
+ # 更新最后一次的状态
183
+ @last_fuse_state = fuse_state
184
+ @last_fuse_describe = fuse_describe
185
+ else
186
+ Cloudwise.log_error { "Cloudwise: Failed to report fuse state: #{result[:error]}" }
187
+ end
188
+ rescue => e
189
+ Cloudwise.log_error { "Cloudwise: Error reporting fuse state: #{e.class.name} #{e.message}" }
190
+ end
107
191
  end
108
192
  end
109
193
  end
@@ -1044,15 +1044,30 @@ module Datadog
1044
1044
  o.default nil
1045
1045
  end
1046
1046
 
1047
- # API 路径前缀,用于在所有 Cloudwise API 请求前添加统一前缀
1048
- # 例如: '/doop-agent-api' 会将请求从 '/api/v2/traces' 改为 '/doop-agent-api/api/v2/traces'
1049
- # 优先级: DD_CLOUDWISE_API_PREFIX > integrated_mode ('/apm') > 无前缀
1047
+ # API 路径前缀模式(简化配置)
1048
+ # 可选值: 'doop', 'apm', 'custom'
1049
+ # 优先级: api_prefix_mode > api_prefix > integrated_mode > 无前缀
1050
+ option :api_prefix_mode do |o|
1051
+ o.type :string, nilable: true
1052
+ o.env 'DD_CLOUDWISE_API_PREFIX_MODE'
1053
+ o.default nil
1054
+ end
1055
+
1056
+ # API 路径前缀(自定义配置)
1057
+ # 优先级: api_prefix_mode > api_prefix > integrated_mode ('/apm') > 无前缀
1050
1058
  option :api_prefix do |o|
1051
1059
  o.type :string, nilable: true
1052
1060
  o.env 'DD_CLOUDWISE_API_PREFIX'
1053
1061
  o.default nil
1054
1062
  end
1055
1063
 
1064
+ # SYS
1065
+ option :sys do |o|
1066
+ o.type :string, nilable: true
1067
+ o.env 'CW_SYS'
1068
+ o.default 'default'
1069
+ end
1070
+
1056
1071
  # Heartbeat interval in seconds
1057
1072
  # @default `DD_CLOUDWISE_HEARTBEAT_INTERVAL` environment variable, otherwise `30`
1058
1073
  # @return [Integer]
@@ -37,6 +37,7 @@ module Datadog
37
37
  "DD_CLOUDWISE_LICENSE_KEY" => {version: ["A"]},
38
38
  "DD_CLOUDWISE_TOKEN" => {version: ["A"]},
39
39
  "CW_SYS" => {version: ["A"]},
40
+ "DD_CLOUDWISE_API_PREFIX_MODE" => {version: ["A"]},
40
41
  "DD_CLOUDWISE_API_PREFIX" => {version: ["A"]},
41
42
  "DD_CRASHTRACKING_ENABLED" => {version: ["A"]},
42
43
  "DD_DATA_STREAMS_ENABLED" => {version: ["A"]},
@@ -42,14 +42,24 @@ module Datadog
42
42
  end
43
43
 
44
44
  # 获取 Traces V4 API 路径
45
- # 优先级:DD_CLOUDWISE_API_PREFIX > integrated_mode > 默认
45
+ # 优先级:api_prefix_mode > api_prefix > integrated_mode > 默认
46
46
  def get_traces_v4_path
47
47
  base_path = '/api/v2/traces'
48
48
 
49
- # 优先级 1: 显式配置的 api_prefix(最高优先级)
50
- if defined?(Datadog.configuration) &&
51
- Datadog.configuration.respond_to?(:cloudwise) &&
52
- Datadog.configuration.cloudwise.respond_to?(:api_prefix)
49
+ return base_path unless defined?(Datadog.configuration) &&
50
+ Datadog.configuration.respond_to?(:cloudwise)
51
+
52
+ # 优先级 1: api_prefix_mode 模式配置(最高优先级,简化配置)
53
+ if Datadog.configuration.cloudwise.respond_to?(:api_prefix_mode)
54
+ api_prefix_mode = Datadog.configuration.cloudwise.api_prefix_mode
55
+ if api_prefix_mode && !api_prefix_mode.empty?
56
+ prefix = get_prefix_by_mode(api_prefix_mode)
57
+ return "#{prefix}#{base_path}" if prefix
58
+ end
59
+ end
60
+
61
+ # 优先级 2: 显式配置的 api_prefix(自定义前缀)
62
+ if Datadog.configuration.cloudwise.respond_to?(:api_prefix)
53
63
  api_prefix = Datadog.configuration.cloudwise.api_prefix
54
64
  if api_prefix && !api_prefix.empty?
55
65
  prefix = api_prefix.start_with?('/') ? api_prefix : "/#{api_prefix}"
@@ -57,15 +67,38 @@ module Datadog
57
67
  end
58
68
  end
59
69
 
60
- # 优先级 2: integrated_mode 使用 /apm 前缀
70
+ # 优先级 3: integrated_mode 使用 /apm 前缀
61
71
  if cloudwise_integrated_mode?
62
72
  return "/apm#{base_path}"
63
73
  end
64
74
 
65
- # 优先级 3: 无前缀(默认)
75
+ # 优先级 4: 无前缀(默认)
66
76
  base_path
67
77
  end
68
78
 
79
+ # 根据模式获取前缀
80
+ # @param mode [String] 前缀模式:'doop', 'apm', 'custom'
81
+ # @return [String, nil] 前缀字符串,如果模式无效返回 nil
82
+ def get_prefix_by_mode(mode)
83
+ case mode.to_s.downcase
84
+ when 'doop'
85
+ '/doop-agent-api'
86
+ when 'apm'
87
+ '/apm'
88
+ when 'custom'
89
+ # 使用 api_prefix 配置的自定义前缀
90
+ if Datadog.configuration.cloudwise.respond_to?(:api_prefix)
91
+ api_prefix = Datadog.configuration.cloudwise.api_prefix
92
+ if api_prefix && !api_prefix.empty?
93
+ return api_prefix.start_with?('/') ? api_prefix : "/#{api_prefix}"
94
+ end
95
+ end
96
+ nil
97
+ else
98
+ nil
99
+ end
100
+ end
101
+
69
102
  # 检查是否启用 integrated_mode
70
103
  def cloudwise_integrated_mode?
71
104
  return false unless defined?(Datadog.configuration) &&
@@ -5,7 +5,7 @@ module Datadog
5
5
  MAJOR = 2
6
6
  MINOR = 23
7
7
  PATCH = 0
8
- PATCH_MINOR = 3
8
+ PATCH_MINOR = 4
9
9
  PRE = nil
10
10
  BUILD = nil
11
11
  # PRE and BUILD above are modified for dev gems during gem build GHA workflow
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cw-datadog
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.23.0.3
4
+ version: 2.23.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Datadog, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-12-01 00:00:00.000000000 Z
11
+ date: 2025-12-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: msgpack
@@ -1070,8 +1070,8 @@ licenses:
1070
1070
  - Apache-2.0
1071
1071
  metadata:
1072
1072
  allowed_push_host: https://rubygems.org
1073
- changelog_uri: https://github.com/DataDog/dd-trace-rb/blob/v2.23.0.3/CHANGELOG.md
1074
- source_code_uri: https://github.com/DataDog/dd-trace-rb/tree/v2.23.0.3
1073
+ changelog_uri: https://github.com/DataDog/dd-trace-rb/blob/v2.23.0.4/CHANGELOG.md
1074
+ source_code_uri: https://github.com/DataDog/dd-trace-rb/tree/v2.23.0.4
1075
1075
  post_install_message:
1076
1076
  rdoc_options: []
1077
1077
  require_paths: