ddtrace 1.6.0 → 1.7.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 (91) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +50 -1
  3. data/ext/ddtrace_profiling_loader/extconf.rb +1 -1
  4. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time.c +66 -6
  5. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +51 -54
  6. data/ext/ddtrace_profiling_native_extension/collectors_stack.c +11 -13
  7. data/ext/ddtrace_profiling_native_extension/extconf.rb +1 -1
  8. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.c +3 -2
  9. data/ext/ddtrace_profiling_native_extension/setup_signal_handler.c +96 -0
  10. data/ext/ddtrace_profiling_native_extension/setup_signal_handler.h +7 -0
  11. data/ext/ddtrace_profiling_native_extension/stack_recorder.c +70 -18
  12. data/ext/ddtrace_profiling_native_extension/stack_recorder.h +1 -0
  13. data/lib/datadog/appsec/assets/blocked.html +98 -3
  14. data/lib/datadog/appsec/assets/blocked.json +1 -0
  15. data/lib/datadog/appsec/assets/blocked.text +5 -0
  16. data/lib/datadog/appsec/assets/waf_rules/recommended.json +35 -46
  17. data/lib/datadog/appsec/assets/waf_rules/risky.json +1 -1
  18. data/lib/datadog/appsec/assets/waf_rules/strict.json +46 -1
  19. data/lib/datadog/appsec/assets.rb +2 -2
  20. data/lib/datadog/appsec/configuration/settings.rb +6 -0
  21. data/lib/datadog/appsec/configuration.rb +4 -0
  22. data/lib/datadog/appsec/contrib/rack/reactive/request.rb +4 -8
  23. data/lib/datadog/appsec/contrib/rack/request.rb +17 -0
  24. data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +2 -2
  25. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +2 -2
  26. data/lib/datadog/appsec/contrib/rails/patcher.rb +3 -6
  27. data/lib/datadog/appsec/contrib/sinatra/ext.rb +1 -0
  28. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +1 -1
  29. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +11 -8
  30. data/lib/datadog/appsec/extensions.rb +10 -0
  31. data/lib/datadog/appsec/processor.rb +18 -0
  32. data/lib/datadog/appsec/response.rb +54 -0
  33. data/lib/datadog/core/runtime/ext.rb +1 -1
  34. data/lib/datadog/opentracer/distributed_headers.rb +5 -7
  35. data/lib/datadog/opentracer/rack_propagator.rb +0 -3
  36. data/lib/datadog/opentracer/text_map_propagator.rb +5 -7
  37. data/lib/datadog/profiling/collectors/cpu_and_wall_time.rb +10 -4
  38. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +4 -0
  39. data/lib/datadog/profiling/collectors/old_stack.rb +7 -0
  40. data/lib/datadog/profiling/exporter.rb +5 -0
  41. data/lib/datadog/profiling/old_recorder.rb +8 -0
  42. data/lib/datadog/profiling/profiler.rb +7 -0
  43. data/lib/datadog/profiling/scheduler.rb +4 -7
  44. data/lib/datadog/profiling/stack_recorder.rb +22 -0
  45. data/lib/datadog/profiling/tasks/setup.rb +0 -7
  46. data/lib/datadog/tracing/contrib/delayed_job/plugin.rb +4 -0
  47. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +2 -1
  48. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +6 -12
  49. data/lib/datadog/tracing/contrib/grpc/distributed/fetcher.rb +27 -0
  50. data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +38 -0
  51. data/lib/datadog/tracing/contrib/grpc/patcher.rb +0 -2
  52. data/lib/datadog/tracing/contrib/http/distributed/fetcher.rb +32 -0
  53. data/lib/datadog/tracing/contrib/http/distributed/propagation.rb +33 -0
  54. data/lib/datadog/tracing/contrib/kafka/consumer_event.rb +1 -0
  55. data/lib/datadog/tracing/contrib/kafka/events/produce_operation/send_messages.rb +1 -0
  56. data/lib/datadog/tracing/contrib/kafka/events/producer/deliver_messages.rb +1 -0
  57. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +2 -0
  58. data/lib/datadog/tracing/contrib/que/tracer.rb +2 -0
  59. data/lib/datadog/tracing/contrib/racecar/events/batch.rb +4 -1
  60. data/lib/datadog/tracing/contrib/racecar/events/message.rb +4 -1
  61. data/lib/datadog/tracing/contrib/rack/middlewares.rb +2 -0
  62. data/lib/datadog/tracing/contrib/redis/instrumentation.rb +2 -0
  63. data/lib/datadog/tracing/contrib/redis/integration.rb +2 -1
  64. data/lib/datadog/tracing/contrib/redis/patcher.rb +2 -3
  65. data/lib/datadog/tracing/contrib/resque/resque_job.rb +2 -0
  66. data/lib/datadog/tracing/contrib/shoryuken/tracer.rb +2 -0
  67. data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +5 -0
  68. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +5 -0
  69. data/lib/datadog/tracing/contrib/sneakers/tracer.rb +2 -0
  70. data/lib/datadog/tracing/distributed/b3.rb +66 -0
  71. data/lib/datadog/tracing/distributed/b3_single.rb +66 -0
  72. data/lib/datadog/tracing/distributed/datadog.rb +153 -0
  73. data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +1 -0
  74. data/lib/datadog/tracing/distributed/fetcher.rb +30 -0
  75. data/lib/datadog/tracing/distributed/headers/ext.rb +18 -16
  76. data/lib/datadog/tracing/distributed/helpers.rb +7 -6
  77. data/lib/datadog/tracing/distributed/propagation.rb +127 -0
  78. data/lib/datadog/tracing/propagation/http.rb +3 -106
  79. data/lib/datadog/tracing/trace_segment.rb +1 -1
  80. data/lib/ddtrace/transport/trace_formatter.rb +2 -5
  81. data/lib/ddtrace/version.rb +1 -1
  82. metadata +19 -14
  83. data/lib/datadog/tracing/distributed/headers/b3.rb +0 -55
  84. data/lib/datadog/tracing/distributed/headers/b3_single.rb +0 -67
  85. data/lib/datadog/tracing/distributed/headers/datadog.rb +0 -144
  86. data/lib/datadog/tracing/distributed/headers/parser.rb +0 -37
  87. data/lib/datadog/tracing/distributed/metadata/b3.rb +0 -55
  88. data/lib/datadog/tracing/distributed/metadata/b3_single.rb +0 -66
  89. data/lib/datadog/tracing/distributed/metadata/datadog.rb +0 -73
  90. data/lib/datadog/tracing/distributed/metadata/parser.rb +0 -34
  91. data/lib/datadog/tracing/propagation/grpc.rb +0 -98
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ require_relative 'helpers'
5
+ require_relative '../trace_digest'
6
+
7
+ module Datadog
8
+ module Tracing
9
+ module Distributed
10
+ # B3 single header-style trace propagation.
11
+ #
12
+ # DEV: Format:
13
+ # DEV: b3: {TraceId}-{SpanId}-{SamplingState}-{ParentSpanId}
14
+ # DEV: https://github.com/apache/incubator-zipkin-b3-propagation/tree/7c6e9f14d6627832bd80baa87ac7dabee7be23cf#single-header
15
+ # DEV: `{SamplingState}` and `{ParentSpanId}` are optional
16
+ #
17
+ # @see https://github.com/openzipkin/b3-propagation#single-header
18
+ class B3Single
19
+ B3_SINGLE_HEADER_KEY = 'b3'
20
+
21
+ def initialize(fetcher:, key: B3_SINGLE_HEADER_KEY)
22
+ @key = key
23
+ @fetcher = fetcher
24
+ end
25
+
26
+ def inject!(digest, env)
27
+ return if digest.nil?
28
+
29
+ # DEV: We need these to be hex encoded
30
+ value = "#{digest.trace_id.to_s(16)}-#{digest.span_id.to_s(16)}"
31
+
32
+ if digest.trace_sampling_priority
33
+ sampling_priority = Helpers.clamp_sampling_priority(
34
+ digest.trace_sampling_priority
35
+ )
36
+ value += "-#{sampling_priority}"
37
+ end
38
+
39
+ env[@key] = value
40
+ env
41
+ end
42
+
43
+ def extract(env)
44
+ fetcher = @fetcher.new(env)
45
+ value = fetcher[@key]
46
+
47
+ return unless value
48
+
49
+ parts = value.split('-')
50
+ trace_id = Helpers.value_to_id(parts[0], 16) unless parts.empty?
51
+ span_id = Helpers.value_to_id(parts[1], 16) if parts.length > 1
52
+ sampling_priority = Helpers.value_to_number(parts[2]) if parts.length > 2
53
+
54
+ # Return if this propagation is not valid
55
+ return unless trace_id && span_id
56
+
57
+ TraceDigest.new(
58
+ span_id: span_id,
59
+ trace_id: trace_id,
60
+ trace_sampling_priority: sampling_priority
61
+ )
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -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,14 @@
1
+ # frozen_string_literal: true
1
2
  # typed: true
