ddtrace 0.42.0 → 0.43.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/add-milestone-to-pull-requests.yml +42 -0
  3. data/.github/workflows/create-next-milestone.yml +20 -0
  4. data/.simplecov +1 -1
  5. data/Appraisals +160 -132
  6. data/CHANGELOG.md +36 -0
  7. data/CONTRIBUTING.md +1 -1
  8. data/Rakefile +39 -0
  9. data/docs/DevelopmentGuide.md +2 -2
  10. data/docs/GettingStarted.md +71 -1
  11. data/lib/ddtrace.rb +2 -0
  12. data/lib/ddtrace/configuration.rb +20 -4
  13. data/lib/ddtrace/configuration/settings.rb +4 -2
  14. data/lib/ddtrace/context.rb +18 -0
  15. data/lib/ddtrace/context_provider.rb +12 -1
  16. data/lib/ddtrace/contrib/active_support/cache/instrumentation.rb +104 -3
  17. data/lib/ddtrace/contrib/active_support/cache/patcher.rb +21 -0
  18. data/lib/ddtrace/contrib/active_support/ext.rb +3 -0
  19. data/lib/ddtrace/contrib/active_support/notifications/event.rb +10 -0
  20. data/lib/ddtrace/contrib/aws/instrumentation.rb +2 -1
  21. data/lib/ddtrace/contrib/aws/patcher.rb +0 -1
  22. data/lib/ddtrace/contrib/configurable.rb +2 -0
  23. data/lib/ddtrace/contrib/configuration/resolvers/pattern_resolver.rb +4 -5
  24. data/lib/ddtrace/contrib/cucumber/configuration/settings.rb +38 -0
  25. data/lib/ddtrace/contrib/cucumber/ext.rb +19 -0
  26. data/lib/ddtrace/contrib/cucumber/formatter.rb +104 -0
  27. data/lib/ddtrace/contrib/cucumber/instrumentation.rb +24 -0
  28. data/lib/ddtrace/contrib/cucumber/integration.rb +40 -0
  29. data/lib/ddtrace/contrib/cucumber/patcher.rb +23 -0
  30. data/lib/ddtrace/contrib/delayed_job/configuration/settings.rb +1 -0
  31. data/lib/ddtrace/contrib/delayed_job/plugin.rb +3 -1
  32. data/lib/ddtrace/contrib/excon/middleware.rb +7 -1
  33. data/lib/ddtrace/contrib/faraday/patcher.rb +1 -1
  34. data/lib/ddtrace/contrib/grape/configuration/settings.rb +7 -0
  35. data/lib/ddtrace/contrib/grape/endpoint.rb +19 -4
  36. data/lib/ddtrace/contrib/http/instrumentation.rb +2 -2
  37. data/lib/ddtrace/contrib/httprb/instrumentation.rb +2 -2
  38. data/lib/ddtrace/contrib/kafka/event.rb +1 -1
  39. data/lib/ddtrace/contrib/que/configuration/settings.rb +1 -0
  40. data/lib/ddtrace/contrib/que/tracer.rb +2 -1
  41. data/lib/ddtrace/contrib/rails/patcher.rb +5 -2
  42. data/lib/ddtrace/contrib/resque/configuration/settings.rb +1 -0
  43. data/lib/ddtrace/contrib/resque/resque_job.rb +1 -1
  44. data/lib/ddtrace/contrib/rspec/configuration/settings.rb +38 -0
  45. data/lib/ddtrace/contrib/rspec/example.rb +61 -0
  46. data/lib/ddtrace/contrib/rspec/example_group.rb +61 -0
  47. data/lib/ddtrace/contrib/rspec/ext.rb +19 -0
  48. data/lib/ddtrace/contrib/rspec/integration.rb +41 -0
  49. data/lib/ddtrace/contrib/rspec/patcher.rb +25 -0
  50. data/lib/ddtrace/contrib/shoryuken/configuration/settings.rb +1 -0
  51. data/lib/ddtrace/contrib/shoryuken/tracer.rb +4 -1
  52. data/lib/ddtrace/contrib/sidekiq/configuration/settings.rb +1 -0
  53. data/lib/ddtrace/contrib/sidekiq/server_tracer.rb +4 -1
  54. data/lib/ddtrace/contrib/sneakers/configuration/settings.rb +1 -0
  55. data/lib/ddtrace/contrib/sneakers/tracer.rb +17 -20
  56. data/lib/ddtrace/contrib/status_code_matcher.rb +67 -0
  57. data/lib/ddtrace/ext/app_types.rb +1 -0
  58. data/lib/ddtrace/ext/ci.rb +265 -0
  59. data/lib/ddtrace/ext/distributed.rb +8 -2
  60. data/lib/ddtrace/ext/git.rb +12 -0
  61. data/lib/ddtrace/ext/runtime.rb +1 -0
  62. data/lib/ddtrace/ext/test.rb +24 -0
  63. data/lib/ddtrace/runtime/identity.rb +4 -5
  64. data/lib/ddtrace/sampling/rate_limiter.rb +65 -16
  65. data/lib/ddtrace/tracer.rb +14 -1
  66. data/lib/ddtrace/utils.rb +10 -11
  67. data/lib/ddtrace/utils/forking.rb +52 -0
  68. data/lib/ddtrace/version.rb +1 -1
  69. data/lib/ddtrace/writer.rb +19 -1
  70. metadata +23 -31
