ddtrace 0.8.2 → 0.9.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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/.env +3 -1
  3. data/.gitignore +1 -0
  4. data/Appraisals +10 -0
  5. data/Rakefile +27 -1
  6. data/ddtrace.gemspec +2 -2
  7. data/docker-compose.yml +10 -0
  8. data/docs/GettingStarted.md +119 -0
  9. data/gemfiles/contrib.gemfile +5 -0
  10. data/gemfiles/contrib_old.gemfile +4 -0
  11. data/lib/ddtrace.rb +4 -11
  12. data/lib/ddtrace/buffer.rb +14 -0
  13. data/lib/ddtrace/contrib/aws/instrumentation.rb +43 -0
  14. data/lib/ddtrace/contrib/aws/parsed_context.rb +56 -0
  15. data/lib/ddtrace/contrib/aws/patcher.rb +56 -0
  16. data/lib/ddtrace/contrib/aws/services.rb +115 -0
  17. data/lib/ddtrace/contrib/dalli/instrumentation.rb +35 -0
  18. data/lib/ddtrace/contrib/dalli/patcher.rb +50 -0
  19. data/lib/ddtrace/contrib/dalli/quantize.rb +17 -0
  20. data/lib/ddtrace/contrib/faraday/middleware.rb +75 -0
  21. data/lib/ddtrace/contrib/faraday/patcher.rb +52 -0
  22. data/lib/ddtrace/contrib/mongodb/parsers.rb +57 -0
  23. data/lib/ddtrace/contrib/mongodb/patcher.rb +93 -0
  24. data/lib/ddtrace/contrib/mongodb/subscribers.rb +71 -0
  25. data/lib/ddtrace/contrib/rails/action_controller.rb +18 -19
  26. data/lib/ddtrace/contrib/rails/action_view.rb +51 -61
  27. data/lib/ddtrace/contrib/rails/active_support.rb +29 -73
  28. data/lib/ddtrace/contrib/rails/core_extensions.rb +191 -53
  29. data/lib/ddtrace/contrib/redis/quantize.rb +4 -6
  30. data/lib/ddtrace/contrib/resque/patcher.rb +38 -0
  31. data/lib/ddtrace/contrib/resque/resque_job.rb +31 -0
  32. data/lib/ddtrace/contrib/sucker_punch/exception_handler.rb +26 -0
  33. data/lib/ddtrace/contrib/sucker_punch/instrumentation.rb +60 -0
  34. data/lib/ddtrace/contrib/sucker_punch/patcher.rb +50 -0
  35. data/lib/ddtrace/ext/http.rb +1 -0
  36. data/lib/ddtrace/ext/mongo.rb +12 -0
  37. data/lib/ddtrace/monkey.rb +18 -0
  38. data/lib/ddtrace/pipeline.rb +46 -0
  39. data/lib/ddtrace/pipeline/span_filter.rb +38 -0
  40. data/lib/ddtrace/pipeline/span_processor.rb +20 -0
  41. data/lib/ddtrace/tracer.rb +18 -0
  42. data/lib/ddtrace/utils.rb +23 -3
  43. data/lib/ddtrace/version.rb +2 -2
  44. data/lib/ddtrace/workers.rb +30 -22
  45. data/lib/ddtrace/writer.rb +5 -7
  46. metadata +30 -9