2
3
 
3
- require_relative '../../core/configuration'
4
4
  require_relative '../sampling/ext'
5
5
 
6
6
  module Datadog
7
7
  module Tracing
8
8
  module Distributed
9
- # Helpers module provides common helper functions for distributed tracing headers
9
+ # Helpers module provides common helper functions for distributed tracing data
10
10
  module Helpers
11
- # Base provides common methods for distributed header helper classes
11
+ # Base provides common methods for distributed helper classes
12
12
  def self.clamp_sampling_priority(sampling_priority)
13
13
  # B3 doesn't have our -1 (USER_REJECT) and 2 (USER_KEEP) priorities so convert to acceptable 0/1
14
14
  if sampling_priority < 0
@@ -39,6 +39,7 @@ module Datadog
39
39
  value.sub(/^0*(?=(0$)|[^0])/, '')
40
40
  end
41
41
 
42
+ # DEV: move `base` to a keyword argument
42
43
  def self.value_to_id(value, base = 10)
43
44
  id = value_to_number(value, base)
44
45
 
@@ -51,9 +52,9 @@ module Datadog
51
52
  id < 0 ? id + (2**64) : id
52
53
  end
53
54
 
55
+ # DEV: move `base` to a keyword argument
54
56
  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.
57
+ # It's important to make a difference between no data and zero.
57
58
  return if value.nil?
