ddtrace 0.34.1 → 0.36.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +58 -9
  3. data/.circleci/images/primary/Dockerfile-jruby-9.2 +77 -0
  4. data/.rubocop.yml +4 -0
  5. data/Appraisals +9 -7
  6. data/CHANGELOG.md +89 -3
  7. data/Rakefile +11 -2
  8. data/ddtrace.gemspec +5 -3
  9. data/docker-compose.yml +35 -0
  10. data/docs/DevelopmentGuide.md +1 -1
  11. data/docs/GettingStarted.md +89 -36
  12. data/lib/ddtrace.rb +1 -1
  13. data/lib/ddtrace/buffer.rb +9 -9
  14. data/lib/ddtrace/chunker.rb +34 -0
  15. data/lib/ddtrace/configuration.rb +28 -5
  16. data/lib/ddtrace/configuration/base.rb +1 -1
  17. data/lib/ddtrace/configuration/components.rb +154 -0
  18. data/lib/ddtrace/configuration/options.rb +1 -1
  19. data/lib/ddtrace/configuration/settings.rb +131 -63
  20. data/lib/ddtrace/context.rb +6 -6
  21. data/lib/ddtrace/context_flush.rb +1 -1
  22. data/lib/ddtrace/contrib/action_cable/instrumentation.rb +1 -1
  23. data/lib/ddtrace/contrib/action_pack/action_controller/instrumentation.rb +2 -2
  24. data/lib/ddtrace/contrib/action_view/events/render_partial.rb +1 -1
  25. data/lib/ddtrace/contrib/action_view/events/render_template.rb +1 -1
  26. data/lib/ddtrace/contrib/action_view/instrumentation/partial_renderer.rb +1 -1
  27. data/lib/ddtrace/contrib/action_view/instrumentation/template_renderer.rb +2 -2
  28. data/lib/ddtrace/contrib/action_view/patcher.rb +1 -1
  29. data/lib/ddtrace/contrib/active_record/events/instantiation.rb +1 -1
  30. data/lib/ddtrace/contrib/active_record/events/sql.rb +1 -1
  31. data/lib/ddtrace/contrib/active_support/cache/instrumentation.rb +2 -2
  32. data/lib/ddtrace/contrib/active_support/notifications/subscription.rb +2 -2
  33. data/lib/ddtrace/contrib/analytics.rb +1 -1
  34. data/lib/ddtrace/contrib/configuration/settings.rb +1 -1
  35. data/lib/ddtrace/contrib/dalli/patcher.rb +1 -1
  36. data/lib/ddtrace/contrib/dalli/quantize.rb +1 -1
  37. data/lib/ddtrace/contrib/elasticsearch/patcher.rb +1 -1
  38. data/lib/ddtrace/contrib/excon/middleware.rb +2 -2
  39. data/lib/ddtrace/contrib/extensions.rb +29 -5
  40. data/lib/ddtrace/contrib/faraday/patcher.rb +1 -1
  41. data/lib/ddtrace/contrib/grape/endpoint.rb +5 -5
  42. data/lib/ddtrace/contrib/grape/patcher.rb +1 -1
  43. data/lib/ddtrace/contrib/grpc/datadog_interceptor/client.rb +1 -1
  44. data/lib/ddtrace/contrib/grpc/datadog_interceptor/server.rb +2 -2
  45. data/lib/ddtrace/contrib/grpc/patcher.rb +1 -1
  46. data/lib/ddtrace/contrib/http/circuit_breaker.rb +8 -32
  47. data/lib/ddtrace/contrib/http/instrumentation.rb +2 -2
  48. data/lib/ddtrace/contrib/mongodb/subscribers.rb +2 -2
  49. data/lib/ddtrace/contrib/patchable.rb +1 -1
  50. data/lib/ddtrace/contrib/patcher.rb +3 -3
  51. data/lib/ddtrace/contrib/presto/instrumentation.rb +3 -3
  52. data/lib/ddtrace/contrib/presto/patcher.rb +1 -1
  53. data/lib/ddtrace/contrib/rack/middlewares.rb +2 -2
  54. data/lib/ddtrace/contrib/rack/patcher.rb +2 -2
  55. data/lib/ddtrace/contrib/rack/request_queue.rb +1 -1
  56. data/lib/ddtrace/contrib/rails/configuration/settings.rb +14 -0
  57. data/lib/ddtrace/contrib/rails/framework.rb +54 -48
  58. data/lib/ddtrace/contrib/rails/integration.rb +1 -1
  59. data/lib/ddtrace/contrib/rake/instrumentation.rb +2 -2
  60. data/lib/ddtrace/contrib/redis/quantize.rb +1 -1
  61. data/lib/ddtrace/contrib/resque/resque_job.rb +2 -2
  62. data/lib/ddtrace/contrib/sidekiq/tracing.rb +1 -1
  63. data/lib/ddtrace/contrib/sinatra/env.rb +20 -0
  64. data/lib/ddtrace/contrib/sinatra/ext.rb +6 -0
  65. data/lib/ddtrace/contrib/sinatra/patcher.rb +1 -0
  66. data/lib/ddtrace/contrib/sinatra/tracer.rb +98 -35
  67. data/lib/ddtrace/contrib/sinatra/tracer_middleware.rb +16 -13
  68. data/lib/ddtrace/correlation.rb +9 -6
  69. data/lib/ddtrace/diagnostics/health.rb +2 -6
  70. data/lib/ddtrace/encoding.rb +13 -39
  71. data/lib/ddtrace/event.rb +1 -1
  72. data/lib/ddtrace/ext/correlation.rb +1 -0
  73. data/lib/ddtrace/ext/diagnostics.rb +2 -0
  74. data/lib/ddtrace/ext/environment.rb +1 -0
  75. data/lib/ddtrace/ext/forced_tracing.rb +1 -1
  76. data/lib/ddtrace/logger.rb +3 -44
  77. data/lib/ddtrace/metrics.rb +5 -5
  78. data/lib/ddtrace/monkey.rb +1 -1
  79. data/lib/ddtrace/opentracer/global_tracer.rb +1 -1
  80. data/lib/ddtrace/pin.rb +18 -17
  81. data/lib/ddtrace/pipeline.rb +1 -1
  82. data/lib/ddtrace/propagation/http_propagator.rb +2 -2
  83. data/lib/ddtrace/runtime/cgroup.rb +1 -1
  84. data/lib/ddtrace/runtime/container.rb +1 -1
  85. data/lib/ddtrace/runtime/metrics.rb +5 -2
  86. data/lib/ddtrace/sampler.rb +2 -2
  87. data/lib/ddtrace/sampling/rule.rb +1 -1
  88. data/lib/ddtrace/sampling/rule_sampler.rb +1 -1
  89. data/lib/ddtrace/span.rb +4 -4
  90. data/lib/ddtrace/sync_writer.rb +3 -8
  91. data/lib/ddtrace/tracer.rb +26 -31
  92. data/lib/ddtrace/transport/http.rb +1 -1
  93. data/lib/ddtrace/transport/http/api/instance.rb +4 -0
  94. data/lib/ddtrace/transport/http/builder.rb +3 -5
  95. data/lib/ddtrace/transport/http/client.rb +7 -64
  96. data/lib/ddtrace/transport/http/response.rb +1 -1
  97. data/lib/ddtrace/transport/http/statistics.rb +1 -1
  98. data/lib/ddtrace/transport/http/traces.rb +10 -7
  99. data/lib/ddtrace/transport/io.rb +1 -1
  100. data/lib/ddtrace/transport/io/client.rb +2 -2
  101. data/lib/ddtrace/transport/io/response.rb +3 -1
  102. data/lib/ddtrace/transport/io/traces.rb +50 -3
  103. data/lib/ddtrace/transport/parcel.rb +0 -4
  104. data/lib/ddtrace/transport/statistics.rb +2 -2
  105. data/lib/ddtrace/transport/traces.rb +160 -10
  106. data/lib/ddtrace/utils.rb +1 -1
  107. data/lib/ddtrace/version.rb +2 -2
  108. data/lib/ddtrace/workers.rb +5 -13
  109. data/lib/ddtrace/workers/async.rb +2 -2
  110. data/lib/ddtrace/workers/runtime_metrics.rb +47 -0
  111. data/lib/ddtrace/workers/trace_writer.rb +199 -0
  112. data/lib/ddtrace/writer.rb +20 -27
  113. metadata +22 -32
