ddtrace 0.52.0 → 0.54.2

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 (108) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +174 -11
  3. data/ddtrace.gemspec +6 -3
  4. data/docs/DevelopmentGuide.md +1 -6
  5. data/docs/GettingStarted.md +109 -18
  6. data/docs/ProfilingDevelopment.md +2 -2
  7. data/ext/ddtrace_profiling_native_extension/NativeExtensionDesign.md +86 -0
  8. data/ext/ddtrace_profiling_native_extension/clock_id.h +4 -0
  9. data/ext/ddtrace_profiling_native_extension/clock_id_from_pthread.c +52 -0
  10. data/ext/ddtrace_profiling_native_extension/clock_id_noop.c +14 -0
  11. data/ext/ddtrace_profiling_native_extension/extconf.rb +177 -8
  12. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.c +35 -0
  13. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.h +3 -0
  14. data/ext/ddtrace_profiling_native_extension/profiling.c +6 -1
  15. data/lib/datadog/ci/contrib/cucumber/formatter.rb +1 -0
  16. data/lib/datadog/ci/contrib/rspec/example.rb +1 -0
  17. data/lib/datadog/ci/contrib/rspec/integration.rb +2 -2
  18. data/lib/datadog/ci/ext/environment.rb +64 -22
  19. data/lib/datadog/ci/ext/test.rb +1 -0
  20. data/lib/datadog/ci/test.rb +5 -1
  21. data/lib/datadog/contrib.rb +2 -0
  22. data/lib/datadog/core/environment/vm_cache.rb +46 -0
  23. data/lib/ddtrace/buffer.rb +28 -16
  24. data/lib/ddtrace/configuration/agent_settings_resolver.rb +131 -53
  25. data/lib/ddtrace/configuration/components.rb +1 -1
  26. data/lib/ddtrace/configuration/settings.rb +13 -3
  27. data/lib/ddtrace/context.rb +10 -2
  28. data/lib/ddtrace/contrib/action_cable/instrumentation.rb +46 -0
  29. data/lib/ddtrace/contrib/action_cable/patcher.rb +1 -0
  30. data/lib/ddtrace/contrib/action_mailer/configuration/settings.rb +32 -0
  31. data/lib/ddtrace/contrib/action_mailer/event.rb +50 -0
  32. data/lib/ddtrace/contrib/action_mailer/events/deliver.rb +54 -0
  33. data/lib/ddtrace/contrib/action_mailer/events/process.rb +41 -0
  34. data/lib/ddtrace/contrib/action_mailer/events.rb +31 -0
  35. data/lib/ddtrace/contrib/action_mailer/ext.rb +32 -0
  36. data/lib/ddtrace/contrib/action_mailer/integration.rb +45 -0
  37. data/lib/ddtrace/contrib/action_mailer/patcher.rb +27 -0
  38. data/lib/ddtrace/contrib/active_job/configuration/settings.rb +33 -0
  39. data/lib/ddtrace/contrib/active_job/event.rb +54 -0
  40. data/lib/ddtrace/contrib/active_job/events/discard.rb +46 -0
  41. data/lib/ddtrace/contrib/active_job/events/enqueue.rb +45 -0
  42. data/lib/ddtrace/contrib/active_job/events/enqueue_at.rb +45 -0
  43. data/lib/ddtrace/contrib/active_job/events/enqueue_retry.rb +47 -0
  44. data/lib/ddtrace/contrib/active_job/events/perform.rb +45 -0
  45. data/lib/ddtrace/contrib/active_job/events/retry_stopped.rb +46 -0
  46. data/lib/ddtrace/contrib/active_job/events.rb +39 -0
  47. data/lib/ddtrace/contrib/active_job/ext.rb +32 -0
  48. data/lib/ddtrace/contrib/active_job/integration.rb +46 -0
  49. data/lib/ddtrace/contrib/active_job/log_injection.rb +21 -0
  50. data/lib/ddtrace/contrib/active_job/patcher.rb +33 -0
  51. data/lib/ddtrace/contrib/auto_instrument.rb +0 -1
  52. data/lib/ddtrace/contrib/delayed_job/plugin.rb +2 -2
  53. data/lib/ddtrace/contrib/mongodb/instrumentation.rb +1 -1
  54. data/lib/ddtrace/contrib/mongodb/integration.rb +5 -0
  55. data/lib/ddtrace/contrib/rails/auto_instrument_railtie.rb +0 -1
  56. data/lib/ddtrace/contrib/rails/configuration/settings.rb +7 -0
  57. data/lib/ddtrace/contrib/rails/framework.rb +24 -1
  58. data/lib/ddtrace/contrib/rails/patcher.rb +19 -10
  59. data/lib/ddtrace/contrib/redis/instrumentation.rb +90 -0
  60. data/lib/ddtrace/contrib/redis/patcher.rb +2 -84
  61. data/lib/ddtrace/contrib/registerable.rb +0 -1
  62. data/lib/ddtrace/contrib/resque/integration.rb +1 -5
  63. data/lib/ddtrace/contrib/sidekiq/ext.rb +3 -0
  64. data/lib/ddtrace/contrib/sidekiq/integration.rb +10 -0
  65. data/lib/ddtrace/contrib/sidekiq/patcher.rb +26 -0
  66. data/lib/ddtrace/contrib/sidekiq/server_internal_tracer/heartbeat.rb +30 -0
  67. data/lib/ddtrace/contrib/sidekiq/server_internal_tracer/job_fetch.rb +30 -0
  68. data/lib/ddtrace/contrib/sidekiq/server_internal_tracer/scheduled_push.rb +29 -0
  69. data/lib/ddtrace/contrib/sinatra/env.rb +2 -1
  70. data/lib/ddtrace/contrib/sinatra/tracer.rb +15 -2
  71. data/lib/ddtrace/ext/git.rb +12 -0
  72. data/lib/ddtrace/ext/priority.rb +6 -4
  73. data/lib/ddtrace/ext/profiling.rb +8 -11
  74. data/lib/ddtrace/ext/runtime.rb +3 -0
  75. data/lib/ddtrace/ext/transport.rb +11 -0
  76. data/lib/ddtrace/metrics.rb +2 -2
  77. data/lib/ddtrace/profiling/collectors/stack.rb +112 -72
  78. data/lib/ddtrace/profiling/encoding/profile.rb +10 -2
  79. data/lib/ddtrace/profiling/events/stack.rb +13 -13
  80. data/lib/ddtrace/profiling/native_extension.rb +23 -1
  81. data/lib/ddtrace/profiling/pprof/builder.rb +8 -2
  82. data/lib/ddtrace/profiling/pprof/converter.rb +22 -9
  83. data/lib/ddtrace/profiling/pprof/stack_sample.rb +32 -9
  84. data/lib/ddtrace/profiling/pprof/template.rb +2 -2
  85. data/lib/ddtrace/profiling/scheduler.rb +20 -4
  86. data/lib/ddtrace/profiling/tasks/setup.rb +21 -13
  87. data/lib/ddtrace/profiling/trace_identifiers/ddtrace.rb +10 -9
  88. data/lib/ddtrace/profiling/trace_identifiers/helper.rb +5 -5
  89. data/lib/ddtrace/profiling/transport/http/api/endpoint.rb +8 -15
  90. data/lib/ddtrace/profiling/transport/http.rb +8 -17
  91. data/lib/ddtrace/profiling.rb +0 -2
  92. data/lib/ddtrace/runtime/metrics.rb +14 -0
  93. data/lib/ddtrace/sampler.rb +18 -8
  94. data/lib/ddtrace/sampling/rule_sampler.rb +13 -1
  95. data/lib/ddtrace/span.rb +7 -19
  96. data/lib/ddtrace/tracer.rb +1 -1
  97. data/lib/ddtrace/transport/http/adapters/net.rb +13 -3
  98. data/lib/ddtrace/transport/http/adapters/test.rb +4 -2
  99. data/lib/ddtrace/transport/http/adapters/unix_socket.rb +23 -12
  100. data/lib/ddtrace/transport/http/builder.rb +13 -6
  101. data/lib/ddtrace/transport/http.rb +5 -11
  102. data/lib/ddtrace/utils/time.rb +11 -6
  103. data/lib/ddtrace/version.rb +2 -2
  104. data/lib/ddtrace/workers/{loop.rb → interval_loop.rb} +0 -16
  105. data/lib/ddtrace/workers/polling.rb +1 -1
  106. metadata +40 -10
  107. data/lib/ddtrace/profiling/ext/cpu.rb +0 -67
  108. data/lib/ddtrace/profiling/ext/cthread.rb +0 -156
