datadog 2.1.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 +53 -2
- 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/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/settings.rb +39 -0
- data/lib/datadog/core/configuration.rb +3 -17
- data/lib/datadog/core/deprecations.rb +58 -0
- data/lib/datadog/core/environment/yjit.rb +5 -0
- data/lib/datadog/core/runtime/ext.rb +1 -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 +100 -25
- 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/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 +9 -2
- data/lib/datadog/tracing/distributed/trace_context.rb +3 -2
- 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 +22 -9
- data/lib/datadog/core/telemetry/client.rb +0 -95
- data/lib/datadog/core/telemetry/heartbeat.rb +0 -33
@@ -4,6 +4,7 @@ require_relative '../analytics'
|
|
4
4
|
require_relative '../patcher'
|
5
5
|
require_relative 'tracing_patcher'
|
6
6
|
require_relative 'trace_patcher'
|
7
|
+
require_relative 'unified_trace_patcher'
|
7
8
|
|
8
9
|
module Datadog
|
9
10
|
module Tracing
|
@@ -23,10 +24,15 @@ module Datadog
|
|
23
24
|
if configuration[:with_deprecated_tracer]
|
24
25
|
TracingPatcher.patch!(schemas, trace_options)
|
25
26
|
elsif Integration.trace_supported?
|
26
|
-
|
27
|
+
if configuration[:with_unified_tracer]
|
28
|
+
UnifiedTracePatcher.patch!(schemas, trace_options)
|
29
|
+
else
|
30
|
+
TracePatcher.patch!(schemas, trace_options)
|
31
|
+
end
|
27
32
|
else
|
28
33
|
Datadog.logger.warn(
|
29
|
-
"GraphQL version (#{target_version}) does not support GraphQL::Tracing::DataDogTrace
|
34
|
+
"GraphQL version (#{target_version}) does not support GraphQL::Tracing::DataDogTrace"\
|
35
|
+
'or Datadog::Tracing::Contrib::GraphQL::UnifiedTrace.'\
|
30
36
|
'Falling back to GraphQL::Tracing::DataDogTracing.'
|
31
37
|
)
|
32
38
|
TracingPatcher.patch!(schemas, trace_options)
|
@@ -0,0 +1,166 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'graphql/tracing'
|
4
|
+
|
5
|
+
module Datadog
|
6
|
+
module Tracing
|
7
|
+
module Contrib
|
8
|
+
module GraphQL
|
9
|
+
# These methods will be called by the GraphQL runtime to trace the execution of queries.
|
10
|
+
# This tracer differs from the upstream one as it follows the unified naming convention specification,
|
11
|
+
# which is required to use features such as API Catalog.
|
12
|
+
# DEV-3.0: This tracer should be the default one in the next major version.
|
13
|
+
module UnifiedTrace
|
14
|
+
# @param analytics_enabled [Boolean] Deprecated
|
15
|
+
# @param analytics_sample_rate [Float] Deprecated
|
16
|
+
# @param service [String|nil] The service name to be set on the spans
|
17
|
+
def initialize(*args, analytics_enabled: false, analytics_sample_rate: 1.0, service: nil, **kwargs)
|
18
|
+
@analytics_enabled = analytics_enabled
|
19
|
+
@analytics_sample_rate = analytics_sample_rate
|
20
|
+
|
21
|
+
@service_name = service
|
22
|
+
@has_prepare_span = respond_to?(:prepare_span)
|
23
|
+
super
|
24
|
+
end
|
25
|
+
|
26
|
+
def lex(*args, query_string:, **kwargs)
|
27
|
+
trace(proc { super }, 'lex', query_string, query_string: query_string)
|
28
|
+
end
|
29
|
+
|
30
|
+
def parse(*args, query_string:, **kwargs)
|
31
|
+
trace(proc { super }, 'parse', query_string, query_string: query_string) do |span|
|
32
|
+
span.set_tag('graphql.source', query_string)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def validate(*args, query:, validate:, **kwargs)
|
37
|
+
trace(proc { super }, 'validate', query.selected_operation_name, query: query, validate: validate) do |span|
|
38
|
+
span.set_tag('graphql.source', query.query_string)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def analyze_multiplex(*args, multiplex:, **kwargs)
|
43
|
+
trace(proc { super }, 'analyze_multiplex', multiplex_resource(multiplex), multiplex: multiplex)
|
44
|
+
end
|
45
|
+
|
46
|
+
def analyze_query(*args, query:, **kwargs)
|
47
|
+
trace(proc { super }, 'analyze', query.query_string, query: query)
|
48
|
+
end
|
49
|
+
|
50
|
+
def execute_multiplex(*args, multiplex:, **kwargs)
|
51
|
+
trace(proc { super }, 'execute_multiplex', multiplex_resource(multiplex), multiplex: multiplex) do |span|
|
52
|
+
span.set_tag('graphql.source', "Multiplex[#{multiplex.queries.map(&:query_string).join(', ')}]")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def execute_query(*args, query:, **kwargs)
|
57
|
+
trace(proc { super }, 'execute', query.selected_operation_name, query: query) do |span|
|
58
|
+
span.set_tag('graphql.source', query.query_string)
|
59
|
+
span.set_tag('graphql.operation.type', query.selected_operation.operation_type)
|
60
|
+
span.set_tag('graphql.operation.name', query.selected_operation_name) if query.selected_operation_name
|
61
|
+
query.variables.instance_variable_get(:@storage).each do |key, value|
|
62
|
+
span.set_tag("graphql.variables.#{key}", value)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def execute_query_lazy(*args, query:, multiplex:, **kwargs)
|
68
|
+
resource = if query
|
69
|
+
query.selected_operation_name || fallback_transaction_name(query.context)
|
70
|
+
else
|
71
|
+
multiplex_resource(multiplex)
|
72
|
+
end
|
73
|
+
trace(proc { super }, 'execute_lazy', resource, query: query, multiplex: multiplex)
|
74
|
+
end
|
75
|
+
|
76
|
+
def execute_field_span(callable, span_key, **kwargs)
|
77
|
+
# @platform_key_cache is initialized upstream, in ::GraphQL::Tracing::PlatformTrace
|
78
|
+
platform_key = @platform_key_cache[UnifiedTrace].platform_field_key_cache[kwargs[:field]]
|
79
|
+
|
80
|
+
if platform_key
|
81
|
+
trace(callable, span_key, platform_key, **kwargs) do |span|
|
82
|
+
kwargs[:arguments].each do |key, value|
|
83
|
+
span.set_tag("graphql.variables.#{key}", value)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
else
|
87
|
+
callable.call
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def execute_field(*args, **kwargs)
|
92
|
+
execute_field_span(proc { super }, 'resolve', **kwargs)
|
93
|
+
end
|
94
|
+
|
95
|
+
def execute_field_lazy(*args, **kwargs)
|
96
|
+
execute_field_span(proc { super }, 'resolve_lazy', **kwargs)
|
97
|
+
end
|
98
|
+
|
99
|
+
def authorized_span(callable, span_key, **kwargs)
|
100
|
+
platform_key = @platform_key_cache[UnifiedTrace].platform_authorized_key_cache[kwargs[:type]]
|
101
|
+
trace(callable, span_key, platform_key, **kwargs)
|
102
|
+
end
|
103
|
+
|
104
|
+
def authorized(*args, **kwargs)
|
105
|
+
authorized_span(proc { super }, 'authorized', **kwargs)
|
106
|
+
end
|
107
|
+
|
108
|
+
def authorized_lazy(*args, **kwargs)
|
109
|
+
authorized_span(proc { super }, 'authorized_lazy', **kwargs)
|
110
|
+
end
|
111
|
+
|
112
|
+
def resolve_type_span(callable, span_key, **kwargs)
|
113
|
+
platform_key = @platform_key_cache[UnifiedTrace].platform_resolve_type_key_cache[kwargs[:type]]
|
114
|
+
trace(callable, span_key, platform_key, **kwargs)
|
115
|
+
end
|
116
|
+
|
117
|
+
def resolve_type(*args, **kwargs)
|
118
|
+
resolve_type_span(proc { super }, 'resolve_type', **kwargs)
|
119
|
+
end
|
120
|
+
|
121
|
+
def resolve_type_lazy(*args, **kwargs)
|
122
|
+
resolve_type_span(proc { super }, 'resolve_type_lazy', **kwargs)
|
123
|
+
end
|
124
|
+
|
125
|
+
include ::GraphQL::Tracing::PlatformTrace
|
126
|
+
|
127
|
+
def platform_field_key(field, *args, **kwargs)
|
128
|
+
field.path
|
129
|
+
end
|
130
|
+
|
131
|
+
def platform_authorized_key(type, *args, **kwargs)
|
132
|
+
"#{type.graphql_name}.authorized"
|
133
|
+
end
|
134
|
+
|
135
|
+
def platform_resolve_type_key(type, *args, **kwargs)
|
136
|
+
"#{type.graphql_name}.resolve_type"
|
137
|
+
end
|
138
|
+
|
139
|
+
private
|
140
|
+
|
141
|
+
def trace(callable, trace_key, resource, **kwargs)
|
142
|
+
Tracing.trace("graphql.#{trace_key}", resource: resource, service: @service_name, type: 'graphql') do |span|
|
143
|
+
yield(span) if block_given?
|
144
|
+
|
145
|
+
prepare_span(trace_key, kwargs, span) if @has_prepare_span
|
146
|
+
|
147
|
+
callable.call
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def multiplex_resource(multiplex)
|
152
|
+
return nil unless multiplex
|
153
|
+
|
154
|
+
operations = multiplex.queries.map(&:selected_operation_name).compact.join(', ')
|
155
|
+
if operations.empty?
|
156
|
+
first_query = multiplex.queries.first
|
157
|
+
fallback_transaction_name(first_query && first_query.context)
|
158
|
+
else
|
159
|
+
operations
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module Tracing
|
5
|
+
module Contrib
|
6
|
+
module GraphQL
|
7
|
+
# Provides instrumentation for `graphql` through the GraphQL's tracing with methods defined in UnifiedTrace
|
8
|
+
module UnifiedTracePatcher
|
9
|
+
module_function
|
10
|
+
|
11
|
+
def patch!(schemas, options)
|
12
|
+
require_relative 'unified_trace'
|
13
|
+
if schemas.empty?
|
14
|
+
::GraphQL::Schema.trace_with(UnifiedTrace, **options)
|
15
|
+
else
|
16
|
+
schemas.each do |schema|
|
17
|
+
schema.trace_with(UnifiedTrace, **options)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -29,7 +29,7 @@ module Datadog
|
|
29
29
|
Datadog.configuration.tracing[:kafka]
|
30
30
|
end
|
31
31
|
|
32
|
-
def
|
32
|
+
def on_start(span, _event, _id, payload)
|
33
33
|
span.set_tag(Tracing::Metadata::Ext::TAG_COMPONENT, Ext::TAG_COMPONENT)
|
34
34
|
span.set_tag(Contrib::Ext::Messaging::TAG_SYSTEM, Ext::TAG_MESSAGING_SYSTEM)
|
35
35
|
|
@@ -15,7 +15,9 @@ module Datadog
|
|
15
15
|
|
16
16
|
EVENT_NAME = 'request.connection.kafka'
|
17
17
|
|
18
|
-
|
18
|
+
module_function
|
19
|
+
|
20
|
+
def on_start(span, _event, _id, payload)
|
19
21
|
super
|
20
22
|
|
21
23
|
span.resource = payload[:api]
|
@@ -24,8 +26,6 @@ module Datadog
|
|
24
26
|
span.set_tag(Ext::TAG_RESPONSE_SIZE, payload[:response_size]) if payload.key?(:response_size)
|
25
27
|
end
|
26
28
|
|
27
|
-
module_function
|
28
|
-
|
29
29
|
def span_name
|
30
30
|
Ext::SPAN_CONNECTION_REQUEST
|
31
31
|
end
|
@@ -17,7 +17,9 @@ module Datadog
|
|
17
17
|
|
18
18
|
EVENT_NAME = 'process_batch.consumer.kafka'
|
19
19
|
|
20
|
-
|
20
|
+
module_function
|
21
|
+
|
22
|
+
def on_start(span, _event, _id, payload)
|
21
23
|
super
|
22
24
|
|
23
25
|
span.resource = payload[:topic]
|
@@ -31,8 +33,6 @@ module Datadog
|
|
31
33
|
span.set_tag(Ext::TAG_OFFSET_LAG, payload[:offset_lag]) if payload.key?(:offset_lag)
|
32
34
|
end
|
33
35
|
|
34
|
-
module_function
|
35
|
-
|
36
36
|
def span_name
|
37
37
|
Ext::SPAN_PROCESS_BATCH
|
38
38
|
end
|
@@ -17,7 +17,9 @@ module Datadog
|
|
17
17
|
|
18
18
|
EVENT_NAME = 'process_message.consumer.kafka'
|
19
19
|
|
20
|
-
|
20
|
+
module_function
|
21
|
+
|
22
|
+
def on_start(span, _event, _id, payload)
|
21
23
|
super
|
22
24
|
|
23
25
|
span.resource = payload[:topic]
|
@@ -29,8 +31,6 @@ module Datadog
|
|
29
31
|
span.set_tag(Ext::TAG_OFFSET_LAG, payload[:offset_lag]) if payload.key?(:offset_lag)
|
30
32
|
end
|
31
33
|
|
32
|
-
module_function
|
33
|
-
|
34
34
|
def span_name
|
35
35
|
Ext::SPAN_PROCESS_MESSAGE
|
36
36
|
end
|
@@ -19,7 +19,9 @@ module Datadog
|
|
19
19
|
|
20
20
|
EVENT_NAME = 'heartbeat.consumer.kafka'
|
21
21
|
|
22
|
-
|
22
|
+
module_function
|
23
|
+
|
24
|
+
def on_start(span, _event, _id, payload)
|
23
25
|
super
|
24
26
|
|
25
27
|
if payload.key?(:topic_partitions)
|
@@ -29,8 +31,6 @@ module Datadog
|
|
29
31
|
end
|
30
32
|
end
|
31
33
|
|
32
|
-
module_function
|
33
|
-
|
34
34
|
def span_name
|
35
35
|
Ext::SPAN_CONSUMER_HEARTBEAT
|
36
36
|
end
|
@@ -15,7 +15,9 @@ module Datadog
|
|
15
15
|
|
16
16
|
EVENT_NAME = 'send_messages.producer.kafka'
|
17
17
|
|
18
|
-
|
18
|
+
module_function
|
19
|
+
|
20
|
+
def on_start(span, _event, _id, payload)
|
19
21
|
super
|
20
22
|
|
21
23
|
span.set_tag(Ext::TAG_MESSAGE_COUNT, payload[:message_count]) if payload.key?(:message_count)
|
@@ -23,8 +25,6 @@ module Datadog
|
|
23
25
|
span.set_tag(Tracing::Metadata::Ext::TAG_KIND, Tracing::Metadata::Ext::SpanKind::TAG_PRODUCER)
|
24
26
|
end
|
25
27
|
|
26
|
-
module_function
|
27
|
-
|
28
28
|
def span_name
|
29
29
|
Ext::SPAN_SEND_MESSAGES
|
30
30
|
end
|
@@ -15,7 +15,9 @@ module Datadog
|
|
15
15
|
|
16
16
|
EVENT_NAME = 'deliver_messages.producer.kafka'
|
17
17
|
|
18
|
-
|
18
|
+
module_function
|
19
|
+
|
20
|
+
def on_start(span, _event, _id, payload)
|
19
21
|
super
|
20
22
|
|
21
23
|
span.set_tag(Ext::TAG_ATTEMPTS, payload[:attempts]) if payload.key?(:attempts)
|
@@ -26,8 +28,6 @@ module Datadog
|
|
26
28
|
span.set_tag(Tracing::Metadata::Ext::TAG_KIND, Tracing::Metadata::Ext::SpanKind::TAG_PRODUCER)
|
27
29
|
end
|
28
30
|
|
29
|
-
module_function
|
30
|
-
|
31
31
|
def span_name
|
32
32
|
Ext::SPAN_DELIVER_MESSAGES
|
33
33
|
end
|
@@ -19,7 +19,7 @@ module Datadog
|
|
19
19
|
# Class methods for Racecar events.
|
20
20
|
# Note, they share the same process method and before_trace method.
|
21
21
|
module ClassMethods
|
22
|
-
def subscription(*args)
|
22
|
+
def subscription(*args, **kwargs)
|
23
23
|
super.tap do |subscription|
|
24
24
|
subscription.before_trace { ensure_clean_context! }
|
25
25
|
end
|
@@ -33,7 +33,7 @@ module Datadog
|
|
33
33
|
Datadog.configuration.tracing[:racecar]
|
34
34
|
end
|
35
35
|
|
36
|
-
def
|
36
|
+
def on_start(span, event, _id, payload)
|
37
37
|
span.service = configuration[:service_name]
|
38
38
|
span.resource = payload[:consumer_class]
|
39
39
|
|
@@ -14,6 +14,15 @@ module Datadog
|
|
14
14
|
ENV_ANALYTICS_SAMPLE_RATE = 'DD_TRACE_RAILS_ANALYTICS_SAMPLE_RATE'
|
15
15
|
ENV_DISABLE = 'DISABLE_DATADOG_RAILS'
|
16
16
|
|
17
|
+
SPAN_RUNNER_FILE = 'rails.runner.file'
|
18
|
+
SPAN_RUNNER_INLINE = 'rails.runner.inline'
|
19
|
+
SPAN_RUNNER_STDIN = 'rails.runner.stdin'
|
20
|
+
TAG_COMPONENT = 'rails'
|
21
|
+
TAG_OPERATION_FILE = 'runner.file'
|
22
|
+
TAG_OPERATION_INLINE = 'runner.inline'
|
23
|
+
TAG_OPERATION_STDIN = 'runner.stdin'
|
24
|
+
TAG_RUNNER_SOURCE = 'source'
|
25
|
+
|
17
26
|
# @!visibility private
|
18
27
|
MINIMUM_VERSION = Gem::Version.new('4')
|
19
28
|
end
|
@@ -5,6 +5,7 @@ require_relative '../rack/middlewares'
|
|
5
5
|
require_relative 'framework'
|
6
6
|
require_relative 'log_injection'
|
7
7
|
require_relative 'middlewares'
|
8
|
+
require_relative 'runner'
|
8
9
|
require_relative 'utils'
|
9
10
|
require_relative '../semantic_logger/patcher'
|
10
11
|
|
@@ -28,6 +29,7 @@ module Datadog
|
|
28
29
|
def patch
|
29
30
|
patch_before_initialize
|
30
31
|
patch_after_initialize
|
32
|
+
patch_rails_runner
|
31
33
|
end
|
32
34
|
|
33
35
|
def patch_before_initialize
|
@@ -81,6 +83,11 @@ module Datadog
|
|
81
83
|
def setup_tracer
|
82
84
|
Contrib::Rails::Framework.setup
|
83
85
|
end
|
86
|
+
|
87
|
+
# Instruments the `bin/rails runner` command.
|
88
|
+
def patch_rails_runner
|
89
|
+
::Rails::Command.singleton_class.prepend(Command) if defined?(::Rails::Command)
|
90
|
+
end
|
84
91
|
end
|
85
92
|
end
|
86
93
|
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module Tracing
|
5
|
+
module Contrib
|
6
|
+
module Rails
|
7
|
+
# Instruments the `bin/rails runner` command.
|
8
|
+
# This command executes the provided code with the host Rails application loaded.
|
9
|
+
# The command can be either:
|
10
|
+
# * `-`: for code provided through the STDIN.
|
11
|
+
# * File path: for code provided through a local file.
|
12
|
+
# * `inline code`: for code provided directly as a command line argument.
|
13
|
+
# @see https://guides.rubyonrails.org/v6.1/command_line.html#bin-rails-runner
|
14
|
+
module Runner
|
15
|
+
# Limit the maximum size of the source code captured in the source tag.
|
16
|
+
MAX_TAG_VALUE_SIZE = 4096
|
17
|
+
private_constant :MAX_TAG_VALUE_SIZE
|
18
|
+
|
19
|
+
def runner(code_or_file = nil, *_command_argv)
|
20
|
+
if code_or_file == '-'
|
21
|
+
name = Ext::SPAN_RUNNER_STDIN
|
22
|
+
resource = nil
|
23
|
+
operation = Ext::TAG_OPERATION_STDIN
|
24
|
+
# The source is not yet available for STDIN, but it will be captured in `eval`.
|
25
|
+
elsif File.exist?(code_or_file)
|
26
|
+
name = Ext::SPAN_RUNNER_FILE
|
27
|
+
resource = code_or_file
|
28
|
+
operation = Ext::TAG_OPERATION_FILE
|
29
|
+
source = File.read(code_or_file)
|
30
|
+
else
|
31
|
+
name = Ext::SPAN_RUNNER_INLINE
|
32
|
+
resource = nil
|
33
|
+
operation = Ext::TAG_OPERATION_INLINE
|
34
|
+
source = code_or_file
|
35
|
+
end
|
36
|
+
|
37
|
+
Tracing.trace(
|
38
|
+
name,
|
39
|
+
service: Datadog.configuration.tracing[:rails][:service_name],
|
40
|
+
resource: resource,
|
41
|
+
tags: {
|
42
|
+
Tracing::Metadata::Ext::TAG_COMPONENT => Ext::TAG_COMPONENT,
|
43
|
+
Tracing::Metadata::Ext::TAG_OPERATION => operation,
|
44
|
+
}
|
45
|
+
) do |span|
|
46
|
+
if source
|
47
|
+
span.set_tag(
|
48
|
+
Ext::TAG_RUNNER_SOURCE,
|
49
|
+
Core::Utils.truncate(source, MAX_TAG_VALUE_SIZE)
|
50
|
+
)
|
51
|
+
end
|
52
|
+
Contrib::Analytics.set_rate!(span, Datadog.configuration.tracing[:rails])
|
53
|
+
|
54
|
+
super
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Capture the executed source code when provided from STDIN.
|
59
|
+
def eval(*args)
|
60
|
+
span = Datadog::Tracing.active_span
|
61
|
+
if span.name == Ext::SPAN_RUNNER_STDIN
|
62
|
+
source = args[0]
|
63
|
+
span.set_tag(
|
64
|
+
Ext::TAG_RUNNER_SOURCE,
|
65
|
+
Core::Utils.truncate(source, MAX_TAG_VALUE_SIZE)
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
69
|
+
super
|
70
|
+
end
|
71
|
+
|
72
|
+
ruby2_keywords :eval if respond_to?(:ruby2_keywords, true)
|
73
|
+
end
|
74
|
+
|
75
|
+
# The instrumentation target, {Rails::Command::RunnerCommand} is only loaded
|
76
|
+
# right before `bin/rails runner` is executed. This means there's not much
|
77
|
+
# opportunity to patch it ahead of time.
|
78
|
+
# To ensure we can patch it successfully, we patch it's caller, {Rails::Command}
|
79
|
+
# and promptly patch {Rails::Command::RunnerCommand} when it is loaded.
|
80
|
+
module Command
|
81
|
+
def find_by_namespace(*args)
|
82
|
+
ret = super
|
83
|
+
# Patch RunnerCommand if it is loaded and not already patched.
|
84
|
+
if defined?(::Rails::Command::RunnerCommand) && !(::Rails::Command::RunnerCommand < Runner)
|
85
|
+
::Rails::Command::RunnerCommand.prepend(Runner)
|
86
|
+
end
|
87
|
+
ret
|
88
|
+
end
|
89
|
+
|
90
|
+
ruby2_keywords :find_by_namespace if respond_to?(:ruby2_keywords, true)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -31,7 +31,7 @@ module Datadog
|
|
31
31
|
|
32
32
|
# DEV: We need these to be hex encoded
|
33
33
|
data[@trace_id_key] = format('%032x', digest.trace_id)
|
34
|
-
data[@span_id_key] = format('%016x', digest.span_id)
|
34
|
+
data[@span_id_key] = format('%016x', digest.span_id || 0) # # Fall back to zero (invalid) if not present
|
35
35
|
|
36
36
|
if digest.trace_sampling_priority
|
37
37
|
sampling_priority = Helpers.clamp_sampling_priority(
|
@@ -25,8 +25,10 @@ module Datadog
|
|
25
25
|
def inject!(digest, env)
|
26
26
|
return if digest.nil?
|
27
27
|
|
28
|
+
span_id = digest.span_id || 0 # Fall back to zero (invalid) if not present
|
29
|
+
|
28
30
|
# DEV: We need these to be hex encoded
|
29
|
-
value = "#{format('%032x', digest.trace_id)}-#{format('%016x',
|
31
|
+
value = "#{format('%032x', digest.trace_id)}-#{format('%016x', span_id)}"
|
30
32
|
|
31
33
|
if digest.trace_sampling_priority
|
32
34
|
sampling_priority = Helpers.clamp_sampling_priority(
|
@@ -42,7 +42,7 @@ module Datadog
|
|
42
42
|
|
43
43
|
data[@trace_id_key] = Tracing::Utils::TraceId.to_low_order(digest.trace_id).to_s
|
44
44
|
|
45
|
-
data[@parent_id_key] = digest.span_id.to_s
|
45
|
+
data[@parent_id_key] = digest.span_id.to_s if digest.span_id
|
46
46
|
data[@sampling_priority_key] = digest.trace_sampling_priority.to_s if digest.trace_sampling_priority
|
47
47
|
data[@origin_key] = digest.trace_origin.to_s if digest.trace_origin
|
48
48
|
|
@@ -109,7 +109,7 @@ module Datadog
|
|
109
109
|
|
110
110
|
return tags if high_order == 0
|
111
111
|
|
112
|
-
tags.merge(Tracing::Metadata::Ext::Distributed::TAG_TID => high_order
|
112
|
+
tags.merge(Tracing::Metadata::Ext::Distributed::TAG_TID => format('%016x', high_order))
|
113
113
|
end
|
114
114
|
|
115
115
|
# Side effect: Remove high order 64 bit hex-encoded `tid` tag from distributed tags
|
@@ -32,7 +32,9 @@ module Datadog
|
|
32
32
|
|
33
33
|
# inject! populates the env with span ID, trace ID and sampling priority
|
34
34
|
#
|
35
|
-
# This method will never raise errors
|
35
|
+
# This method will never raise errors.
|
36
|
+
# It can propagate partial data, if deemed useful, instead of failing.
|
37
|
+
# In case of unrecoverable errors, it will log them to `Datadog.logger`.
|
36
38
|
#
|
37
39
|
# DEV-2.0: inject! should work without arguments, injecting the active_trace's digest
|
38
40
|
# DEV-2.0: and returning a new Hash with the injected data.
|
@@ -45,7 +47,7 @@ module Datadog
|
|
45
47
|
# @param digest [TraceDigest]
|
46
48
|
# @param data [Hash]
|
47
49
|
# @return [Boolean] `true` if injected successfully, `false` if no propagation style is configured
|
48
|
-
# @return [nil] in case of
|
50
|
+
# @return [nil] in case of unrecoverable errors, see `Datadog.logger` output for details.
|
49
51
|
def inject!(digest, data)
|
50
52
|
if digest.nil?
|
51
53
|
::Datadog.logger.debug('Cannot inject distributed trace data: digest is nil.')
|
@@ -54,6 +56,11 @@ module Datadog
|
|
54
56
|
|
55
57
|
digest = digest.to_digest if digest.respond_to?(:to_digest)
|
56
58
|
|
59
|
+
if digest.trace_id.nil?
|
60
|
+
::Datadog.logger.debug('Cannot inject distributed trace data: digest.trace_id is nil.')
|
61
|
+
return nil
|
62
|
+
end
|
63
|
+
|
57
64
|
result = false
|
58
65
|
|
59
66
|
# Inject all configured propagation styles
|
@@ -107,7 +107,7 @@ module Datadog
|
|
107
107
|
def build_traceparent(digest)
|
108
108
|
build_traceparent_string(
|
109
109
|
digest.trace_id,
|
110
|
-
digest.span_id,
|
110
|
+
digest.span_id || 0, # Fall back to zero (invalid) if not present
|
111
111
|
build_trace_flags(digest)
|
112
112
|
)
|
113
113
|
end
|
@@ -198,7 +198,8 @@ module Datadog
|
|
198
198
|
|
199
199
|
def last_dd_parent_id(digest)
|
200
200
|
if !digest.span_remote
|
201
|
-
|
201
|
+
span_id = digest.span_id || 0 # Fall back to zero (invalid) if not present
|
202
|
+
"p:#{format('%016x', span_id)};"
|
202
203
|
elsif digest.trace_distributed_tags&.key?(Tracing::Metadata::Ext::Distributed::TAG_DD_PARENT_ID)
|
203
204
|
"p:#{digest.trace_distributed_tags[Tracing::Metadata::Ext::Distributed::TAG_DD_PARENT_ID]};"
|
204
205
|
else
|
@@ -48,7 +48,8 @@ module Datadog
|
|
48
48
|
tags: nil,
|
49
49
|
trace_id: nil,
|
50
50
|
type: nil,
|
51
|
-
links: nil
|
51
|
+
links: nil,
|
52
|
+
id: nil
|
52
53
|
)
|
53
54
|
# Ensure dynamically created strings are UTF-8 encoded.
|
54
55
|
#
|
@@ -60,7 +61,7 @@ module Datadog
|
|
60
61
|
self.type = type
|
61
62
|
self.resource = resource
|
62
63
|
|
63
|
-
@id = Tracing::Utils.next_id
|
64
|
+
@id = id.nil? ? Tracing::Utils.next_id : id
|
64
65
|
@parent_id = parent_id || 0
|
65
66
|
@trace_id = trace_id || Tracing::Utils::TraceId.next_id
|
66
67
|
|