@@ -37,7 +37,7 @@ module Datadog
37
37
  pin = datadog_pin(request_options)
38
38
  return super(req, body, &block) unless pin && pin.tracer
39
39
 
40
- if Datadog::Contrib::HTTP.should_skip_tracing?(req, @address, @port, pin.tracer)
40
+ if Datadog::Contrib::HTTP.should_skip_tracing?(req, pin.tracer)
41
41
  return super(req, body, &block)
42
42
  end
43
43
 
@@ -58,7 +58,7 @@ module Datadog
58
58
  # Add additional request specific tags to the span.
59
59
  annotate_span_with_request!(span, req, request_options)
60
60
  rescue StandardError => e
61
- Datadog::Logger.log.error("error preparing span for http request: #{e}")
61
+ Datadog.logger.error("error preparing span for http request: #{e}")
62
62
  ensure
63
63
  response = super(req, body, &block)
64
64
  end
@@ -50,7 +50,7 @@ module Datadog
50
50
  # the framework itself, so we set only the error and the message
51
51
  span.set_error(event)
52
52
  rescue StandardError => e
53
- Datadog::Logger.log.debug("error when handling MongoDB 'failed' event: #{e}")
53
+ Datadog.logger.debug("error when handling MongoDB 'failed' event: #{e}")
54
54
  ensure