@@ -0,0 +1,57 @@
1
+ module Datadog
2
+ module Contrib
3
+ # MongoDB module includes classes and functions to instrument MongoDB clients
4
+ module MongoDB
5
+ module_function
6
+
7
+ # skipped keys are related to command names, since they are already
8
+ # extracted by the query_builder
9
+ SKIP_KEYS = [:_id].freeze
10
+ PLACEHOLDER = '?'.freeze
11
+
12
+ # returns a formatted and normalized query
13
+ def query_builder(command_name, database_name, command)
14
+ # always skip the command name
15
+ skip = SKIP_KEYS | [command_name.to_s]
16
+
17
+ result = {
18
+ operation: command_name,
19
+ database: database_name,
20
+ collection: command.values.first
21
+ }
22
+
23
+ command.each do |key, value|
24
+ result[key] = quantize_statement(value, skip) unless skip.include?(key)
25
+ end
26
+
27
+ result
28
+ end
29
+
30
+ # removes the values from the given query; this quantization recursively
31
+ # replace elements available in a given query, so that Arrays, Hashes and so
32
+ # on are compacted. It ensures a low cardinality so that it can be used
33
+ # as a Span resource.
34
+ def quantize_statement(statement, skip = [])
35
+ case statement
36
+ when Hash
37
+ statement.each_with_object({}) do |(key, value), quantized|
38
+ quantized[key] = quantize_value(value, skip) unless skip.include?(key)
39
+ end
40
+ else
41
+ quantize_value(statement, skip)
42
+ end
43
+ end
44
+
45
+ def quantize_value(value, skip = [])
46
+ case value
47
+ when Hash
48
+ quantize_statement(value, skip)
49
+ when Array
50
+ quantize_value(value.first, skip)
51
+ else
52
+ PLACEHOLDER
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,93 @@
1
+ # requirements should be kept minimal as Patcher is a shared requirement.
2
+
3
+ module Datadog
4
+ module Contrib
5
+ # MongoDB module includes classes and functions to instrument MongoDB clients
6
+ module MongoDB
7
+ APP = 'mongodb'.freeze
8
+ SERVICE = 'mongodb'.freeze
9
+
10
+ # Patcher adds subscribers to the MongoDB driver so that each command is traced.
11
+ # Use the `Datadog::Monkey.patch_module(:mongodb)` to activate tracing for
12
+ # this module.
13
+ module Patcher
14
+ @patched = false
15
+
16
+ module_function
17
+
18
+ def patched?
19
+ @patched
20
+ end
21
+
22
+ def patch
23
+ # versions prior to 2.1.0 don't support the Monitoring API
24
+ if !@patched && (defined?(::Mongo::Monitoring::Global) && \
25
+ Gem::Version.new(::Mongo::VERSION) >= Gem::Version.new('2.1.0'))
26
+ begin
27
+ require 'ddtrace/pin'
28
+ require 'ddtrace/ext/net'
29
+ require 'ddtrace/ext/mongo'
30
+ require 'ddtrace/ext/app_types'
31
+ require 'ddtrace/contrib/mongodb/parsers'
32
+ require 'ddtrace/contrib/mongodb/subscribers'
33
+
34
+ patch_mongo_client()
35
+ add_mongo_monitoring()
36
+
37
+ @patched = true
38
+ rescue StandardError => e
39
+ Datadog::Tracer.log.error("Unable to apply MongoDB integration: #{e}")
40
+ end
41
+ end
42
+ @patched
43
+ end
44
+
45
+ def add_mongo_monitoring
46
+ # Subscribe to all COMMAND queries with our subscriber class
47
+ ::Mongo::Monitoring::Global.subscribe(
48
+ ::Mongo::Monitoring::COMMAND,
49
+ Datadog::Contrib::MongoDB::MongoCommandSubscriber.new
50
+ )
51
+ end
52
+
53
+ def patch_mongo_client
54
+ ::Mongo::Client.class_eval do
55
+ alias_method :initialize_without_datadog, :initialize
56
+ Datadog::Monkey.without_warnings do
57
+ remove_method :initialize
58
+ end
59
+
60
+ def initialize(*args, &blk)
61
+ # attach the Pin instance
62
+ initialize_without_datadog(*args, &blk)
63
+ pin = Datadog::Pin.new(SERVICE, app: APP, app_type: Datadog::Ext::AppTypes::DB)
64
+ pin.onto(self)
65
+ if pin.tracer && pin.service
66
+ pin.tracer.set_service_info(pin.service, 'mongodb', pin.app_type)
67
+ end
68
+ end
69
+
70
+ def datadog_pin
71
+ # safe-navigation to avoid crashes during each query
72
+ return unless respond_to? :cluster
73
+ return unless cluster.respond_to? :addresses
74
+ return unless cluster.addresses.respond_to? :first
75
+ Datadog::Pin.get_from(cluster.addresses.first)
76
+ end
77
+
78
+ def datadog_pin=(pin)
79
+ # safe-navigation to avoid crashes during each query
80
+ return unless respond_to? :cluster
81
+ return unless cluster.respond_to? :addresses
82
+ return unless cluster.addresses.respond_to? :each
83
+ # attach the PIN to all cluster addresses. One of them is used
84
+ # when executing a Command and it is attached to the Monitoring
85
+ # Event instance.
86
+ cluster.addresses.each { |x| pin.onto(x) }
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,71 @@
1
+ module Datadog
2
+ module Contrib
3
+ # MongoDB module includes classes and functions to instrument MongoDB clients
4
+ module MongoDB
5
+ # `MongoCommandSubscriber` listens to all events from the `Monitoring`
6
+ # system available in the Mongo driver.
7
+ class MongoCommandSubscriber
8
+ def started(event)
9
+ pin = Datadog::Pin.get_from(event.address)
10
+ return unless pin && pin.enabled?
11
+
12
+ # start a trace and store it in the current thread; using the `operation_id`
13
+ # is safe since it's a unique id used to link events together. Also only one
14
+ # thread is involved in this execution so thread-local storage should be safe. Reference:
15
+ # https://github.com/mongodb/mongo-ruby-driver/blob/master/lib/mongo/monitoring.rb#L70
16
+ # https://github.com/mongodb/mongo-ruby-driver/blob/master/lib/mongo/monitoring/publishable.rb#L38-L56
17
+ span = pin.tracer.trace('mongo.cmd', service: pin.service, span_type: Datadog::Ext::Mongo::TYPE)
18
+ Thread.current[:datadog_mongo_span] = span
19
+
20
+ # build a quantized Query using the Parser module
21
+ query = Datadog::Contrib::MongoDB.query_builder(event.command_name, event.database_name, event.command)
22
+ serialized_query = query.to_s
23
+
24
+ # add operation tags; the full query is stored and used as a resource,
25
+ # since it has been quantized and reduced
26
+ span.set_tag(Datadog::Ext::Mongo::DB, query[:database])
27
+ span.set_tag(Datadog::Ext::Mongo::COLLECTION, query[:collection])
28
+ span.set_tag(Datadog::Ext::Mongo::OPERATION, query[:operation])
29
+ span.set_tag(Datadog::Ext::Mongo::QUERY, serialized_query)
30
+ span.set_tag(Datadog::Ext::NET::TARGET_HOST, event.address.host)
31
+ span.set_tag(Datadog::Ext::NET::TARGET_PORT, event.address.port)
32
+
33
+ # set the resource with the quantized query
34
+ span.resource = serialized_query
35
+ end
36
+
37
+ def failed(event)
38
+ span = Thread.current[:datadog_mongo_span]
39
+ return unless span
40
+
41
+ # the failure is not a real exception because it's handled by
42
+ # the framework itself, so we set only the error and the message
43
+ span.set_error(event)
44
+ rescue StandardError => e
45
+ Datadog::Tracer.log.debug("error when handling MongoDB 'failed' event: #{e}")
46
+ ensure
47
+ # whatever happens, the Span must be removed from the local storage and
48
+ # it must be finished to prevent any leak
49
+ span.finish() unless span.nil?
50
+ Thread.current[:datadog_mongo_span] = nil
51
+ end
52
+
53
+ def succeeded(event)
54
+ span = Thread.current[:datadog_mongo_span]
55
+ return unless span
56
+
57
+ # add fields that are available only after executing the query
58
+ rows = event.reply.fetch('n', nil)
59
+ span.set_tag(Datadog::Ext::Mongo::ROWS, rows) unless rows.nil?
60
+ rescue StandardError => e
61
+ Datadog::Tracer.log.debug("error when handling MongoDB 'succeeded' event: #{e}")
62
+ ensure
63
+ # whatever happens, the Span must be removed from the local storage and
64
+ # it must be finished to prevent any leak
65
+ span.finish() unless span.nil?
66
+ Thread.current[:datadog_mongo_span] = nil
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -6,40 +6,40 @@ module Datadog
6
6
  module Rails