@@ -0,0 +1,33 @@
1
+ # typed: false
2
+ require 'ddtrace/contrib/patcher'
3
+ require 'ddtrace/contrib/active_job/ext'
4
+ require 'ddtrace/contrib/active_job/events'
5
+ require 'ddtrace/contrib/active_job/log_injection'
6
+
7
+ module Datadog
8
+ module Contrib
9
+ module ActiveJob
10
+ # Patcher enables patching of 'active_job' module.
11
+ module Patcher
12
+ include Contrib::Patcher
13
+
14
+ module_function
15
+
16
+ def target_version
17
+ Integration.version
18
+ end
19
+
20
+ def patch
21
+ Events.subscribe!
22
+ inject_log_correlation if Datadog.configuration[:active_job][:log_injection]
23
+ end
24
+
25
+ def inject_log_correlation
26
+ ::ActiveSupport.on_load(:active_job) do
27
+ include LogInjection
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -1,5 +1,4 @@
1
1
  # typed: false
2
- require 'ddtrace'
3
2
 
4
3
  module Datadog
5
4
  module Contrib
@@ -9,7 +9,7 @@ module Datadog
9
9
  # DelayedJob plugin that instruments invoke_job hook
10
10
  class Plugin < Delayed::Plugin
11
11
  def self.instrument_invoke(job, &block)
