ddtrace 0.35.0 → 0.38.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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +3 -1
  3. data/.gitignore +2 -0
  4. data/.gitlab-ci.yml +26 -0
  5. data/.rubocop.yml +4 -0
  6. data/Appraisals +23 -6
  7. data/CHANGELOG.md +116 -1
  8. data/Rakefile +43 -12
  9. data/ddtrace.gemspec +5 -0
  10. data/docker-compose.yml +37 -2
  11. data/docs/GettingStarted.md +63 -34
  12. data/lib/ddtrace.rb +2 -0
  13. data/lib/ddtrace/configuration/base.rb +1 -1
  14. data/lib/ddtrace/configuration/components.rb +2 -2
  15. data/lib/ddtrace/configuration/options.rb +1 -1
  16. data/lib/ddtrace/configuration/pin_setup.rb +3 -2
  17. data/lib/ddtrace/configuration/settings.rb +18 -0
  18. data/lib/ddtrace/contrib/active_support/cache/redis.rb +1 -1
  19. data/lib/ddtrace/contrib/active_support/notifications/event.rb +3 -1
  20. data/lib/ddtrace/contrib/active_support/notifications/subscription.rb +1 -1
  21. data/lib/ddtrace/contrib/concurrent_ruby/context_composite_executor_service.rb +9 -3
  22. data/lib/ddtrace/contrib/configuration/settings.rb +19 -1
  23. data/lib/ddtrace/contrib/dalli/patcher.rb +1 -5
  24. data/lib/ddtrace/contrib/elasticsearch/patcher.rb +1 -2
  25. data/lib/ddtrace/contrib/extensions.rb +38 -4
  26. data/lib/ddtrace/contrib/faraday/middleware.rb +5 -3
  27. data/lib/ddtrace/contrib/faraday/patcher.rb +4 -5
  28. data/lib/ddtrace/contrib/grape/patcher.rb +1 -1
  29. data/lib/ddtrace/contrib/graphql/patcher.rb +6 -3
  30. data/lib/ddtrace/contrib/grpc/datadog_interceptor.rb +1 -1
  31. data/lib/ddtrace/contrib/grpc/datadog_interceptor/client.rb +1 -3
  32. data/lib/ddtrace/contrib/grpc/patcher.rb +1 -5
  33. data/lib/ddtrace/contrib/http/circuit_breaker.rb +8 -32
  34. data/lib/ddtrace/contrib/http/instrumentation.rb +13 -8
  35. data/lib/ddtrace/contrib/httprb/configuration/settings.rb +27 -0
  36. data/lib/ddtrace/contrib/httprb/ext.rb +14 -0
  37. data/lib/ddtrace/contrib/httprb/instrumentation.rb +163 -0
  38. data/lib/ddtrace/contrib/httprb/integration.rb +43 -0
  39. data/lib/ddtrace/contrib/httprb/patcher.rb +35 -0
  40. data/lib/ddtrace/contrib/kafka/configuration/settings.rb +25 -0
  41. data/lib/ddtrace/contrib/kafka/consumer_event.rb +14 -0
  42. data/lib/ddtrace/contrib/kafka/consumer_group_event.rb +14 -0
  43. data/lib/ddtrace/contrib/kafka/event.rb +51 -0
  44. data/lib/ddtrace/contrib/kafka/events.rb +44 -0
  45. data/lib/ddtrace/contrib/kafka/events/connection/request.rb +34 -0
  46. data/lib/ddtrace/contrib/kafka/events/consumer/process_batch.rb +41 -0
  47. data/lib/ddtrace/contrib/kafka/events/consumer/process_message.rb +39 -0
  48. data/lib/ddtrace/contrib/kafka/events/consumer_group/heartbeat.rb +39 -0
  49. data/lib/ddtrace/contrib/kafka/events/consumer_group/join_group.rb +29 -0
  50. data/lib/ddtrace/contrib/kafka/events/consumer_group/leave_group.rb +29 -0
  51. data/lib/ddtrace/contrib/kafka/events/consumer_group/sync_group.rb +29 -0
  52. data/lib/ddtrace/contrib/kafka/events/produce_operation/send_messages.rb +32 -0
  53. data/lib/ddtrace/contrib/kafka/events/producer/deliver_messages.rb +35 -0
  54. data/lib/ddtrace/contrib/kafka/ext.rb +38 -0
  55. data/lib/ddtrace/contrib/kafka/integration.rb +39 -0
  56. data/lib/ddtrace/contrib/kafka/patcher.rb +26 -0
  57. data/lib/ddtrace/contrib/mongodb/instrumentation.rb +1 -2
  58. data/lib/ddtrace/contrib/mysql2/instrumentation.rb +1 -1
  59. data/lib/ddtrace/contrib/patcher.rb +14 -8
  60. data/lib/ddtrace/contrib/rack/middlewares.rb +15 -12
  61. data/lib/ddtrace/contrib/rails/configuration/settings.rb +13 -11
  62. data/lib/ddtrace/contrib/rails/framework.rb +52 -46
  63. data/lib/ddtrace/contrib/rails/integration.rb +1 -1
  64. data/lib/ddtrace/contrib/redis/patcher.rb +1 -1
  65. data/lib/ddtrace/contrib/rest_client/request_patch.rb +2 -2
  66. data/lib/ddtrace/contrib/sequel/database.rb +1 -1
  67. data/lib/ddtrace/contrib/sidekiq/ext.rb +1 -0
  68. data/lib/ddtrace/contrib/sidekiq/patcher.rb +8 -1
  69. data/lib/ddtrace/contrib/sidekiq/server_tracer.rb +1 -0
  70. data/lib/ddtrace/contrib/sucker_punch/patcher.rb +1 -1
  71. data/lib/ddtrace/diagnostics/environment_logger.rb +278 -0
  72. data/lib/ddtrace/environment.rb +5 -1
  73. data/lib/ddtrace/ext/diagnostics.rb +2 -0
  74. data/lib/ddtrace/ext/environment.rb +2 -0
  75. data/lib/ddtrace/pin.rb +39 -15
  76. data/lib/ddtrace/pipeline/span_filter.rb +15 -15
  77. data/lib/ddtrace/sampler.rb +2 -0
  78. data/lib/ddtrace/span.rb +10 -0
  79. data/lib/ddtrace/tracer.rb +15 -8
  80. data/lib/ddtrace/transport/http/adapters/net.rb +8 -0
  81. data/lib/ddtrace/transport/http/adapters/test.rb +4 -0
  82. data/lib/ddtrace/transport/http/adapters/unix_socket.rb +4 -0
  83. data/lib/ddtrace/transport/response.rb +11 -0
  84. data/lib/ddtrace/version.rb +1 -1
  85. data/lib/ddtrace/workers/trace_writer.rb +3 -0
  86. data/lib/ddtrace/writer.rb +33 -12
  87. metadata +98 -3
