ddtrace 1.6.1 → 1.8.0

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 (171) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +89 -2
  3. data/README.md +2 -2
  4. data/ext/ddtrace_profiling_loader/extconf.rb +5 -2
  5. data/ext/ddtrace_profiling_native_extension/NativeExtensionDesign.md +1 -1
  6. data/ext/ddtrace_profiling_native_extension/clock_id_from_pthread.c +3 -2
  7. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time.c +81 -47
  8. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time.h +1 -1
  9. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +332 -125
  10. data/ext/ddtrace_profiling_native_extension/collectors_dynamic_sampling_rate.c +142 -0
  11. data/ext/ddtrace_profiling_native_extension/collectors_dynamic_sampling_rate.h +14 -0
  12. data/ext/ddtrace_profiling_native_extension/collectors_idle_sampling_helper.c +241 -0
  13. data/ext/ddtrace_profiling_native_extension/collectors_idle_sampling_helper.h +3 -0
  14. data/ext/ddtrace_profiling_native_extension/collectors_stack.c +11 -13
  15. data/ext/ddtrace_profiling_native_extension/extconf.rb +22 -8
  16. data/ext/ddtrace_profiling_native_extension/helpers.h +5 -0
  17. data/ext/ddtrace_profiling_native_extension/native_extension_helpers.rb +8 -0
  18. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.c +111 -26
  19. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.h +9 -0
  20. data/ext/ddtrace_profiling_native_extension/profiling.c +205 -0
  21. data/ext/ddtrace_profiling_native_extension/ruby_helpers.c +86 -0
  22. data/ext/ddtrace_profiling_native_extension/ruby_helpers.h +28 -6
  23. data/ext/ddtrace_profiling_native_extension/setup_signal_handler.c +115 -0
  24. data/ext/ddtrace_profiling_native_extension/setup_signal_handler.h +11 -0
  25. data/ext/ddtrace_profiling_native_extension/stack_recorder.c +84 -35
  26. data/ext/ddtrace_profiling_native_extension/stack_recorder.h +1 -0
  27. data/ext/ddtrace_profiling_native_extension/time_helpers.c +17 -0
  28. data/ext/ddtrace_profiling_native_extension/time_helpers.h +10 -0
  29. data/lib/datadog/appsec/assets/blocked.html +98 -3
  30. data/lib/datadog/appsec/assets/blocked.json +1 -0
  31. data/lib/datadog/appsec/assets/blocked.text +5 -0
  32. data/lib/datadog/appsec/assets/waf_rules/recommended.json +35 -46
  33. data/lib/datadog/appsec/assets/waf_rules/risky.json +1 -1
  34. data/lib/datadog/appsec/assets/waf_rules/strict.json +46 -1
  35. data/lib/datadog/appsec/assets.rb +2 -2
  36. data/lib/datadog/appsec/configuration/settings.rb +6 -0
  37. data/lib/datadog/appsec/configuration.rb +4 -0
  38. data/lib/datadog/appsec/contrib/rack/reactive/request.rb +4 -8
  39. data/lib/datadog/appsec/contrib/rack/request.rb +17 -0
  40. data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +2 -2
  41. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +2 -2
  42. data/lib/datadog/appsec/contrib/rails/patcher.rb +3 -6
  43. data/lib/datadog/appsec/contrib/sinatra/ext.rb +1 -0
  44. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +1 -1
  45. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +11 -8
  46. data/lib/datadog/appsec/extensions.rb +10 -0
  47. data/lib/datadog/appsec/processor.rb +18 -0
  48. data/lib/datadog/appsec/response.rb +54 -0
  49. data/lib/datadog/core/configuration/components.rb +27 -6
  50. data/lib/datadog/core/configuration/ext.rb +18 -0
  51. data/lib/datadog/core/configuration/settings.rb +14 -341
  52. data/lib/datadog/core/diagnostics/health.rb +4 -22
  53. data/lib/datadog/core/environment/variable_helpers.rb +58 -10
  54. data/lib/datadog/core/runtime/ext.rb +1 -1
  55. data/lib/datadog/core/utils.rb +0 -21
  56. data/lib/datadog/core.rb +21 -1
  57. data/lib/datadog/opentracer/distributed_headers.rb +7 -9
  58. data/lib/datadog/opentracer/rack_propagator.rb +0 -3
  59. data/lib/datadog/opentracer/text_map_propagator.rb +5 -7
  60. data/lib/datadog/profiling/collectors/cpu_and_wall_time.rb +10 -4
  61. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +20 -5
  62. data/lib/datadog/profiling/collectors/dynamic_sampling_rate.rb +14 -0
  63. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +68 -0
  64. data/lib/datadog/profiling/collectors/old_stack.rb +7 -0
  65. data/lib/datadog/profiling/exporter.rb +5 -0
  66. data/lib/datadog/profiling/old_recorder.rb +8 -0
  67. data/lib/datadog/profiling/profiler.rb +7 -0
  68. data/lib/datadog/profiling/scheduler.rb +4 -7
  69. data/lib/datadog/profiling/stack_recorder.rb +36 -0
  70. data/lib/datadog/profiling/tasks/setup.rb +0 -7
  71. data/lib/datadog/profiling.rb +2 -0
  72. data/lib/datadog/tracing/configuration/ext.rb +33 -3
  73. data/lib/datadog/tracing/configuration/settings.rb +433 -0
  74. data/lib/datadog/tracing/contrib/aws/configuration/settings.rb +4 -1
  75. data/lib/datadog/tracing/contrib/aws/ext.rb +1 -0
  76. data/lib/datadog/tracing/contrib/dalli/configuration/settings.rb +4 -1
  77. data/lib/datadog/tracing/contrib/dalli/ext.rb +1 -0
  78. data/lib/datadog/tracing/contrib/delayed_job/plugin.rb +4 -0
  79. data/lib/datadog/tracing/contrib/elasticsearch/configuration/settings.rb +5 -1
  80. data/lib/datadog/tracing/contrib/elasticsearch/ext.rb +1 -0
  81. data/lib/datadog/tracing/contrib/ethon/configuration/settings.rb +6 -1
  82. data/lib/datadog/tracing/contrib/ethon/ext.rb +1 -0
  83. data/lib/datadog/tracing/contrib/excon/configuration/settings.rb +5 -1
  84. data/lib/datadog/tracing/contrib/excon/ext.rb +1 -0
  85. data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +5 -1
  86. data/lib/datadog/tracing/contrib/faraday/ext.rb +1 -0
  87. data/lib/datadog/tracing/contrib/grpc/configuration/settings.rb +6 -1
  88. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +2 -1
  89. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +6 -12
  90. data/lib/datadog/tracing/contrib/grpc/distributed/fetcher.rb +27 -0
  91. data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +43 -0
  92. data/lib/datadog/tracing/contrib/grpc/ext.rb +1 -0
  93. data/lib/datadog/tracing/contrib/grpc/patcher.rb +0 -2
  94. data/lib/datadog/tracing/contrib/http/configuration/settings.rb +6 -1
  95. data/lib/datadog/tracing/contrib/http/distributed/fetcher.rb +32 -0
  96. data/lib/datadog/tracing/contrib/http/distributed/propagation.rb +38 -0
  97. data/lib/datadog/tracing/contrib/http/ext.rb +1 -0
  98. data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +6 -1
  99. data/lib/datadog/tracing/contrib/httpclient/ext.rb +1 -0
  100. data/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +6 -1
  101. data/lib/datadog/tracing/contrib/httprb/ext.rb +1 -0
  102. data/lib/datadog/tracing/contrib/kafka/consumer_event.rb +1 -0
  103. data/lib/datadog/tracing/contrib/kafka/events/produce_operation/send_messages.rb +1 -0
  104. data/lib/datadog/tracing/contrib/kafka/events/producer/deliver_messages.rb +1 -0
  105. data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +5 -1
  106. data/lib/datadog/tracing/contrib/mongodb/ext.rb +1 -0
  107. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +2 -0
  108. data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +4 -1
  109. data/lib/datadog/tracing/contrib/mysql2/ext.rb +1 -0
  110. data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +2 -2
  111. data/lib/datadog/tracing/contrib/patcher.rb +3 -2
  112. data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +4 -1
  113. data/lib/datadog/tracing/contrib/pg/ext.rb +1 -0
  114. data/lib/datadog/tracing/contrib/pg/instrumentation.rb +12 -2
  115. data/lib/datadog/tracing/contrib/presto/configuration/settings.rb +4 -1
  116. data/lib/datadog/tracing/contrib/presto/ext.rb +1 -0
  117. data/lib/datadog/tracing/contrib/propagation/sql_comment/ext.rb +1 -0
  118. data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +10 -12
  119. data/lib/datadog/tracing/contrib/que/tracer.rb +2 -0
  120. data/lib/datadog/tracing/contrib/racecar/events/batch.rb +4 -1
  121. data/lib/datadog/tracing/contrib/racecar/events/message.rb +4 -1
  122. data/lib/datadog/tracing/contrib/rack/middlewares.rb +2 -0
  123. data/lib/datadog/tracing/contrib/redis/configuration/settings.rb +4 -1
  124. data/lib/datadog/tracing/contrib/redis/ext.rb +1 -0
  125. data/lib/datadog/tracing/contrib/redis/instrumentation.rb +30 -21
  126. data/lib/datadog/tracing/contrib/redis/integration.rb +34 -2
  127. data/lib/datadog/tracing/contrib/redis/patcher.rb +18 -14
  128. data/lib/datadog/tracing/contrib/redis/quantize.rb +12 -9
  129. data/lib/datadog/tracing/contrib/redis/tags.rb +4 -6
  130. data/lib/datadog/tracing/contrib/redis/trace_middleware.rb +72 -0
  131. data/lib/datadog/tracing/contrib/resque/resque_job.rb +2 -0
  132. data/lib/datadog/tracing/contrib/rest_client/configuration/settings.rb +6 -1
  133. data/lib/datadog/tracing/contrib/rest_client/ext.rb +1 -0
  134. data/lib/datadog/tracing/contrib/shoryuken/tracer.rb +2 -0
  135. data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +5 -0
  136. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +5 -0
  137. data/lib/datadog/tracing/contrib/sneakers/tracer.rb +2 -0
  138. data/lib/datadog/{core → tracing}/diagnostics/ext.rb +1 -6
  139. data/lib/datadog/tracing/diagnostics/health.rb +40 -0
  140. data/lib/datadog/tracing/distributed/b3_multi.rb +66 -0
  141. data/lib/datadog/tracing/distributed/b3_single.rb +66 -0
  142. data/lib/datadog/tracing/distributed/datadog.rb +153 -0
  143. data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +1 -0
  144. data/lib/datadog/tracing/distributed/fetcher.rb +30 -0
  145. data/lib/datadog/tracing/distributed/headers/ext.rb +18 -16
  146. data/lib/datadog/tracing/distributed/helpers.rb +9 -7
  147. data/lib/datadog/tracing/distributed/none.rb +19 -0
  148. data/lib/datadog/tracing/distributed/propagation.rb +127 -0
  149. data/lib/datadog/tracing/distributed/trace_context.rb +369 -0
  150. data/lib/datadog/tracing/metadata/ext.rb +1 -1
  151. data/lib/datadog/tracing/propagation/http.rb +3 -106
  152. data/lib/datadog/tracing/sampling/priority_sampler.rb +11 -0
  153. data/lib/datadog/tracing/sampling/rate_sampler.rb +3 -3
  154. data/lib/datadog/tracing/span.rb +3 -19
  155. data/lib/datadog/tracing/span_operation.rb +5 -4
  156. data/lib/datadog/tracing/trace_digest.rb +75 -2
  157. data/lib/datadog/tracing/trace_operation.rb +5 -4
  158. data/lib/datadog/tracing/trace_segment.rb +1 -1
  159. data/lib/datadog/tracing/utils.rb +50 -0
  160. data/lib/ddtrace/transport/trace_formatter.rb +2 -5
  161. data/lib/ddtrace/version.rb +2 -2
  162. metadata +35 -15
  163. data/lib/datadog/tracing/distributed/headers/b3.rb +0 -55
  164. data/lib/datadog/tracing/distributed/headers/b3_single.rb +0 -67
  165. data/lib/datadog/tracing/distributed/headers/datadog.rb +0 -144
  166. data/lib/datadog/tracing/distributed/headers/parser.rb +0 -37
  167. data/lib/datadog/tracing/distributed/metadata/b3.rb +0 -55
  168. data/lib/datadog/tracing/distributed/metadata/b3_single.rb +0 -66
  169. data/lib/datadog/tracing/distributed/metadata/datadog.rb +0 -73
  170. data/lib/datadog/tracing/distributed/metadata/parser.rb +0 -34
  171. data/lib/datadog/tracing/propagation/grpc.rb +0 -98