55
55
  # whatever happens, the Span must be removed from the local storage and
56
56
  # it must be finished to prevent any leak
@@ -66,7 +66,7 @@ module Datadog
66
66
  rows = event.reply.fetch('n', nil)
67
67
  span.set_tag(Ext::TAG_ROWS, rows) unless rows.nil?
68
68
  rescue StandardError => e
69
- Datadog::Logger.log.debug("error when handling MongoDB 'succeeded' event: #{e}")
69
+ Datadog.logger.debug("error when handling MongoDB 'succeeded' event: #{e}")
70
70
  ensure
71
71
  # whatever happens, the Span must be removed from the local storage and
72
72
  # it must be finished to prevent any leak
@@ -47,7 +47,7 @@ module Datadog
47
47
  desc += ", Compatible? #{self.class.compatible?}"
48
48
  desc += ", Patchable? #{self.class.patchable?}"
49
49
 
50
- Datadog::Logger.log.warn("Unable to patch #{self.class.name} (#{desc})")
50
+ Datadog.logger.warn("Unable to patch #{self.class.name} (#{desc})")
51
51
  return
52
52
  end
53
53
 
@@ -28,17 +28,17 @@ module Datadog
28
28
  begin
29
29
  super.tap do
30
30
  # Emit a metric
31
- Diagnostics::Health.metrics.instrumentation_patched(1, tags: default_tags)
31
+ Datadog.health_metrics.instrumentation_patched(1, tags: default_tags)
32
32
  end
33
33
  rescue StandardError => e
34
34
  # Log the error
35
- Datadog::Logger.log.error("Failed to apply #{patch_name} patch. Cause: #{e} Location: #{e.backtrace.first}")
35
+ Datadog.logger.error("Failed to apply #{patch_name} patch. Cause: #{e} Location: #{e.backtrace.first}")
36
36
 
37
37
  # Emit a metric
38
38
  tags = default_tags
39
39
  tags << "error:#{e.class.name}"
40
40
 
41
- Diagnostics::Health.metrics.error_instrumentation_patch(1, tags: tags)
41
+ Datadog.health_metrics.error_instrumentation_patch(1, tags: tags)
42
42
  end
43
43
  end
44
44
  end
@@ -24,7 +24,7 @@ module Datadog
24
24
  span.span_type = Datadog::Ext::SQL::TYPE
25
25
  span.set_tag(Ext::TAG_QUERY_ASYNC, false)
26
26
  rescue StandardError => e
27
- Datadog::Logger.log.debug("error preparing span for presto: #{e}")
27
+ Datadog.logger.debug("error preparing span for presto: #{e}")
28
28
  end
29
29
 
30
30
  super(query)
@@ -39,7 +39,7 @@ module Datadog
39
39
  span.span_type = Datadog::Ext::SQL::TYPE
40
40
  span.set_tag(Ext::TAG_QUERY_ASYNC, !blk.nil?)
41
41
  rescue StandardError => e
42
- Datadog::Logger.log.debug("error preparing span for presto: #{e}")
42
+ Datadog.logger.debug("error preparing span for presto: #{e}")
43
43
  end
44
44
 
45
45
  super(query, &blk)
@@ -55,7 +55,7 @@ module Datadog
55
55
  # ^ not an SQL type span, since there's no SQL query
56
56
  span.set_tag(Ext::TAG_QUERY_ID, query_id)
57
57
  rescue StandardError => e
58
- Datadog::Logger.log.debug("error preparing span for presto: #{e}")
58
+ Datadog.logger.debug("error preparing span for presto: #{e}")
59
59
  end
60
60
 
61
61
  super(query_id)
@@ -20,7 +20,7 @@ module Datadog
20
20
  begin
21
21
  ::Presto::Client::Client.send(:include, Instrumentation::Client)
22
22
  rescue StandardError => e
23
- Datadog::Logger.log.error("Unable to apply Presto integration: #{e}")
23
+ Datadog.logger.error("Unable to apply Presto integration: #{e}")
24
24
  end