@@ -45,7 +45,7 @@ module Datadog
45
45
  # Instance methods for configuration
46
46
  module InstanceMethods
47
47
  def initialize(options = {})
48
- configure(options)
48
+ configure(options) unless options.empty?
49
49
  end
50
50
 
51
51
  def configure(opts = {})
@@ -135,13 +135,13 @@ module Datadog
135
135
  old_statsd = [
136
136
  runtime_metrics.metrics.statsd,
137
137
  health_metrics.statsd
138
- ].uniq
138
+ ].compact.uniq
139
139
 
140
140
  new_statsd = if replacement
141
141
  [
142
142
  replacement.runtime_metrics.metrics.statsd,
143
143
  replacement.health_metrics.statsd
144
- ].uniq
144
+ ].compact.uniq
145
145
  else
146
146
  []
147
147
  end
@@ -80,7 +80,7 @@ module Datadog
80
80
  end
81
81
 
82
82
  def options_hash
83
- options.each_with_object({}) do |(key, _), hash|
83
+ self.class.options.merge(options).each_with_object({}) do |(key, _), hash|
84
84
  hash[key] = get_option(key)
85
85
  end
86
86
  end
@@ -13,7 +13,7 @@ module Datadog
13
13
 
14
14
  ATTRS.each { |key| pin.public_send("#{key}=", opts[key]) if opts[key] }