@@ -0,0 +1,153 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ require_relative '../metadata/ext'
5
+ require_relative '../trace_digest'
6
+ require_relative 'datadog_tags_codec'
7
+
8
+ module Datadog
9
+ module Tracing
10
+ module Distributed
11
+ # Datadog-style trace propagation.
12
+ class Datadog
13
+ TRACE_ID_KEY = 'x-datadog-trace-id'
14
+ PARENT_ID_KEY = 'x-datadog-parent-id'
15
+ SAMPLING_PRIORITY_KEY = 'x-datadog-sampling-priority'
16
+ ORIGIN_KEY = 'x-datadog-origin'
17
+ # Distributed trace-level tags
18
+ TAGS_KEY = 'x-datadog-tags'
19
+
20
+ # Prefix used by all Datadog-specific distributed tags
21
+ TAGS_PREFIX = 'x-datadog-'
22
+
23
+ def initialize(
24
+ fetcher:,
25
+ trace_id_key: TRACE_ID_KEY,
26
+ parent_id_key: PARENT_ID_KEY,
27
+ sampling_priority_key: SAMPLING_PRIORITY_KEY,
28
+ origin_key: ORIGIN_KEY,
29
+ tags_key: TAGS_KEY
30
+ )
31
+ @trace_id_key = trace_id_key
32
+ @parent_id_key = parent_id_key
33
+ @sampling_priority_key = sampling_priority_key
34
+ @origin_key = origin_key
35
+ @tags_key = tags_key
36
+ @fetcher = fetcher
37
+ end
38
+
39
+ def inject!(digest, data)
40
+ return if digest.nil?
41
+
42
+ data[@trace_id_key] = digest.trace_id.to_s
43
+ data[@parent_id_key] = digest.span_id.to_s
44
+ data[@sampling_priority_key] = digest.trace_sampling_priority.to_s if digest.trace_sampling_priority
45
+ data[@origin_key] = digest.trace_origin.to_s if digest.trace_origin
46
+
47
+ inject_tags(digest, data)
48
+
49
+ data
50
+ end
51
+
52
+ def extract(data)
53
+ fetcher = @fetcher.new(data)
54
+ trace_id = fetcher.id(@trace_id_key)
55
+ parent_id = fetcher.id(@parent_id_key)
56
+ sampling_priority = fetcher.number(@sampling_priority_key)
57
+ origin = fetcher[@origin_key]
58
+
59
+ # Return early if this propagation is not valid
60
+ # DEV: To be valid we need to have a trace id and a parent id
61
+ # or when it is a synthetics trace, just the trace id.
62
+ # DEV: `Fetcher#id` will not return 0
63
+ return unless (trace_id && parent_id) || (origin && trace_id)
64
+
65
+ trace_distributed_tags = extract_tags(fetcher)
66
+
67
+ TraceDigest.new(
68
+ span_id: parent_id,
69
+ trace_id: trace_id,
70
+ trace_origin: origin,
71
+ trace_sampling_priority: sampling_priority,
72
+ trace_distributed_tags: trace_distributed_tags,
73
+ )
74
+ end
75
+
76
+ private
77
+
78
+ # Export trace distributed tags through the `x-datadog-tags` key.
79
+ #
80
+ # DEV: This method accesses global state (the active trace) to record its error state as a trace tag.
81
+ # DEV: This means errors cannot be reported if there's not active span.
82
+ # DEV: Ideally, we'd have a dedicated error reporting stream for all of ddtrace.
83
+ def inject_tags(digest, data)
84
+ return if digest.trace_distributed_tags.nil? || digest.trace_distributed_tags.empty?
85
+ return set_tags_propagation_error(reason: 'disabled') if tags_disabled?
86
+
87
+ tags = DatadogTagsCodec.encode(digest.trace_distributed_tags)
88
+
89
+ return set_tags_propagation_error(reason: 'inject_max_size') if tags_too_large?(tags.size, scenario: 'inject')
90
+
91
+ data[@tags_key] = tags
92
+ rescue => e
93
+ set_tags_propagation_error(reason: 'encoding_error')
94
+ ::Datadog.logger.warn(
95
+ "Failed to inject x-datadog-tags: #{e.class.name} #{e.message} at #{Array(e.backtrace).first}"
96
+ )
97
+ end
98
+
99
+ # Import `x-datadog-tags` tags as trace distributed tags.
100
+ # Only tags that have the `_dd.p.` prefix are processed.
101
+ #
102
+ # DEV: This method accesses global state (the active trace) to record its error state as a trace tag.
103
+ # DEV: This means errors cannot be reported if there's not active span.
104
+ # DEV: Ideally, we'd have a dedicated error reporting stream for all of ddtrace.
105
+ def extract_tags(fetcher)
106
+ tags = fetcher[@tags_key]
107
+
108
+ return if !tags || tags.empty?
109
+ return set_tags_propagation_error(reason: 'disabled') if tags_disabled?
110
+ return set_tags_propagation_error(reason: 'extract_max_size') if tags_too_large?(tags.size, scenario: 'extract')
111
+
112
+ tags_hash = DatadogTagsCodec.decode(tags)
113
+ # Only extract keys with the expected Datadog prefix
114
+ tags_hash.select! do |key, _|
115
+ key.start_with?(Tracing::Metadata::Ext::Distributed::TAGS_PREFIX) && key != EXCLUDED_TAG
116
+ end
117
+ tags_hash
118
+ rescue => e
119
+ set_tags_propagation_error(reason: 'decoding_error')
120
+ ::Datadog.logger.warn(
121
+ "Failed to extract x-datadog-tags: #{e.class.name} #{e.message} at #{Array(e.backtrace).first}"
122
+ )
123
+ end
124
+
125
+ def set_tags_propagation_error(reason:)
126
+ active_trace = Tracing.active_trace
127
+ active_trace.set_tag('_dd.propagation_error', reason) if active_trace
128
+ nil
129
+ end
130
+
131
+ def tags_disabled?
132
+ ::Datadog.configuration.tracing.x_datadog_tags_max_length <= 0
133
+ end
134
+
135
+ def tags_too_large?(size, scenario:)
136
+ return false if size <= ::Datadog.configuration.tracing.x_datadog_tags_max_length
137
+
138
+ ::Datadog.logger.warn(
139
+ "Failed to #{scenario} x-datadog-tags: tags are too large for configured limit (size:#{size} >= " \
140
+ "limit:#{::Datadog.configuration.tracing.x_datadog_tags_max_length}). This limit can be configured " \
141
+ 'through the DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH environment variable.'
142
+ )
143
+
144
+ true
145
+ end
146
+
147
+ # We want to exclude tags that we don't want to propagate downstream.
148
+ EXCLUDED_TAG = '_dd.p.upstream_services'
149
+ private_constant :EXCLUDED_TAG
150
+ end
151
+ end
152
+ end
153
+ end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # typed: false
2
3
 
