ddtrace 0.8.2 → 0.9.0

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