ddtrace 0.33.1 → 0.34.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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +3 -0
  3. data/Appraisals +29 -5
  4. data/CHANGELOG.md +23 -1
  5. data/Rakefile +72 -11
  6. data/docker-compose.yml +20 -0
  7. data/docs/GettingStarted.md +63 -10
  8. data/lib/ddtrace.rb +4 -0
  9. data/lib/ddtrace/analytics.rb +7 -0
  10. data/lib/ddtrace/configuration/base.rb +2 -1
  11. data/lib/ddtrace/configuration/option.rb +9 -1
  12. data/lib/ddtrace/configuration/option_definition.rb +0 -4
  13. data/lib/ddtrace/configuration/settings.rb +78 -23
  14. data/lib/ddtrace/contrib/action_cable/events/perform_action.rb +3 -0
  15. data/lib/ddtrace/contrib/action_pack/action_controller/instrumentation.rb +4 -0
  16. data/lib/ddtrace/contrib/action_view/events/render_partial.rb +3 -0
  17. data/lib/ddtrace/contrib/action_view/events/render_template.rb +3 -0
  18. data/lib/ddtrace/contrib/action_view/instrumentation/partial_renderer.rb +3 -0
  19. data/lib/ddtrace/contrib/action_view/instrumentation/template_renderer.rb +6 -0
  20. data/lib/ddtrace/contrib/active_model_serializers/event.rb +3 -0
  21. data/lib/ddtrace/contrib/active_record/events/instantiation.rb +3 -0
  22. data/lib/ddtrace/contrib/analytics.rb +4 -0
  23. data/lib/ddtrace/contrib/configuration/resolvers/pattern_resolver.rb +39 -0
  24. data/lib/ddtrace/contrib/delayed_job/plugin.rb +4 -0
  25. data/lib/ddtrace/contrib/ethon/configuration/settings.rb +1 -0
  26. data/lib/ddtrace/contrib/ethon/easy_patch.rb +22 -13
  27. data/lib/ddtrace/contrib/ethon/integration.rb +5 -0
  28. data/lib/ddtrace/contrib/excon/integration.rb +5 -0
  29. data/lib/ddtrace/contrib/excon/middleware.rb +12 -9
  30. data/lib/ddtrace/contrib/faraday/integration.rb +5 -0
  31. data/lib/ddtrace/contrib/faraday/middleware.rb +20 -32
  32. data/lib/ddtrace/contrib/faraday/patcher.rb +6 -1
  33. data/lib/ddtrace/contrib/faraday/rack_builder.rb +18 -0
  34. data/lib/ddtrace/contrib/grape/endpoint.rb +9 -0
  35. data/lib/ddtrace/contrib/grpc/datadog_interceptor/server.rb +3 -0
  36. data/lib/ddtrace/contrib/http/configuration/settings.rb +1 -0
  37. data/lib/ddtrace/contrib/http/instrumentation.rb +65 -21
  38. data/lib/ddtrace/contrib/http/integration.rb +5 -0
  39. data/lib/ddtrace/contrib/http_annotation_helper.rb +10 -0
  40. data/lib/ddtrace/contrib/presto/configuration/settings.rb +8 -6
  41. data/lib/ddtrace/contrib/presto/instrumentation.rb +8 -8
  42. data/lib/ddtrace/contrib/racecar/event.rb +4 -0
  43. data/lib/ddtrace/contrib/rack/middlewares.rb +4 -0
  44. data/lib/ddtrace/contrib/rake/instrumentation.rb +4 -0
  45. data/lib/ddtrace/contrib/resque/resque_job.rb +4 -0
  46. data/lib/ddtrace/contrib/shoryuken/tracer.rb +4 -0
  47. data/lib/ddtrace/contrib/sidekiq/server_tracer.rb +4 -0
  48. data/lib/ddtrace/contrib/sinatra/tracer.rb +3 -0
  49. data/lib/ddtrace/contrib/sinatra/tracer_middleware.rb +3 -0
  50. data/lib/ddtrace/contrib/sucker_punch/instrumentation.rb +14 -0
  51. data/lib/ddtrace/correlation.rb +12 -5
  52. data/lib/ddtrace/environment.rb +4 -0
  53. data/lib/ddtrace/event.rb +52 -0
  54. data/lib/ddtrace/ext/analytics.rb +1 -0
  55. data/lib/ddtrace/ext/correlation.rb +10 -0
  56. data/lib/ddtrace/ext/environment.rb +13 -0
  57. data/lib/ddtrace/metrics.rb +7 -0
  58. data/lib/ddtrace/opentelemetry/extensions.rb +13 -0
  59. data/lib/ddtrace/opentelemetry/span.rb +33 -0
  60. data/lib/ddtrace/span.rb +2 -1
  61. data/lib/ddtrace/tracer.rb +13 -3
  62. data/lib/ddtrace/version.rb +2 -2
  63. data/lib/ddtrace/worker.rb +20 -0
  64. data/lib/ddtrace/workers/async.rb +165 -0
  65. data/lib/ddtrace/workers/loop.rb +105 -0
  66. data/lib/ddtrace/workers/polling.rb +48 -0
  67. data/lib/ddtrace/workers/queue.rb +39 -0
  68. metadata +15 -2
