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
|
@@ -14,6 +14,11 @@ module Datadog
|
|
|
14
14
|
class Propagation
|
|
15
15
|
TYPE_FROM = 'RUBY'
|
|
16
16
|
HEADER_NAME = 'CLOUDWISE'
|
|
17
|
+
HEADER_OTHER_NAME = 'CLOUDWISE-OTHER'
|
|
18
|
+
|
|
19
|
+
# 服务类型
|
|
20
|
+
SERVICE_TYPE_APPLICATION = 'APPLICATION'
|
|
21
|
+
SERVICE_TYPE_TASK = 'task'
|
|
17
22
|
|
|
18
23
|
# CLOUDWISE 字段索引
|
|
19
24
|
FIELD_TYPE_FROM = 0
|
|
@@ -27,6 +32,10 @@ module Datadog
|
|
|
27
32
|
FIELD_SEGMENT_ID = 8
|
|
28
33
|
FIELD_APP_NAME = 9
|
|
29
34
|
|
|
35
|
+
# CLOUDWISE-OTHER 字段索引
|
|
36
|
+
FIELD_OTHER_SERVICE_TYPE_FROM = 0
|
|
37
|
+
FIELD_OTHER_PARENT_SYS = 1
|
|
38
|
+
|
|
30
39
|
# 注入 CLOUDWISE 请求头
|
|
31
40
|
# @param span [Datadog::Tracing::SpanOperation] 当前 span
|
|
32
41
|
# @param trace [Datadog::Tracing::TraceOperation] 当前 trace
|
|
@@ -41,6 +50,9 @@ module Datadog
|
|
|
41
50
|
# 获取目标 URL
|
|
42
51
|
target_url = extract_target_url(request)
|
|
43
52
|
|
|
53
|
+
# 生成 assumed_app_id
|
|
54
|
+
assumed_app_id = generate_assumed_app_id(target_url)
|
|
55
|
+
|
|
44
56
|
# 构建 CLOUDWISE header 值
|
|
45
57
|
cloudwise_value = build_cloudwise_value(
|
|
46
58
|
span: span,
|
|
@@ -52,6 +64,14 @@ module Datadog
|
|
|
52
64
|
# 添加到请求头
|
|
53
65
|
request[HEADER_NAME] = cloudwise_value if cloudwise_value
|
|
54
66
|
|
|
67
|
+
# 注入 CLOUDWISE-OTHER 请求头
|
|
68
|
+
inject_other_header!(request)
|
|
69
|
+
|
|
70
|
+
# 将 assumed_app_id 添加到 span 的 tags 中
|
|
71
|
+
if assumed_app_id && assumed_app_id != '-1'
|
|
72
|
+
span.set_tag('assumed_app_id', assumed_app_id)
|
|
73
|
+
end
|
|
74
|
+
|
|
55
75
|
Datadog.logger.debug do
|
|
56
76
|
"Injected CLOUDWISE header: #{cloudwise_value}"
|
|
57
77
|
end if defined?(Datadog.logger)
|
|
@@ -257,8 +277,7 @@ module Datadog
|
|
|
257
277
|
span.set_tag('app_name_from', fields[:app_name]) if fields[:app_name]
|
|
258
278
|
|
|
259
279
|
Datadog.logger.debug do
|
|
260
|
-
"Extracted CLOUDWISE header
|
|
261
|
-
"app_id_from=#{fields[:app_id]}, app_name_from=#{fields[:app_name]}"
|
|
280
|
+
"Extracted CLOUDWISE header : cloudwise_header=#{cloudwise_header}"
|
|
262
281
|
end if defined?(Datadog.logger)
|
|
263
282
|
rescue => e
|
|
264
283
|
Datadog.logger.error do
|
|
@@ -288,17 +307,17 @@ module Datadog
|
|
|
288
307
|
return nil
|
|
289
308
|
end
|
|
290
309
|
|
|
291
|
-
#
|
|
310
|
+
# 构建字段哈希(将 "null" 字符串转换为空字符串)
|
|
292
311
|
{
|
|
293
312
|
type_from: parts[FIELD_TYPE_FROM]&.strip,
|
|
294
|
-
sample: parts[FIELD_SAMPLE]
|
|
295
|
-
host_id: parts[FIELD_HOST_ID]
|
|
313
|
+
sample: normalize_field_value(parts[FIELD_SAMPLE]),
|
|
314
|
+
host_id: normalize_field_value(parts[FIELD_HOST_ID]),
|
|
296
315
|
app_id: parts[FIELD_APP_ID]&.strip,
|
|
297
|
-
instance_id: parts[FIELD_INSTANCE_ID]
|
|
316
|
+
instance_id: normalize_field_value(parts[FIELD_INSTANCE_ID]),
|
|
298
317
|
trace_id: parts[FIELD_TRACE_ID]&.strip,
|
|
299
318
|
assumed_app_id: parts[FIELD_ASSUMED_APP_ID]&.strip,
|
|
300
319
|
span_id: parts[FIELD_SPAN_ID]&.strip,
|
|
301
|
-
segment_id: parts[FIELD_SEGMENT_ID]
|
|
320
|
+
segment_id: normalize_field_value(parts[FIELD_SEGMENT_ID]),
|
|
302
321
|
app_name: parts[FIELD_APP_NAME]&.strip
|
|
303
322
|
}
|
|
304
323
|
rescue => e
|
|
@@ -307,6 +326,144 @@ module Datadog
|
|
|
307
326
|
end if defined?(Datadog.logger)
|
|
308
327
|
nil
|
|
309
328
|
end
|
|
329
|
+
|
|
330
|
+
# 标准化字段值:去除空格,将 "null" 转换为空字符串
|
|
331
|
+
# @param value [String, nil] 原始字段值
|
|
332
|
+
# @return [String] 标准化后的字段值
|
|
333
|
+
def self.normalize_field_value(value)
|
|
334
|
+
return '-1' if value.nil?
|
|
335
|
+
|
|
336
|
+
normalized = value.strip
|
|
337
|
+
# 将字符串 "null" 转换为空字符串
|
|
338
|
+
normalized == 'null' ? '-1' : normalized
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
# 获取当前服务的 sys 值
|
|
342
|
+
# @return [String] sys 值,默认为 'default'
|
|
343
|
+
def self.get_sys
|
|
344
|
+
ENV['CW_SYS'] || 'default'
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
# 生成 service_instance_id(基于 IP + 进程路径 + PID)
|
|
348
|
+
# @return [String] service_instance_id
|
|
349
|
+
def self.generate_service_instance_id
|
|
350
|
+
host_ip = get_host_ip
|
|
351
|
+
process_path = $PROGRAM_NAME || ''
|
|
352
|
+
process_pid = Process.pid.to_s
|
|
353
|
+
|
|
354
|
+
# 组合:IP + 进程路径 + PID
|
|
355
|
+
combined = "#{host_ip}#{process_path}#{process_pid}"
|
|
356
|
+
|
|
357
|
+
# 使用 MD5 生成唯一 ID
|
|
358
|
+
require 'digest/md5'
|
|
359
|
+
md5_hex = Digest::MD5.hexdigest(combined)
|
|
360
|
+
# 取前15位转为整数(避免超过 Java Long.MAX_VALUE)
|
|
361
|
+
md5_hex[0..14].to_i(16).to_s
|
|
362
|
+
rescue => e
|
|
363
|
+
Datadog.logger.debug { "Error generating service_instance_id: #{e.message}" } if defined?(Datadog.logger)
|
|
364
|
+
# 降级方案:使用 PID
|
|
365
|
+
Process.pid.to_s
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
# 检测当前服务类型
|
|
369
|
+
# @return [String] 服务类型:'APPLICATION' 或 'task'
|
|
370
|
+
def self.detect_service_type
|
|
371
|
+
# 优先检查环境变量显式设置
|
|
372
|
+
service_type_env = ENV['CLOUDWISE_SERVICE_TYPE']
|
|
373
|
+
if service_type_env
|
|
374
|
+
return SERVICE_TYPE_TASK if service_type_env.downcase == 'task'
|
|
375
|
+
return SERVICE_TYPE_APPLICATION if service_type_env.downcase == 'application'
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
# 检查是否在 Worker 进程中运行(更精确的判断)
|
|
379
|
+
# Sidekiq Worker 进程(检查 Sidekiq 是否作为服务器运行)
|
|
380
|
+
if defined?(::Sidekiq) && ::Sidekiq.respond_to?(:server?) && ::Sidekiq.server?
|
|
381
|
+
return SERVICE_TYPE_TASK
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
# Resque Worker 进程
|
|
385
|
+
if defined?(::Resque) && ENV['QUEUE']
|
|
386
|
+
return SERVICE_TYPE_TASK
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
# DelayedJob Worker 进程
|
|
390
|
+
if defined?(::Delayed::Worker) && ENV['DELAYED_JOB']
|
|
391
|
+
return SERVICE_TYPE_TASK
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
# 显式的 Worker 模式
|
|
395
|
+
if ENV['WORKER_MODE'] == 'true'
|
|
396
|
+
return SERVICE_TYPE_TASK
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
# 默认为 Web 应用
|
|
400
|
+
SERVICE_TYPE_APPLICATION
|
|
401
|
+
rescue => e
|
|
402
|
+
# 如果检测出错,默认为 Web 应用
|
|
403
|
+
Datadog.logger.debug { "Error detecting service type: #{e.message}, defaulting to APPLICATION" } if defined?(Datadog.logger)
|
|
404
|
+
SERVICE_TYPE_APPLICATION
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
# 注入 CLOUDWISE-OTHER 请求头到下游服务
|
|
408
|
+
# @param request [Net::HTTPRequest] HTTP 请求对象
|
|
409
|
+
def self.inject_other_header!(request)
|
|
410
|
+
return unless request
|
|
411
|
+
|
|
412
|
+
service_type = detect_service_type
|
|
413
|
+
sys = get_sys
|
|
414
|
+
|
|
415
|
+
# 构建 CLOUDWISE-OTHER 值:service_type_from:sys
|
|
416
|
+
other_value = "#{service_type}:#{sys}"
|
|
417
|
+
request[HEADER_OTHER_NAME] = other_value
|
|
418
|
+
|
|
419
|
+
Datadog.logger.debug do
|
|
420
|
+
"Injected CLOUDWISE-OTHER header: #{other_value}"
|
|
421
|
+
end if defined?(Datadog.logger)
|
|
422
|
+
rescue => e
|
|
423
|
+
Datadog.logger.error do
|
|
424
|
+
"Error injecting CLOUDWISE-OTHER header: #{e.message}"
|
|
425
|
+
end if defined?(Datadog.logger)
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
# 从请求头中提取 CLOUDWISE-OTHER 并添加到根 span
|
|
429
|
+
# @param span [Datadog::Tracing::SpanOperation] 根 span
|
|
430
|
+
# @param request_headers [Hash] 请求头
|
|
431
|
+
def self.extract_other_from_request!(span, request_headers)
|
|
432
|
+
return unless span
|
|
433
|
+
|
|
434
|
+
# 从请求头中获取 CLOUDWISE-OTHER
|
|
435
|
+
other_header = request_headers[HEADER_OTHER_NAME] ||
|
|
436
|
+
request_headers['HTTP_' + HEADER_OTHER_NAME.upcase.gsub('-', '_')]
|
|
437
|
+
|
|
438
|
+
if other_header
|
|
439
|
+
# 解析 CLOUDWISE-OTHER:service_type_from:parent_sys
|
|
440
|
+
parts = other_header.split(':')
|
|
441
|
+
|
|
442
|
+
service_type_from = normalize_field_value(parts[FIELD_OTHER_SERVICE_TYPE_FROM])
|
|
443
|
+
parent_sys = normalize_field_value(parts[FIELD_OTHER_PARENT_SYS])
|
|
444
|
+
|
|
445
|
+
# 只添加上游相关的字段到 span tags
|
|
446
|
+
# sys 和 service_instance_id 将在 tag_cloudwise_metadata! 中设置
|
|
447
|
+
span.set_tag('service_type_from', service_type_from)
|
|
448
|
+
span.set_tag('parent_sys', parent_sys)
|
|
449
|
+
|
|
450
|
+
Datadog.logger.debug do
|
|
451
|
+
"Extracted CLOUDWISE-OTHER from request: service_type_from=#{service_type_from}, parent_sys=#{parent_sys}"
|
|
452
|
+
end if defined?(Datadog.logger)
|
|
453
|
+
else
|
|
454
|
+
# 如果没有上游请求头,设置为空字符串
|
|
455
|
+
span.set_tag('service_type_from', '')
|
|
456
|
+
span.set_tag('parent_sys', '')
|
|
457
|
+
|
|
458
|
+
Datadog.logger.debug do
|
|
459
|
+
"No CLOUDWISE-OTHER header in request, set service_type_from and parent_sys to empty"
|
|
460
|
+
end if defined?(Datadog.logger)
|
|
461
|
+
end
|
|
462
|
+
rescue => e
|
|
463
|
+
Datadog.logger.error do
|
|
464
|
+
"Error extracting CLOUDWISE-OTHER: #{e.message}"
|
|
465
|
+
end if defined?(Datadog.logger)
|
|
466
|
+
end
|
|
310
467
|
end
|
|
311
468
|
end
|
|
312
469
|
end
|
|
@@ -176,6 +176,26 @@ module Datadog
|
|
|
176
176
|
"#{type.graphql_name}.resolve_type"
|
|
177
177
|
end
|
|
178
178
|
|
|
179
|
+
# Serialize error's `locations` array as an array of Strings, given
|
|
180
|
+
# Span Events do not support hashes nested inside arrays.
|
|
181
|
+
#
|
|
182
|
+
# Here's an example in which `locations`:
|
|
183
|
+
# [
|
|
184
|
+
# {"line" => 3, "column" => 10},
|
|
185
|
+
# {"line" => 7, "column" => 8},
|
|
186
|
+
# ]
|
|
187
|
+
# is serialized as:
|
|
188
|
+
# ["3:10", "7:8"]
|
|
189
|
+
def self.serialize_error_locations(locations)
|
|
190
|
+
# locations are only provided by the `graphql` library when the error can
|
|
191
|
+
# be associated to a particular point in the query.
|
|
192
|
+
return [] if locations.nil?
|
|
193
|
+
|
|
194
|
+
locations.map do |location|
|
|
195
|
+
"#{location["line"]}:#{location["column"]}"
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
179
199
|
private
|
|
180
200
|
|
|
181
201
|
# Traces the given callable with the given trace key, resource, and kwargs.
|
|
@@ -268,28 +288,13 @@ module Datadog
|
|
|
268
288
|
@type_key => parsed_error.type,
|
|
269
289
|
@stacktrace_key => parsed_error.backtrace,
|
|
270
290
|
@message_key => graphql_error['message'],
|
|
271
|
-
@locations_key =>
|
|
291
|
+
@locations_key =>
|
|
292
|
+
Datadog::Tracing::Contrib::GraphQL::UnifiedTrace.serialize_error_locations(graphql_error['locations']),
|
|
272
293
|
@path_key => graphql_error['path'],
|
|
273
294
|
)
|
|
274
295
|
)
|
|
275
296
|
end
|
|
276
297
|
end
|
|
277
|
-
|
|
278
|
-
# Serialize error's `locations` array as an array of Strings, given
|
|
279
|
-
# Span Events do not support hashes nested inside arrays.
|
|
280
|
-
#
|
|
281
|
-
# Here's an example in which `locations`:
|
|
282
|
-
# [
|
|
283
|
-
# {"line" => 3, "column" => 10},
|
|
284
|
-
# {"line" => 7, "column" => 8},
|
|
285
|
-
# ]
|
|
286
|
-
# is serialized as:
|
|
287
|
-
# ["3:10", "7:8"]
|
|
288
|
-
def serialize_error_locations(locations)
|
|
289
|
-
locations.map do |location|
|
|
290
|
-
"#{location["line"]}:#{location["column"]}"
|
|
291
|
-
end
|
|
292
|
-
end
|
|
293
298
|
end
|
|
294
299
|
end
|
|
295
300
|
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Datadog
|
|
4
|
+
module Tracing
|
|
5
|
+
module Contrib
|
|
6
|
+
module Karafka
|
|
7
|
+
# Karafka framework code, used to essentially:
|
|
8
|
+
# - handle configuration entries which are specific to Datadog tracing
|
|
9
|
+
# - instrument parts of the framework when needed
|
|
10
|
+
module Framework
|
|
11
|
+
def self.setup
|
|
12
|
+
Datadog.configure do |datadog_config|
|
|
13
|
+
karafka_config = datadog_config.tracing[:karafka]
|
|
14
|
+
activate_waterdrop!(datadog_config, karafka_config)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Apply relevant configuration from Karafka to WaterDrop
|
|
19
|
+
def self.activate_waterdrop!(datadog_config, karafka_config)
|
|
20
|
+
datadog_config.tracing.instrument(
|
|
21
|
+
:waterdrop,
|
|
22
|
+
service_name: karafka_config[:service_name],
|
|
23
|
+
distributed_tracing: karafka_config[:distributed_tracing],
|
|
24
|
+
)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -66,6 +66,18 @@ module Datadog
|
|
|
66
66
|
end
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
+
module AppPatch
|
|
70
|
+
ONLY_ONCE_PER_APP = Hash.new { |h, key| h[key] = Core::Utils::OnlyOnce.new }
|
|
71
|
+
|
|
72
|
+
def initialized!
|
|
73
|
+
ONLY_ONCE_PER_APP[self].run do
|
|
74
|
+
# Activate tracing on components related to Karafka (e.g. WaterDrop)
|
|
75
|
+
Contrib::Karafka::Framework.setup
|
|
76
|
+
end
|
|
77
|
+
super
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
69
81
|
# Patcher enables patching of 'karafka' module.
|
|
70
82
|
module Patcher
|
|
71
83
|
include Contrib::Patcher
|
|
@@ -78,9 +90,11 @@ module Datadog
|
|
|
78
90
|
|
|
79
91
|
def patch
|
|
80
92
|
require_relative 'monitor'
|
|
93
|
+
require_relative 'framework'
|
|
81
94
|
|
|
82
95
|
::Karafka::Instrumentation::Monitor.prepend(Monitor)
|
|
83
96
|
::Karafka::Messages::Messages.prepend(MessagesPatch)
|
|
97
|
+
::Karafka::App.singleton_class.prepend(AppPatch)
|
|
84
98
|
end
|
|
85
99
|
end
|
|
86
100
|
end
|
|
@@ -92,6 +92,10 @@ module Datadog
|
|
|
92
92
|
Cloudwise::Propagation.extract_and_tag_from_header!(request_span, cloudwise_header)
|
|
93
93
|
end
|
|
94
94
|
|
|
95
|
+
# 提取 CLOUDWISE-OTHER 头并添加到根 span
|
|
96
|
+
require_relative '../cloudwise/propagation'
|
|
97
|
+
Cloudwise::Propagation.extract_other_from_request!(request_span, request_headers)
|
|
98
|
+
|
|
95
99
|
# When tracing and distributed tracing are both disabled, `.active_trace` will be `nil`,
|
|
96
100
|
# Return a null object to continue operation
|
|
97
101
|
request_trace = Tracing.active_trace || TraceOperation.new
|
|
@@ -116,8 +120,8 @@ module Datadog
|
|
|
116
120
|
end
|
|
117
121
|
|
|
118
122
|
# 如果启用了 CLOUDWISE_JS_CONFIG,在响应头中添加 CLOUDWISE(用于 RUM 追踪)
|
|
119
|
-
#
|
|
120
|
-
cloudwise_js_enabled = ENV.fetch('CLOUDWISE_JS_CONFIG', '
|
|
123
|
+
# 默认关闭,可通过环境变量 CLOUDWISE_JS_CONFIG=true 开启
|
|
124
|
+
cloudwise_js_enabled = ENV.fetch('CLOUDWISE_JS_CONFIG', 'false') == 'true'
|
|
121
125
|
if cloudwise_js_enabled
|
|
122
126
|
headers ||= {}
|
|
123
127
|
require_relative '../cloudwise/propagation'
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../configuration/settings'
|
|
4
|
+
require_relative '../ext'
|
|
5
|
+
|
|
6
|
+
module Datadog
|
|
7
|
+
module Tracing
|
|
8
|
+
module Contrib
|
|
9
|
+
module WaterDrop
|
|
10
|
+
module Configuration
|
|
11
|
+
# @public_api
|
|
12
|
+
class Settings < Contrib::Configuration::Settings
|
|
13
|
+
option :enabled do |o|
|
|
14
|
+
o.type :bool
|
|
15
|
+
o.env Ext::ENV_ENABLED
|
|
16
|
+
o.default true
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
option :service_name
|
|
20
|
+
|
|
21
|
+
option :distributed_tracing, default: false, type: :bool
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../../distributed/fetcher'
|
|
4
|
+
require_relative '../../../distributed/propagation'
|
|
5
|
+
require_relative '../../../distributed/b3_multi'
|
|
6
|
+
require_relative '../../../distributed/b3_single'
|
|
7
|
+
require_relative '../../../distributed/datadog'
|
|
8
|
+
require_relative '../../../distributed/none'
|
|
9
|
+
require_relative '../../../distributed/trace_context'
|
|
10
|
+
require_relative '../../../configuration/ext'
|
|
11
|
+
|
|
12
|
+
module Datadog
|
|
13
|
+
module Tracing
|
|
14
|
+
module Contrib
|
|
15
|
+
module WaterDrop
|
|
16
|
+
module Distributed
|
|
17
|
+
# Extracts and injects propagation through Kafka message headers.
|
|
18
|
+
class Propagation < Tracing::Distributed::Propagation
|
|
19
|
+
def initialize(
|
|
20
|
+
propagation_style_inject:,
|
|
21
|
+
propagation_style_extract:,
|
|
22
|
+
propagation_extract_first:
|
|
23
|
+
)
|
|
24
|
+
super(
|
|
25
|
+
propagation_styles: {
|
|
26
|
+
Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_MULTI_HEADER =>
|
|
27
|
+
Tracing::Distributed::B3Multi.new(fetcher: Tracing::Distributed::Fetcher),
|
|
28
|
+
Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER =>
|
|
29
|
+
Tracing::Distributed::B3Single.new(fetcher: Tracing::Distributed::Fetcher),
|
|
30
|
+
Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_DATADOG =>
|
|
31
|
+
Tracing::Distributed::Datadog.new(fetcher: Tracing::Distributed::Fetcher),
|
|
32
|
+
Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_TRACE_CONTEXT =>
|
|
33
|
+
Tracing::Distributed::TraceContext.new(fetcher: Tracing::Distributed::Fetcher),
|
|
34
|
+
Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_BAGGAGE =>
|
|
35
|
+
Tracing::Distributed::Baggage.new(fetcher: Tracing::Distributed::Fetcher),
|
|
36
|
+
Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_NONE => Tracing::Distributed::None.new
|
|
37
|
+
},
|
|
38
|
+
propagation_style_inject: propagation_style_inject,
|
|
39
|
+
propagation_style_extract: propagation_style_extract,
|
|
40
|
+
propagation_extract_first: propagation_extract_first
|
|
41
|
+
)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Datadog
|
|
4
|
+
module Tracing
|
|
5
|
+
module Contrib
|
|
6
|
+
module WaterDrop
|
|
7
|
+
module Ext
|
|
8
|
+
ENV_ENABLED = 'DD_TRACE_WATERDROP_ENABLED'
|
|
9
|
+
|
|
10
|
+
SPAN_PRODUCER = 'karafka.produce'
|
|
11
|
+
|
|
12
|
+
TAG_PRODUCER = 'kafka.producer'
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../integration'
|
|
4
|
+
require_relative 'configuration/settings'
|
|
5
|
+
require_relative 'patcher'
|
|
6
|
+
|
|
7
|
+
module Datadog
|
|
8
|
+
module Tracing
|
|
9
|
+
module Contrib
|
|
10
|
+
module WaterDrop
|
|
11
|
+
# Description of WaterDrop integration
|
|
12
|
+
class Integration
|
|
13
|
+
include Contrib::Integration
|
|
14
|
+
|
|
15
|
+
# WaterDrop added class-level instrumentation in version 2.8.8.rc1
|
|
16
|
+
MINIMUM_VERSION = Gem::Version.new('2.8.8.rc1')
|
|
17
|
+
|
|
18
|
+
register_as :waterdrop, auto_patch: false
|
|
19
|
+
|
|
20
|
+
def self.version
|
|
21
|
+
Gem.loaded_specs['waterdrop']&.version
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.loaded?
|
|
25
|
+
!defined?(::WaterDrop).nil?
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.compatible?
|
|
29
|
+
super && version >= MINIMUM_VERSION
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def new_configuration
|
|
33
|
+
Configuration::Settings.new
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def patcher
|
|
37
|
+
Patcher
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'ext'
|
|
4
|
+
|
|
5
|
+
module Datadog
|
|
6
|
+
module Tracing
|
|
7
|
+
module Contrib
|
|
8
|
+
module WaterDrop
|
|
9
|
+
# Middleware to propagate tracing context in messages produced by WaterDrop
|
|
10
|
+
module Middleware
|
|
11
|
+
class << self
|
|
12
|
+
def call(message)
|
|
13
|
+
trace_op = Datadog::Tracing.active_trace
|
|
14
|
+
|
|
15
|
+
if trace_op && Datadog::Tracing::Distributed::PropagationPolicy.enabled?(
|
|
16
|
+
global_config: configuration,
|
|
17
|
+
trace: trace_op
|
|
18
|
+
)
|
|
19
|
+
WaterDrop.inject(trace_op.to_digest, message[:headers] ||= {})
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
if Datadog::DataStreams.enabled?
|
|
23
|
+
Datadog::DataStreams.set_produce_checkpoint(
|
|
24
|
+
type: 'kafka',
|
|
25
|
+
destination: message[:topic],
|
|
26
|
+
auto_instrumentation: true
|
|
27
|
+
) do |key, value|
|
|
28
|
+
message[:headers] ||= {}
|
|
29
|
+
message[:headers][key] = value
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
message
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def configuration
|
|
39
|
+
Datadog.configuration.tracing[:waterdrop]
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../patcher'
|
|
4
|
+
require_relative 'ext'
|
|
5
|
+
require_relative 'distributed/propagation'
|
|
6
|
+
|
|
7
|
+
module Datadog
|
|
8
|
+
module Tracing
|
|
9
|
+
module Contrib
|
|
10
|
+
module WaterDrop
|
|
11
|
+
# Patcher enables patching of 'waterdrop' module.
|
|
12
|
+
module Patcher
|
|
13
|
+
include Contrib::Patcher
|
|
14
|
+
|
|
15
|
+
module_function
|
|
16
|
+
|
|
17
|
+
def target_version
|
|
18
|
+
Integration.version
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def patch
|
|
22
|
+
require_relative 'producer'
|
|
23
|
+
require_relative 'middleware'
|
|
24
|
+
|
|
25
|
+
::WaterDrop::Producer.prepend(Producer)
|
|
26
|
+
::WaterDrop.instrumentation.subscribe('producer.configured') do |event|
|
|
27
|
+
producer = event[:producer]
|
|
28
|
+
|
|
29
|
+
included_middlewares = producer.middleware.instance_variable_get(:@steps)
|
|
30
|
+
producer.middleware.append(Middleware) unless included_middlewares.include?(Middleware)
|
|
31
|
+
|
|
32
|
+
if Datadog.configuration.data_streams.enabled
|
|
33
|
+
producer.monitor.subscribe('message.acknowledged') do |ack_event|
|
|
34
|
+
if Datadog::DataStreams.enabled?
|
|
35
|
+
payload = ack_event.payload
|
|
36
|
+
Datadog::DataStreams.track_kafka_produce(payload[:topic], payload[:partition], payload[:offset])
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'ext'
|
|
4
|
+
|
|
5
|
+
module Datadog
|
|
6
|
+
module Tracing
|
|
7
|
+
module Contrib
|
|
8
|
+
module WaterDrop
|
|
9
|
+
# Producer integration for WaterDrop
|
|
10
|
+
module Producer
|
|
11
|
+
%i[
|
|
12
|
+
produce_many_sync
|
|
13
|
+
produce_many_async
|
|
14
|
+
produce_sync
|
|
15
|
+
produce_async
|
|
16
|
+
].each do |method|
|
|
17
|
+
define_method(method) do |messages|
|
|
18
|
+
Datadog::Tracing.trace(Ext::SPAN_PRODUCER, resource: "waterdrop.#{__method__}") do
|
|
19
|
+
extract_span_tags(messages)
|
|
20
|
+
super(messages)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def extract_span_tags(messages)
|
|
28
|
+
messages = [messages] if messages.is_a?(Hash)
|
|
29
|
+
span = Datadog::Tracing.active_span
|
|
30
|
+
return unless span
|
|
31
|
+
|
|
32
|
+
topics = []
|
|
33
|
+
partitions = []
|
|
34
|
+
messages.each do |message|
|
|
35
|
+
topics << message[:topic]
|
|
36
|
+
partitions << message[:partition] if message.key?(:partition)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
span.set_tag(Ext::TAG_PRODUCER, id)
|
|
40
|
+
span.set_tag(Contrib::Karafka::Ext::TAG_MESSAGE_COUNT, messages.size)
|
|
41
|
+
span.set_tag(Contrib::Ext::Messaging::TAG_SYSTEM, Contrib::Karafka::Ext::TAG_SYSTEM)
|
|
42
|
+
|
|
43
|
+
span.set_tag(Contrib::Ext::Messaging::TAG_DESTINATION, topics.uniq.sort.join(','))
|
|
44
|
+
span.set_tag(Contrib::Karafka::Ext::TAG_PARTITION, partitions.uniq.sort.join(',')) if partitions.any?
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'component'
|
|
4
|
+
require_relative 'waterdrop/integration'
|
|
5
|
+
require_relative 'waterdrop/distributed/propagation'
|
|
6
|
+
|
|
7
|
+
module Datadog
|
|
8
|
+
module Tracing
|
|
9
|
+
module Contrib
|
|
10
|
+
# `WaterDrop` integration public API
|
|
11
|
+
module WaterDrop
|
|
12
|
+
def self.inject(digest, data)
|
|
13
|
+
raise 'Please invoke Datadog.configure at least once before calling this method' unless @propagation
|
|
14
|
+
|
|
15
|
+
@propagation.inject!(digest, data)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.extract(data)
|
|
19
|
+
raise 'Please invoke Datadog.configure at least once before calling this method' unless @propagation
|
|
20
|
+
|
|
21
|
+
@propagation.extract(data)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
Contrib::Component.register('waterdrop') do |config|
|
|
25
|
+
tracing = config.tracing
|
|
26
|
+
tracing.propagation_style
|
|
27
|
+
|
|
28
|
+
@propagation = WaterDrop::Distributed::Propagation.new(
|
|
29
|
+
propagation_style_inject: tracing.propagation_style_inject,
|
|
30
|
+
propagation_style_extract: tracing.propagation_style_extract,
|
|
31
|
+
propagation_extract_first: tracing.propagation_extract_first
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|