25
25
  end
26
26
  end
@@ -222,7 +222,7 @@ module Datadog
222
222
  if key == :datadog_rack_request_span \
223
223
  && @datadog_span_warning \
224
224
  && @datadog_deprecation_warnings
225
- Datadog::Logger.log.warn(REQUEST_SPAN_DEPRECATION_WARNING)
225
+ Datadog.logger.warn(REQUEST_SPAN_DEPRECATION_WARNING)
226
226
  @datadog_span_warning = true
227
227
  end
228
228
  super
@@ -232,7 +232,7 @@ module Datadog
232
232
  if key == :datadog_rack_request_span \
233
233
  && @datadog_span_warning \
234
234
  && @datadog_deprecation_warnings
235
- Datadog::Logger.log.warn(REQUEST_SPAN_DEPRECATION_WARNING)
235
+ Datadog.logger.warn(REQUEST_SPAN_DEPRECATION_WARNING)
236
236
  @datadog_span_warning = true
237
237
  end
238
238
  super
@@ -38,7 +38,7 @@ module Datadog
38
38
  # context of middleware patching outside a Rails server process (eg. a
39
39
  # process that doesn't serve HTTP requests but has Rails environment
40
40
  # loaded such as a Resque master process)
41
- Logger.log.debug("Error patching middleware stack: #{e}")
41
+ Datadog.logger.debug("Error patching middleware stack: #{e}")
42
42
  end
43
43
 
44
44
  def retain_middleware_name(middleware)
@@ -90,7 +90,7 @@ module Datadog
90
90
  if get_option(:application)
91
91
  MiddlewareNamePatcher.patch
92
92
  else