12
- return block.call(job) unless tracer && tracer.enabled
12
+ return yield(job) unless tracer && tracer.enabled
13
13
 
14
14
  tracer.trace(Ext::SPAN_JOB, service: configuration[:service_name], resource: job_name(job),
15
15
  on_error: configuration[:error_handler]) do |span|
@@ -29,7 +29,7 @@ module Datadog
29
29
  end
30
30
 
31
31
  def self.instrument_enqueue(job, &block)
32
- return block.call(job) unless tracer && tracer.enabled
32
+ return yield(job) unless tracer && tracer.enabled
33
33
 
34
34
  tracer.trace(Ext::SPAN_ENQUEUE, service: configuration[:client_service_name], resource: job_name(job)) do |span|
35
35
  set_sample_rate(span)
@@ -52,7 +52,7 @@ module Datadog
52
52
  module InstanceMethods
53
53
  def datadog_pin
54
54
  @datadog_pin ||= begin
55
- service = Datadog.configuration[:mongo][:service_name]
55
+ service = Datadog.configuration[:mongo, seed][:service_name]
56
56
 
57
57
  Datadog::Pin.new(
58
58
  service,
@@ -1,5 +1,6 @@
1
1
  # typed: false
2
2
  require 'ddtrace/contrib/integration'
3
+ require 'ddtrace/contrib/configuration/resolvers/pattern_resolver'
3
4
  require 'ddtrace/contrib/mongodb/configuration/settings'
4
5
  require 'ddtrace/contrib/mongodb/patcher'
5
6
 
@@ -33,6 +34,10 @@ module Datadog
33
34
  def patcher
34
35
  Patcher
35
36
  end
37
+
38
+ def resolver
39
+ @resolver ||= Contrib::Configuration::Resolvers::PatternResolver.new
40
+ end
36
41
  end
37
42
  end
38
43
  end
@@ -1,5 +1,4 @@
1
1
  # typed: ignore
2
- require 'ddtrace'
3
2
 
4
3
  # Railtie to include AutoInstrumentation in rails loading
5
4
  class DatadogAutoInstrumentRailtie < Rails::Railtie
@@ -73,6 +73,13 @@ module Datadog
73
73
  end
74
74
  end
75
75
 
76
+ option :job_service do |o|
77
+ o.on_set do |value|
78
+ # Update ActiveJob service name too
79
+ Datadog.configuration[:active_job][:service_name] = value
80
+ end
81
+ end
82
+
76
83
  option :middleware, default: true
77
84
  option :middleware_names, default: false
78
85
  option :template_base_path do |o|
@@ -5,6 +5,7 @@ require 'ddtrace/ext/app_types'
5
5
  require 'ddtrace/contrib/active_record/integration'
6
6
  require 'ddtrace/contrib/active_support/integration'
7
7
  require 'ddtrace/contrib/action_cable/integration'
8
+ require 'ddtrace/contrib/action_mailer/integration'
8
9
  require 'ddtrace/contrib/action_pack/integration'
9
10
  require 'ddtrace/contrib/action_view/integration'
10
11
  require 'ddtrace/contrib/grape/endpoint'
@@ -21,7 +22,7 @@ module Datadog
21
22
  # Rails framework code, used to essentially:
22
23
  # - handle configuration entries which are specific to Datadog tracing
23
24
  # - instrument parts of the framework when needed
24
- module Framework
25
+ module Framework # rubocop:disable Metrics/ModuleLength
25
26
  # After the Rails application finishes initializing, we configure the Rails
26
27
  # integration and all its sub-components with the application information
27
28
  # available.
@@ -45,9 +46,11 @@ module Datadog
45
46
 
46
47
  activate_rack!(datadog_config, rails_config)
47
48
  activate_action_cable!(datadog_config, rails_config)
49
+ activate_action_mailer!(datadog_config, rails_config)
48
50
  activate_active_support!(datadog_config, rails_config)
49
51
  activate_action_pack!(datadog_config, rails_config)
50
52
  activate_action_view!(datadog_config, rails_config)
53
+ activate_active_job!(datadog_config, rails_config)
51
54
  activate_active_record!(datadog_config, rails_config)
52
55
  activate_lograge!(datadog_config, rails_config)
53
56
  activate_semantic_logger!(datadog_config, rails_config)
@@ -62,6 +65,7 @@ module Datadog
62
65
  config[:database_service] ||= "#{config[:service_name]}-#{Contrib::ActiveRecord::Utils.adapter_name}"
63
66
  config[:controller_service] ||= config[:service_name]
64
67
  config[:cache_service] ||= "#{config[:service_name]}-cache"
68
+ config[:job_service] ||= "#{config[:service_name]}-#{Contrib::ActiveJob::Ext::SERVICE_NAME}"
65
69
  end
66
70
  end
67
71
 
@@ -93,6 +97,15 @@ module Datadog
93
97
  )