7
7
  # Code used to create and handle 'rails.action_controller' spans.
8
8
  module ActionController
9
- KEY = 'datadog_actioncontroller'.freeze
10
-
11
9
  def self.instrument
10
+ # patch Rails core components
11
+ Datadog::RailsActionPatcher.patch_action_controller
12
+
12
13
  # subscribe when the request processing starts
13
- ::ActiveSupport::Notifications.subscribe('start_processing.action_controller') do |*args|
14
+ ::ActiveSupport::Notifications.subscribe('!datadog.start_processing.action_controller') do |*args|
14
15
  start_processing(*args)
15
16
  end
16
17
 
17
18
  # subscribe when the request processing has been completed
18
- ::ActiveSupport::Notifications.subscribe('process_action.action_controller') do |*args|
19
- process_action(*args)
19
+ ::ActiveSupport::Notifications.subscribe('!datadog.finish_processing.action_controller') do |*args|
20
+ finish_processing(*args)
20
21
  end
21
22
  end
22
23
 
23
- def self.start_processing(*)
24
- return if Thread.current[KEY]
25
-
24
+ def self.start_processing(_name, _start, _finish, _id, payload)
25
+ # trace the execution
26
26
  tracer = ::Rails.configuration.datadog_trace.fetch(:tracer)