58
59
 
59
60
  # Be sure we have a string
@@ -62,7 +63,7 @@ module Datadog
62
63
  # If we are parsing base16 number then truncate to 64-bit
63
64
  value = Helpers.truncate_base16_number(value) if base == 16
64
65
 
65
- # Convert header to an integer
66
+ # Convert value to an integer
66
67
  # DEV: Ruby `.to_i` will return `0` if a number could not be parsed
67
68
  num = value.to_i(base)
68
69
 
@@ -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
@@ -1,117 +1,14 @@
1
1
  # typed: false
2
2
 
3
- require_relative '../../core'
4
-
5
- require_relative '../configuration/ext'
6
- require_relative '../sampling/ext'
7
- require_relative '../distributed/headers/b3'
8
- require_relative '../distributed/headers/b3_single'
9
- require_relative '../distributed/headers/datadog'
10
-
11
- require_relative '../trace_digest'
12
- require_relative '../trace_operation'
3
+ require_relative '../contrib/http/distributed/propagation'
13
4
 
14
5
  module Datadog
15
6
  module Tracing
16
7
  module Propagation
17
8
  # Propagation::HTTP helps extracting and injecting HTTP headers.
9
+ # DEV-2.0: This file has been moved to Contrib. Should be deleted in the next release.
18
10
  # @public_api
