ddtrace 0.42.0 → 0.43.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 (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