ddtrace 1.6.1 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +40 -2
  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/resque/resque_job.rb +2 -0
  64. data/lib/datadog/tracing/contrib/shoryuken/tracer.rb +2 -0
  65. data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +5 -0
  66. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +5 -0
  67. data/lib/datadog/tracing/contrib/sneakers/tracer.rb +2 -0
  68. data/lib/datadog/tracing/distributed/b3.rb +66 -0
  69. data/lib/datadog/tracing/distributed/b3_single.rb +66 -0
  70. data/lib/datadog/tracing/distributed/datadog.rb +153 -0
  71. data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +1 -0
  72. data/lib/datadog/tracing/distributed/fetcher.rb +30 -0
  73. data/lib/datadog/tracing/distributed/headers/ext.rb +18 -16
  74. data/lib/datadog/tracing/distributed/helpers.rb +7 -6
  75. data/lib/datadog/tracing/distributed/propagation.rb +127 -0
  76. data/lib/datadog/tracing/propagation/http.rb +3 -106
  77. data/lib/datadog/tracing/trace_segment.rb +1 -1
  78. data/lib/ddtrace/transport/trace_formatter.rb +2 -5
  79. data/lib/ddtrace/version.rb +2 -2
  80. metadata +19 -14
  81. data/lib/datadog/tracing/distributed/headers/b3.rb +0 -55
  82. data/lib/datadog/tracing/distributed/headers/b3_single.rb +0 -67
  83. data/lib/datadog/tracing/distributed/headers/datadog.rb +0 -144
  84. data/lib/datadog/tracing/distributed/headers/parser.rb +0 -37
  85. data/lib/datadog/tracing/distributed/metadata/b3.rb +0 -55
  86. data/lib/datadog/tracing/distributed/metadata/b3_single.rb +0 -66
  87. data/lib/datadog/tracing/distributed/metadata/datadog.rb +0 -73
  88. data/lib/datadog/tracing/distributed/metadata/parser.rb +0 -34
  89. 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,8 +3,8 @@
3
3
  module DDTrace
4
4
  module VERSION
5
5
  MAJOR = 1
6
- MINOR = 6
7
- PATCH = 1
6
+ MINOR = 7
7
+ PATCH = 0
8
8
  PRE = nil
9
9
 
10
10
  STRING = [MAJOR, MINOR, PATCH, PRE].compact.join('.')