19
- module HTTP
20
- PROPAGATION_STYLES = {
21
- Configuration::Ext::Distributed::PROPAGATION_STYLE_B3 => Distributed::Headers::B3,
22
- Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER => Distributed::Headers::B3Single,
23
- Configuration::Ext::Distributed::PROPAGATION_STYLE_DATADOG => Distributed::Headers::Datadog
24
- }.freeze
25
-
26
- # inject! populates the env with span ID, trace ID and sampling priority
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 headers.
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
- def self.inject!(digest, env)
36
- # Prevent propagation from being attempted if trace headers provided are nil.
37
- if digest.nil?
38
- Datadog.logger.debug(
39
- 'Cannot inject trace headers into env to propagate over HTTP: trace headers are nil.'.freeze
40
- )
41
- return
42
- end
43
-
44
- digest = digest.to_digest if digest.is_a?(TraceOperation)
45
-
46
- # Inject all configured propagation styles
47
- Datadog.configuration.tracing.distributed_tracing.propagation_inject_style.each do |style|
48
- propagator = PROPAGATION_STYLES[style]
49
- begin
50
- propagator.inject!(digest, env) unless propagator.nil?
51
- rescue => e
52
- Datadog.logger.error(
53
- 'Error injecting propagated trace headers into the environment. ' \
54
- "Cause: #{e} Location: #{Array(e.backtrace).first}"
55
- )
56
- end
57
- end
58
- end
59
-
60
- # extract returns trace headers containing the span ID, trace ID and
61
- # sampling priority defined in env.
62
- def self.extract(env)
63
- trace_digest = nil
64
- dd_trace_digest = nil
65
-
66
- Datadog.configuration.tracing.distributed_tracing.propagation_extract_style.each do |style|
67
- propagator = PROPAGATION_STYLES[style]
68
- next if propagator.nil?
69
-
70
- # Extract trace headers
71
- # DEV: `propagator.extract` will return `nil`, where `Propagation::HTTP#extract` will not
72
- begin
73
- extracted_trace_digest = propagator.extract(env)
74
- rescue => e
75
- Datadog.logger.error(
76
- 'Error extracting propagated trace headers from the environment. ' \
77
- "Cause: #{e} Location: #{Array(e.backtrace).first}"
78
- )
79
- end
80
-
81
- # Skip this style if no valid headers were found
82
- next if extracted_trace_digest.nil?
83
-
84
- # Keep track of the Datadog extract trace headers, we want to return
85
- # this one if we have one
86
- if extracted_trace_digest && style == Configuration::Ext::Distributed::PROPAGATION_STYLE_DATADOG
87
- dd_trace_digest = extracted_trace_digest
88
- end
89
-
90
- # No previously extracted trace headers, use the one we just extracted
91
- if trace_digest.nil?
92
- trace_digest = extracted_trace_digest
93
- else
94
- unless trace_digest.trace_id == extracted_trace_digest.trace_id \
95
- && trace_digest.span_id == extracted_trace_digest.span_id
96
- # Return an empty/new trace headers if we have a mismatch in values extracted
97
- msg = "#{trace_digest.trace_id} != #{extracted_trace_digest.trace_id} && " \
98
- "#{trace_digest.span_id} != #{extracted_trace_digest.span_id}"
99
- Datadog.logger.debug(
100
- "Cannot extract trace headers from HTTP: extracted trace headers differ, #{msg}"
101
- )
102
- # DEV: This will return from `self.extract` not this `each` block
103
- return TraceDigest.new
104
- end
105
- end
106
- end
107
-
108
- # Return the extracted trace headers if we found one or else a new empty trace headers
109
- # Always return the Datadog trace headers if one exists since it has more
110
- # information than the B3 headers e.g. origin, expanded priority
111
- # sampling values, etc
112
- dd_trace_digest || trace_digest || nil
113
- end
114
- end
11
+ HTTP = Tracing::Contrib::HTTP::Distributed::Propagation.new
115
12
  end
116
13
  end
117
14
  end
@@ -173,7 +173,7 @@ module Datadog
173
173
  end
174
174
 
175
175
  def process_id_tag
176
- meta[Core::Runtime::Ext::TAG_PID]
176
+ meta[Core::Runtime::Ext::TAG_PROCESS_ID]
177
177
  end
178
178
 
179
179
  def rate_limiter_rate_tag
@@ -94,7 +94,7 @@ module Datadog
94
94
  end
95
95
 
96
96
  def tag_lang!
97
- return if trace.lang.nil? || root_span.get_tag(Tracing::Metadata::Ext::TAG_PEER_SERVICE)
97
+ return if trace.lang.nil?
98
98
 
99
99
  root_span.set_tag(
100
100
  Core::Runtime::Ext::TAG_LANG,
@@ -114,10 +114,7 @@ module Datadog
114
114
  def tag_process_id!
115
115
  return unless trace.process_id
116
116
 
117
- root_span.set_tag(
118
- Core::Runtime::Ext::TAG_PID,
119
- trace.process_id
120
- )
117
+ root_span.set_tag(Core::Runtime::Ext::TAG_PROCESS_ID, trace.process_id)
121
118
  end
122
119
 
123
120
  def tag_rate_limiter_rate!
@@ -3,7 +3,7 @@
3
3
  module DDTrace
4
4
  module VERSION
5
5
  MAJOR = 1
6
- MINOR = 6
6
+ MINOR = 7
7
7
  PATCH = 0
8
8
  PRE = nil
9
9