15
15
 
16
- pin.config = opts.reject { |key, _| ATTRS.include?(key) }
16
+ pin.config = opts.reject { |key, _| ATTRS.include?(key) || DEPRECATED_ATTRS.include?(key) }
17
17
 
18
18
  true
19
19
  end
@@ -22,7 +22,8 @@ module Datadog
22
22
 
23
23
  attr_reader :pin, :opts
24
24
 
25
- ATTRS = [:app, :tags, :app_type, :name, :tracer, :service_name].freeze
25
+ ATTRS = [:app, :tags, :app_type, :name, :service_name].freeze
26
+ DEPRECATED_ATTRS = [:tracer].freeze
26
27
 
27
28
  private_constant :ATTRS
28
29
  end
@@ -31,6 +31,11 @@ module Datadog
31
31
  end
32
32
  end
33
33
 
34
+ option :api_key do |o|
35
+ o.default { ENV.fetch(Ext::Environment::ENV_API_KEY, nil) }
36
+ o.lazy
37
+ end
38
+
34
39
  settings :diagnostics do
35
40
  option :debug, default: false
36
41
 
@@ -42,6 +47,14 @@ module Datadog
42
47
 
43
48
  option :statsd
44
49
  end
50
+
51
+ settings :startup_logs do
52
+ option :enabled do |o|
53
+ # Defaults to nil as we want to know when the default value is being used
54
+ o.default { env_to_bool(Datadog::Ext::Diagnostics::DD_TRACE_STARTUP_LOGS, nil) }
55
+ o.lazy
56
+ end
57
+ end
45
58
  end
46
59
 
47
60
  settings :distributed_tracing do
@@ -138,6 +151,11 @@ module Datadog
138
151
  o.lazy
139
152
  end
140
153
 
154
+ option :site do |o|
155
+ o.default { ENV.fetch(Ext::Environment::ENV_SITE, nil) }
156
+ o.lazy
157
+ end
158
+
141
159
  option :tags do |o|
142
160
  o.default do
143
161
  tags = {}
@@ -14,7 +14,7 @@ module Datadog
14
14
  # We need to do a per-method monkey patching as some of them might
15
15
  # be redefined, and some of them not. The latest version of redis-activesupport
16
16
  # redefines write but leaves untouched read and delete:
17
- # https://github.com/redis-store/redis-activesupport/blob/master/lib/active_support/cache/redis_store.rb
17
+ # https://github.com/redis-store/redis-activesupport/blob/v4.1.5/lib/active_support/cache/redis_store.rb
18
18
  #
19
19
  # For Rails >= 5.2 w/o redis-activesupport...
20
20
  # ActiveSupport includes a Redis cache store internally, and does not require these overrides.
@@ -18,6 +18,8 @@ module Datadog
18
18
  # Redefines some class behaviors for a Subscriber to make
19
19
  # it a bit simpler for an Event.
20
20
  module ClassMethods
21
+ DEFAULT_TRACER = -> { Datadog.tracer }
22
+
21
23
  def subscribe!
22
24
  super
23
25
  end
@@ -52,7 +54,7 @@ module Datadog
52
54
  end
53
55
 
54
56
  def tracer
55
- Datadog.tracer
57
+ DEFAULT_TRACER
56
58
  end
57
59
  end
58
60
  end
@@ -75,7 +75,7 @@ module Datadog
75
75
  callbacks.run(name, :before_trace, id, payload, start)
76
76
 
77
77
  # Start a trace
78
- tracer.trace(@span_name, @options).tap do |span|
78
+ tracer.trace(@span_name, @options.dup).tap do |span|
79
79
  # Assign start time if provided
80
80
  span.start_time = start unless start.nil?
81
81
  payload[:datadog_span] = span
@@ -16,11 +16,17 @@ module Datadog
16
16
 
17
17
  # post method runs the task within composited executor - in a different thread
18
18
  def post(*args, &task)
19
- context = datadog_configuration.tracer.provider.context
19
+ parent_context = datadog_configuration.tracer.provider.context
20
20
 
21
21
  @composited_executor.post(*args) do