@@ -1,27 +1,34 @@
1
+ require 'ddtrace/ext/correlation'
2
+ require 'ddtrace/environment'
3
+
1
4
  module Datadog
2
5
  # Contains behavior for managing correlations with tracing
3
6
  # e.g. Retrieve a correlation to the current trace for logging, etc.
4
7
  module Correlation
5
8
  # Struct representing correlation
6
- Identifier = Struct.new(:trace_id, :span_id) do
9
+ Identifier = Struct.new(:trace_id, :span_id, :env, :version) do
7
10
  def initialize(*args)
8
11
  super
9
12
  self.trace_id = trace_id || 0
10
13
  self.span_id = span_id || 0
14
+ self.env = env || Datadog.configuration.env
15
+ self.version = version || Datadog.configuration.version
11
16
  end
12
17
 
13
18
  def to_s
14
- "dd.trace_id=#{trace_id} dd.span_id=#{span_id}"
19
+ str = "#{Ext::Correlation::ATTR_TRACE_ID}=#{trace_id}"
20
+ str += " #{Ext::Correlation::ATTR_SPAN_ID}=#{span_id}"
21
+ str += " #{Ext::Correlation::ATTR_ENV}=#{env}"
22
+ str += " #{Ext::Correlation::ATTR_VERSION}=#{version}"
23
+ str
15
24
  end
16
25
  end.freeze
17
26
 
18
- NULL_IDENTIFIER = Identifier.new.freeze
19
-
20
27
  module_function
21
28
 
22
29
  # Produces a CorrelationIdentifier from the Context provided
23
30
  def identifier_from_context(context)
24
- return NULL_IDENTIFIER if context.nil?
31
+ return Identifier.new.freeze if context.nil?
25
32
  Identifier.new(context.trace_id, context.span_id).freeze
26
33
  end
27
34
  end
@@ -1,3 +1,5 @@
1
+ require 'ddtrace/ext/environment'
2
+
1
3
  module Datadog
2
4
  # Namespace for handling application environment
3
5
  module Environment
@@ -19,5 +21,7 @@ module Datadog
19
21
  end
20
22
  end
21
23
  end
24
+
25
+ extend Helpers
22
26
  end
23
27
  end
@@ -0,0 +1,52 @@
1
+ require 'ddtrace/logger'
2
+
3
+ module Datadog
4
+ # A simple pub-sub event model for components to exchange messages through.
5
+ class Event
6
+ attr_reader \
7
+ :name,
8
+ :subscriptions
9
+
10
+ def initialize(name)
11
+ @name = name
12
+ @subscriptions = {}
13
+ @mutex = Mutex.new
14
+ end
15
+
16
+ def subscribe(key, &block)
17
+ raise ArgumentError, 'Must give a block to subscribe!' unless block
18
+
19
+ @mutex.synchronize do
20
+ subscriptions[key] = block
21
+ end
22
+ end
23
+
24
+ def unsubscribe(key)
25
+ @mutex.synchronize do
26
+ subscriptions.delete(key)
27
+ end
28
+ end
29
+
30
+ def unsubscribe_all!
31
+ @mutex.synchronize do
32
+ subscriptions.clear
33
+ end
34
+
35
+ true
36
+ end
37
+
38
+ def publish(*args)
39
+ @mutex.synchronize do
40
+ subscriptions.each do |key, block|
41
+ begin
42
+ block.call(*args)
43
+ rescue StandardError => e
44
+ Datadog::Logger.log.debug("Error while handling '#{key}' for '#{name}' event: #{e.message}")
45
+ end
46
+ end
47
+
48
+ true
49
+ end
50
+ end
51
+ end
52
+ end
@@ -5,6 +5,7 @@ module Datadog
5
5
  DEFAULT_SAMPLE_RATE = 1.0
