ddtrace 0.43.0 → 0.45.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 (67) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +148 -130
  3. data/.circleci/images/primary/Dockerfile-3.0.0 +73 -0
  4. data/.github/workflows/add-milestone-to-pull-requests.yml +1 -1
  5. data/.simplecov +4 -1
  6. data/Appraisals +215 -14
  7. data/CHANGELOG.md +1048 -377
  8. data/Gemfile +4 -2
  9. data/README.md +1 -0
  10. data/Rakefile +172 -6
  11. data/ddtrace.gemspec +6 -8
  12. data/docker-compose.yml +30 -0
  13. data/docs/GettingStarted.md +112 -14
  14. data/lib/ddtrace.rb +8 -0
  15. data/lib/ddtrace/auto_instrument.rb +3 -0
  16. data/lib/ddtrace/auto_instrument_base.rb +6 -0
  17. data/lib/ddtrace/contrib/action_cable/integration.rb +7 -0
  18. data/lib/ddtrace/contrib/action_pack/integration.rb +7 -0
  19. data/lib/ddtrace/contrib/action_view/event.rb +0 -4
  20. data/lib/ddtrace/contrib/action_view/events/render_partial.rb +1 -0
  21. data/lib/ddtrace/contrib/action_view/events/render_template.rb +1 -0
  22. data/lib/ddtrace/contrib/action_view/integration.rb +7 -0
  23. data/lib/ddtrace/contrib/active_record/integration.rb +7 -0
  24. data/lib/ddtrace/contrib/active_record/utils.rb +67 -21
  25. data/lib/ddtrace/contrib/active_support/integration.rb +7 -1
  26. data/lib/ddtrace/contrib/auto_instrument.rb +48 -0
  27. data/lib/ddtrace/contrib/aws/services.rb +1 -0
  28. data/lib/ddtrace/contrib/configuration/resolvers/pattern_resolver.rb +2 -0
  29. data/lib/ddtrace/contrib/cucumber/integration.rb +5 -0
  30. data/lib/ddtrace/contrib/ethon/easy_patch.rb +6 -5
  31. data/lib/ddtrace/contrib/ethon/ext.rb +1 -0
  32. data/lib/ddtrace/contrib/extensions.rb +27 -1
  33. data/lib/ddtrace/contrib/grape/endpoint.rb +29 -11
  34. data/lib/ddtrace/contrib/grape/ext.rb +1 -0
  35. data/lib/ddtrace/contrib/httpclient/configuration/settings.rb +32 -0
  36. data/lib/ddtrace/contrib/httpclient/ext.rb +17 -0
  37. data/lib/ddtrace/contrib/httpclient/instrumentation.rb +152 -0
  38. data/lib/ddtrace/contrib/httpclient/integration.rb +43 -0
  39. data/lib/ddtrace/contrib/httpclient/patcher.rb +35 -0
  40. data/lib/ddtrace/contrib/httprb/instrumentation.rb +1 -1
  41. data/lib/ddtrace/contrib/patchable.rb +18 -7
  42. data/lib/ddtrace/contrib/qless/configuration/settings.rb +35 -0
  43. data/lib/ddtrace/contrib/qless/ext.rb +20 -0
  44. data/lib/ddtrace/contrib/qless/integration.rb +38 -0
  45. data/lib/ddtrace/contrib/qless/patcher.rb +35 -0
  46. data/lib/ddtrace/contrib/qless/qless_job.rb +72 -0
  47. data/lib/ddtrace/contrib/qless/tracer_cleaner.rb +32 -0
  48. data/lib/ddtrace/contrib/rack/integration.rb +7 -0
  49. data/lib/ddtrace/contrib/rack/middlewares.rb +1 -1
  50. data/lib/ddtrace/contrib/rack/request_queue.rb +6 -1
  51. data/lib/ddtrace/contrib/rails/auto_instrument_railtie.rb +10 -0
  52. data/lib/ddtrace/contrib/rails/utils.rb +4 -0
  53. data/lib/ddtrace/contrib/rake/integration.rb +1 -1
  54. data/lib/ddtrace/contrib/redis/configuration/resolver.rb +3 -1
  55. data/lib/ddtrace/contrib/redis/configuration/settings.rb +5 -0
  56. data/lib/ddtrace/contrib/redis/ext.rb +1 -0
  57. data/lib/ddtrace/contrib/redis/patcher.rb +20 -3
  58. data/lib/ddtrace/contrib/redis/quantize.rb +27 -0
  59. data/lib/ddtrace/contrib/redis/tags.rb +5 -1
  60. data/lib/ddtrace/contrib/rspec/integration.rb +5 -0
  61. data/lib/ddtrace/contrib/sinatra/tracer_middleware.rb +2 -2
  62. data/lib/ddtrace/ext/ci.rb +42 -10
  63. data/lib/ddtrace/ext/git.rb +0 -1
  64. data/lib/ddtrace/propagation/http_propagator.rb +17 -2
  65. data/lib/ddtrace/version.rb +1 -1
  66. data/lib/ddtrace/workers/runtime_metrics.rb +7 -3
  67. metadata +91 -20