93
- Datadog::Logger.log.warn(%(
93
+ Datadog.logger.warn(%(
94
94
  Rack :middleware_names requires you to also pass :application.
95
95
  Middleware names have NOT been patched; please provide :application.
96
96
  e.g. use: :rack, middleware_names: true, application: my_rack_app).freeze)
@@ -30,7 +30,7 @@ module Datadog
30
30
  rescue StandardError => e
31
31
  # in case of an Exception we don't create a
32
32
  # `request.queuing` span
33
- Datadog::Logger.log.debug("[rack] unable to parse request queue headers: #{e}")
33
+ Datadog.logger.debug("[rack] unable to parse request queue headers: #{e}")
34
34
  nil
35
35
  end
36
36
  end
@@ -6,6 +6,19 @@ module Datadog
6
6
  module Configuration
7
7
  # Custom settings for the Rails integration
8
8
  class Settings < Contrib::Configuration::Settings
9
+ def initialize(options = {})
10
+ super(options)
11
+
12
+ # NOTE: Eager load these
13
+ # Rails integration is responsible for orchestrating other integrations.
14
+ # When using environment variables, settings will not be automatically
15
+ # filled because nothing explicitly calls them. They must though, so
16
+ # integrations like ActionPack can receive the value as it should.
17
+ # Trigger these manually to force an eager load and propagate them.
18
+ analytics_enabled
19
+ analytics_sample_rate
20
+ end
21
+
9
22
  option :analytics_enabled do |o|
10
23
  o.default { env_to_bool(Ext::ENV_ANALYTICS_ENABLED, nil) }
11
24
  o.lazy
@@ -72,6 +85,7 @@ module Datadog
72
85
  Datadog.configuration[:active_support][:tracer] = value
73
86
  Datadog.configuration[:action_pack][:tracer] = value
74
87
  Datadog.configuration[:action_view][:tracer] = value
88
+ Datadog.configuration[:rack][:tracer] = value
75
89
  end
76
90
  end
77
91
  end
@@ -21,30 +21,32 @@ module Datadog
21
21
  module Framework
22
22
  # configure Datadog settings
23
23
  def self.setup
24
- config = config_with_defaults
25
-
26
- activate_rack!(config)
27
- activate_action_cable!(config)
28
- activate_active_support!(config)
29
- activate_action_pack!(config)
30
- activate_action_view!(config)
31
- activate_active_record!(config)
32
-
33
- # By default, default service would be guessed from the script
34
- # being executed, but here we know better, get it from Rails config.
35
- # Don't set this if service has been explicitly provided by the user.
36
- Datadog.configuration.service ||= config[:service_name]
37
-
38
- # Set the environment to the Rails environment.
39
- # Don't set this if env has been explicitly provided by the user.
40
- Datadog.configuration.env ||= ::Rails.env if ::Rails.respond_to?(:env)
24
+ rails_config = config_with_defaults
25
+
26
+ # NOTE: #configure has the side effect of rebuilding trace components.
27
+ # During a typical Rails application lifecycle, we will see trace
28
+ # components initialized twice because of this. This is necessary
29
+ # because key configuration is not available until after the Rails
30
+ # application has fully loaded, and some of this configuration is
31
+ # used to reconfigure tracer components with Rails-sourced defaults.
32
+ # This is a trade-off we take to get nice defaults.
33
+ Datadog.configure do |datadog_config|
34
+ # By default, default service would be guessed from the script
35
+ # being executed, but here we know better, get it from Rails config.
36
+ # Don't set this if service has been explicitly provided by the user.
37
+ datadog_config.service ||= rails_config[:service_name]
38
+
39
+ activate_rack!(datadog_config, rails_config)
40
+ activate_action_cable!(datadog_config, rails_config)
41
+ activate_active_support!(datadog_config, rails_config)
42
+ activate_action_pack!(datadog_config, rails_config)
43
+ activate_action_view!(datadog_config, rails_config)
44
+ activate_active_record!(datadog_config, rails_config)
45
+ end
41
46
 
42
47
  # Update the tracer if its not the default tracer.
43
- if config[:tracer] != Datadog.configuration.tracer
44
- config[:tracer].default_service = config[:service_name]
45
-
46
- env = Datadog.configuration.env || (::Rails.respond_to?(:env) && ::Rails.env)
47
- config[:tracer].set_tags('env' => env) if env
48
+ if rails_config[:tracer] != Datadog.configuration.tracer
49
+ rails_config[:tracer].default_service = rails_config[:service_name]
48
50
  end
49
51
  end
50
52
 
@@ -59,64 +61,68 @@ module Datadog
59
61
  end
60
62
  end
61
63
 
62
- def self.activate_rack!(config)
63
- Datadog.configuration.use(
64
+ def self.activate_rack!(datadog_config, rails_config)
65
+ datadog_config.use(
64
66
  :rack,
65
- tracer: config[:tracer],
67
+ tracer: rails_config[:tracer],
66
68
  application: ::Rails.application,
67
- service_name: config[:service_name],
68
- middleware_names: config[:middleware_names],
69
- distributed_tracing: config[:distributed_tracing]
69
+ service_name: rails_config[:service_name],
70
+ middleware_names: rails_config[:middleware_names],
71
+ distributed_tracing: rails_config[:distributed_tracing]
70
72
  )
71
73
  end
72
74
 
73
- def self.activate_active_support!(config)
75
+ def self.activate_active_support!(datadog_config, rails_config)
74
76
  return unless defined?(::ActiveSupport)
75
77
 
76
- Datadog.configuration.use(
78
+ datadog_config.use(
77
79
  :active_support,
78
- cache_service: config[:cache_service],
79
- tracer: config[:tracer]
80
+ cache_service: rails_config[:cache_service],
81
+ tracer: rails_config[:tracer]
80
82
  )
81
83
  end
82
84
 
83
- def self.activate_action_cable!(config)
85
+ def self.activate_action_cable!(datadog_config, rails_config)
84
86
  return unless defined?(::ActionCable)
85
87
 
86
- Datadog.configuration.use(
88
+ datadog_config.use(
87
89
  :action_cable,
88
- service_name: "#{config[:service_name]}-#{Contrib::ActionCable::Ext::SERVICE_NAME}",
89
- tracer: config[:tracer]
90
+ service_name: "#{rails_config[:service_name]}-#{Contrib::ActionCable::Ext::SERVICE_NAME}",
91
+ tracer: rails_config[:tracer]
90
92
  )
91
93
  end
92
94
 
93
- def self.activate_action_pack!(config)
95
+ def self.activate_action_pack!(datadog_config, rails_config)
94
96
  return unless defined?(::ActionPack)
95
97
 
96
- Datadog.configuration.use(
98
+ # TODO: This is configuring ActionPack but not patching. It will queue ActionPack
99
+ # for patching, but patching won't take place until Datadog.configure completes.
100
+ # Should we manually patch here?
101
+
102
+ datadog_config.use(
97
103
  :action_pack,
98
- service_name: config[:service_name],
99
- tracer: config[:tracer]
104
+ service_name: rails_config[:service_name],
105
+ tracer: rails_config[:tracer]
100
106
  )
101
107
  end
102
108
 
103
- def self.activate_action_view!(config)
109
+ def self.activate_action_view!(datadog_config, rails_config)
104
110
  return unless defined?(::ActionView)
105
111
 
106
- Datadog.configuration.use(
112
+ datadog_config.use(
107
113
  :action_view,
108
- service_name: config[:service_name],
109
- tracer: config[:tracer]
114
+ service_name: rails_config[:service_name],
115
+ tracer: rails_config[:tracer]
110
116
  )
111
117
  end
112
118
 
113
- def self.activate_active_record!(config)
119
+ def self.activate_active_record!(datadog_config, rails_config)
114
120
  return unless defined?(::ActiveRecord)
115
121
 
116
- Datadog.configuration.use(
122
+ datadog_config.use(
117
123
  :active_record,
118
- service_name: config[:database_service],
119
- tracer: config[:tracer]
124
+ service_name: rails_config[:database_service],
125
+ tracer: rails_config[:tracer]
120
126
  )
121
127
  end
122
128
  end
@@ -16,7 +16,7 @@ module Datadog
16
16
  register_as :rails, auto_patch: false
17
17
 
18
18
  def self.version
19
- Gem.loaded_specs['rails'] && Gem.loaded_specs['rails'].version
19
+ Gem.loaded_specs['railties'] && Gem.loaded_specs['railties'].version
20
20
  end
21
21
 
22
22
  def self.loaded?
@@ -51,14 +51,14 @@ module Datadog
51
51
  span.set_tag(Ext::TAG_TASK_ARG_NAMES, arg_names)
52
52
  span.set_tag(Ext::TAG_INVOKE_ARGS, quantize_args(args)) unless args.nil?
53
53
  rescue StandardError => e
54
- Datadog::Logger.log.debug("Error while tracing Rake invoke: #{e.message}")
54
+ Datadog.logger.debug("Error while tracing Rake invoke: #{e.message}")
55
55
  end
56
56
 
57
57
  def annotate_execute!(span, args)
58
58
  span.resource = name
59
59
  span.set_tag(Ext::TAG_EXECUTE_ARGS, quantize_args(args.to_hash)) unless args.nil?
60
60
  rescue StandardError => e
61
- Datadog::Logger.log.debug("Error while tracing Rake execute: #{e.message}")
61
+ Datadog.logger.debug("Error while tracing Rake execute: #{e.message}")
62
62
  end
63
63
 
64
64
  def quantize_args(args)
@@ -15,7 +15,7 @@ module Datadog
15
15
  str = Utils.utf8_encode(str, binary: true, placeholder: PLACEHOLDER)
16
16
  Utils.truncate(str, VALUE_MAX_LEN, TOO_LONG_MARK)
17
17
  rescue => e
18
- Datadog::Logger.log.debug("non formattable Redis arg #{str}: #{e}")
18
+ Datadog.logger.debug("non formattable Redis arg #{str}: #{e}")
19
19
  PLACEHOLDER
20
20
  end
21
21
 
@@ -9,11 +9,11 @@ module Datadog
9
9
  module Resque
10
10
  # Uses Resque job hooks to create traces
11
11
  module ResqueJob
12
- def around_perform(*_)
12
+ def around_perform(*args)
13
13
  return yield unless datadog_configuration && tracer
14
14
 
15
15
  tracer.trace(Ext::SPAN_JOB, span_options) do |span|
16
- span.resource = name
16
+ span.resource = args.first.is_a?(Hash) && args.first['job_class'] || name
17
17
  span.span_type = Datadog::Ext::AppTypes::WORKER
18
18
  # Set analytics sample rate
19
19
  if Contrib::Analytics.enabled?(datadog_configuration[:analytics_enabled])
@@ -26,7 +26,7 @@ module Datadog
26
26
  job['class'].to_s
27
27
  end
28
28
  rescue => e
29
- Datadog::Logger.log.debug { "Error retrieving Sidekiq job class name (jid:#{job['jid']}): #{e}" }
29
+ Datadog.logger.debug { "Error retrieving Sidekiq job class name (jid:#{job['jid']}): #{e}" }
30
30
 
31
31
  job['class'].to_s
32
32
  end
@@ -32,6 +32,26 @@ module Datadog
32
32
  def header_to_rack_header(name)
33
33
  "HTTP_#{name.to_s.upcase.gsub(/[-\s]/, '_')}"
34
34
  end
35
+
36
+ # Was a Sinatra already traced in this request?
37
+ # We don't want to create spans for intermediate Sinatra
38
+ # middlewares that don't match the request at hand.
39
+ def middleware_traced?(env)
40
+ env[Ext::RACK_ENV_MIDDLEWARE_TRACED]
41
+ end
42
+
43
+ def set_middleware_traced(env, bool)
44
+ env[Ext::RACK_ENV_MIDDLEWARE_TRACED] = bool
45
+ end
46
+
47
+ # The start time of the top-most Sinatra middleware.
48
+ def middleware_start_time(env)
49
+ env[Ext::RACK_ENV_MIDDLEWARE_START_TIME]
50
+ end
51
+
52
+ def set_middleware_start_time(env, time = Time.now.utc)
53
+ env[Ext::RACK_ENV_MIDDLEWARE_START_TIME] = time
54
+ end
35
55
  end
36
56
  end
37
57
  end
@@ -7,10 +7,16 @@ module Datadog
7
7
  ENV_ANALYTICS_ENABLED = 'DD_SINATRA_ANALYTICS_ENABLED'.freeze
8
8
  ENV_ANALYTICS_SAMPLE_RATE = 'DD_SINATRA_ANALYTICS_SAMPLE_RATE'.freeze
9
9
  RACK_ENV_REQUEST_SPAN = 'datadog.sinatra_request_span'.freeze
10
+ RACK_ENV_MIDDLEWARE_START_TIME = 'datadog.sinatra_middleware_start_time'.freeze
11
+ RACK_ENV_MIDDLEWARE_TRACED = 'datadog.sinatra_middleware_traced'.freeze
10
12
  SERVICE_NAME = 'sinatra'.freeze
11
13
  SPAN_RENDER_TEMPLATE = 'sinatra.render_template'.freeze
12
14
  SPAN_REQUEST = 'sinatra.request'.freeze
15
+ SPAN_ROUTE = 'sinatra.route'.freeze
16
+ TAG_APP_NAME = 'sinatra.app.name'.freeze
13
17
  TAG_ROUTE_PATH = 'sinatra.route.path'.freeze
18
+ TAG_SCRIPT_NAME = 'sinatra.script_name'.freeze
19
+ TAG_TEMPLATE_ENGINE = 'sinatra.template_engine'.freeze
14
20
  TAG_TEMPLATE_NAME = 'sinatra.template_name'.freeze
15
21
  end
16
22
  end
@@ -20,6 +20,7 @@ module Datadog
20
20
 
21
21
  def register_tracer
22
22
  ::Sinatra.send(:register, Datadog::Contrib::Sinatra::Tracer)
23
+ ::Sinatra::Base.send(:prepend, Sinatra::Tracer::Base)
23
24
  end
24
25
  end
25
26
  end
@@ -21,6 +21,10 @@ module Datadog
21
21
  condition do
22
22
  # If the option to prepend script names is enabled, then
23
23
  # prepend the script name from the request onto the action.
24
+ #
25
+ # DEV: env['sinatra.route'] already exists with very similar information,
26
+ # DEV: but doesn't account for our `resource_script_names` logic.
27
+ #
24
28
  @datadog_route = if Datadog.configuration[:sinatra][:resource_script_names]
25
29
  "#{request.script_name}#{action}"
26
30
  else
@@ -32,53 +36,112 @@ module Datadog
32
36
  end
33
37
 
34
38
  def self.registered(app)
35
- ::Sinatra::Base.module_eval do
36
- def render(engine, data, *)
37
- output = ''
38
- tracer = Datadog.configuration[:sinatra][:tracer]
39
- if tracer.enabled
40
- tracer.trace(Ext::SPAN_RENDER_TEMPLATE, span_type: Datadog::Ext::HTTP::TEMPLATE) do |span|
41
- # If data is a string, it is a literal template and we don't
42
- # want to record it.
43
- span.set_tag(Ext::TAG_TEMPLATE_NAME, data) if data.is_a? Symbol
44
-
45
- # Measure service stats
46
- Contrib::Analytics.set_measured(span)
47
-
48
- output = super
49
- end
50
- else
51
- output = super
52
- end
39
+ app.use TracerMiddleware
53
40
 
54
- output
55
- end
56
- end
41
+ app.after do
42
+ configuration = Datadog.configuration[:sinatra]
43
+ next unless configuration[:tracer].enabled
57
44
 
58
- app.use TracerMiddleware
45
+ # Ensures we only create a span for the top-most Sinatra middleware.
46
+ #
47
+ # If we traced all Sinatra middleware apps, we would have a chain
48
+ # of nested spans that were not responsible for handling this request,
49
+ # adding little value to users.
50
+ next if Sinatra::Env.middleware_traced?(env)
51
+
52
+ span = Sinatra::Env.datadog_span(env) || Sinatra::Tracer.create_middleware_span(env, configuration)
53
+
54
+ route = if defined?(@datadog_route)
55
+ @datadog_route
56
+ else
57
+ # Fallback in case no routes have matched
58
+ request.path
59
+ end
59
60
 
60
- app.before do
61
- return unless Datadog.configuration[:sinatra][:tracer].enabled
61
+ span.resource = "#{request.request_method} #{route}"
62
62
 
63
- span = Sinatra::Env.datadog_span(env)
64
63
  span.set_tag(Datadog::Ext::HTTP::URL, request.path)
65
64
  span.set_tag(Datadog::Ext::HTTP::METHOD, request.request_method)
65
+ span.set_tag(Ext::TAG_APP_NAME, app.settings.name)
66
+ span.set_tag(Ext::TAG_ROUTE_PATH, route)
67
+ if request.script_name && !request.script_name.empty?
68
+ span.set_tag(Ext::TAG_SCRIPT_NAME, request.script_name)
69
+ end
70
+
71
+ span.set_tag(Datadog::Ext::HTTP::STATUS_CODE, response.status)
72
+ span.set_error(env['sinatra.error']) if response.server_error?
73
+
74
+ Sinatra::Env.set_middleware_traced(env, true)
66
75
  end
76
+ end
67
77
 
68
- app.after do
69
- return unless Datadog.configuration[:sinatra][:tracer].enabled
78
+ # Initializes a span for the top-most Sinatra middleware.
79
+ def self.create_middleware_span(env, configuration)
80
+ tracer = configuration[:tracer]
81
+ span = tracer.trace(
82
+ Ext::SPAN_REQUEST,
83
+ service: configuration[:service_name],
84
+ span_type: Datadog::Ext::HTTP::TYPE_INBOUND,
85
+ start_time: Sinatra::Env.middleware_start_time(env)
86
+ )
87
+
88
+ Sinatra::Env.set_datadog_span(env, span)
89
+ span
90
+ end
91
+
92
+ # Method overrides for Sinatra::Base
93
+ module Base
94
+ def render(engine, data, *)
95
+ tracer = Datadog.configuration[:sinatra][:tracer]
96
+ return super unless tracer.enabled
97
+
98
+ tracer.trace(Ext::SPAN_RENDER_TEMPLATE, span_type: Datadog::Ext::HTTP::TEMPLATE) do |span|
99
+ span.set_tag(Ext::TAG_TEMPLATE_ENGINE, engine)
100
+
101
+ # If data is a string, it is a literal template and we don't
102
+ # want to record it.
103
+ span.set_tag(Ext::TAG_TEMPLATE_NAME, data) if data.is_a? Symbol
70
104
 
71
- span = Sinatra::Env.datadog_span(env)
105
+ # Measure service stats
106
+ Contrib::Analytics.set_measured(span)
72
107
 
73
- unless span
74
- Datadog::Logger.log.error('missing request span in :after hook')
75
- return
108
+ super
76
109
  end
110
+ end
77
111
 
78
- span.resource = "#{request.request_method} #{@datadog_route}"
79
- span.set_tag(Ext::TAG_ROUTE_PATH, @datadog_route)
80
- span.set_tag(Datadog::Ext::HTTP::STATUS_CODE, response.status)
81
- span.set_error(env['sinatra.error']) if response.server_error?
112
+ # Invoked when a matching route is found.
113
+ # This method yields directly to user code.
114
+ def route_eval
115
+ configuration = Datadog.configuration[:sinatra]
116
+ tracer = configuration[:tracer]
117
+
118
+ return super unless tracer.enabled
119
+
120
+ # For initialization of Sinatra middleware span in order
121
+ # guarantee that the Ext::SPAN_ROUTE span being created below
122
+ # has the middleware span as its parent.
123
+ Sinatra::Tracer.create_middleware_span(env, configuration) unless Sinatra::Env.datadog_span(env)
124
+
125
+ tracer.trace(
126
+ Ext::SPAN_ROUTE,
127
+ service: configuration[:service_name],
128
+ span_type: Datadog::Ext::HTTP::TYPE_INBOUND
129
+ ) do |span|
130
+ span.resource = "#{request.request_method} #{@datadog_route}"
131
+
132
+ span.set_tag(Ext::TAG_APP_NAME, settings.name || settings.superclass.name)
133
+ span.set_tag(Ext::TAG_ROUTE_PATH, @datadog_route)
134
+ if request.script_name && !request.script_name.empty?
135
+ span.set_tag(Ext::TAG_SCRIPT_NAME, request.script_name)
136
+ end
137
+
138
+ rack_request_span = env[Datadog::Contrib::Rack::TraceMiddleware::RACK_REQUEST_SPAN]
139
+ rack_request_span.resource = span.resource if rack_request_span
140
+
141
+ Contrib::Analytics.set_measured(span)
142
+
143
+ super
144
+ end
82
145
  end
83
146
  end
84
147
  end