6
6
  ENV_TRACE_ANALYTICS_ENABLED = 'DD_TRACE_ANALYTICS_ENABLED'.freeze
7
7
  TAG_ENABLED = 'analytics.enabled'.freeze
8
+ TAG_MEASURED = '_dd.measured'.freeze
8
9
  TAG_SAMPLE_RATE = '_dd1.sr.eausr'.freeze
9
10
  end
10
11
  end
@@ -0,0 +1,10 @@
1
+ module Datadog
2
+ module Ext
3
+ module Correlation
4
+ ATTR_ENV = 'dd.env'.freeze
5
+ ATTR_SPAN_ID = 'dd.span_id'.freeze
6
+ ATTR_TRACE_ID = 'dd.trace_id'.freeze
7
+ ATTR_VERSION = 'dd.version'.freeze
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,13 @@
1
+ module Datadog
2
+ module Ext
3
+ module Environment
4
+ ENV_ENVIRONMENT = 'DD_ENV'.freeze
5
+ ENV_SERVICE = 'DD_SERVICE'.freeze
6
+ ENV_TAGS = 'DD_TAGS'.freeze
7
+ ENV_VERSION = 'DD_VERSION'.freeze
8
+
9
+ TAG_ENV = 'env'.freeze
10
+ TAG_VERSION = 'version'.freeze
11
+ end
12
+ end
13
+ end
@@ -2,6 +2,7 @@ require 'ddtrace/ext/metrics'
2
2
 
3
3
  require 'set'
4
4
  require 'logger'
5
+ require 'ddtrace/environment'
5
6
  require 'ddtrace/utils/time'
6
7
  require 'ddtrace/runtime/identity'
7
8
 
@@ -151,6 +152,12 @@ module Datadog
151
152
  # and defaults are unfrozen for mutation in Statsd.
152
153
  DEFAULT.dup.tap do |options|
153
154
  options[:tags] = options[:tags].dup
155
+
156
+ env = Datadog.configuration.env
157
+ options[:tags] << "#{Datadog::Ext::Environment::TAG_ENV}:#{env}" unless env.nil?
158
+
159
+ version = Datadog.configuration.version
160
+ options[:tags] << "#{Datadog::Ext::Environment::TAG_VERSION}:#{version}" unless version.nil?
154
161
  end
155
162
  end
156
163
  end
@@ -0,0 +1,13 @@
1
+ require 'ddtrace/span'
2
+ require 'ddtrace/opentelemetry/span'
3
+
4
+ module Datadog
5
+ module OpenTelemetry
6
+ # Defines extensions to ddtrace for OpenTelemetry support
7
+ module Extensions
8
+ def self.extended(base)
9
+ Datadog::Span.send(:prepend, OpenTelemetry::Span)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,33 @@
1
+ require 'ddtrace/ext/environment'
2
+
3
+ module Datadog
4
+ module OpenTelemetry
5
+ # Extensions for Datadog::Span
6
+ module Span
7
+ TAG_SERVICE_NAME = 'service.name'.freeze
8
+ TAG_SERVICE_VERSION = 'service.version'.freeze
9
+
10
+ def set_tag(key, value)
11
+ # Configure sampling priority if they give us a forced tracing tag
12
+ # DEV: Do not set if the value they give us is explicitly "false"
13
+ case key
14
+ when TAG_SERVICE_NAME
15
+ if defined?(super)
16
+ # Set original tag and Datadog version tag
17
+ self.service = value
18
+ super
19
+ end
20
+ when TAG_SERVICE_VERSION
21
+ if defined?(super)
22
+ # Set original tag and Datadog version tag
23
+ super
24
+ super(Datadog::Ext::Environment::TAG_VERSION, value)
25
+ end
26
+ else
27
+ # Otherwise, set the tag normally.
28
+ super if defined?(super)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -4,6 +4,7 @@ require 'thread'
4
4
  require 'ddtrace/utils'