@@ -0,0 +1,17 @@
1
+ module Datadog
2
+ module Contrib
3
+ module Httpclient
4
+ # Httpclient integration constants
5
+ module Ext
6
+ APP = 'httpclient'.freeze
7
+ ENV_ENABLED = 'DD_TRACE_HTTPCLIENT_ENABLED'.freeze
8
+ ENV_ANALYTICS_ENABLED = 'DD_TRACE_HTTPCLIENT_ANALYTICS_ENABLED'.freeze
9
+ ENV_ANALYTICS_ENABLED_OLD = 'DD_HTTPCLIENT_ANALYTICS_ENABLED'.freeze
10
+ ENV_ANALYTICS_SAMPLE_RATE = 'DD_TRACE_HTTPCLIENT_ANALYTICS_SAMPLE_RATE'.freeze
11
+ ENV_ANALYTICS_SAMPLE_RATE_OLD = 'DD_HTTPCLIENT_ANALYTICS_SAMPLE_RATE'.freeze
12
+ SERVICE_NAME = 'httpclient'.freeze
13
+ SPAN_REQUEST = 'httpclient.request'.freeze
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,152 @@
1
+ require 'ddtrace/ext/app_types'
2
+ require 'ddtrace/ext/http'
3
+ require 'ddtrace/ext/net'
4
+ require 'ddtrace/ext/distributed'
5
+ require 'ddtrace/contrib/analytics'
6
+ require 'ddtrace/propagation/http_propagator'
7
+ require 'ddtrace/contrib/http_annotation_helper'
8
+
9
+ module Datadog
10
+ module Contrib
11
+ module Httpclient
12
+ # Instrumentation for Httpclient
13
+ module Instrumentation
14
+ def self.included(base)
15
+ base.send(:prepend, InstanceMethods)
16
+ end
17
+
18
+ # Instance methods for configuration
19
+ module InstanceMethods
20
+ include Datadog::Contrib::HttpAnnotationHelper
21
+
22
+ def do_get_block(req, proxy, conn, &block)
23
+ host = req.header.request_uri.host
24
+ request_options = datadog_configuration(host)
25
+ pin = datadog_pin(request_options)
26
+
27
+ return super unless pin && pin.tracer
28
+
29
+ pin.tracer.trace(Ext::SPAN_REQUEST, on_error: method(:annotate_span_with_error!)) do |span|
30
+ begin
31
+ request_options[:service_name] = pin.service_name
32
+ span.service = service_name(host, request_options)
33
+ span.span_type = Datadog::Ext::HTTP::TYPE_OUTBOUND
34
+
35
+ if pin.tracer.enabled && !should_skip_distributed_tracing?(pin)
36
+ Datadog::HTTPPropagator.inject!(span.context, req.header)
37
+ end
38
+
39
+ # Add additional request specific tags to the span.
40
+ annotate_span_with_request!(span, req, request_options)
41
+ rescue StandardError => e
42
+ logger.error("error preparing span for httpclient request: #{e}, Source: #{e.backtrace}")
43
+ ensure
44
+ res = super
45
+ end
46
+
47
+ # Add additional response specific tags to the span.
48
+ annotate_span_with_response!(span, res)
49
+
50
+ res
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ def annotate_span_with_request!(span, req, req_options)
57
+ http_method = req.header.request_method.upcase
58
+ uri = req.header.request_uri
59
+
60
+ span.resource = http_method
61
+ span.set_tag(Datadog::Ext::HTTP::METHOD, http_method)
62
+ span.set_tag(Datadog::Ext::HTTP::URL, uri.path)
63
+ span.set_tag(Datadog::Ext::NET::TARGET_HOST, uri.host)
64
+ span.set_tag(Datadog::Ext::NET::TARGET_PORT, uri.port)
65
+
66
+ # Tag as an external peer service
67
+ span.set_tag(Datadog::Ext::Integration::TAG_PEER_SERVICE, span.service)
68
+
69
+ set_analytics_sample_rate(span, req_options)
70
+ end
71
+
72
+ def annotate_span_with_response!(span, response)
73
+ return unless response && response.status
74
+
75
+ span.set_tag(Datadog::Ext::HTTP::STATUS_CODE, response.status)
76
+
77
+ case response.status.to_i
78
+ when 400...599
79
+ span.set_error(["Error #{response.status}", response.body])
80
+ end
81
+ end
82
+
83
+ def annotate_span_with_error!(span, error)
84
+ span.set_error(error)
85
+ end
86
+
87
+ def datadog_pin(config = Datadog.configuration[:httprb])
88
+ service = config[:service_name]
89
+ tracer = config[:tracer]
90
+
91
+ @datadog_pin ||= begin
92
+ Datadog::Pin.new(
93
+ service,
94
+ app: Ext::APP,
95
+ app_type: Datadog::Ext::HTTP::TYPE_OUTBOUND,
96
+ tracer: -> { config[:tracer] }
97
+ )
98
+ end
99
+
100
+ if @datadog_pin.service_name == default_datadog_pin.service_name && @datadog_pin.service_name != service
101
+ @datadog_pin.service = service
102
+ end
103
+ if @datadog_pin.tracer == default_datadog_pin.tracer && @datadog_pin.tracer != tracer
104
+ @datadog_pin.tracer = tracer
105
+ end
106
+
107
+ @datadog_pin
108
+ end
109
+
110
+ def default_datadog_pin
111
+ config = Datadog.configuration[:httpclient]
112
+ service = config[:service_name]
113
+
114
+ @default_datadog_pin ||= begin
115
+ Datadog::Pin.new(
116
+ service,
117
+ app: Ext::APP,
118
+ app_type: Datadog::Ext::HTTP::TYPE_OUTBOUND,
119
+ tracer: -> { config[:tracer] }
120
+ )
121
+ end
122
+ end
123
+
124
+ def datadog_configuration(host = :default)
125
+ Datadog.configuration[:httpclient, host]
126
+ end
127
+
128
+ def analytics_enabled?(request_options)
129
+ Contrib::Analytics.enabled?(request_options[:analytics_enabled])
130
+ end
131
+
132
+ def logger
133
+ Datadog.logger
134
+ end
135
+
136
+ def should_skip_distributed_tracing?(pin)
137
+ if pin.config && pin.config.key?(:distributed_tracing)
138
+ return !pin.config[:distributed_tracing]
139
+ end
140
+
141
+ !Datadog.configuration[:httpclient][:distributed_tracing]
142
+ end
143
+
144
+ def set_analytics_sample_rate(span, request_options)
145
+ return unless analytics_enabled?(request_options)
146
+ Contrib::Analytics.set_sample_rate(span, request_options[:analytics_sample_rate])
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,43 @@
1
+ require 'ddtrace/contrib/integration'
2
+ require 'ddtrace/contrib/httpclient/configuration/settings'
3
+ require 'ddtrace/contrib/configuration/resolvers/pattern_resolver'
4
+ require 'ddtrace/contrib/httpclient/patcher'
5
+
6
+ module Datadog
7
+ module Contrib
8
+ module Httpclient
9
+ # Description of Httpclient integration
10
+ class Integration
11
+ include Contrib::Integration
12
+
13
+ MINIMUM_VERSION = Gem::Version.new('2.2.0')
14
+
15
+ register_as :httpclient
16
+
17
+ def self.version
18
+ Gem.loaded_specs['httpclient'] && Gem.loaded_specs['httpclient'].version
19
+ end
20
+
21
+ def self.loaded?
22
+ !defined?(::HTTPClient).nil?
23
+ end
24
+
25
+ def self.compatible?
26
+ super && version >= MINIMUM_VERSION
27
+ end
28
+
29
+ def default_configuration
30
+ Configuration::Settings.new
31
+ end
32
+
33
+ def patcher
34
+ Patcher
35
+ end
36
+
37
+ def resolver
38
+ @resolver ||= Contrib::Configuration::Resolvers::PatternResolver.new
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,35 @@
1
+ require 'ddtrace/contrib/patcher'
2
+ require 'ddtrace/contrib/httpclient/instrumentation'
3
+
4
+ module Datadog
5
+ module Contrib
6
+ # Datadog Httpclient integration.
7
+ module Httpclient
8
+ # Patcher enables patching of 'httpclient' module.
9
+ module Patcher
10
+ include Contrib::Patcher
11
+
12
+ module_function
13
+
14
+ def patched?
15
+ done?(:httpclient)
16
+ end
17
+
18
+ def target_version
19
+ Integration.version
20
+ end
21
+
22
+ # patch applies our patch
23
+ def patch
24
+ do_once(:httpclient) do
25
+ begin
26
+ ::HTTPClient.send(:include, Instrumentation)
27
+ rescue StandardError => e
28
+ Datadog::Logger.error("Unable to apply httpclient integration: #{e}")
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -40,7 +40,7 @@ module Datadog
40
40
  # Add additional request specific tags to the span.