@@ -69,7 +69,8 @@ module Datadog
69
69
  option :propagation_extract_style do |o|
70
70
  o.default do
71
71
  # Look for all headers by default
72
- env_to_list(Ext::DistributedTracing::PROPAGATION_EXTRACT_STYLE_ENV,
72
+ env_to_list([Ext::DistributedTracing::PROPAGATION_STYLE_EXTRACT_ENV,
73
+ Ext::DistributedTracing::PROPAGATION_EXTRACT_STYLE_ENV_OLD],
73
74
  [Ext::DistributedTracing::PROPAGATION_STYLE_DATADOG,
74
75
  Ext::DistributedTracing::PROPAGATION_STYLE_B3,
75
76
  Ext::DistributedTracing::PROPAGATION_STYLE_B3_SINGLE_HEADER])
@@ -81,7 +82,8 @@ module Datadog
81
82
  option :propagation_inject_style do |o|
82
83
  o.default do
83
84
  # Only inject Datadog headers by default
84
- env_to_list(Ext::DistributedTracing::PROPAGATION_INJECT_STYLE_ENV,
85
+ env_to_list([Ext::DistributedTracing::PROPAGATION_STYLE_INJECT_ENV,
86
+ Ext::DistributedTracing::PROPAGATION_INJECT_STYLE_ENV_OLD],
85
87
  [Ext::DistributedTracing::PROPAGATION_STYLE_DATADOG])
86
88
  end
87
89
 
@@ -3,6 +3,7 @@ require 'ddtrace/diagnostics/health'
3
3
 
4
4
  require 'ddtrace/context_flush'
5
5
  require 'ddtrace/context_provider'
6
+ require 'ddtrace/utils/forking'
6
7
 
7
8
  module Datadog
8
9
  # \Context is used to keep track of a hierarchy of spans for the current
@@ -19,6 +20,8 @@ module Datadog
19
20
  # This data structure is thread-safe.
20
21
  # rubocop:disable Metrics/ClassLength
21
22
  class Context
23
+ include Datadog::Utils::Forking
24
+
22
25
  # 100k spans is about a 100Mb footprint
23
26
  DEFAULT_MAX_LENGTH = 100_000
24
27
 
@@ -232,6 +235,21 @@ module Datadog
232
235
  end
233
236
  end
234
237
 
238
+ # Generates equivalent context for forked processes.
239
+ #
240
+ # When Context from parent process is forked, child process
241
+ # should have a Context belonging to the same trace but not
242
+ # have the parent process spans.
243
+ def fork_clone
244
+ self.class.new(
245
+ trace_id: trace_id,
246
+ span_id: span_id,
247
+ sampled: sampled?,
248
+ sampling_priority: sampling_priority,
249
+ origin: origin
250
+ )
251
+ end
252
+
235
253
  private
236
254
 
237
255
  def reset(options = {})
@@ -15,7 +15,18 @@ module Datadog
15
15
 
16
16
  # Return the local context.
17
17
  def context(key = nil)
18
- key.nil? ? @context.local : @context.local(key)
18
+ current_context = key.nil? ? @context.local : @context.local(key)
19
+
20
+ # Rebuild/reset context after a fork
21
+ #
22
+ # We don't want forked processes to copy and retransmit spans
23
+ # that were generated from the parent process. Reset it such
24
+ # that it acts like a distributed trace.
25
+ current_context.after_fork! do
26
+ current_context = self.context = current_context.fork_clone
27
+ end
28
+
29
+ current_context
19
30
  end
20
31
  end
21
32
 
@@ -18,9 +18,13 @@ module Datadog
18
18
  # NOTE: the ``finish_trace_cache()`` is fired but it already has a safe-guard
19
19
  # to avoid any kind of issue.
20
20
  current_span = tracer.active_span
21
- return if payload[:action] == Ext::RESOURCE_CACHE_GET &&
22
- current_span.try(:name) == Ext::SPAN_CACHE &&
23
- current_span.try(:resource) == Ext::RESOURCE_CACHE_GET
21
+ return if current_span.try(:name) == Ext::SPAN_CACHE &&
22
+ (
23
+ payload[:action] == Ext::RESOURCE_CACHE_GET &&
24
+ current_span.try(:resource) == Ext::RESOURCE_CACHE_GET ||
25
+ payload[:action] == Ext::RESOURCE_CACHE_MGET &&
26
+ current_span.try(:resource) == Ext::RESOURCE_CACHE_MGET
27
+ )
24
28
 
25
29
  tracing_context = payload.fetch(:tracing_context)
26
30
 
@@ -59,6 +63,32 @@ module Datadog
59
63
  Datadog.logger.debug(e.message)
60
64
  end
61
65
 
66
+ def finish_trace_cache_multi(payload)
67
+ # retrieve the tracing context and continue the trace
68
+ tracing_context = payload.fetch(:tracing_context)
69
+ span = tracing_context[:dd_cache_span]
70
+ return unless span && !span.finished?
71
+
72
+ begin
73
+ # discard parameters from the cache_store configuration
74
+ if defined?(::Rails)
75
+ store, = *Array.wrap(::Rails.configuration.cache_store).flatten
76
+ span.set_tag(Ext::TAG_CACHE_BACKEND, store)
77
+ end
78
+ normalized_keys = payload.fetch(:keys, []).map do |key|
79
+ ::ActiveSupport::Cache.expand_cache_key(key)
80
+ end
81
+ cache_keys = Datadog::Utils.truncate(normalized_keys, Ext::QUANTIZE_CACHE_MAX_KEY_SIZE)
82
+ span.set_tag(Ext::TAG_CACHE_KEY_MULTI, cache_keys)
83
+
84
+ span.set_error(payload[:exception]) if payload[:exception]
85
+ ensure
86
+ span.finish
87
+ end
88
+ rescue StandardError => e
89
+ Datadog.logger.debug(e.message)
90
+ end
91
+
62
92
  # Defines instrumentation for ActiveSupport cache reading
63
93
  module Read
64
94
  def read(*args, &block)
@@ -82,6 +112,29 @@ module Datadog
82
112
  end
83
113
  end
84
114
 
115
+ # Defines instrumentation for ActiveSupport cache reading of multiple keys
116
+ module ReadMulti
117
+ def read_multi(*keys, &block)
118
+ payload = {
119
+ action: Ext::RESOURCE_CACHE_MGET,
120
+ keys: keys,
121
+ tracing_context: {}
122
+ }
123
+
124
+ begin
125
+ # process and catch cache exceptions
126
+ Instrumentation.start_trace_cache(payload)
127
+ super
128
+ rescue Exception => e
129
+ payload[:exception] = [e.class.name, e.message]
130
+ payload[:exception_object] = e
131
+ raise e
132
+ end
133
+ ensure
134
+ Instrumentation.finish_trace_cache_multi(payload)
135
+ end
136
+ end
137
+
85
138
  # Defines instrumentation for ActiveSupport cache fetching
86
139
  module Fetch
87
140
  def fetch(*args, &block)
@@ -105,6 +158,31 @@ module Datadog
105
158
  end
106
159
  end
107
160
 
161
+ # Defines instrumentation for ActiveSupport cache fetching of multiple keys
162
+ module FetchMulti
163
+ def fetch_multi(*args, &block)
164
+ # extract options hash
165
+ keys = args[-1].instance_of?(Hash) ? args[0..-2] : args
166
+ payload = {
167
+ action: Ext::RESOURCE_CACHE_MGET,
168
+ keys: keys,
169
+ tracing_context: {}
170
+ }
171
+
172
+ begin
173
+ # process and catch cache exceptions
174
+ Instrumentation.start_trace_cache(payload)
175
+ super
176
+ rescue Exception => e
177
+ payload[:exception] = [e.class.name, e.message]
178
+ payload[:exception_object] = e
179
+ raise e
180
+ end
181
+ ensure
182
+ Instrumentation.finish_trace_cache_multi(payload)
183
+ end
184
+ end
185
+
108
186
  # Defines instrumentation for ActiveSupport cache writing
109
187
  module Write
110
188
  def write(*args, &block)
@@ -128,6 +206,29 @@ module Datadog
128
206
  end
129
207
  end
130
208
 
209
+ # Defines instrumentation for ActiveSupport cache writing of multiple keys
210
+ module WriteMulti
211
+ def write_multi(hash, options = nil)
212
+ payload = {
213
+ action: Ext::RESOURCE_CACHE_MSET,
214
+ keys: hash.keys,
215
+ tracing_context: {}
216
+ }
217
+
218
+ begin
219
+ # process and catch cache exceptions
220
+ Instrumentation.start_trace_cache(payload)
221
+ super
222
+ rescue Exception => e
223
+ payload[:exception] = [e.class.name, e.message]
224
+ payload[:exception_object] = e
225
+ raise e
226
+ end
227
+ ensure
228
+ Instrumentation.finish_trace_cache_multi(payload)
229
+ end
230
+ end
231
+
131
232
  # Defines instrumentation for ActiveSupport cache deleting
132
233
  module Delete
133
234
  def delete(*args, &block)
@@ -17,8 +17,11 @@ module Datadog
17
17
 
18
18
  def patch
19
19
  patch_cache_store_read
20
+ patch_cache_store_read_multi
20
21
  patch_cache_store_fetch
22
+ patch_cache_store_fetch_multi
21
23
  patch_cache_store_write
24
+ patch_cache_store_write_multi
22
25
  patch_cache_store_delete
23
26
  end
24
27
 
@@ -30,14 +33,32 @@ module Datadog
30
33
  cache_store_class(:read).send(:prepend, Cache::Instrumentation::Read)
31
34
  end
32
35
 
36
+ def patch_cache_store_read_multi
37
+ cache_store_class(:read_multi).send(:prepend, Cache::Instrumentation::ReadMulti)
38
+ end
39
+
33
40
  def patch_cache_store_fetch
34
41
  cache_store_class(:fetch).send(:prepend, Cache::Instrumentation::Fetch)
35
42
  end
36
43
 
44
+ def patch_cache_store_fetch_multi
45
+ klass = cache_store_class(:fetch_multi)
46
+ return unless klass.public_method_defined?(:fetch_multi)
47
+
48
+ klass.send(:prepend, Cache::Instrumentation::FetchMulti)
49
+ end
50
+
37
51
  def patch_cache_store_write
38
52
  cache_store_class(:write).send(:prepend, Cache::Instrumentation::Write)
39
53
  end
40
54
 
55
+ def patch_cache_store_write_multi
56
+ klass = cache_store_class(:write_multi)
57
+ return unless klass.public_method_defined?(:write_multi)
58
+
59
+ klass.send(:prepend, Cache::Instrumentation::WriteMulti)
60
+ end
61
+
41
62
  def patch_cache_store_delete
42
63
  cache_store_class(:delete).send(:prepend, Cache::Instrumentation::Delete)
43
64
  end
@@ -12,12 +12,15 @@ module Datadog
12
12
  QUANTIZE_CACHE_MAX_KEY_SIZE = 300
13
13
  RESOURCE_CACHE_DELETE = 'DELETE'.freeze
14
14
  RESOURCE_CACHE_GET = 'GET'.freeze
15
+ RESOURCE_CACHE_MGET = 'MGET'.freeze
15
16
  RESOURCE_CACHE_SET = 'SET'.freeze
17
+ RESOURCE_CACHE_MSET = 'MSET'.freeze
16
18
  SERVICE_CACHE = 'active_support-cache'.freeze
17
19
  SPAN_CACHE = 'rails.cache'.freeze
18
20
  SPAN_TYPE_CACHE = 'cache'.freeze
19
21
  TAG_CACHE_BACKEND = 'rails.cache.backend'.freeze
20
22
  TAG_CACHE_KEY = 'rails.cache.key'.freeze
23
+ TAG_CACHE_KEY_MULTI = 'rails.cache.keys'.freeze
21
24
  end
22
25
  end
23
26
  end
@@ -56,6 +56,16 @@ module Datadog
56
56
  def tracer
57
57
  DEFAULT_TRACER
58
58
  end
59
+
60
+ def report_if_exception(span, payload)
61
+ exception = payload_exception(payload)
62
+ span.set_error(payload[:exception]) if exception
63
+ end
64
+
65
+ def payload_exception(payload)
66
+ payload[:exception_object] ||
67
+ payload[:exception] # Fallback for ActiveSupport < 5.0
68
+ end
59
69
  end
60
70
  end
61
71
  end
@@ -1,5 +1,6 @@
1
1
  require 'ddtrace/contrib/analytics'
2
2
  require 'ddtrace/contrib/aws/ext'
3
+ require 'ddtrace/ext/http'
3
4
  require 'ddtrace/ext/integration'
4
5
 
5
6
  module Datadog
@@ -26,7 +27,7 @@ module Datadog
26
27
 
27
28
  def annotate!(span, context)
28
29
  span.service = configuration[:service_name]
29
- span.span_type = Datadog::Ext::AppTypes::WEB
30
+ span.span_type = Datadog::Ext::HTTP::TYPE_OUTBOUND
30
31
  span.name = Ext::SPAN_COMMAND
31
32
  span.resource = context.safely(:resource)
32
33
 
@@ -1,5 +1,4 @@
1
1
  require 'ddtrace/contrib/patcher'
2
- require 'ddtrace/ext/app_types'
3
2
  require 'ddtrace/contrib/aws/ext'
4
3
 
5
4
  module Datadog
@@ -28,6 +28,8 @@ module Datadog
28
28
 
29
29
  # If the key has matching configuration explicitly defined for it,
30
30
  # then return true. Otherwise return false.
31
+ # Note: a resolver's resolve method should not return a fallback value
32
+ # See: https://github.com/DataDog/dd-trace-rb/issues/1204
31
33
  def configuration_for?(key)
32
34
  key = resolver.resolve(key) unless key == :default
33
35
  configurations.key?(key)
@@ -10,17 +10,16 @@ module Datadog
10
10
  def resolve(name)
11
11
  # Try to find a matching pattern
12
12
  matching_pattern = patterns.find do |pattern|
13
- # Rubocop incorrectly thinks assignment is done here...
14
- # rubocop:disable Style/ConditionalAssignment
15
13
  if pattern.is_a?(Proc)
16
- pattern === name
14
+ (pattern === name)
17
15
  else
18
- pattern === name.to_s # Co-erce to string
16
+ (pattern === name.to_s) ||
17
+ (pattern == name) # Only required during configuration time.
19
18
  end
20
19
  end
21
20
 
22
21
  # Return match or default
23
- matching_pattern || :default
22
+ matching_pattern
24
23
  end
25
24
 
26
25
  def add(pattern)
@@ -0,0 +1,38 @@
1
+ require 'ddtrace/contrib/configuration/settings'
2
+ require 'ddtrace/contrib/cucumber/ext'
3
+
4
+ module Datadog
5
+ module Contrib
6
+ module Cucumber
7
+ module Configuration
8
+ # Custom settings for the Cucumber integration
9
+ class Settings < Contrib::Configuration::Settings
10
+ option :enabled do |o|
11
+ o.default { env_to_bool(Ext::ENV_ENABLED, true) }
12
+ o.lazy
13
+ end
14
+
15
+ option :analytics_enabled do |o|
16
+ o.default { env_to_bool(Ext::ENV_ANALYTICS_ENABLED, true) }
17
+ o.lazy
18
+ end
19
+
20
+ option :analytics_sample_rate do |o|
21
+ o.default { env_to_float(Ext::ENV_ANALYTICS_SAMPLE_RATE, 1.0) }
22
+ o.lazy
23
+ end
24
+
25
+ option :service_name do |o|
26
+ o.default { Datadog.configuration.service || Ext::SERVICE_NAME }
27
+ o.lazy
28
+ end
29
+
30
+ option :operation_name do |o|
31
+ o.default { ENV.key?(Ext::ENV_OPERATION_NAME) ? ENV[Ext::ENV_OPERATION_NAME] : Ext::OPERATION_NAME }
32
+ o.lazy
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,19 @@
1
+ module Datadog
2
+ module Contrib
3
+ module Cucumber
4
+ # Cucumber integration constants
5
+ module Ext
6
+ APP = 'cucumber'.freeze
7
+ ENV_ANALYTICS_ENABLED = 'DD_TRACE_CUCUMBER_ANALYTICS_ENABLED'.freeze
8
+ ENV_ANALYTICS_SAMPLE_RATE = 'DD_TRACE_CUCUMBER_ANALYTICS_SAMPLE_RATE'.freeze
9
+ ENV_ENABLED = 'DD_TRACE_CUCUMBER_ENABLED'.freeze
10
+ ENV_OPERATION_NAME = 'DD_TRACE_CUCUMBER_OPERATION_NAME'.freeze
11
+ FRAMEWORK = 'cucumber'.freeze
12
+ OPERATION_NAME = 'cucumber.test'.freeze
13
+ SERVICE_NAME = 'cucumber'.freeze
14
+ STEP_SPAN_TYPE = 'step'.freeze
15
+ TEST_TYPE = 'test'.freeze
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,104 @@
1
+ require 'ddtrace/ext/app_types'
2
+ require 'ddtrace/ext/ci'
3
+ require 'ddtrace/ext/test'
4
+ require 'ddtrace/contrib/analytics'
5
+ require 'ddtrace/contrib/cucumber/ext'
6
+
7
+ module Datadog
8
+ module Contrib
9
+ module Cucumber
10
+ # Defines collection of instrumented Cucumber events
11
+ class Formatter
12
+ attr_reader :config
13
+ private :config
14
+
15
+ attr_reader :current_feature_span, :current_step_span
16
+ private :current_feature_span, :current_step_span
17
+
18
+ def initialize(config)
19
+ @config = config
20
+
21
+ bind_events(config)
22
+ end
23
+
24
+ def bind_events(config)
25
+ config.on_event :test_case_started, &method(:on_test_case_started)
26
+ config.on_event :test_case_finished, &method(:on_test_case_finished)
27
+ config.on_event :test_step_started, &method(:on_test_step_started)
28
+ config.on_event :test_step_finished, &method(:on_test_step_finished)
29
+ end
30
+
31
+ def on_test_case_started(event)
32
+ trace_options = {
33
+ app: Ext::APP,
34
+ resource: event.test_case.name,
35
+ service: configuration[:service_name],
36
+ span_type: Datadog::Ext::AppTypes::TEST,
37
+ tags: tags.merge(Datadog.configuration.tags)
38
+ }
39
+ @current_feature_span = tracer.trace(configuration[:operation_name], trace_options)
40
+ @current_feature_span.set_tag(Datadog::Ext::Test::TAG_FRAMEWORK, Ext::FRAMEWORK)
41
+ @current_feature_span.set_tag(Datadog::Ext::Test::TAG_NAME, event.test_case.name)
42
+ @current_feature_span.set_tag(Datadog::Ext::Test::TAG_SUITE, event.test_case.location.file)
43
+ @current_feature_span.set_tag(Datadog::Ext::Test::TAG_TYPE, Ext::TEST_TYPE)
44
+ @current_feature_span.set_tag(Datadog::Ext::Test::TAG_SPAN_KIND, Datadog::Ext::AppTypes::TEST)
45
+
46
+ # Set analytics sample rate
47
+ if Datadog::Contrib::Analytics.enabled?(configuration[:analytics_enabled])
48
+ Datadog::Contrib::Analytics.set_sample_rate(@current_feature_span, configuration[:analytics_sample_rate])
49
+ end
50
+
51
+ # Measure service stats
52
+ Contrib::Analytics.set_measured(@current_feature_span)
53
+ end
54
+
55
+ def on_test_case_finished(event)
56
+ return if @current_feature_span.nil?
57
+ @current_feature_span.status = 1 if event.result.failed?
58
+ @current_feature_span.set_tag(Datadog::Ext::Test::TAG_STATUS, status_from_result(event.result))
59
+ @current_feature_span.finish
60
+ end
61
+
62
+ def on_test_step_started(event)
63
+ trace_options = {
64
+ resource: event.test_step.to_s,
65
+ span_type: Ext::STEP_SPAN_TYPE
66
+ }
67
+ @current_step_span = tracer.trace(Ext::STEP_SPAN_TYPE, trace_options)
68
+ end
69
+
70
+ def on_test_step_finished(event)
71
+ return if @current_step_span.nil?
72
+ unless event.result.passed?
73
+ @current_step_span.set_error event.result.exception
74
+ end
75
+ @current_step_span.set_tag(Datadog::Ext::Test::TAG_STATUS, status_from_result(event.result))
76
+ @current_step_span.finish
77
+ end
78
+
79
+ private
80
+
81
+ def status_from_result(result)
82
+ if result.skipped?
83
+ return Datadog::Ext::Test::Status::SKIP
84
+ elsif result.ok?
85
+ return Datadog::Ext::Test::Status::PASS
86
+ end
87
+ Datadog::Ext::Test::Status::FAIL
88
+ end
89
+
90
+ def configuration
91
+ Datadog.configuration[:cucumber]
92
+ end
93
+
94
+ def tracer
95
+ configuration[:tracer]
96
+ end
97
+
98
+ def tags
99
+ @tags ||= Datadog::Ext::CI.tags(ENV)
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end