3
4
  module Datadog
4
5
  module Tracing
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ require_relative 'helpers'
5
+
6
+ module Datadog
7
+ module Tracing
8
+ module Distributed
9
+ # Common fetcher that retrieves fields from a Hash data input
10
+ class Fetcher
11
+ # @param data [Hash]
12
+ def initialize(data)
13
+ @data = data
14
+ end
15
+
16
+ def [](key)
17
+ @data[key]
18
+ end
19
+
20
+ def id(key, base: 10)
21
+ Helpers.value_to_id(self[key], base)
22
+ end
23
+
24
+ def number(key, base: 10)
25
+ Helpers.value_to_number(self[key], base)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,31 +1,33 @@
1
+ # frozen_string_literal: true
1
2
  # typed: true
2
3
 
3
4
  module Datadog
4
5
  module Tracing
5
6
  module Distributed
6
7
  module Headers
7
- # HTTP headers one should set for distributed tracing.
8
- # These are cross-language (eg: Python, Go and other implementations should honor these)
8
+ # DEV-2.0: This module only exists for backwards compatibility with the public API. It should be removed.
9
+ # @deprecated use [Datadog::Tracing::Distributed::Ext]
9
10
  # @public_api
10
11
  module Ext
11
- HTTP_HEADER_TRACE_ID = 'x-datadog-trace-id'.freeze
12
- HTTP_HEADER_PARENT_ID = 'x-datadog-parent-id'.freeze
13
- HTTP_HEADER_SAMPLING_PRIORITY = 'x-datadog-sampling-priority'.freeze
14
- HTTP_HEADER_ORIGIN = 'x-datadog-origin'.freeze
12
+ HTTP_HEADER_TRACE_ID = 'x-datadog-trace-id'
13
+ HTTP_HEADER_PARENT_ID = 'x-datadog-parent-id'
14
+ HTTP_HEADER_SAMPLING_PRIORITY = 'x-datadog-sampling-priority'
15
+ HTTP_HEADER_ORIGIN = 'x-datadog-origin'
15
16
  # Distributed trace-level tags