41
41
  annotate_span_with_request!(span, req, request_options)
42
42
  rescue StandardError => e
43
- logger.error("error preparing span for http.rb request: #{e}, Soure: #{e.backtrace}")
43
+ logger.error("error preparing span for http.rb request: #{e}, Source: #{e.backtrace}")
44
44
  ensure
45
45
  res = super(req, options)
46
46
  end
@@ -42,16 +42,27 @@ module Datadog
42
42
 
43
43
  def patch
44
44
  if !self.class.patchable? || patcher.nil?
45
- desc = "Available?: #{self.class.available?}"
46
- desc += ", Loaded? #{self.class.loaded?}"
47
- desc += ", Compatible? #{self.class.compatible?}"
48
- desc += ", Patchable? #{self.class.patchable?}"
49
-
50
- Datadog.logger.warn("Unable to patch #{self.class.name} (#{desc})")
51
- return
45
+ return {
46
+ name: self.class.name,
47
+ available: self.class.available?,
48
+ loaded: self.class.loaded?,
49
+ compatible: self.class.compatible?,
50
+ patchable: self.class.patchable?
51
+ }
52
52
  end
53
53
 
54
54
  patcher.patch
55
+ true
56
+ end
57
+
58
+ # Can the patch for this integration be applied automatically?
59
+ # For example: test integrations should only be applied
60
+ # by the user explicitly setting `c.use :rspec`
61
+ # and rails sub-modules are auto-instrumented by enabling rails
62
+ # so auto-instrumenting them on their own will cause changes in
63
+ # service naming behavior
64
+ def auto_instrument?
65
+ true
55
66
  end