94
98
  end
95
99
 
100
+ def self.activate_action_mailer!(datadog_config, rails_config)
101
+ return unless defined?(::ActionMailer)
102
+
103
+ datadog_config.use(
104
+ :action_mailer,
105
+ service_name: "#{rails_config[:service_name]}-#{Contrib::ActionMailer::Ext::SERVICE_NAME}"
106
+ )
107
+ end
108
+
96
109
  def self.activate_action_pack!(datadog_config, rails_config)
97
110
  return unless defined?(::ActionPack)
98
111
 
@@ -115,6 +128,16 @@ module Datadog
115
128
  )
116
129
  end
117
130
 
131
+ def self.activate_active_job!(datadog_config, rails_config)
132
+ return unless defined?(::ActiveJob)
133
+
134
+ datadog_config.use(
135
+ :active_job,
136
+ service_name: rails_config[:job_service],
137
+ log_injection: rails_config[:log_injection]
138
+ )
139
+ end
140
+
118
141
  def self.activate_active_record!(datadog_config, rails_config)
119
142
  return unless defined?(::ActiveRecord)
120
143
 
@@ -1,4 +1,4 @@
1
- # typed: false
1
+ # typed: ignore
2
2
  require 'ddtrace/contrib/rails/utils'
3
3
  require 'ddtrace/contrib/rails/framework'
4
4
  require 'ddtrace/contrib/rails/middlewares'
@@ -45,17 +45,26 @@ module Datadog
45
45
  end
46
46
 
47
47
  def add_middleware(app)
48
- # Add trace middleware
48
+ # Add trace middleware at the top of the middleware stack,
49
+ # to ensure we capture the complete execution time.
49
50
  app.middleware.insert_before(0, Datadog::Contrib::Rack::TraceMiddleware)
50
51
 
51
- # Insert right after Rails exception handling middleware, because if it's before,
52
- # it catches and swallows the error. If it's too far after, custom middleware can find itself
53
- # between, and raise exceptions that don't end up getting tagged on the request properly.
54
- # e.g lost stack trace.
55
- app.middleware.insert_after(
56
- ActionDispatch::ShowExceptions,
57
- Datadog::Contrib::Rails::ExceptionMiddleware
58
- )
52
+ # Some Rails middleware can swallow an application error, preventing
53
+ # the error propagation to the encompassing Rack span.
54
+ #
55
+ # We insert our own middleware right before these Rails middleware
56
+ # have a chance to swallow the error.
57
+ #
58
+ # Note: because the middleware stack is push/pop, "before" and "after" are reversed
59
+ # for our use case: we insert ourselves with "after" a middleware to ensure we are
60
+ # able to pop the request "before" it.
61
+ if defined?(::ActionDispatch::DebugExceptions)
62
+ # Rails >= 3.2
63
+ app.middleware.insert_after(::ActionDispatch::DebugExceptions, Datadog::Contrib::Rails::ExceptionMiddleware)
64
+ else
65
+ # Rails < 3.2
66
+ app.middleware.insert_after(::ActionDispatch::ShowExceptions, Datadog::Contrib::Rails::ExceptionMiddleware)
67
+ end
59
68
  end
60
69
 
61
70
  def add_logger(app)