16
- HTTP_HEADER_TAGS = 'x-datadog-tags'.freeze
17
+ HTTP_HEADER_TAGS = 'x-datadog-tags'
17
18
 
18
- # B3 headers used for distributed tracing
19
- B3_HEADER_TRACE_ID = 'x-b3-traceid'.freeze
20
- B3_HEADER_SPAN_ID = 'x-b3-spanid'.freeze
21
- B3_HEADER_SAMPLED = 'x-b3-sampled'.freeze
22
- B3_HEADER_SINGLE = 'b3'.freeze
19
+ # B3 keys used for distributed tracing.
20
+ # @see https://github.com/openzipkin/b3-propagation
21
+ B3_HEADER_TRACE_ID = 'x-b3-traceid'
22
+ B3_HEADER_SPAN_ID = 'x-b3-spanid'
23
+ B3_HEADER_SAMPLED = 'x-b3-sampled'
24
+ B3_HEADER_SINGLE = 'b3'
23
25
 
24
26
  # gRPC metadata keys for distributed tracing. https://github.com/grpc/grpc-go/blob/v1.10.x/Documentation/grpc-metadata.md
25
- GRPC_METADATA_TRACE_ID = 'x-datadog-trace-id'.freeze
26
- GRPC_METADATA_PARENT_ID = 'x-datadog-parent-id'.freeze
27
- GRPC_METADATA_SAMPLING_PRIORITY = 'x-datadog-sampling-priority'.freeze
28
- GRPC_METADATA_ORIGIN = 'x-datadog-origin'.freeze
27
+ GRPC_METADATA_TRACE_ID = 'x-datadog-trace-id'
28
+ GRPC_METADATA_PARENT_ID = 'x-datadog-parent-id'
29
+ GRPC_METADATA_SAMPLING_PRIORITY = 'x-datadog-sampling-priority'
30
+ GRPC_METADATA_ORIGIN = 'x-datadog-origin'
29
31
  end