27
27
  service = ::Rails.configuration.datadog_trace.fetch(:default_controller_service)
28
28
  type = Datadog::Ext::HTTP::TYPE
29
- tracer.trace('rails.action_controller', service: service, span_type: type)
29
+ span = tracer.trace('rails.action_controller', service: service, span_type: type)
30
30
 
31
- Thread.current[KEY] = true
31
+ # attach the current span to the tracing context
32
+ tracing_context = payload.fetch(:tracing_context)
33
+ tracing_context[:dd_request_span] = span
32
34
  rescue StandardError => e
33
35
  Datadog::Tracer.log.error(e.message)
34
36
  end
35
37
 
36
- def self.process_action(_name, start, finish, _id, payload)
37
- return unless Thread.current[KEY]
38
- Thread.current[KEY] = false
39
-
40
- tracer = ::Rails.configuration.datadog_trace.fetch(:tracer)
41
- span = tracer.active_span()
42
- return unless span
38
+ def self.finish_processing(_name, start, finish, _id, payload)
39
+ # retrieve the tracing context and the latest active span
40
+ tracing_context = payload.fetch(:tracing_context)
41
+ span = tracing_context[:dd_request_span]
42
+ return unless span && !span.finished?
43
43
 
44
44
  begin
45
45
  resource = "#{payload.fetch(:controller)}##{payload.fetch(:action)}"
@@ -69,8 +69,7 @@ module Datadog
69
69
  span.set_error(error) if status.starts_with?('5')
70
70
  end
71
71
  ensure
72
- span.start_time = start
73
- span.finish(finish)
72
+ span.finish()
74
73
  end
75
74
  rescue StandardError => e
76
75
  Datadog::Tracer.log.error(e.message)
@@ -10,99 +10,89 @@ module Datadog
10
10
  Datadog::RailsRendererPatcher.patch_renderer()
11
11
 
12
12
  # subscribe when the template rendering starts
13
- ::ActiveSupport::Notifications.subscribe('start_render_template.action_view') do |*args|
13
+ ::ActiveSupport::Notifications.subscribe('!datadog.start_render_template.action_view') do |*args|
14
14
  start_render_template(*args)
15
15
  end
16
16
 
17
- # subscribe when the partial rendering starts
18
- ::ActiveSupport::Notifications.subscribe('start_render_partial.action_view') do |*args|
19
- start_render_partial(*args)
17
+ # subscribe when the template rendering has been processed
18
+ ::ActiveSupport::Notifications.subscribe('!datadog.finish_render_template.action_view') do |*args|
19
+ finish_render_template(*args)
20
20
  end
21
21
 