@@ -0,0 +1,90 @@
1
+ # typed: false
2
+ require 'ddtrace/contrib/patcher'
3
+ require 'ddtrace/contrib/redis/ext'
4
+ require 'ddtrace/contrib/redis/configuration/resolver'
5
+
6
+ module Datadog
7
+ module Contrib
8
+ module Redis
9
+ # Instrumentation for Redis
10
+ module Instrumentation
11
+ def self.included(base)
12
+ base.prepend(InstanceMethods)
13
+ end
14
+
15
+ # InstanceMethods - implementing instrumentation
16
+ module InstanceMethods
17
+ def call(*args, &block)
18
+ pin = Datadog::Pin.get_from(self)
19
+ return super unless pin && pin.tracer
20
+
21
+ response = nil
22
+ pin.tracer.trace(Datadog::Contrib::Redis::Ext::SPAN_COMMAND) do |span|
23
+ span.service = pin.service
24
+ span.span_type = Datadog::Contrib::Redis::Ext::TYPE
25
+ span.resource = get_command(args)
26
+ Datadog::Contrib::Redis::Tags.set_common_tags(self, span)
27
+
28
+ response = super
29
+ end
30
+
31
+ response
32
+ end
33
+
34
+ def call_pipeline(*args, &block)
35
+ pin = Datadog::Pin.get_from(self)
36
+ return super unless pin && pin.tracer
37
+
38
+ response = nil
39
+ pin.tracer.trace(Datadog::Contrib::Redis::Ext::SPAN_COMMAND) do |span|
40
+ span.service = pin.service
41
+ span.span_type = Datadog::Contrib::Redis::Ext::TYPE
42
+ commands = get_pipeline_commands(args)
43
+ span.resource = commands.join("\n")
44
+ span.set_metric Datadog::Contrib::Redis::Ext::METRIC_PIPELINE_LEN, commands.length
45
+ Datadog::Contrib::Redis::Tags.set_common_tags(self, span)
46
+
47
+ response = super
48
+ end
49
+
50
+ response
51
+ end
52
+
53
+ def datadog_pin
54
+ @datadog_pin ||= begin
55
+ pin = Datadog::Pin.new(
56
+ datadog_configuration[:service_name],
57
+ app: Ext::APP,
58
+ app_type: Datadog::Ext::AppTypes::DB,
59
+ tracer: -> { datadog_configuration[:tracer] }
60
+ )
61
+ pin.onto(self)
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ def get_command(args)
68
+ if datadog_configuration[:command_args]
69
+ Datadog::Contrib::Redis::Quantize.format_command_args(*args)
70
+ else
71
+ Datadog::Contrib::Redis::Quantize.get_verb(*args)
72
+ end
73
+ end
74
+
75
+ def get_pipeline_commands(args)
76
+ if datadog_configuration[:command_args]
77
+ args[0].commands.map { |c| Datadog::Contrib::Redis::Quantize.format_command_args(c) }
78
+ else
79
+ args[0].commands.map { |c| Datadog::Contrib::Redis::Quantize.get_verb(c) }
80
+ end
81
+ end
82
+
83
+ def datadog_configuration
84
+ Datadog.configuration[:redis, options]
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -23,92 +23,10 @@ module Datadog
23
23
  require 'ddtrace/ext/app_types'
24
24
  require 'ddtrace/contrib/redis/tags'
25
25
  require 'ddtrace/contrib/redis/quantize'
26
+ require 'ddtrace/contrib/redis/instrumentation'
26
27
 
27
- patch_redis_client
28
+ ::Redis::Client.include(Instrumentation)
28
29
  end