30
32
  end
31
33
  end
@@ -1,14 +1,15 @@
1
+ # frozen_string_literal: true
1
2
  # typed: true
2
3
 
3
- require_relative '../../core/configuration'
4
4
  require_relative '../sampling/ext'
5
+ require_relative '../utils'
5
6
 
6
7
  module Datadog
7
8
  module Tracing
8
9
  module Distributed
9
- # Helpers module provides common helper functions for distributed tracing headers
10
+ # Helpers module provides common helper functions for distributed tracing data
10
11
  module Helpers
11
- # Base provides common methods for distributed header helper classes
12
+ # Base provides common methods for distributed helper classes
12
13
  def self.clamp_sampling_priority(sampling_priority)
13
14
  # B3 doesn't have our -1 (USER_REJECT) and 2 (USER_KEEP) priorities so convert to acceptable 0/1
14
15
  if sampling_priority < 0
@@ -39,6 +40,7 @@ module Datadog
39
40
  value.sub(/^0*(?=(0$)|[^0])/, '')
40
41
  end
41
42
 
43
+ # DEV: move `base` to a keyword argument
42
44
  def self.value_to_id(value, base = 10)
43
45
  id = value_to_number(value, base)
44
46
 
@@ -46,14 +48,14 @@ module Datadog
46
48
  return if id.nil?