5
5
  require 'ddtrace/ext/errors'
6
6
  require 'ddtrace/ext/priority'
7
+ require 'ddtrace/environment'
7
8
  require 'ddtrace/analytics'
8
9
  require 'ddtrace/forced_tracing'
9
10
  require 'ddtrace/diagnostics/health'
@@ -172,7 +173,7 @@ module Datadog
172
173
  # spans without a service would be dropped, so here we provide a default.
173
174
  # This should really never happen with integrations in contrib, as a default
174
175
  # service is always set. It's only for custom instrumentation.
175
- @service ||= @tracer.default_service unless @tracer.nil?
176
+ @service ||= (Datadog.configuration.service || (@tracer && @tracer.default_service))
176
177
 
177
178
  begin
178
179
  @context.close_span(self)
@@ -3,6 +3,7 @@ require 'thread'
3
3
  require 'logger'
4
4
  require 'pathname'
5
5
 
6
+ require 'ddtrace/environment'
6
7
  require 'ddtrace/span'
7
8
  require 'ddtrace/context'
8
9
  require 'ddtrace/logger'
@@ -83,7 +84,7 @@ module Datadog
83
84
  end
84
85
 
85
86
  @mutex = Mutex.new
86
- @tags = {}
87
+ @tags = options.fetch(:tags, Datadog.configuration.tags)
87
88
 
88
89
  # Enable priority sampling by default
89
90
  activate_priority_sampling!(@sampler)
@@ -154,7 +155,8 @@ module Datadog
154
155
  #
155
156
  # tracer.set_tags('env' => 'prod', 'component' => 'core')
156
157
  def set_tags(tags)
157
- @tags.update(tags)
158
+ string_tags = Hash[tags.collect { |k, v| [k.to_s, v] }]
159
+ @tags = @tags.merge(string_tags)
158
160
  end
159
161
 
160
162
  # Guess context and parent from child_of entry.
@@ -206,8 +208,8 @@ module Datadog
206
208
  # child span
207
209
  span.parent = parent # sets service, trace_id, parent_id, sampled
208
210
  end
209
- tags.each { |k, v| span.set_tag(k, v) } unless tags.empty?
210
211
  @tags.each { |k, v| span.set_tag(k, v) } unless @tags.empty?
212
+ tags.each { |k, v| span.set_tag(k, v) } unless tags.empty?
211
213
  span.start_time = start_time
212
214
 
213
215
  # this could at some point be optional (start_active_span vs start_manual_span)
@@ -392,6 +394,14 @@ module Datadog
392
394
 
393
395
  writer_options[:transport_options] = transport_options
394
396
 
397
+ # ensure any configuration to runtime_metrics statsd client is
398
+ # passed on when writer gets rebuilt
399
+ unless writer_options.key?(:runtime_metrics)
400
+ if @writer && !@writer.runtime_metrics.nil?
401
+ writer_options[:runtime_metrics] = @writer.runtime_metrics
402
+ end
403
+ end
404
+
395
405
  if rebuild_writer || writer
396
406
  # Make sure old writer is shut down before throwing away.
397
407
  # Don't want additional threads running...
@@ -1,8 +1,8 @@
1
1
  module Datadog
2
2
  module VERSION
3
3
  MAJOR = 0
4
- MINOR = 33
5
- PATCH = 1
4
+ MINOR = 34
5
+ PATCH = 0
6
6
  PRE = nil
7
7
 
8
8
  STRING = [MAJOR, MINOR, PATCH, PRE].compact.join('.')