29
-
30
- # rubocop:disable Metrics/MethodLength
31
- # rubocop:disable Metrics/BlockLength
32
- # rubocop:disable Metrics/AbcSize
33
- def patch_redis_client
34
- ::Redis::Client.class_eval do
35
- alias_method :call_without_datadog, :call
36
- remove_method :call
37
- def call(*args, &block)
38
- pin = Datadog::Pin.get_from(self)
39
- return call_without_datadog(*args, &block) unless pin && pin.tracer
40
-
41
- response = nil
42
- pin.tracer.trace(Datadog::Contrib::Redis::Ext::SPAN_COMMAND) do |span|
43
- span.service = pin.service
44
- span.span_type = Datadog::Contrib::Redis::Ext::TYPE
45
- span.resource = get_command(args)
46
- Datadog::Contrib::Redis::Tags.set_common_tags(self, span)
47
-
48
- response = call_without_datadog(*args, &block)
49
- end
50
-
51
- response
52
- end
53
-
54
- alias_method :call_pipeline_without_datadog, :call_pipeline
55
- remove_method :call_pipeline
56
- def call_pipeline(*args, &block)
57
- pin = Datadog::Pin.get_from(self)
58
- return call_pipeline_without_datadog(*args, &block) unless pin && pin.tracer
59
-
60
- response = nil
61
- pin.tracer.trace(Datadog::Contrib::Redis::Ext::SPAN_COMMAND) do |span|
62
- span.service = pin.service
63
- span.span_type = Datadog::Contrib::Redis::Ext::TYPE
64
- commands = get_pipeline_commands(args)
65
- span.resource = commands.join("\n")
66
- span.set_metric Datadog::Contrib::Redis::Ext::METRIC_PIPELINE_LEN, commands.length
67
- Datadog::Contrib::Redis::Tags.set_common_tags(self, span)
68
-
69
- response = call_pipeline_without_datadog(*args, &block)
70
- end
71
-
72
- response
73
- end
74
-
75
- def datadog_pin
76
- @datadog_pin ||= begin
77
- pin = Datadog::Pin.new(
78
- datadog_configuration[:service_name],
79
- app: Ext::APP,
80
- app_type: Datadog::Ext::AppTypes::DB,
81
- tracer: -> { datadog_configuration[:tracer] }
82
- )
83
- pin.onto(self)
84
- end
85
- end
86
-
87
- private
88
-
89
- def get_command(args)
90
- if datadog_configuration[:command_args]
91
- Datadog::Contrib::Redis::Quantize.format_command_args(*args)
92
- else
93
- Datadog::Contrib::Redis::Quantize.get_verb(*args)
94
- end
95
- end
96
-
97
- def get_pipeline_commands(args)
98
- if datadog_configuration[:command_args]
99
- args[0].commands.map { |c| Datadog::Contrib::Redis::Quantize.format_command_args(c) }
100
- else
101
- args[0].commands.map { |c| Datadog::Contrib::Redis::Quantize.get_verb(c) }
102
- end
103
- end
104
-
105
- def datadog_configuration
106
- Datadog.configuration[:redis, options]
107
- end
108
- end
109
- end
110
- # rubocop:enable Metrics/MethodLength
111
- # rubocop:enable Metrics/BlockLength
112
30
  end
113
31
  end
114
32
  end
@@ -1,5 +1,4 @@
1
1
  # typed: false
2
- require 'datadog/contrib'
3
2
 
4
3
  module Datadog
5
4
  module Contrib
@@ -11,8 +11,6 @@ module Datadog
11
11
  include Contrib::Integration
12
12
 
13
13
  MINIMUM_VERSION = Gem::Version.new('1.0')
14
- # Maximum is first version it's NOT compatible with (not inclusive)
15
- MAXIMUM_VERSION = Gem::Version.new('3.0')
16
14
 
17
15
  register_as :resque, auto_patch: true
18
16
 
@@ -25,9 +23,7 @@ module Datadog
25
23
  end
26
24
 
27
25
  def self.compatible?
28
- super \
29
- && version >= MINIMUM_VERSION \
30
- && version < MAXIMUM_VERSION
26
+ super && version >= MINIMUM_VERSION
31
27
  end
32
28
 
33
29
  def default_configuration
@@ -15,6 +15,9 @@ module Datadog
15
15
  SERVICE_NAME = 'sidekiq'.freeze
16
16
  SPAN_PUSH = 'sidekiq.push'.freeze
17
17
  SPAN_JOB = 'sidekiq.job'.freeze
18
+ SPAN_JOB_FETCH = 'sidekiq.job_fetch'.freeze
19
+ SPAN_HEARTBEAT = 'sidekiq.heartbeat'.freeze
20
+ SPAN_SCHEDULED_PUSH = 'sidekiq.scheduled_push'.freeze
18
21
  TAG_JOB_DELAY = 'sidekiq.job.delay'.freeze
19
22
  TAG_JOB_ID = 'sidekiq.job.id'.freeze
20
23
  TAG_JOB_QUEUE = 'sidekiq.job.queue'.freeze
@@ -11,6 +11,7 @@ module Datadog
11
11
  include Contrib::Integration
12
12
 
13
13
  MINIMUM_VERSION = Gem::Version.new('3.5.4')
14
+ MINIMUM_SERVER_INTERNAL_TRACING_VERSION = Gem::Version.new('5.2.4')
14
15
 
15
16
  register_as :sidekiq
16
17
 
@@ -26,6 +27,15 @@ module Datadog
26
27
  super && version >= MINIMUM_VERSION
27
28
  end
28
29
 