56
67
  end
57
68
  end
@@ -0,0 +1,35 @@
1
+ require 'ddtrace/contrib/configuration/settings'
2
+ require 'ddtrace/contrib/qless/ext'
3
+
4
+ module Datadog
5
+ module Contrib
6
+ module Qless
7
+ module Configuration
8
+ # Custom settings for the Qless integration
9
+ class Settings < Contrib::Configuration::Settings
10
+ option :analytics_enabled do |o|
11
+ o.default { env_to_bool(Ext::ENV_ANALYTICS_ENABLED, false) }
12
+ o.lazy
13
+ end
14
+
15
+ option :analytics_sample_rate do |o|
16
+ o.default { env_to_float(Ext::ENV_ANALYTICS_SAMPLE_RATE, 1.0) }
17
+ o.lazy
18
+ end
19
+
20
+ option :tag_job_data do |o|
21
+ o.default { env_to_bool(Ext::ENV_TAG_JOB_DATA, false) }
22
+ o.lazy
23
+ end
24
+
25
+ option :tag_job_tags do |o|
26
+ o.default { env_to_bool(Ext::ENV_TAG_JOB_TAGS, false) }
27
+ o.lazy
28
+ end
29
+
30
+ option :service_name, default: Ext::SERVICE_NAME
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,20 @@
1
+ module Datadog
2
+ module Contrib
3
+ module Qless
4
+ # Qless integration constants
5
+ module Ext
6
+ APP = 'qless'.freeze
7
+ ENV_ANALYTICS_ENABLED = 'DD_QLESS_ANALYTICS_ENABLED'.freeze
8
+ ENV_ANALYTICS_SAMPLE_RATE = 'DD_QLESS_ANALYTICS_SAMPLE_RATE'.freeze
9
+ ENV_TAG_JOB_DATA = 'DD_QLESS_TAG_JOB_DATA'.freeze
10
+ ENV_TAG_JOB_TAGS = 'DD_QLESS_TAG_JOB_TAGS'.freeze
11
+ SERVICE_NAME = 'qless'.freeze
12
+ SPAN_JOB = 'qless.job'.freeze
13
+ TAG_JOB_ID = 'qless.job.id'.freeze
14
+ TAG_JOB_DATA = 'qless.job.data'.freeze
15
+ TAG_JOB_QUEUE = 'qless.job.queue'.freeze
16
+ TAG_JOB_TAGS = 'qless.job.tags'.freeze
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,38 @@
1
+ require 'ddtrace/contrib/integration'
2
+ require 'ddtrace/contrib/qless/configuration/settings'
3
+ require 'ddtrace/contrib/qless/patcher'
4
+
5
+ module Datadog
6
+ module Contrib
7
+ module Qless
8
+ # Description of Qless integration
9
+ class Integration
10
+ include Contrib::Integration
11
+
12
+ MINIMUM_VERSION = Gem::Version.new('0.10.0')
13
+
14
+ register_as :qless, auto_patch: true
15
+
16
+ def self.version
17
+ Gem.loaded_specs['qless'] && Gem.loaded_specs['qless'].version
18
+ end
19
+
20
+ def self.loaded?
21
+ !defined?(::Qless).nil?
22
+ end
23
+
24
+ def self.compatible?
25
+ super && version >= MINIMUM_VERSION
26
+ end
27
+
28
+ def default_configuration
29
+ Configuration::Settings.new
30
+ end
31
+
32
+ def patcher
33
+ Patcher
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,35 @@
1
+ require 'ddtrace/contrib/patcher'
2
+ require 'ddtrace/ext/app_types'
3
+
4
+ module Datadog
5
+ module Contrib
6
+ module Qless
7
+ # Patcher enables patching of 'qless' module.
8
+ module Patcher
9
+ include Contrib::Patcher
10
+
11
+ module_function
12
+
13
+ def target_version
14
+ Integration.version
15
+ end
16
+
17
+ def patch
18
+ require_relative 'qless_job'
19
+ require_relative 'tracer_cleaner'
20
+
21
+ # Instrument all Qless Workers
22
+ ::Qless::Workers::BaseWorker.class_eval do
23
+ # These are executed in inverse order of listing here
24
+ include QlessJob
25
+ include TracerCleaner
26
+ end
27
+ end
28
+
29
+ def get_option(option)
30
+ Datadog.configuration[:qless].get_option(option)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,72 @@
1
+ require 'ddtrace/ext/app_types'
2
+ require 'ddtrace/contrib/analytics'
3
+ require 'qless'
4
+
5
+ module Datadog
6
+ module Contrib
7
+ module Qless
8
+ # Uses Qless job hooks to create traces
9
+ module QlessJob
10
+ def around_perform(job)
11
+ return super unless datadog_configuration && tracer
12
+ tracer.trace(Ext::SPAN_JOB, span_options) do |span|
13
+ span.resource = job.klass_name
14
+ span.span_type = Datadog::Ext::AppTypes::WORKER
15
+ span.set_tag(Ext::TAG_JOB_ID, job.jid)
16
+ span.set_tag(Ext::TAG_JOB_QUEUE, job.queue_name)
17
+
18
+ tag_job_tags = datadog_configuration[:tag_job_tags]
19
+ span.set_tag(Ext::TAG_JOB_TAGS, job.tags) if tag_job_tags
20
+
21
+ tag_job_data = datadog_configuration[:tag_job_data]
22
+ if tag_job_data && !job.data.empty?
23
+ job_data = job.data.with_indifferent_access
24
+ formatted_data = job_data.except(:tags).map do |key, value|
25
+ "#{key}:#{value}".underscore
26
+ end
27
+
28
+ span.set_tag(Ext::TAG_JOB_DATA, formatted_data)
29
+ end
30
+
31
+ # Set analytics sample rate
32
+ if Contrib::Analytics.enabled?(datadog_configuration[:analytics_enabled])
33
+ Contrib::Analytics.set_sample_rate(span, datadog_configuration[:analytics_sample_rate])
34
+ end
35
+
36
+ # Measure service stats
37
+ Contrib::Analytics.set_measured(span)
38
+
39
+ super
40
+ end
41
+ end
42
+
43
+ def after_fork
44
+ configuration = Datadog.configuration[:qless]
45
+ return if configuration.nil?
46
+
47
+ # Add a pin, marking the job as forked.
48
+ # Used to trigger shutdown in forks for performance reasons.
49
+ # Cleanup happens in the TracerCleaner class
50
+ Datadog::Pin.new(
51
+ configuration[:service_name],
52
+ config: { forked: true }
53
+ ).onto(::Qless)
54
+ end
55
+
56
+ private
57
+
58
+ def span_options
59
+ { service: datadog_configuration[:service_name] }
60
+ end
61
+
62
+ def tracer
63
+ datadog_configuration.tracer
64
+ end
65
+
66
+ def datadog_configuration
67
+ Datadog.configuration[:qless]
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end