datadog 2.0.0 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +66 -2
- data/README.md +1 -1
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +19 -1
- data/ext/datadog_profiling_native_extension/collectors_stack.c +41 -0
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +1 -1
- data/ext/datadog_profiling_native_extension/crashtracker.c +1 -1
- data/ext/datadog_profiling_native_extension/extconf.rb +6 -4
- data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +47 -1
- data/ext/datadog_profiling_native_extension/setup_signal_handler.c +1 -1
- data/ext/datadog_profiling_native_extension/stack_recorder.c +13 -6
- data/ext/datadog_profiling_native_extension/stack_recorder.h +1 -0
- data/lib/datadog/appsec/configuration/settings.rb +5 -0
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +0 -1
- data/lib/datadog/appsec/contrib/sinatra/patcher.rb +1 -1
- data/lib/datadog/appsec/extensions.rb +1 -0
- data/lib/datadog/core/configuration/components.rb +6 -3
- data/lib/datadog/core/configuration/ext.rb +1 -0
- data/lib/datadog/core/configuration/option.rb +21 -14
- data/lib/datadog/core/configuration/options.rb +5 -1
- data/lib/datadog/core/configuration/settings.rb +68 -5
- data/lib/datadog/core/configuration.rb +3 -17
- data/lib/datadog/core/deprecations.rb +58 -0
- data/lib/datadog/core/environment/ext.rb +2 -0
- data/lib/datadog/core/environment/yjit.rb +5 -0
- data/lib/datadog/core/runtime/ext.rb +2 -0
- data/lib/datadog/core/runtime/metrics.rb +6 -0
- data/lib/datadog/core/telemetry/component.rb +107 -0
- data/lib/datadog/core/telemetry/event.rb +124 -31
- data/lib/datadog/core/telemetry/ext.rb +2 -0
- data/lib/datadog/core/telemetry/http/adapters/net.rb +1 -1
- data/lib/datadog/core/telemetry/metric.rb +167 -0
- data/lib/datadog/core/telemetry/metrics_collection.rb +81 -0
- data/lib/datadog/core/telemetry/metrics_manager.rb +81 -0
- data/lib/datadog/core/telemetry/request.rb +1 -1
- data/lib/datadog/core/telemetry/worker.rb +173 -0
- data/lib/datadog/core/utils/only_once_successful.rb +76 -0
- data/lib/datadog/core.rb +2 -19
- data/lib/datadog/opentelemetry/sdk/propagator.rb +5 -10
- data/lib/datadog/opentelemetry/sdk/span_processor.rb +5 -2
- data/lib/datadog/profiling/collectors/code_provenance.rb +18 -5
- data/lib/datadog/profiling/component.rb +18 -1
- data/lib/datadog/profiling/ext/dir_monkey_patches.rb +410 -0
- data/lib/datadog/profiling.rb +1 -0
- data/lib/datadog/tracing/configuration/ext.rb +7 -0
- data/lib/datadog/tracing/configuration/settings.rb +52 -3
- data/lib/datadog/tracing/contrib/action_cable/event.rb +1 -1
- data/lib/datadog/tracing/contrib/action_cable/events/broadcast.rb +1 -1
- data/lib/datadog/tracing/contrib/action_cable/events/perform_action.rb +1 -1
- data/lib/datadog/tracing/contrib/action_cable/events/transmit.rb +1 -1
- data/lib/datadog/tracing/contrib/action_mailer/event.rb +4 -6
- data/lib/datadog/tracing/contrib/action_mailer/events/deliver.rb +9 -4
- data/lib/datadog/tracing/contrib/action_mailer/events/process.rb +3 -2
- data/lib/datadog/tracing/contrib/action_view/events/render_partial.rb +1 -5
- data/lib/datadog/tracing/contrib/action_view/events/render_template.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/discard.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/enqueue.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/enqueue_at.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/enqueue_retry.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/perform.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/retry_stopped.rb +1 -1
- data/lib/datadog/tracing/contrib/active_model_serializers/events/render.rb +1 -1
- data/lib/datadog/tracing/contrib/active_model_serializers/events/serialize.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/events/sql.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/cache/event.rb +32 -0
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +156 -0
- data/lib/datadog/tracing/contrib/active_support/cache/events.rb +34 -0
- data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +45 -41
- data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +17 -40
- data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +4 -1
- data/lib/datadog/tracing/contrib/active_support/notifications/event.rb +29 -6
- data/lib/datadog/tracing/contrib/active_support/notifications/subscriber.rb +16 -4
- data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +33 -29
- data/lib/datadog/tracing/contrib/analytics.rb +5 -0
- data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +5 -0
- data/lib/datadog/tracing/contrib/graphql/patcher.rb +8 -2
- data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +166 -0
- data/lib/datadog/tracing/contrib/graphql/unified_trace_patcher.rb +25 -0
- data/lib/datadog/tracing/contrib/kafka/consumer_event.rb +1 -1
- data/lib/datadog/tracing/contrib/kafka/consumer_group_event.rb +1 -1
- data/lib/datadog/tracing/contrib/kafka/event.rb +1 -1
- data/lib/datadog/tracing/contrib/kafka/events/connection/request.rb +3 -3
- data/lib/datadog/tracing/contrib/kafka/events/consumer/process_batch.rb +3 -3
- data/lib/datadog/tracing/contrib/kafka/events/consumer/process_message.rb +3 -3
- data/lib/datadog/tracing/contrib/kafka/events/consumer_group/heartbeat.rb +3 -3
- data/lib/datadog/tracing/contrib/kafka/events/produce_operation/send_messages.rb +3 -3
- data/lib/datadog/tracing/contrib/kafka/events/producer/deliver_messages.rb +3 -3
- data/lib/datadog/tracing/contrib/racecar/event.rb +2 -2
- data/lib/datadog/tracing/contrib/rails/ext.rb +9 -0
- data/lib/datadog/tracing/contrib/rails/patcher.rb +7 -0
- data/lib/datadog/tracing/contrib/rails/runner.rb +95 -0
- data/lib/datadog/tracing/distributed/b3_multi.rb +1 -1
- data/lib/datadog/tracing/distributed/b3_single.rb +3 -1
- data/lib/datadog/tracing/distributed/datadog.rb +2 -2
- data/lib/datadog/tracing/distributed/propagation.rb +39 -4
- data/lib/datadog/tracing/distributed/trace_context.rb +5 -3
- data/lib/datadog/tracing/metadata/ext.rb +1 -0
- data/lib/datadog/tracing/span_operation.rb +3 -2
- data/lib/datadog/tracing/trace_operation.rb +7 -3
- data/lib/datadog/tracing/trace_segment.rb +4 -1
- data/lib/datadog/tracing/tracer.rb +9 -2
- data/lib/datadog/tracing.rb +5 -1
- data/lib/datadog/version.rb +2 -2
- metadata +21 -8
- data/lib/datadog/core/telemetry/client.rb +0 -95
- data/lib/datadog/core/telemetry/heartbeat.rb +0 -33
@@ -27,9 +27,11 @@ module Datadog
|
|
27
27
|
Datadog.configuration.tracing[:action_mailer]
|
28
28
|
end
|
29
29
|
|
30
|
-
def
|
30
|
+
def on_start(span, event, _id, payload)
|
31
|
+
super
|
32
|
+
|
33
|
+
span.type = span_type
|
31
34
|
span.service = configuration[:service_name] if configuration[:service_name]
|
32
|
-
span.resource = payload[:mailer]
|
33
35
|
span.set_tag(Tracing::Metadata::Ext::TAG_COMPONENT, Ext::TAG_COMPONENT)
|
34
36
|
|
35
37
|
# Set analytics sample rate
|
@@ -39,10 +41,6 @@ module Datadog
|
|
39
41
|
|
40
42
|
# Measure service stats
|
41
43
|
Contrib::Analytics.set_measured(span)
|
42
|
-
|
43
|
-
report_if_exception(span, payload)
|
44
|
-
rescue StandardError => e
|
45
|
-
Datadog.logger.debug(e.message)
|
46
44
|
end
|
47
45
|
end
|
48
46
|
end
|
@@ -30,15 +30,20 @@ module Datadog
|
|
30
30
|
Tracing::Metadata::Ext::AppTypes::TYPE_WORKER
|
31
31
|
end
|
32
32
|
|
33
|
-
def
|
33
|
+
def on_start(span, event, _id, payload)
|
34
34
|
super
|
35
35
|
|
36
|
-
span.
|
36
|
+
span.set_tag(Tracing::Metadata::Ext::TAG_OPERATION, Ext::TAG_OPERATION_DELIVER)
|
37
|
+
end
|
38
|
+
|
39
|
+
def on_finish(span, event, _id, payload)
|
40
|
+
super
|
41
|
+
|
42
|
+
span.resource = payload[:mailer] # Mailer is not available at `on_start`
|
43
|
+
|
37
44
|
span.set_tag(Ext::TAG_MAILER, payload[:mailer])
|
38
45
|
span.set_tag(Ext::TAG_MSG_ID, payload[:message_id])
|
39
46
|
|
40
|
-
span.set_tag(Tracing::Metadata::Ext::TAG_OPERATION, Ext::TAG_OPERATION_DELIVER)
|
41
|
-
|
42
47
|
# Since email data can contain PII we disable by default
|
43
48
|
# Some of these fields can be either strings or arrays, so we try to normalize
|
44
49
|
# https://github.com/rails/rails/blob/18707ab17fa492eb25ad2e8f9818a320dc20b823/actionmailer/lib/action_mailer/base.rb#L742-L754
|
@@ -30,10 +30,11 @@ module Datadog
|
|
30
30
|
Tracing::Metadata::Ext::HTTP::TYPE_TEMPLATE
|
31
31
|
end
|
32
32
|
|
33
|
-
def
|
33
|
+
def on_start(span, event, _id, payload)
|
34
34
|
super
|
35
35
|
|
36
|
-
span.
|
36
|
+
span.resource = payload[:mailer] # Mailer is not available at `on_start`
|
37
|
+
|
37
38
|
span.set_tag(Ext::TAG_ACTION, payload[:action])
|
38
39
|
span.set_tag(Ext::TAG_MAILER, payload[:mailer])
|
39
40
|
|
@@ -27,7 +27,7 @@ module Datadog
|
|
27
27
|
Ext::SPAN_RENDER_PARTIAL
|
28
28
|
end
|
29
29
|
|
30
|
-
def
|
30
|
+
def on_start(span, _event, _id, payload)
|
31
31
|
span.service = configuration[:service_name] if configuration[:service_name]
|
32
32
|
span.type = Tracing::Metadata::Ext::HTTP::TYPE_TEMPLATE
|
33
33
|
|
@@ -41,10 +41,6 @@ module Datadog
|
|
41
41
|
|
42
42
|
# Measure service stats
|
43
43
|
Contrib::Analytics.set_measured(span)
|
44
|
-
|
45
|
-
record_exception(span, payload)
|
46
|
-
rescue StandardError => e
|
47
|
-
Datadog.logger.debug(e.message)
|
48
44
|
end
|
49
45
|
end
|
50
46
|
end
|
@@ -27,7 +27,7 @@ module Datadog
|
|
27
27
|
Ext::SPAN_RENDER_TEMPLATE
|
28
28
|
end
|
29
29
|
|
30
|
-
def
|
30
|
+
def on_start(span, _event, _id, payload)
|
31
31
|
span.service = configuration[:service_name] if configuration[:service_name]
|
32
32
|
span.type = Tracing::Metadata::Ext::HTTP::TYPE_TEMPLATE
|
33
33
|
|
@@ -26,7 +26,7 @@ module Datadog
|
|
26
26
|
Ext::SPAN_DISCARD
|
27
27
|
end
|
28
28
|
|
29
|
-
def
|
29
|
+
def on_start(span, event, _id, payload)
|
30
30
|
span.name = span_name
|
31
31
|
span.service = configuration[:service_name] if configuration[:service_name]
|
32
32
|
span.resource = payload[:job].class.name
|
@@ -26,7 +26,7 @@ module Datadog
|
|
26
26
|
Ext::SPAN_ENQUEUE
|
27
27
|
end
|
28
28
|
|
29
|
-
def
|
29
|
+
def on_start(span, event, _id, payload)
|
30
30
|
span.name = span_name
|
31
31
|
span.service = configuration[:service_name] if configuration[:service_name]
|
32
32
|
span.resource = payload[:job].class.name
|
@@ -26,7 +26,7 @@ module Datadog
|
|
26
26
|
Ext::SPAN_ENQUEUE
|
27
27
|
end
|
28
28
|
|
29
|
-
def
|
29
|
+
def on_start(span, event, _id, payload)
|
30
30
|
span.name = span_name
|
31
31
|
span.service = configuration[:service_name] if configuration[:service_name]
|
32
32
|
span.resource = payload[:job].class.name
|
@@ -26,7 +26,7 @@ module Datadog
|
|
26
26
|
Ext::SPAN_ENQUEUE_RETRY
|
27
27
|
end
|
28
28
|
|
29
|
-
def
|
29
|
+
def on_start(span, event, _id, payload)
|
30
30
|
span.name = span_name
|
31
31
|
span.service = configuration[:service_name] if configuration[:service_name]
|
32
32
|
span.resource = payload[:job].class.name
|
@@ -26,7 +26,7 @@ module Datadog
|
|
26
26
|
Ext::SPAN_PERFORM
|
27
27
|
end
|
28
28
|
|
29
|
-
def
|
29
|
+
def on_start(span, event, _id, payload)
|
30
30
|
span.name = span_name
|
31
31
|
span.service = configuration[:service_name] if configuration[:service_name]
|
32
32
|
span.resource = payload[:job].class.name
|
@@ -26,7 +26,7 @@ module Datadog
|
|
26
26
|
Ext::SPAN_RETRY_STOPPED
|
27
27
|
end
|
28
28
|
|
29
|
-
def
|
29
|
+
def on_start(span, event, _id, payload)
|
30
30
|
span.name = span_name
|
31
31
|
span.service = configuration[:service_name] if configuration[:service_name]
|
32
32
|
span.resource = payload[:job].class.name
|
@@ -31,7 +31,7 @@ module Datadog
|
|
31
31
|
Ext::SPAN_INSTANTIATION
|
32
32
|
end
|
33
33
|
|
34
|
-
def
|
34
|
+
def on_start(span, event, _id, payload)
|
35
35
|
span.resource = payload.fetch(:class_name)
|
36
36
|
span.type = Ext::SPAN_TYPE_INSTANTIATION
|
37
37
|
span.set_tag(Tracing::Metadata::Ext::TAG_COMPONENT, Ext::TAG_COMPONENT)
|
@@ -29,7 +29,7 @@ module Datadog
|
|
29
29
|
Ext::SPAN_SQL
|
30
30
|
end
|
31
31
|
|
32
|
-
def
|
32
|
+
def on_start(span, event, _id, payload)
|
33
33
|
config = Utils.connection_config(payload[:connection], payload[:connection_id])
|
34
34
|
settings = Datadog.configuration.tracing[:active_record, config]
|
35
35
|
adapter_name = Contrib::Utils::Database.normalize_vendor(config[:adapter])
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../notifications/event'
|
4
|
+
|
5
|
+
module Datadog
|
6
|
+
module Tracing
|
7
|
+
module Contrib
|
8
|
+
module ActiveSupport
|
9
|
+
module Cache
|
10
|
+
# Defines basic behaviors for an ActiveSupport event.
|
11
|
+
module Event
|
12
|
+
def self.included(base)
|
13
|
+
base.include(ActiveSupport::Notifications::Event)
|
14
|
+
base.extend(ClassMethods)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Class methods for ActiveRecord events.
|
18
|
+
module ClassMethods
|
19
|
+
def span_options
|
20
|
+
{}
|
21
|
+
end
|
22
|
+
|
23
|
+
def configuration
|
24
|
+
Datadog.configuration.tracing[:active_support]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../ext'
|
4
|
+
require_relative '../event'
|
5
|
+
|
6
|
+
module Datadog
|
7
|
+
module Tracing
|
8
|
+
module Contrib
|
9
|
+
module ActiveSupport
|
10
|
+
module Cache
|
11
|
+
module Events
|
12
|
+
# Defines instrumentation for instantiation.active_record event
|
13
|
+
module Cache
|
14
|
+
include ActiveSupport::Cache::Event
|
15
|
+
|
16
|
+
module_function
|
17
|
+
|
18
|
+
# Acts as this module's initializer.
|
19
|
+
def subscribe!
|
20
|
+
@cache_backend = {}
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
def event_name
|
25
|
+
/\Acache_(?:delete|read|read_multi|write|write_multi)\.active_support\z/
|
26
|
+
end
|
27
|
+
|
28
|
+
def span_name
|
29
|
+
Ext::SPAN_CACHE
|
30
|
+
end
|
31
|
+
|
32
|
+
def span_options
|
33
|
+
{
|
34
|
+
type: Ext::SPAN_TYPE_CACHE
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
# DEV: Look for other uses of `ActiveSupport::Cache::Store#instrument`, to find other useful event keys.
|
39
|
+
MAPPING = {
|
40
|
+
'cache_delete.active_support' => { resource: Ext::RESOURCE_CACHE_DELETE },
|
41
|
+
'cache_read.active_support' => { resource: Ext::RESOURCE_CACHE_GET },
|
42
|
+
'cache_read_multi.active_support' => { resource: Ext::RESOURCE_CACHE_MGET, multi_key: true },
|
43
|
+
'cache_write.active_support' => { resource: Ext::RESOURCE_CACHE_SET },
|
44
|
+
'cache_write_multi.active_support' => { resource: Ext::RESOURCE_CACHE_MSET, multi_key: true }
|
45
|
+
}.freeze
|
46
|
+
|
47
|
+
def trace?(event, _payload)
|
48
|
+
return false if !Tracing.enabled? || !configuration.enabled
|
49
|
+
|
50
|
+
# DEV-3.0: Backwards compatibility code for the 2.x gem series.
|
51
|
+
# DEV-3.0: See documentation at {Datadog::Tracing::Contrib::ActiveSupport::Cache::Instrumentation}
|
52
|
+
# DEV-3.0: for the complete information about this backwards compatibility code.
|
53
|
+
case event
|
54
|
+
when 'cache_read.active_support'
|
55
|
+
!ActiveSupport::Cache::Instrumentation.nested_read?
|
56
|
+
when 'cache_read_multi.active_support'
|
57
|
+
!ActiveSupport::Cache::Instrumentation.nested_multiread?
|
58
|
+
else
|
59
|
+
true
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def on_start(span, event, _id, payload)
|
64
|
+
key = payload[:key]
|
65
|
+
store = payload[:store]
|
66
|
+
|
67
|
+
mapping = MAPPING[event]
|
68
|
+
|
69
|
+
span.service = configuration[:cache_service]
|
70
|
+
span.resource = mapping[:resource]
|
71
|
+
|
72
|
+
span.set_tag(Tracing::Metadata::Ext::TAG_COMPONENT, Ext::TAG_COMPONENT)
|
73
|
+
span.set_tag(Tracing::Metadata::Ext::TAG_OPERATION, Ext::TAG_OPERATION_CACHE)
|
74
|
+
|
75
|
+
if span.service != Datadog.configuration.service
|
76
|
+
span.set_tag(Tracing::Contrib::Ext::Metadata::TAG_BASE_SERVICE, Datadog.configuration.service)
|
77
|
+
end
|
78
|
+
|
79
|
+
span.set_tag(Ext::TAG_CACHE_BACKEND, cache_backend(store))
|
80
|
+
|
81
|
+
span.set_tag('EVENT', event)
|
82
|
+
|
83
|
+
set_cache_key(span, key, mapping[:multi_key])
|
84
|
+
end
|
85
|
+
|
86
|
+
def set_cache_key(span, key, multi_key)
|
87
|
+
if multi_key
|
88
|
+
keys = key.is_a?(Hash) ? key.keys : key # `write`s use Hashes, while `read`s use Arrays
|
89
|
+
resolved_key = keys.map { |k| ::ActiveSupport::Cache.expand_cache_key(k) }
|
90
|
+
cache_key = Core::Utils.truncate(resolved_key, Ext::QUANTIZE_CACHE_MAX_KEY_SIZE)
|
91
|
+
span.set_tag(Ext::TAG_CACHE_KEY_MULTI, cache_key)
|
92
|
+
else
|
93
|
+
resolved_key = ::ActiveSupport::Cache.expand_cache_key(key)
|
94
|
+
cache_key = Core::Utils.truncate(resolved_key, Ext::QUANTIZE_CACHE_MAX_KEY_SIZE)
|
95
|
+
span.set_tag(Ext::TAG_CACHE_KEY, cache_key)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# The name of the `store` is never saved by Rails.
|
100
|
+
# ActiveSupport looks up stores by converting a symbol into a 'require' path,
|
101
|
+
# then "camelizing" it for a `const_get` call:
|
102
|
+
# ```
|
103
|
+
# require "active_support/cache/#{store}"
|
104
|
+
# ActiveSupport::Cache.const_get(store.to_s.camelize)
|
105
|
+
# ```
|
106
|
+
# @see https://github.com/rails/rails/blob/261975dbef77731d2c76f907f1076c5132ebc0e4/activesupport/lib/active_support/cache.rb#L139-L149
|
107
|
+
#
|
108
|
+
# We can reverse engineer
|
109
|
+
# the original symbol by converting the class name to snake case:
|
110
|
+
# e.g. ActiveSupport::Cache::RedisStore -> active_support/cache/redis_store
|
111
|
+
# In this case, `redis_store` is the store name.
|
112
|
+
#
|
113
|
+
# Because there's no API retrieve only the class name
|
114
|
+
# (only `RedisStore`, and not `ActiveSupport::Cache::RedisStore`)
|
115
|
+
# the easiest way to retrieve the store symbol is to convert the fully qualified
|
116
|
+
# name using the Rails-provided method `#underscore`, which is the reverse of `#camelize`,
|
117
|
+
# then extracting the last part of it.
|
118
|
+
#
|
119
|
+
# Also, this method caches the store name, given this value will be retrieve
|
120
|
+
# multiple times and involves string manipulation.
|
121
|
+
def cache_backend(store)
|
122
|
+
# Cache the backend name to avoid the expensive string manipulation required to calculate it.
|
123
|
+
# DEV: We can't store it directly in the `store` object because it is a frozen String.
|
124
|
+
if (name = @cache_backend[store])
|
125
|
+
return name
|
126
|
+
end
|
127
|
+
|
128
|
+
# DEV: #underscore is available through ActiveSupport, and is
|
129
|
+
# DEV: the exact reverse operation to `#camelize`.
|
130
|
+
# DEV: #demodulize is available through ActiveSupport, and is
|
131
|
+
# DEV: used to remove the module ('*::') part of a constant name.
|
132
|
+
name = ::ActiveSupport::Inflector.demodulize(store)
|
133
|
+
name = ::ActiveSupport::Inflector.underscore(name)
|
134
|
+
|
135
|
+
# Despite a given application only ever having 1-3 store types,
|
136
|
+
# we limit the size of the `@cache_backend` just in case, because
|
137
|
+
# the user can create custom Cache store classes themselves.
|
138
|
+
@cache_backend[store] = name if @cache_backend.size < 50
|
139
|
+
|
140
|
+
name
|
141
|
+
end
|
142
|
+
|
143
|
+
# DEV: There are two possibly interesting fields in the `on_finish` payload:
|
144
|
+
# | `:hit` | If this read is a hit |
|
145
|
+
# | `:super_operation` | `:fetch` if a read is done with [`fetch`][ActiveSupport::Cache::Store#fetch] |
|
146
|
+
# @see https://github.com/rails/rails/blob/b9d6759401c3d50a51e0a7650cb2331f4218d11f/guides/source/active_support_instrumentation.md?plain=1#L528-L529
|
147
|
+
# def on_finish(span, event, id, payload)
|
148
|
+
# super
|
149
|
+
# end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'events/cache'
|
4
|
+
|
5
|
+
module Datadog
|
6
|
+
module Tracing
|
7
|
+
module Contrib
|
8
|
+
module ActiveSupport
|
9
|
+
module Cache
|
10
|
+
# Defines collection of instrumented ActiveSupport events
|
11
|
+
module Events
|
12
|
+
ALL = [
|
13
|
+
Events::Cache,
|
14
|
+
].freeze
|
15
|
+
|
16
|
+
module_function
|
17
|
+
|
18
|
+
def all
|
19
|
+
self::ALL
|
20
|
+
end
|
21
|
+
|
22
|
+
def subscriptions
|
23
|
+
all.collect(&:subscriptions).collect(&:to_a).flatten
|
24
|
+
end
|
25
|
+
|
26
|
+
def subscribe!
|
27
|
+
all.each(&:subscribe!)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -9,7 +9,31 @@ module Datadog
|
|
9
9
|
module Contrib
|
10
10
|
module ActiveSupport
|
11
11
|
module Cache
|
12
|
-
#
|
12
|
+
# DEV-3.0: Backwards compatibility code for the 2.x gem series.
|
13
|
+
# DEV-3.0:
|
14
|
+
# DEV-3.0: `ActiveSupport::Cache` is now instrumented by subscribing to ActiveSupport::Notifications events.
|
15
|
+
# DEV-3.0: The implementation is located at {Datadog::Tracing::Contrib::ActiveSupport::Cache::Events::Cache}.
|
16
|
+
# DEV-3.0: The events emitted provide richer introspection points (e.g. events for cache misses on `#fetch`) while
|
17
|
+
# DEV-3.0: also ensuring we are using Rails' public API for improved compatibility.
|
18
|
+
# DEV-3.0:
|
19
|
+
# DEV-3.0: But a few operations holds us back:
|
20
|
+
# DEV-3.0: 1. `ActiveSupport::Cache::Store#fetch`:
|
21
|
+
# DEV-3.0: This method does not have an event that can produce an equivalent span to today's 2.x implementation.
|
22
|
+
# DEV-3.0: In 2.x, `#fetch` produces two separate, *nested* spans: one for the `#read` operation and
|
23
|
+
# DEV-3.0: another for the `#write` operation that is called internally by `#fetch` when the cache key needs
|
24
|
+
# DEV-3.0: to be populated on a cache miss.
|
25
|
+
# DEV-3.0: But the ActiveSupport events emitted by `#fetch` provide two *sibling* events for the`#read` and
|
26
|
+
# DEV-3.0: `#write` operations.
|
27
|
+
# DEV-3.0: Moving from nested spans to sibling spans would be a breaking change. One notable difference is
|
28
|
+
# DEV-3.0: that if the nested `#write` operation fails 2.x, the `#read` span is marked as an error. This would
|
29
|
+
# DEV-3.0: not be the case with sibling spans, and would be a very visible change.
|
30
|
+
# DEV-3.0: 2. `ActiveSupport::Cache::Store#read_multi` & `ActiveSupport::Cache::Store#fetch_multi`:
|
31
|
+
# DEV-3.0: ActiveSupport events were introduced in ActiveSupport 5.2.0 for these methods.
|
32
|
+
# DEV-3.0:
|
33
|
+
# DEV-3.0: At the end of the day, moving to ActiveSupport events is the better approach, but we have to retain
|
34
|
+
# DEV-3.0: this last few monkey patches (and all the supporting code) to avoid a breaking change for now.
|
35
|
+
#
|
36
|
+
# Defines the deprecate monkey-patch instrumentation for `ActiveSupport::Cache::Store#fetch`
|
13
37
|
module Instrumentation
|
14
38
|
module_function
|
15
39
|
|
@@ -43,6 +67,10 @@ module Datadog
|
|
43
67
|
# In most of the cases, `#fetch()` and `#read()` calls are nested.
|
44
68
|
# Instrument both does not add any value.
|
45
69
|
# This method checks if these two operations are nested.
|
70
|
+
#
|
71
|
+
# DEV-3.0: We should not have these checks in the 3.x series because ActiveSupport events provide more
|
72
|
+
# DEV-3.0: legible nested spans. While using ActiveSupport events, the nested spans actually provide meaningful
|
73
|
+
# DEV-3.0: information.
|
46
74
|
def nested_read?
|
47
75
|
current_span = Tracing.active_span
|
48
76
|
current_span && current_span.name == Ext::SPAN_CACHE && current_span.resource == Ext::RESOURCE_CACHE_GET
|
@@ -107,29 +135,20 @@ module Datadog
|
|
107
135
|
end
|
108
136
|
end
|
109
137
|
|
110
|
-
# Defines instrumentation for ActiveSupport cache
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
def read(*args, &block)
|
115
|
-
return super if Instrumentation.nested_read?
|
116
|
-
|
117
|
-
Instrumentation.trace(Ext::RESOURCE_CACHE_GET, dd_store_name, key: args[0]) { super }
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
# Defines instrumentation for ActiveSupport cache reading of multiple keys
|
138
|
+
# Defines the the legacy monkey-patching instrumentation for ActiveSupport cache read_multi
|
139
|
+
# DEV-3.0: ActiveSupport::Notifications events were introduced in ActiveSupport 5.2.0 for this method.
|
140
|
+
# DEV-3.0: As long as we support ActiveSupport < 5.2.0, we have to keep this method.
|
122
141
|
module ReadMulti
|
123
142
|
include InstanceMethods
|
124
143
|
|
125
|
-
def read_multi(*keys, &block)
|
144
|
+
def read_multi(*keys, **options, &block)
|
126
145
|
return super if Instrumentation.nested_multiread?
|
127
146
|
|
128
147
|
Instrumentation.trace(Ext::RESOURCE_CACHE_MGET, dd_store_name, multi_key: keys) { super }
|
129
148
|
end
|
130
149
|
end
|
131
150
|
|
132
|
-
# Defines instrumentation for ActiveSupport cache
|
151
|
+
# Defines the the legacy monkey-patching instrumentation for ActiveSupport cache fetch
|
133
152
|
module Fetch
|
134
153
|
include InstanceMethods
|
135
154
|
|
@@ -140,11 +159,13 @@ module Datadog
|
|
140
159
|
end
|
141
160
|
end
|
142
161
|
|
143
|
-
# Defines instrumentation for ActiveSupport cache
|
162
|
+
# Defines the the legacy monkey-patching instrumentation for ActiveSupport cache fetch_multi
|
163
|
+
# DEV-3.0: ActiveSupport::Notifications events were introduced in ActiveSupport 5.2.0 for this method.
|
164
|
+
# DEV-3.0: As long as we support ActiveSupport < 5.2.0, we have to keep this method.
|
144
165
|
module FetchMulti
|
145
166
|
include InstanceMethods
|
146
167
|
|
147
|
-
def fetch_multi(*args, &block)
|
168
|
+
def fetch_multi(*args, **options, &block)
|
148
169
|
return super if Instrumentation.nested_multiread?
|
149
170
|
|
150
171
|
keys = args[-1].instance_of?(Hash) ? args[0..-2] : args
|
@@ -152,30 +173,13 @@ module Datadog
|
|
152
173
|
end
|
153
174
|
end
|
154
175
|
|
155
|
-
#
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
end
|
163
|
-
|
164
|
-
# Defines instrumentation for ActiveSupport cache writing of multiple keys
|
165
|
-
module WriteMulti
|
166
|
-
include InstanceMethods
|
167
|
-
|
168
|
-
def write_multi(hash, options = nil)
|
169
|
-
Instrumentation.trace(Ext::RESOURCE_CACHE_MSET, dd_store_name, multi_key: hash.keys) { super }
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
# Defines instrumentation for ActiveSupport cache deleting
|
174
|
-
module Delete
|
175
|
-
include InstanceMethods
|
176
|
-
|
177
|
-
def delete(*args, &block)
|
178
|
-
Instrumentation.trace(Ext::RESOURCE_CACHE_DELETE, dd_store_name, key: args[0]) { super }
|
176
|
+
# Backports the payload[:store] key present since Rails 6.1:
|
177
|
+
# https://github.com/rails/rails/commit/6fa747f2946ee244b2aab0cd8c3c064f05d950a5
|
178
|
+
module Store
|
179
|
+
def instrument(operation, key, options = nil)
|
180
|
+
polyfill_options = options&.dup || {}
|
181
|
+
polyfill_options[:store] = self.class.name
|
182
|
+
super(operation, key, polyfill_options)
|
179
183
|
end
|
180
184
|
end
|
181
185
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require_relative '../../patcher'
|
4
4
|
require_relative 'instrumentation'
|
5
|
+
require_relative 'events'
|
5
6
|
|
6
7
|
module Datadog
|
7
8
|
module Tracing
|
@@ -19,54 +20,30 @@ module Datadog
|
|
19
20
|
end
|
20
21
|
|
21
22
|
def patch
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
23
|
+
Events.subscribe!
|
24
|
+
|
25
|
+
# Backfill the `:store` key in the ActiveSupport event payload for older Rails.
|
26
|
+
if Integration.version < Gem::Version.new('6.1.0')
|
27
|
+
::ActiveSupport::Cache::Store.prepend(Cache::Instrumentation::Store)
|
28
|
+
end
|
29
|
+
|
30
|
+
# DEV-3.0: Backwards compatibility code for the 2.x gem series.
|
31
|
+
# DEV-3.0: See documentation at {Datadog::Tracing::Contrib::ActiveSupport::Cache::Instrumentation}
|
32
|
+
# DEV-3.0: for the complete information about this backwards compatibility code.
|
33
|
+
patch_legacy_cache_store
|
29
34
|
end
|
30
35
|
|
31
36
|
# This method is overwritten by
|
32
37
|
# `datadog/tracing/contrib/active_support/cache/redis.rb`
|
33
38
|
# with more complex behavior.
|
34
39
|
def cache_store_class(meth)
|
35
|
-
::ActiveSupport::Cache::Store
|
36
|
-
end
|
37
|
-
|
38
|
-
def patch_cache_store_read
|
39
|
-
cache_store_class(:read).prepend(Cache::Instrumentation::Read)
|
40
|
-
end
|
41
|
-
|
42
|
-
def patch_cache_store_read_multi
|
43
|
-
cache_store_class(:read_multi).prepend(Cache::Instrumentation::ReadMulti)
|
44
|
-
end
|
45
|
-
|
46
|
-
def patch_cache_store_fetch
|
47
|
-
cache_store_class(:fetch).prepend(Cache::Instrumentation::Fetch)
|
48
|
-
end
|
49
|
-
|
50
|
-
def patch_cache_store_fetch_multi
|
51
|
-
klass = cache_store_class(:fetch_multi)
|
52
|
-
return unless klass.public_method_defined?(:fetch_multi)
|
53
|
-
|
54
|
-
klass.prepend(Cache::Instrumentation::FetchMulti)
|
55
|
-
end
|
56
|
-
|
57
|
-
def patch_cache_store_write
|
58
|
-
cache_store_class(:write).prepend(Cache::Instrumentation::Write)
|
59
|
-
end
|
60
|
-
|
61
|
-
def patch_cache_store_write_multi
|
62
|
-
klass = cache_store_class(:write_multi)
|
63
|
-
return unless klass.public_method_defined?(:write_multi)
|
64
|
-
|
65
|
-
klass.prepend(Cache::Instrumentation::WriteMulti)
|
40
|
+
[::ActiveSupport::Cache::Store]
|
66
41
|
end
|
67
42
|
|
68
|
-
def
|
69
|
-
cache_store_class(:
|
43
|
+
def patch_legacy_cache_store
|
44
|
+
cache_store_class(:read_multi).each { |clazz| clazz.prepend(Cache::Instrumentation::ReadMulti) }
|
45
|
+
cache_store_class(:fetch).each { |clazz| clazz.prepend(Cache::Instrumentation::Fetch) }
|
46
|
+
cache_store_class(:fetch_multi).each { |clazz| clazz.prepend(Cache::Instrumentation::FetchMulti) }
|
70
47
|
end
|
71
48
|
end
|
72
49
|
end
|
@@ -30,7 +30,10 @@ module Datadog
|
|
30
30
|
|
31
31
|
def cache_store_class(meth)
|
32
32
|
if patch_redis?(meth)
|
33
|
-
::ActiveSupport::Cache::RedisStore
|
33
|
+
[::ActiveSupport::Cache::RedisStore, ::ActiveSupport::Cache::Store]
|
34
|
+
elsif Gem.loaded_specs['redis'] && defined?(::ActiveSupport::Cache::RedisCacheStore) \
|
35
|
+
&& ::ActiveSupport::Cache::RedisCacheStore.instance_methods(false).include?(meth)
|
36
|
+
[::ActiveSupport::Cache::RedisCacheStore, ::ActiveSupport::Cache::Store]
|
34
37
|
else
|
35
38
|
super
|
36
39
|
end
|