30
+ # Only patch server internals on v5.2.4+ because that's when loading of
31
+ # `Sidekiq::Launcher` stabilized. Sidekiq 4+ technically can support our
32
+ # patches (with minor adjustments), but in order to avoid explicitly
33
+ # requiring `sidekiq/launcher` ourselves (which could affect gem
34
+ # initialization order), we are limiting this tracing to v5.2.4+.
35
+ def self.compatible_with_server_internal_tracing?
36
+ version >= MINIMUM_SERVER_INTERNAL_TRACING_VERSION
37
+ end
38
+
29
39
  def default_configuration
30
40
  Configuration::Settings.new
31
41
  end
@@ -34,8 +34,34 @@ module Datadog
34
34
  config.server_middleware do |chain|
35
35
  chain.add(Sidekiq::ServerTracer)
36
36
  end
37
+
38
+ patch_server_internals if Integration.compatible_with_server_internal_tracing?
37
39
  end
38
40
  end
41
+
42
+ def patch_server_internals
43
+ patch_server_heartbeat
44
+ patch_server_job_fetch
45
+ patch_server_scheduled_push
46
+ end
47
+
48
+ def patch_server_heartbeat
49
+ require 'ddtrace/contrib/sidekiq/server_internal_tracer/heartbeat'
50
+
51
+ ::Sidekiq::Launcher.prepend(ServerInternalTracer::Heartbeat)
52
+ end
53
+
54
+ def patch_server_job_fetch
55
+ require 'ddtrace/contrib/sidekiq/server_internal_tracer/job_fetch'
56
+
57
+ ::Sidekiq::Processor.prepend(ServerInternalTracer::JobFetch)
58
+ end
59
+
60
+ def patch_server_scheduled_push
61
+ require 'ddtrace/contrib/sidekiq/server_internal_tracer/scheduled_push'
62
+
63
+ ::Sidekiq::Scheduled::Poller.prepend(ServerInternalTracer::ScheduledPush)
64
+ end
39
65
  end
40
66
  end
41
67
  end
@@ -0,0 +1,30 @@
1
+ # typed: true
2
+
3
+ module Datadog
4
+ module Contrib
5
+ module Sidekiq
6
+ module ServerInternalTracer
7
+ # Trace when a Sidekiq process has a heartbeat
8
+ module Heartbeat
9
+ private
10
+
11
+ def ❤ # rubocop:disable Naming/AsciiIdentifiers, Naming/MethodName
12
+ configuration = Datadog.configuration[:sidekiq]
13
+
14
+ configuration[:tracer].trace(Ext::SPAN_HEARTBEAT) do |span|
15
+ span.service = configuration[:service_name]
16
+ span.span_type = Datadog::Ext::AppTypes::WORKER
17
+
18
+ # Set analytics sample rate
19
+ if Contrib::Analytics.enabled?(configuration[:analytics_enabled])
20
+ Contrib::Analytics.set_sample_rate(span, configuration[:analytics_sample_rate])
21
+ end
22
+
23
+ super
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ # typed: true
2
+
3
+ module Datadog
4
+ module Contrib
5
+ module Sidekiq
6
+ module ServerInternalTracer
7
+ # Trace when Sidekiq looks for another job to work
8
+ module JobFetch
9
+ private
10
+
11
+ def fetch
12
+ configuration = Datadog.configuration[:sidekiq]
13
+
14
+ configuration[:tracer].trace(Ext::SPAN_JOB_FETCH) do |span|
15
+ span.service = configuration[:service_name]
16
+ span.span_type = Datadog::Ext::AppTypes::WORKER
17
+
18
+ # Set analytics sample rate
19
+ if Contrib::Analytics.enabled?(configuration[:analytics_enabled])
20
+ Contrib::Analytics.set_sample_rate(span, configuration[:analytics_sample_rate])
21
+ end
22
+
23
+ super
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,29 @@
1
+ # typed: true
2
+
3
+ module Datadog
4
+ module Contrib
5
+ module Sidekiq
6
+ module ServerInternalTracer
7
+ # Trace when Sidekiq checks to see if there are scheduled jobs that need to be worked
8
+ # https://github.com/mperham/sidekiq/wiki/Scheduled-Jobs
9
+ module ScheduledPush
10
+ def enqueue
11
+ configuration = Datadog.configuration[:sidekiq]
12
+
13
+ configuration[:tracer].trace(Ext::SPAN_SCHEDULED_PUSH) do |span|
14
+ span.service = configuration[:service_name]
15
+ span.span_type = Datadog::Ext::AppTypes::WORKER
16
+
17
+ # Set analytics sample rate
18
+ if Contrib::Analytics.enabled?(configuration[:analytics_enabled])
19
+ Contrib::Analytics.set_sample_rate(span, configuration[:analytics_sample_rate])
20
+ end
21
+
22
+ super
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -10,7 +10,8 @@ module Datadog
10
10
  module_function