22
- datadog_configuration.tracer.provider.context = context
23
- yield
22
+ begin
23
+ original_context = datadog_configuration.tracer.provider.context
24
+ datadog_configuration.tracer.provider.context = parent_context
25
+ yield
26
+ ensure
27
+ # Restore context in case the current thread gets reused
28
+ datadog_configuration.tracer.provider.context = original_context
29
+ end
24
30
  end
25
31
  end
26
32
 
@@ -12,11 +12,14 @@ module Datadog
12
12
  option :service_name
13
13
  option :tracer do |o|
14
14
  o.delegate_to { Datadog.tracer }
15
+ o.on_set do |_value|
16
+ log_deprecation_warning(:tracer)
17
+ end
15
18
  end
16
19
 
17
20
  def configure(options = {})
18
21
  self.class.options.dependency_order.each do |name|
19
- self[name] = options.fetch(name, self[name])
22
+ self[name] = options[name] if options.key?(name)
20
23
  end
21
24
 
22
25
  yield(self) if block_given?
@@ -29,6 +32,21 @@ module Datadog
29
32
  def []=(name, value)
30
33
  respond_to?("#{name}=") ? send("#{name}=", value) : set_option(name, value)
31
34
  end
35
+
36
+ DEPRECATION_WARNING = %(
37
+ Explicitly providing a tracer instance is DEPRECATED.
38
+ It's recommended to not provide an explicit tracer instance
39
+ and let Datadog::Contrib::Configuration::Settings resolve
40
+ the correct tracer internally.
41
+ ).freeze
42
+
43
+ include Datadog::Patcher # DEV includes #do_once here. We should move that logic to a generic component.
44
+
45
+ def log_deprecation_warning(method_name)
46
+ do_once(method_name) do
47
+ Datadog.logger.warn("#{method_name}:#{DEPRECATION_WARNING}:#{caller.join("\n")}")
48
+ end
49
+ end
32
50
  end
33
51
  end
34
52
  end
@@ -29,7 +29,7 @@ module Datadog
29
29
  get_option(:service_name),
30
30
  app: Ext::APP,
31
31
  app_type: Datadog::Ext::AppTypes::CACHE,
32
- tracer: get_option(:tracer)
32
+ tracer: -> { get_option(:tracer) }
33
33
  ).onto(::Dalli)
34
34
  end
35
35
 
@@ -47,10 +47,6 @@ module Datadog
47
47
  Upgrade to the configuration API using the migration guide here:
48
48
  https://github.com/DataDog/dd-trace-rb/releases/tag/v0.11.0).freeze
49
49
 
50
- def tracer=(tracer)
51
- Datadog.configuration[:dalli][:tracer] = tracer
52
- end
53
-
54
50
  def service_name=(service_name)
55
51
  Datadog.configuration[:dalli][:service_name] = service_name
56
52
  end
@@ -37,14 +37,13 @@ module Datadog
37
37
  end
38
38
 
39
39
  def initialize(*args, &block)
40
- tracer = Datadog.configuration[:elasticsearch][:tracer]
41
40
  service = Datadog.configuration[:elasticsearch][:service_name]
42
41
 
43
42
  pin = Datadog::Pin.new(
44
43
  service,
45
44
  app: Datadog::Contrib::Elasticsearch::Ext::APP,
46
45
  app_type: Datadog::Ext::AppTypes::DB,
47
- tracer: tracer
46
+ tracer: -> { Datadog.configuration[:elasticsearch][:tracer] }
48
47
  )
49
48
  pin.onto(self)
50
49
  initialize_without_datadog(*args, &block)
@@ -1,3 +1,4 @@
1
+ require 'set'
1
2
  require 'ddtrace/contrib/registry'
2
3
 
3
4
  module Datadog
@@ -7,6 +8,7 @@ module Datadog
7
8
  module Extensions
8
9
  def self.extended(base)
9
10
  Datadog.send(:extend, Helpers)
11
+ Datadog.send(:extend, Configuration)
10
12
  Datadog::Configuration::Settings.send(:include, Configuration::Settings)
11
13
  end
12
14
 
@@ -17,7 +19,24 @@ module Datadog
17
19
  end