47
49
 
48
50
  # Zero or greater than max allowed value of 2**64
49
- return if id.zero? || id > Span::EXTERNAL_MAX_ID
51
+ return if id.zero? || id > Tracing::Utils::EXTERNAL_MAX_ID
50
52
 
51
53
  id < 0 ? id + (2**64) : id
52
54
  end
53
55
 
56
+ # DEV: move `base` to a keyword argument
54
57
  def self.value_to_number(value, base = 10)
55
- # It's important to make a difference between no header,
56
- # and a header defined to zero.
58
+ # It's important to make a difference between no data and zero.
57
59
  return if value.nil?
58
60
 
59
61
  # Be sure we have a string
@@ -62,7 +64,7 @@ module Datadog
62
64
  # If we are parsing base16 number then truncate to 64-bit
63
65
  value = Helpers.truncate_base16_number(value) if base == 16
64
66
 
65
- # Convert header to an integer
67
+ # Convert value to an integer
66
68
  # DEV: Ruby `.to_i` will return `0` if a number could not be parsed
67
69
  num = value.to_i(base)
68
70
 
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+ # typed: false
3
+
4
+ module Datadog
5
+ module Tracing
6
+ module Distributed
7
+ # Propagator that does not inject nor extract data. It performs no operation.
8
+ # Supported for feature parity with OpenTelemetry.
9
+ # @see https://github.com/open-telemetry/opentelemetry-specification/blob/255a6c52b8914a2ed7e26bb5585abecab276aafc/specification/sdk-environment-variables.md?plain=1#L88
10
+ class None
11
+ # No-op
12
+ def inject!(_digest, _data); end
13
+
14
+ # No-op
15
+ def extract(_data); end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+ # typed: false
3
+
4
+ require_relative '../configuration/ext'
5
+ require_relative '../trace_digest'
6
+ require_relative '../trace_operation'
7
+
8
+ module Datadog
9
+ module Tracing
10
+ module Distributed
11
+ # Provides extraction and injection of distributed trace data.
12
+ class Propagation
13
+ # DEV: This class should receive the value for
14
+ # DEV: `Datadog.configuration.tracing.distributed_tracing.propagation_inject_style`
15
+ # DEV: at initialization time, instead of constantly reading global values.
16
+ # DEV: This means this class should be reconfigured on `Datadog.configure` calls, thus
17
+ # DEV: singleton instances should not used as they will become stale.
18
+ #
19
+ # @param propagation_styles [Hash<String,Object>]
20
+ def initialize(propagation_styles:)
21
+ @propagation_styles = propagation_styles
22
+ end
23
+
24
+ # inject! populates the env with span ID, trace ID and sampling priority
25
+ #
26
+ # This method will never raise errors, but instead log them to `Datadog.logger`.
27
+ #
28
+ # DEV-2.0: inject! should work without arguments, injecting the active_trace's digest
29
+ # DEV-2.0: and returning a new Hash with the injected data.
30
+ # DEV-2.0: inject! should also accept either a `trace` or a `digest`, as a `trace`
31
+ # DEV-2.0: argument is the common use case, but also allows us to set error tags in the `trace`
32
+ # DEV-2.0: if needed.
33
+ # DEV-2.0: Ideally, we'd have a separate stream to report tracer errors and never
34
+ # DEV-2.0: touch the active span.
35
+ #
36
+ # @param digest [TraceDigest]
37
+ # @param data [Hash]
38
+ # @return [Boolean] `true` if injected successfully, `false` if no propagation style is configured
39
+ # @return [nil] in case of error, see `Datadog.logger` output for details.
40
+ def inject!(digest, data)
41
+ if digest.nil?
42
+ ::Datadog.logger.debug('Cannot inject distributed trace data: digest is nil.')
43
+ return nil
44
+ end
45
+
46
+ digest = digest.to_digest if digest.respond_to?(:to_digest)
47
+
48
+ result = false
49
+
50
+ # Inject all configured propagation styles
51
+ ::Datadog.configuration.tracing.distributed_tracing.propagation_inject_style.each do |style|
52
+ propagator = @propagation_styles[style]
53
+ begin
54
+ if propagator
55
+ propagator.inject!(digest, data)
56
+ result = true
57
+ end
58
+ rescue => e
59
+ result = nil
60
+ ::Datadog.logger.error(
61
+ "Error injecting distributed trace data. Cause: #{e} Location: #{Array(e.backtrace).first}"
62
+ )
63
+ end
64
+ end
65
+
66
+ result
67
+ end
68
+
69
+ # extract returns {TraceDigest} containing the distributed trace information.
70
+ # sampling priority defined in data.
71
+ #
72
+ # This method will never raise errors, but instead log them to `Datadog.logger`.
73
+ #
74
+ # @param data [Hash]
75
+ def extract(data)
76
+ trace_digest = nil
77
+ dd_trace_digest = nil
78
+
79
+ ::Datadog.configuration.tracing.distributed_tracing.propagation_extract_style.each do |style|
80
+ propagator = @propagation_styles[style]
81
+ next if propagator.nil?
82
+
83
+ begin
84
+ extracted_trace_digest = propagator.extract(data)
85
+ rescue => e
86
+ ::Datadog.logger.error(
87
+ 'Error extracting distributed trace data. ' \
88
+ "Cause: #{e} Location: #{Array(e.backtrace).first}"
89
+ )
90
+ end
91
+
92
+ # Skip if no valid data was found
93
+ next if extracted_trace_digest.nil?
94
+
95
+ # Keep track of the Datadog extracted digest, we want to return it if we have it.
96
+ if extracted_trace_digest && style == Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_DATADOG
97
+ dd_trace_digest = extracted_trace_digest
98
+ end
99
+
100
+ # No previously extracted trace data, use the one we just extracted
101
+ if trace_digest.nil?
102
+ trace_digest = extracted_trace_digest
103
+ else
104
+ unless trace_digest.trace_id == extracted_trace_digest.trace_id \
105
+ && trace_digest.span_id == extracted_trace_digest.span_id
106
+ # We have two mismatched propagation contexts
107
+ ::Datadog.logger.debug do
108
+ 'Cannot extract distributed trace data: extracted styles differ, ' \
109
+ "#{trace_digest.trace_id} != #{extracted_trace_digest.trace_id} && " \
110
+ "#{trace_digest.span_id} != #{extracted_trace_digest.span_id}"
111
+ end
112
+
113
+ # It's safer to create a new context than to attach ourselves to the wrong context
114
+ return TraceDigest.new # Early return from the whole method
115
+ end
116
+ end
117
+ end
118
+
119
+ # Return the extracted trace digest if we found one or else a new empty digest.
120
+ # Always return the Datadog trace digest if one exists since it has more
121
+ # information than the B3 digest, e.g. origin, priority sampling values.
122
+ dd_trace_digest || trace_digest || nil
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end