11
11
 
12
12
  def datadog_span(env, app)
13
- env[Ext::RACK_ENV_REQUEST_SPAN][app]
13
+ request_span = env[Ext::RACK_ENV_REQUEST_SPAN]
14
+ request_span && request_span[app]
14
15
  end
15
16
 
16
17
  def set_datadog_span(env, app, span)
@@ -5,7 +5,7 @@ require 'ddtrace/ext/app_types'
5
5
  require 'ddtrace/ext/errors'
6
6
  require 'ddtrace/ext/http'
7
7
  require 'ddtrace/propagation/http_propagator'
8
-
8
+ require 'ddtrace/utils/only_once'
9
9
  require 'ddtrace/contrib/sinatra/ext'
10
10
  require 'ddtrace/contrib/sinatra/tracer_middleware'
11
11
  require 'ddtrace/contrib/sinatra/env'
@@ -77,6 +77,9 @@ module Datadog
77
77
 
78
78
  # Method overrides for Sinatra::Base
79
79
  module Base
80
+ MISSING_REQUEST_SPAN_ONLY_ONCE = Datadog::Utils::OnlyOnce.new
81
+ private_constant :MISSING_REQUEST_SPAN_ONLY_ONCE
82
+
80
83
  def render(engine, data, *)
81
84
  tracer = Datadog.configuration[:sinatra][:tracer]
82
85
  return super unless tracer.enabled
@@ -121,8 +124,18 @@ module Datadog
121
124
  else
122
125
  Sinatra::Env.datadog_span(env, self.class)
123
126
  end
124
- if sinatra_request_span # DEV: Is it possible for sinatra_request_span to ever be nil here?
127
+ if sinatra_request_span
125
128
  sinatra_request_span.resource = span.resource
129
+ else
130
+ MISSING_REQUEST_SPAN_ONLY_ONCE.run do
131
+ Datadog.logger.warn do
132
+ 'Sinatra integration is misconfigured, reported traces will be missing request metadata ' \
133
+ 'such as path and HTTP status code. ' \
134
+ 'Did you forget to add `register Datadog::Contrib::Sinatra::Tracer` to your ' \
135
+ '`Sinatra::Base` subclass? ' \
136
+ 'See <https://docs.datadoghq.com/tracing/setup_overview/setup/ruby/#sinatra> for more details.'
137
+ end
138
+ end
126
139
  end
127
140
 
128
141
  Contrib::Analytics.set_measured(span)
@@ -15,6 +15,18 @@ module Datadog
15
15
  TAG_COMMIT_COMMITTER_NAME = 'git.commit.committer.name'.freeze
16
16
  TAG_COMMIT_MESSAGE = 'git.commit.message'.freeze
17
17
  TAG_COMMIT_SHA = 'git.commit.sha'.freeze
18
+
19
+ ENV_REPOSITORY_URL = 'DD_GIT_REPOSITORY_URL'.freeze
20
+ ENV_COMMIT_SHA = 'DD_GIT_COMMIT_SHA'.freeze
21
+ ENV_BRANCH = 'DD_GIT_BRANCH'.freeze
22
+ ENV_TAG = 'DD_GIT_TAG'.freeze
23
+ ENV_COMMIT_MESSAGE = 'DD_GIT_COMMIT_MESSAGE'.freeze
24
+ ENV_COMMIT_AUTHOR_NAME = 'DD_GIT_COMMIT_AUTHOR_NAME'.freeze
25
+ ENV_COMMIT_AUTHOR_EMAIL = 'DD_GIT_COMMIT_AUTHOR_EMAIL'.freeze
26
+ ENV_COMMIT_AUTHOR_DATE = 'DD_GIT_COMMIT_AUTHOR_DATE'.freeze
27
+ ENV_COMMIT_COMMITTER_NAME = 'DD_GIT_COMMIT_COMMITTER_NAME'.freeze
28
+ ENV_COMMIT_COMMITTER_EMAIL = 'DD_GIT_COMMIT_COMMITTER_EMAIL'.freeze
29
+ ENV_COMMIT_COMMITTER_DATE = 'DD_GIT_COMMIT_COMMITTER_DATE'.freeze
18
30
  end
19
31
  end
20
32
  end