18
20
  end
19
21
 
22
+ # Configuration methods for Datadog module.
20
23
  module Configuration
24
+ def configure(target = configuration, opts = {})
25
+ # Reconfigure core settings
26
+ super
27
+
28
+ # Activate integrations
29
+ if target.respond_to?(:integrations_pending_activation)
30
+ target.integrations_pending_activation.each do |integration|
31
+ integration.patch if integration.respond_to?(:patch)
32
+ end
33
+
34
+ target.integrations_pending_activation.clear
35
+ end
36
+
37
+ target
38
+ end
39
+
21
40
  # Extensions for Datadog::Configuration::Settings
22
41
  module Settings
23
42
  InvalidIntegrationError = Class.new(StandardError)
@@ -34,22 +53,37 @@ module Datadog
34
53
  integration.configuration(configuration_name) unless integration.nil?
35
54
  end
36
55
 
37
- def use(integration_name, options = {}, &block)
56
+ def instrument(integration_name, options = {}, &block)
38
57
  integration = fetch_integration(integration_name)
39
58
 
40
59
  unless integration.nil?
41
60
  configuration_name = options[:describes] || :default
42
61
  filtered_options = options.reject { |k, _v| k == :describes }
43
62
  integration.configure(configuration_name, filtered_options, &block)
63
+ instrumented_integrations[integration_name] = integration
64
+
65
+ # Add to activation list
66
+ integrations_pending_activation << integration
44
67
  end
68
+ end
69
+
70
+ alias_method :use, :instrument
45
71
 
46
- integration.patch if integration.respond_to?(:patch)
72
+ def integrations_pending_activation
73
+ @integrations_pending_activation ||= Set.new
47
74
  end
48
75
 
49
- private
76
+ def instrumented_integrations
77
+ @instrumented_integrations ||= {}
78
+ end
79
+
80
+ def reset!
81
+ instrumented_integrations.clear
82
+ super
83
+ end
50
84
 
51
85
  def fetch_integration(name)
52
- get_option(:registry)[name] ||
86
+ registry[name] ||
53
87
  raise(InvalidIntegrationError, "'#{name}' is not a valid integration.")
54
88
  end
55
89
  end
@@ -16,7 +16,7 @@ module Datadog
16
16
 
17
17
  def initialize(app, options = {})
18
18
  super(app)
19
- @options = datadog_configuration.options_hash.merge(options)
19
+ @options = options
20
20
  end
21
21
 
22
22
  def call(env)
@@ -33,7 +33,7 @@ module Datadog
33
33
 
34
34
  private
35
35
 
36
- attr_reader :app, :options
36
+ attr_reader :app
37
37
 
38
38
  def annotate!(span, env, options)
39
39
  span.resource = resource_name(env)
@@ -69,7 +69,9 @@ module Datadog
69
69
  end
70
70
 
71
71
  def build_request_options!(env)
72
- datadog_configuration(env[:url].host).options_hash.merge(options)
72
+ datadog_configuration.options_hash # integration level settings
73
+ .merge(datadog_configuration(env[:url].host).options_hash) # per-host override
74
+ .merge(@options) # middleware instance override
73
75
  end
74
76
 
75
77
  def datadog_configuration(host = :default)
@@ -31,7 +31,7 @@ module Datadog
31
31
  get_option(:service_name),
32
32
  app: Ext::APP,
33
33
  app_type: Datadog::Ext::AppTypes::WEB,
34
- tracer: get_option(:tracer)
34
+ tracer: -> { get_option(:tracer) }
35
35
  ).onto(::Faraday)
36
36
  end
37
37
 
@@ -45,6 +45,9 @@ module Datadog
45
45
  else
46
46
  ::Faraday::RackBuilder.send(:prepend, RackBuilder)
47
47
  end
48
+
49
+ # Instrument the Faraday default connection (e.g. +Faraday.get+)
50
+ ::Faraday.default_connection.use(:ddtrace)
48
51
  end
49
52
 
50
53
  def get_option(option)
@@ -61,10 +64,6 @@ module Datadog
61
64
  Upgrade to the configuration API using the migration guide here:
62
65
  https://github.com/DataDog/dd-trace-rb/releases/tag/v0.11.0).freeze
63
66
 
64
- def tracer=(tracer)
65
- Datadog.configuration[:faraday][:tracer] = tracer
66
- end
67
-
68
67
  def service_name=(service_name)
69
68
  Datadog.configuration[:faraday][:service_name] = service_name
70
69
  end
@@ -34,7 +34,7 @@ module Datadog
34
34
  get_option(:service_name),
35
35
  app: Ext::APP,
36
36
  app_type: Datadog::Ext::AppTypes::WEB,
37
- tracer: get_option(:tracer)
37
+ tracer: -> { get_option(:tracer) }
38
38
  )
39
39
  pin.onto(::Grape)
40
40
  end
@@ -22,7 +22,6 @@ module Datadog
22
22
  end
23
23
 
24
24
  def patch_schema!(schema)
25
- tracer = get_option(:tracer)
26
25
  service_name = get_option(:service_name)
27
26
  analytics_enabled = Contrib::Analytics.enabled?(get_option(:analytics_enabled))
28
27
  analytics_sample_rate = get_option(:analytics_sample_rate)
@@ -30,7 +29,9 @@ module Datadog
30
29
  if schema.respond_to?(:use)
31
30
  schema.use(
32
31
  ::GraphQL::Tracing::DataDogTracing,
33
- tracer: tracer,
32
+ # By default, Tracing::DataDogTracing indirectly delegates the tracer instance
33
+ # to +Datadog.tracer+. If we provide a tracer argument here it will be eagerly cached,
34
+ # and Tracing::DataDogTracing will send traces to a stale tracer instance.
34
35
  service: service_name,
35
36
  analytics_enabled: analytics_enabled,
36
37
  analytics_sample_rate: analytics_sample_rate
@@ -39,7 +40,9 @@ module Datadog
39
40
  schema.define do
40
41
  use(
41
42
  ::GraphQL::Tracing::DataDogTracing,
42
- tracer: tracer,
43
+ # By default, Tracing::DataDogTracing indirectly delegates the tracer instance
44
+ # to +Datadog.tracer+. If we provide a tracer argument here it will be eagerly cached,
45
+ # and Tracing::DataDogTracing will send traces to a stale tracer instance.
43
46
  service: service_name,
44
47
  analytics_enabled: analytics_enabled,
45
48
  analytics_sample_rate: analytics_sample_rate
@@ -38,7 +38,7 @@ module Datadog
38
38
  service_name,
39
39
  app: Ext::APP,
40
40
  app_type: Datadog::Ext::AppTypes::WEB,
41
- tracer: tracer
41
+ tracer: -> { datadog_configuration[:tracer] }
42
42
  ).tap do |pin|
43
43
  yield(pin) if block_given?
44
44
  pin.onto(self)
@@ -30,9 +30,7 @@ module Datadog
30
30
  private
31
31
 
32
32
  def annotate!(span, metadata)
33
- metadata.each do |header, value|
34
- span.set_tag(header, value)
35
- end
33
+ span.set_tags(metadata)
36
34
 
37
35
  # Set analytics sample rate
38
36
  Contrib::Analytics.set_sample_rate(span, analytics_sample_rate) if analytics_enabled?
@@ -29,7 +29,7 @@ module Datadog
29
29
  get_option(:service_name),
30
30
  app: Ext::APP,
31
31
  app_type: Datadog::Ext::AppTypes::WEB,
32
- tracer: get_option(:tracer)
32
+ tracer: -> { get_option(:tracer) }
33
33
  ).onto(::GRPC)
34
34
  end
35
35
 
@@ -52,10 +52,6 @@ module Datadog
52
52
  Upgrade to the configuration API using the migration guide here:
53
53
  https://github.com/DataDog/dd-trace-rb/releases/tag/v0.11.0).freeze
54
54
 
55
- def tracer=(tracer)
56
- Datadog.configuration[:grpc][:tracer] = tracer
57
- end
58
-
59
55
  def service_name=(service_name)
60
56
  Datadog.configuration[:grpc][:service_name] = service_name
61
57
  end