22
- # subscribe when the template rendering has been processed
23
- ::ActiveSupport::Notifications.subscribe('render_template.action_view') do |*args|
24
- render_template(*args)
22
+ # subscribe when the partial rendering starts
23
+ ::ActiveSupport::Notifications.subscribe('!datadog.start_render_partial.action_view') do |*args|
24
+ start_render_partial(*args)
25
25
  end
26
26
 
27
27
  # subscribe when the partial rendering has been processed
28
- ::ActiveSupport::Notifications.subscribe('render_partial.action_view') do |*args|
29
- render_partial(*args)
28
+ ::ActiveSupport::Notifications.subscribe('!datadog.finish_render_partial.action_view') do |*args|
29
+ finish_render_partial(*args)
30
30
  end
31
31
  end
32
32
 
33
- def self.get_key(f)
34
- 'datadog_actionview_' + f
35
- end
36
-
37
- def self.start_render_template(*)
38
- key = get_key('render_template')
39
- return if Thread.current[key]
33
+ def self.start_render_template(_name, _start, _finish, _id, payload)
34
+ # retrieve the tracing context
35
+ tracing_context = payload.fetch(:tracing_context)
40
36
 
37
+ # create a new Span and add it to the tracing context
41
38
  tracer = ::Rails.configuration.datadog_trace.fetch(:tracer)
42
- type = Datadog::Ext::HTTP::TEMPLATE
43
- tracer.trace('rails.render_template', span_type: type)
44
-
45
- Thread.current[key] = true
39
+ span = tracer.trace('rails.render_template', span_type: Datadog::Ext::HTTP::TEMPLATE)
40
+ tracing_context[:dd_rails_template_span] = span
46
41
  rescue StandardError => e
47
- Datadog::Tracer.log.error(e.message)
42
+ Datadog::Tracer.log.debug(e.message)
48
43
  end
49
44
 
50
- def self.start_render_partial(*)
51
- key = get_key('render_partial')
52
- return if Thread.current[key]
45
+ def self.finish_render_template(_name, _start, _finish, _id, payload)
46
+ # retrieve the tracing context and the latest active span
47
+ tracing_context = payload.fetch(:tracing_context)
48
+ span = tracing_context[:dd_rails_template_span]
49
+ return if !span || span.finished?
53
50
 
54
- tracer = ::Rails.configuration.datadog_trace.fetch(:tracer)
55
- type = Datadog::Ext::HTTP::TEMPLATE
56
- tracer.trace('rails.render_partial', span_type: type)
51
+ # finish the tracing and update the execution time
52
+ begin
53
+ template_name = tracing_context[:template_name]
54
+ layout = tracing_context[:layout]
55
+ exception = tracing_context[:exception]
57
56
 
58
- Thread.current[key] = true
57
+ span.set_tag('rails.template_name', template_name) if template_name
58
+ span.set_tag('rails.layout', layout) if layout
59
+ span.set_error(exception) if exception
60
+ ensure
61
+ span.finish()
62
+ end
59
63
  rescue StandardError => e
60
- Datadog::Tracer.log.error(e.message)
64
+ Datadog::Tracer.log.debug(e.message)
61
65
  end
62
66
 
63
- def self.render_template(_name, start, finish, _id, payload)
64
- key = get_key('render_template')
65
- return unless Thread.current[key]
66
- Thread.current[key] = false
67
+ def self.start_render_partial(_name, _start, _finish, _id, payload)
68
+ # retrieve the tracing context
69
+ tracing_context = payload.fetch(:tracing_context)
67
70
 
68
- # finish the tracing and update the execution time
69
71
  tracer = ::Rails.configuration.datadog_trace.fetch(:tracer)
70
- span = tracer.active_span()
71
- return unless span
72
-
73
- begin
74
- template_name = Datadog::Contrib::Rails::Utils.normalize_template_name(payload.fetch(:identifier))
75
- span.set_tag('rails.template_name', template_name)
76
- span.set_tag('rails.layout', payload.fetch(:layout))
77
- span.set_error(payload[:exception]) if payload[:exception]
78
- ensure
79
- span.start_time = start
80
- span.finish(finish)
81
- end
72
+ span = tracer.trace('rails.render_partial', span_type: Datadog::Ext::HTTP::TEMPLATE)
73
+ tracing_context[:dd_rails_partial_span] = span
82
74
  rescue StandardError => e
