ddtrace 0.34.1 → 0.36.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 (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