ddtrace 0.52.0 → 0.54.2

Sign up to get free protection for your applications and to get access to all the features.
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