83
- Datadog::Tracer.log.error(e.message)
75
+ Datadog::Tracer.log.debug(e.message)
84
76
  end
85
77
 
86
- def self.render_partial(_name, start, finish, _id, payload)
87
- key = get_key('render_partial')
88
- return unless Thread.current[key]
89
- Thread.current[key] = false
78
+ def self.finish_render_partial(_name, start, finish, _id, payload)
79
+ # retrieve the tracing context and the latest active span
80
+ tracing_context = payload.fetch(:tracing_context)
81
+ span = tracing_context[:dd_rails_partial_span]
82
+ return if !span || span.finished?
90
83
 
91
84
  # finish the tracing and update the execution time
92
- tracer = ::Rails.configuration.datadog_trace.fetch(:tracer)
93
- span = tracer.active_span()
94
- return unless span
95
-
96
85
  begin
97
- template_name = Datadog::Contrib::Rails::Utils.normalize_template_name(payload.fetch(:identifier))
98
- span.set_tag('rails.template_name', template_name)
99
- span.set_error(payload[:exception]) if payload[:exception]
86
+ template_name = tracing_context[:template_name]
87
+ exception = tracing_context[:exception]
88
+
89
+ span.set_tag('rails.template_name', template_name) if template_name
90
+ span.set_error(exception) if exception
100
91
  ensure
101
- span.start_time = start
102
- span.finish(finish)
92
+ span.finish()
103
93
  end
104
94
  rescue StandardError => e
105
- Datadog::Tracer.log.error(e.message)
95
+ Datadog::Tracer.log.debug(e.message)
106
96
  end
107
97
  end
108
98
  end
@@ -11,102 +11,58 @@ module Datadog
11
11
  Datadog::RailsCachePatcher.patch_cache_store()
12
12
 
13
13
  # subscribe when a cache read starts being processed
14
- ::ActiveSupport::Notifications.subscribe('start_cache_read.active_support') do |*args|
15
- start_trace_cache('GET', *args)
16
- end
17
-
18
- # subscribe when a cache fetch starts being processed
19
- ::ActiveSupport::Notifications.subscribe('start_cache_fetch.active_support') do |*args|
20
- start_trace_cache('GET', *args)
21
- end
22
-
23
- # subscribe when a cache write starts being processed
24
- ::ActiveSupport::Notifications.subscribe('start_cache_write.active_support') do |*args|
25
- start_trace_cache('SET', *args)
26
- end
27
-
28
- # subscribe when a cache delete starts being processed
29
- ::ActiveSupport::Notifications.subscribe('start_cache_delete.active_support') do |*args|
30
- start_trace_cache('DELETE', *args)
14
+ ::ActiveSupport::Notifications.subscribe('!datadog.start_cache_tracing.active_support') do |*args|
15
+ start_trace_cache(*args)
31
16
  end
32
17
 
33
18
  # subscribe when a cache read has been processed
34
- ::ActiveSupport::Notifications.subscribe('cache_read.active_support') do |*args|
35
- trace_cache('GET', *args)
19
+ ::ActiveSupport::Notifications.subscribe('!datadog.finish_cache_tracing.active_support') do |*args|
20
+ finish_trace_cache(*args)
36
21
  end
22
+ end
37
23
 
38
- # subscribe when a cache write has been processed
39
- ::ActiveSupport::Notifications.subscribe('cache_write.active_support') do |*args|
40
- trace_cache('SET', *args)
41
- end
24
+ def self.start_trace_cache(_name, _start, _finish, _id, payload)
25
+ tracer = ::Rails.configuration.datadog_trace.fetch(:tracer)
26
+ tracing_context = payload.fetch(:tracing_context)
42
27
 