@@ -0,0 +1,20 @@
1
+ module Datadog
2
+ # Base class for work tasks
3
+ class Worker
4
+ attr_reader \
5
+ :task
6
+
7
+ def initialize(&block)
8
+ @task = block
9
+ end
10
+
11
+ def perform(*args)
12
+ task.call(*args) unless task.nil?
13
+ end
14
+
15
+ protected
16
+
17
+ attr_writer \
18
+ :task
19
+ end
20
+ end
@@ -0,0 +1,165 @@
1
+ require 'ddtrace/logger'
2
+
3
+ module Datadog
4
+ module Workers
5
+ module Async
6
+ # Adds threading behavior to workers
7
+ # to run tasks asynchronously.
8
+ # rubocop:disable Metrics/ModuleLength
9
+ module Thread
10
+ FORK_POLICY_STOP = :stop
11
+ FORK_POLICY_RESTART = :restart
12
+ SHUTDOWN_TIMEOUT = 1
13
+
14
+ def self.included(base)
15
+ base.send(:prepend, PrependedMethods)
16
+ end
17
+
18
+ # Methods that must be prepended
19
+ module PrependedMethods
20
+ def perform(*args)
21
+ start { self.result = super(*args) } unless started?
22
+ end
23
+ end
24
+
25
+ attr_reader \
26
+ :error,
27
+ :result
28
+
29
+ attr_writer \
30
+ :fork_policy
31
+
32
+ def join(timeout = nil)
33
+ return true unless running?
34
+ !worker.join(timeout).nil?
35
+ end
36
+
37
+ def terminate
38
+ return false unless running?
39
+ @run_async = false
40
+ worker.terminate
41
+ true
42
+ end
43
+
44
+ def run_async?
45
+ @run_async = false unless instance_variable_defined?(:@run_async)
46
+ @run_async == true
47
+ end
48
+
49
+ def started?
50
+ !(worker.nil? || forked?)
51
+ end
52
+
53
+ def running?
54
+ !worker.nil? && worker.alive?
55
+ end
56
+
57
+ def error?
58
+ @error = nil unless instance_variable_defined?(:@error)
59
+ !@error.nil?
60
+ end
61
+
62
+ def completed?
63
+ !worker.nil? && worker.status == false && !error?
64
+ end
65
+
66
+ def failed?
67
+ !worker.nil? && worker.status.nil?
68
+ end
69
+
70
+ def forked?
71
+ !pid.nil? && pid != Process.pid
72
+ end
73
+
74
+ def fork_policy
75
+ @fork_policy ||= FORK_POLICY_STOP
76
+ end
77
+
78
+ protected
79
+
80
+ attr_writer \
81
+ :result
82
+
83
+ def mutex
84
+ @mutex ||= Mutex.new
85
+ end
86
+
87
+ def after_fork
88
+ # Do nothing by default
89
+ end
90
+
91
+ private
92
+
93
+ attr_reader \
94
+ :pid
95
+
96
+ def mutex_after_fork
97
+ @mutex_after_fork ||= Mutex.new
98
+ end
99
+
100
+ def worker
101
+ @worker ||= nil
102
+ end
103
+
104
+ def start(&block)
105
+ mutex.synchronize do
106
+ return if running?
107
+ if forked?
108
+ case fork_policy
109
+ when FORK_POLICY_STOP
110
+ stop_fork
111
+ when FORK_POLICY_RESTART
112
+ restart_after_fork(&block)
113
+ end
114
+ elsif !run_async?
115
+ start_worker(&block)
116
+ end
117
+ end
118
+ end
119
+
120
+ def start_worker
121
+ @run_async = true
122
+ @pid = Process.pid
123
+ @error = nil
124
+ Logger.log.debug("Starting thread in the process: #{Process.pid}")
125
+
126
+ @worker = ::Thread.new do
127
+ begin
128
+ yield
129
+ # rubocop:disable Lint/RescueException
130
+ rescue Exception => e
131
+ @error = e
132
+ Logger.log.debug("Worker thread error. Cause #{e.message} Location: #{e.backtrace.first}")
133
+ raise
134
+ end
135
+ end
136
+ end
137
+
138
+ def stop_fork
139
+ mutex_after_fork.synchronize do
140
+ if forked?
141
+ # Trigger callback to allow workers to reset themselves accordingly
142
+ after_fork
143
+
144
+ # Reset and turn off
145
+ @pid = Process.pid
146
+ @run_async = false
147
+ end
148
+ end
149
+ end
150
+
151
+ def restart_after_fork(&block)
152
+ mutex_after_fork.synchronize do
153
+ if forked?
154
+ # Trigger callback to allow workers to reset themselves accordingly
155
+ after_fork
156
+
157
+ # Start worker
158
+ start_worker(&block)
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end