43
- # subscribe when a cache delete has been processed
44
- ::ActiveSupport::Notifications.subscribe('cache_delete.active_support') do |*args|
45
- trace_cache('DELETE', *args)
46
- end
47
- end
28
+ # In most of the cases Rails ``fetch()`` and ``read()`` calls are nested.
29
+ # This check ensures that two reads are not nested since they don't provide
30
+ # interesting details.
31
+ # NOTE: the ``finish_trace_cache()`` is fired but it already has a safe-guard
32
+ # to avoid any kind of issue.
33
+ current_span = tracer.active_span
34
+ return if current_span.try('name') == 'rails.cache' &&
35
+ current_span.try('resource') == 'GET' &&
36
+ payload[:action] == 'GET'
48
37
 
49
- def self.create_span(tracer)
38
+ # create a new ``Span`` and add it to the tracing context
50
39
  service = ::Rails.configuration.datadog_trace.fetch(:default_cache_service)
51
40
  type = Datadog::Ext::CACHE::TYPE
52
- tracer.trace('rails.cache', service: service, span_type: type)
53
- end
54
-
55
- def self.get_key(resource)
56
- 'datadog_activesupport_' + resource
57
- end
58
-
59
- def self.start_trace_cache(resource, *_args)
60
- key = get_key(resource)
61
- # This is mostly to trap the case of fetch/read. In some cases the framework
62
- # will call fetch but fetch won't call read. In some cases read can be called
63
- # alone. And in some cases they are nested. In all cases we want to have one
64
- # and only one span.
65
- return if Thread.current[key]
66
- create_span(::Rails.configuration.datadog_trace.fetch(:tracer))
67
- Thread.current[key] = true
41
+ span = tracer.trace('rails.cache', service: service, span_type: type)
42
+ span.resource = payload.fetch(:action)
43
+ tracing_context[:dd_cache_span] = span
68
44
  rescue StandardError => e
69
- Datadog::Tracer.log.error(e.message)
45
+ Datadog::Tracer.log.debug(e.message)
70
46
  end
71
47
 
72
- def self.trace_cache(resource, _name, start, finish, _id, payload)
73
- tracer = ::Rails.configuration.datadog_trace.fetch(:tracer)
74
- key = get_key(resource)
75
- if Thread.current[key]
76
- # span was created by start_trace_cache, plan to re-use this one
77
- Thread.current[key] = false
78
- else
79
- # Create a span now, as start_trace_cache was not called.
80
- #
81
- # This could typically happen if, for some reason the monkey-patching
82
- # of the cache class did not work as expected. Doing this, we might
83
- # loose some interesting parentship between some spans, because this
84
- # span is created too late, and children won't "find" their parent.
85
- # But, it's better than no span at all, and it case there is no child
86
- # at all, it will work just as expected. In practice, it's required to
87
- # have standard file cache work together with redis cache.
88
- create_span(tracer)
89
- end
90
- span = tracer.active_span()
91
- return unless span
48
+ def self.finish_trace_cache(_name, _start, _finish, _id, payload)
49
+ # retrieve the tracing context and continue the trace
50
+ tracing_context = payload.fetch(:tracing_context)
51
+ span = tracing_context[:dd_cache_span]
52
+ return unless span && !span.finished?
92
53
 
93
54
  begin
94
- # finish the tracing and update the execution time
95
- span.resource = resource
96
55
  # discard parameters from the cache_store configuration
97
56
  store, = *Array.wrap(::Rails.configuration.cache_store).flatten
98
57
  span.set_tag('rails.cache.backend', store)
99
58
  span.set_tag('rails.cache.key', payload.fetch(:key))
100
59
  span.set_error(payload[:exception]) if payload[:exception]
101
60
  ensure
102
- span.start_time = start
103
- span.finish(finish)
61
+ span.finish()
104
62
  end
105
63
  rescue StandardError => e
106
- Datadog::Tracer.log.error(e.message)
64
+ Datadog::Tracer.log.debug(e.message)
107
65
  end
108
-
109
- private_class_method :create_span, :get_key, :start_trace_cache, :trace_cache
110
66
  end
111
67
  end
112
68
  end