datadog 2.32.0 → 2.34.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +30 -1
- data/ext/datadog_profiling_native_extension/clock_id.h +9 -1
- data/ext/datadog_profiling_native_extension/clock_id_from_mach.c +73 -0
- data/ext/datadog_profiling_native_extension/clock_id_from_pthread.c +1 -1
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +20 -0
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +5 -1
- data/ext/datadog_profiling_native_extension/extconf.rb +3 -0
- data/ext/datadog_profiling_native_extension/macos_sampler_thread.h +55 -0
- data/ext/datadog_profiling_native_extension/stack_recorder.c +3 -9
- data/ext/datadog_profiling_native_extension/time_helpers.h +1 -0
- data/ext/libdatadog_api/crashtracker.c +2 -0
- data/ext/libdatadog_extconf_helpers.rb +1 -1
- data/lib/datadog/ai_guard/autoload.rb +10 -0
- data/lib/datadog/ai_guard/component.rb +1 -1
- data/lib/datadog/ai_guard/contrib/auto_instrument.rb +24 -0
- data/lib/datadog/ai_guard/contrib/rack/integration.rb +42 -0
- data/lib/datadog/ai_guard/contrib/rack/patcher.rb +26 -0
- data/lib/datadog/ai_guard/contrib/rack/request_middleware.rb +83 -0
- data/lib/datadog/ai_guard/contrib/rails/integration.rb +41 -0
- data/lib/datadog/ai_guard/contrib/rails/patcher.rb +97 -0
- data/lib/datadog/ai_guard/evaluation.rb +1 -0
- data/lib/datadog/ai_guard/ext.rb +1 -0
- data/lib/datadog/ai_guard.rb +8 -0
- data/lib/datadog/appsec/component.rb +4 -1
- data/lib/datadog/appsec/compressed_json.rb +2 -2
- data/lib/datadog/appsec/contrib/aws_lambda/gateway/watcher.rb +75 -0
- data/lib/datadog/appsec/contrib/aws_lambda/integration.rb +39 -0
- data/lib/datadog/appsec/contrib/aws_lambda/patcher.rb +30 -0
- data/lib/datadog/appsec/contrib/aws_lambda/waf_addresses.rb +111 -0
- data/lib/datadog/appsec/contrib/rack/ext.rb +1 -1
- data/lib/datadog/appsec.rb +1 -0
- data/lib/datadog/core/configuration/components.rb +8 -1
- data/lib/datadog/core/configuration/settings.rb +16 -1
- data/lib/datadog/core/configuration/supported_configurations.rb +12 -0
- data/lib/datadog/core/environment/ext.rb +5 -0
- data/lib/datadog/core/environment/identity.rb +15 -1
- data/lib/datadog/core/environment/process.rb +48 -27
- data/lib/datadog/core/environment/socket.rb +13 -0
- data/lib/datadog/core/remote/client/capabilities.rb +11 -2
- data/lib/datadog/core/remote/transport/http/config.rb +5 -5
- data/lib/datadog/core/telemetry/request.rb +0 -2
- data/lib/datadog/core/transport/response.rb +1 -1
- data/lib/datadog/core/utils/{base64.rb → base64_codec.rb} +3 -2
- data/lib/datadog/core/utils/hash.rb +0 -23
- data/lib/datadog/core/utils/spawn_monkey_patch.rb +46 -16
- data/lib/datadog/data_streams/pathway_context.rb +3 -3
- data/lib/datadog/di/code_tracker.rb +43 -22
- data/lib/datadog/di/contrib/active_record.rb +6 -2
- data/lib/datadog/di/instrumenter.rb +24 -4
- data/lib/datadog/di/probe_notification_builder.rb +1 -1
- data/lib/datadog/di/remote.rb +4 -4
- data/lib/datadog/di/serializer.rb +5 -5
- data/lib/datadog/di/utils.rb +42 -14
- data/lib/datadog/opentelemetry/configuration/settings.rb +65 -0
- data/lib/datadog/opentelemetry/ext.rb +9 -0
- data/lib/datadog/opentelemetry/logs.rb +98 -0
- data/lib/datadog/opentelemetry/metrics.rb +10 -37
- data/lib/datadog/opentelemetry/sdk/configurator.rb +40 -0
- data/lib/datadog/opentelemetry/sdk/id_generator.rb +16 -10
- data/lib/datadog/opentelemetry/sdk/logs_exporter.rb +37 -0
- data/lib/datadog/opentelemetry/signal_configuration.rb +53 -0
- data/lib/datadog/opentelemetry.rb +1 -0
- data/lib/datadog/profiling/component.rb +0 -1
- data/lib/datadog/profiling/stack_recorder.rb +0 -4
- data/lib/datadog/symbol_database/component.rb +409 -0
- data/lib/datadog/symbol_database/configuration.rb +2 -2
- data/lib/datadog/symbol_database/extractor.rb +45 -26
- data/lib/datadog/symbol_database/remote.rb +175 -0
- data/lib/datadog/symbol_database/scope.rb +16 -12
- data/lib/datadog/symbol_database/scope_batcher.rb +288 -0
- data/lib/datadog/symbol_database/service_version.rb +15 -6
- data/lib/datadog/symbol_database/symbol.rb +6 -3
- data/lib/datadog/symbol_database/uploader.rb +65 -8
- data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +8 -0
- data/lib/datadog/tracing/contrib/active_record/events/sql.rb +0 -4
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +0 -4
- data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +0 -4
- data/lib/datadog/tracing/contrib/aws/instrumentation.rb +0 -5
- data/lib/datadog/tracing/contrib/dalli/instrumentation.rb +0 -5
- data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +0 -5
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +0 -5
- data/lib/datadog/tracing/contrib/ethon/multi_patch.rb +0 -8
- data/lib/datadog/tracing/contrib/excon/middleware.rb +0 -5
- data/lib/datadog/tracing/contrib/ext.rb +2 -3
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +0 -5
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +0 -5
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +0 -5
- data/lib/datadog/tracing/contrib/http/instrumentation.rb +0 -5
- data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +0 -5
- data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +0 -5
- data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +0 -5
- data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +0 -5
- data/lib/datadog/tracing/contrib/opensearch/patcher.rb +0 -5
- data/lib/datadog/tracing/contrib/pg/instrumentation.rb +0 -5
- data/lib/datadog/tracing/contrib/presto/instrumentation.rb +0 -5
- data/lib/datadog/tracing/contrib/racecar/event.rb +0 -5
- data/lib/datadog/tracing/contrib/rack/configuration/settings.rb +6 -0
- data/lib/datadog/tracing/contrib/rack/ext.rb +27 -0
- data/lib/datadog/tracing/contrib/rack/trace_proxy_middleware.rb +117 -1
- data/lib/datadog/tracing/contrib/redis/tags.rb +0 -5
- data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +0 -5
- data/lib/datadog/tracing/contrib/sequel/utils.rb +0 -5
- data/lib/datadog/tracing/contrib/trilogy/instrumentation.rb +0 -5
- data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +0 -13
- data/lib/datadog/tracing/distributed/trace_context.rb +0 -28
- data/lib/datadog/tracing/metadata/ext.rb +3 -0
- data/lib/datadog/tracing/span_operation.rb +13 -0
- data/lib/datadog/tracing/trace_operation.rb +22 -0
- data/lib/datadog/tracing/tracer.rb +7 -3
- data/lib/datadog/version.rb +1 -1
- metadata +27 -8
- data/ext/datadog_profiling_native_extension/clock_id_noop.c +0 -21
data/lib/datadog/di/utils.rb
CHANGED
|
@@ -82,15 +82,31 @@ module Datadog
|
|
|
82
82
|
# we just strip leading directory components from the "probe path"
|
|
83
83
|
# until we get a match via a "suffix of the suffix".
|
|
84
84
|
|
|
85
|
+
# Returns +path+ with Windows-style backslash separators translated to
|
|
86
|
+
# forward slashes (DEBUG-5111). Used to normalize probe source paths
|
|
87
|
+
# that originate from IDE tooling running on Windows.
|
|
88
|
+
module_function def normalize_windows_separators(path)
|
|
89
|
+
path.tr('\\', '/')
|
|
90
|
+
end
|
|
91
|
+
|
|
85
92
|
# Returns whether the provided +path+ matches the user-designated
|
|
86
93
|
# file suffix (of a line probe).
|
|
87
94
|
#
|
|
88
|
-
#
|
|
89
|
-
#
|
|
95
|
+
# Backslash separators in +suffix+ are translated to forward slashes
|
|
96
|
+
# (DEBUG-5111) so paths typed by IDE tooling on Windows can match.
|
|
97
|
+
# Case-insensitive matching (DEBUG-5107) is opt-in via
|
|
98
|
+
# +case_insensitive: true+; callers that orchestrate matching against a
|
|
99
|
+
# set of known paths perform case-sensitive comparisons first and only
|
|
100
|
+
# fall back to case-insensitive when no case-sensitive match is found
|
|
101
|
+
# (see the design comment above, steps 5-8).
|
|
102
|
+
#
|
|
103
|
+
# If suffix is an absolute path (i.e., it starts with a slash, possibly
|
|
104
|
+
# after backslash normalization), the path must be identical for it to
|
|
105
|
+
# match.
|
|
90
106
|
#
|
|
91
107
|
# If suffix is not an absolute path, the path matches if its suffix is
|
|
92
108
|
# the provided suffix, at a path component boundary.
|
|
93
|
-
module_function def path_matches_suffix?(path, suffix)
|
|
109
|
+
module_function def path_matches_suffix?(path, suffix, case_insensitive: false)
|
|
94
110
|
if path.nil?
|
|
95
111
|
raise ArgumentError, "nil path passed"
|
|
96
112
|
end
|
|
@@ -98,6 +114,12 @@ module Datadog
|
|
|
98
114
|
raise ArgumentError, "nil suffix passed"
|
|
99
115
|
end
|
|
100
116
|
|
|
117
|
+
suffix = normalize_windows_separators(suffix)
|
|
118
|
+
if case_insensitive
|
|
119
|
+
path = path.downcase
|
|
120
|
+
suffix = suffix.downcase
|
|
121
|
+
end
|
|
122
|
+
|
|
101
123
|
if suffix.start_with?('/')
|
|
102
124
|
path == suffix
|
|
103
125
|
else
|
|
@@ -105,11 +127,6 @@ module Datadog
|
|
|
105
127
|
# has to be longer than the suffix. Require full component matches,
|
|
106
128
|
# meaning either the first character of the suffix is a slash
|
|
107
129
|
# or the previous character in the path is a slash.
|
|
108
|
-
# For now only check for forward slashes for Unix-like OSes;
|
|
109
|
-
# backslash is a legitimate character of a file name in Unix
|
|
110
|
-
# therefore simply permitting forward or back slash is not
|
|
111
|
-
# sufficient, we need to perform an OS check to know which
|
|
112
|
-
# path separator to use.
|
|
113
130
|
!!
|
|
114
131
|
if path.length > suffix.length && path.end_with?(suffix)
|
|
115
132
|
previous_char = path[path.length - suffix.length - 1]
|
|
@@ -125,15 +142,26 @@ module Datadog
|
|
|
125
142
|
# +spec+. Attempts all of the fuzzy matches by stripping directories
|
|
126
143
|
# from the front of +spec+. Does not consider othr known paths to
|
|
127
144
|
# identify the case of (potentially) multiple matching paths for +spec+.
|
|
145
|
+
#
|
|
146
|
+
# Matching is attempted case-sensitively first (steps 5-6 in the design
|
|
147
|
+
# comment above) and only falls back to case-insensitive (steps 7-8)
|
|
148
|
+
# when no case-sensitive match is found.
|
|
128
149
|
module_function def path_can_match_spec?(path, spec)
|
|
129
|
-
|
|
150
|
+
# Normalize Windows-style backslash separators (DEBUG-5111) so the
|
|
151
|
+
# suffix-shortening loop's "/+" regex can strip leading components.
|
|
152
|
+
spec = normalize_windows_separators(spec)
|
|
130
153
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
return
|
|
134
|
-
|
|
135
|
-
|
|
154
|
+
[false, true].each do |case_insensitive|
|
|
155
|
+
working_spec = spec.dup
|
|
156
|
+
return true if path_matches_suffix?(path, working_spec, case_insensitive: case_insensitive)
|
|
157
|
+
|
|
158
|
+
loop do
|
|
159
|
+
break unless working_spec.include?('/')
|
|
160
|
+
working_spec.sub!(%r{.*/+}, '')
|
|
161
|
+
return true if path_matches_suffix?(path, working_spec, case_insensitive: case_insensitive)
|
|
162
|
+
end
|
|
136
163
|
end
|
|
164
|
+
false
|
|
137
165
|
end
|
|
138
166
|
end
|
|
139
167
|
end
|
|
@@ -152,6 +152,71 @@ module Datadog
|
|
|
152
152
|
o.setter(&Settings.normalize_protocol('OTEL_EXPORTER_OTLP_METRICS_PROTOCOL'))
|
|
153
153
|
end
|
|
154
154
|
end
|
|
155
|
+
|
|
156
|
+
settings :logs do
|
|
157
|
+
option :enabled do |o|
|
|
158
|
+
o.type :bool
|
|
159
|
+
o.env 'DD_LOGS_OTEL_ENABLED'
|
|
160
|
+
o.default false
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
option :exporter do |o|
|
|
164
|
+
o.type :string
|
|
165
|
+
o.env 'OTEL_LOGS_EXPORTER'
|
|
166
|
+
o.default 'otlp'
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
option :endpoint do |o|
|
|
170
|
+
o.type :string, nilable: true
|
|
171
|
+
o.env 'OTEL_EXPORTER_OTLP_LOGS_ENDPOINT'
|
|
172
|
+
o.default nil
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
option :headers do |o|
|
|
176
|
+
o.skip_telemetry true
|
|
177
|
+
o.type :hash, nilable: true
|
|
178
|
+
o.env 'OTEL_EXPORTER_OTLP_LOGS_HEADERS'
|
|
179
|
+
o.default nil
|
|
180
|
+
o.env_parser(&Settings.headers_parser('OTEL_EXPORTER_OTLP_LOGS_HEADERS'))
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
option :timeout_millis do |o|
|
|
184
|
+
o.type :int, nilable: true
|
|
185
|
+
o.env 'OTEL_EXPORTER_OTLP_LOGS_TIMEOUT'
|
|
186
|
+
o.default 10_000
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
option :protocol do |o|
|
|
190
|
+
o.type :string, nilable: true
|
|
191
|
+
o.env 'OTEL_EXPORTER_OTLP_LOGS_PROTOCOL'
|
|
192
|
+
o.default "http/protobuf"
|
|
193
|
+
o.setter(&Settings.normalize_protocol('OTEL_EXPORTER_OTLP_LOGS_PROTOCOL'))
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
option :max_queue_size do |o|
|
|
197
|
+
o.type :int
|
|
198
|
+
o.env 'OTEL_BLRP_MAX_QUEUE_SIZE'
|
|
199
|
+
o.default 2048
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
option :schedule_delay_millis do |o|
|
|
203
|
+
o.type :int
|
|
204
|
+
o.env 'OTEL_BLRP_SCHEDULE_DELAY'
|
|
205
|
+
o.default 1000
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
option :export_timeout_millis do |o|
|
|
209
|
+
o.type :int
|
|
210
|
+
o.env 'OTEL_BLRP_EXPORT_TIMEOUT'
|
|
211
|
+
o.default 30_000
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
option :max_export_batch_size do |o|
|
|
215
|
+
o.type :int
|
|
216
|
+
o.env 'OTEL_BLRP_MAX_EXPORT_BATCH_SIZE'
|
|
217
|
+
o.default 512
|
|
218
|
+
end
|
|
219
|
+
end
|
|
155
220
|
end
|
|
156
221
|
end
|
|
157
222
|
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'ext'
|
|
4
|
+
require_relative 'signal_configuration'
|
|
5
|
+
|
|
6
|
+
module Datadog
|
|
7
|
+
module OpenTelemetry
|
|
8
|
+
class Logs
|
|
9
|
+
include SignalConfiguration
|
|
10
|
+
|
|
11
|
+
def self.initialize!(components)
|
|
12
|
+
new(components).configure_logs_sdk
|
|
13
|
+
true
|
|
14
|
+
rescue => exc
|
|
15
|
+
components.logger.warn(
|
|
16
|
+
"Failed to initialize OpenTelemetry logs: #{exc.class}: #{exc.message}\n#{(exc.backtrace || []).join("\n")}"
|
|
17
|
+
)
|
|
18
|
+
false
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def initialize(components)
|
|
22
|
+
@logger = components.logger
|
|
23
|
+
@settings = components.settings
|
|
24
|
+
@agent_host = components.agent_settings.hostname
|
|
25
|
+
@agent_ssl = components.agent_settings.ssl
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def configure_logs_sdk
|
|
29
|
+
provider = ::OpenTelemetry.logger_provider
|
|
30
|
+
provider.shutdown if provider.is_a?(::OpenTelemetry::SDK::Logs::LoggerProvider)
|
|
31
|
+
|
|
32
|
+
resource = create_resource
|
|
33
|
+
provider = ::OpenTelemetry::SDK::Logs::LoggerProvider.new(resource: resource)
|
|
34
|
+
processor_configured = configure_log_record_processor(provider)
|
|
35
|
+
::OpenTelemetry.logger_provider = provider
|
|
36
|
+
|
|
37
|
+
disable_log_injection if processor_configured
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def disable_log_injection
|
|
43
|
+
@logger.warn('OTel logs enabled: disabling Datadog log injection to prevent duplicate trace correlation fields')
|
|
44
|
+
Datadog.configure do |c|
|
|
45
|
+
c.tracing.log_injection = false # steep:ignore
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def configure_log_record_processor(provider)
|
|
50
|
+
exporter_name = @settings.opentelemetry.logs.exporter
|
|
51
|
+
return false if exporter_name == Ext::EXPORTER_NONE
|
|
52
|
+
|
|
53
|
+
configure_otlp_exporter(provider)
|
|
54
|
+
rescue => e
|
|
55
|
+
@logger.warn("Failed to configure OTLP logs exporter: #{e.class}: #{e.message}")
|
|
56
|
+
false
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def default_logs_endpoint
|
|
60
|
+
"#{@agent_ssl ? 'https' : 'http'}://#{@agent_host}:4318/v1/logs"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def configure_otlp_exporter(provider)
|
|
64
|
+
require_relative 'sdk/logs_exporter'
|
|
65
|
+
|
|
66
|
+
logs_config = @settings.opentelemetry.logs
|
|
67
|
+
endpoint = config_or_exporter_fallback(
|
|
68
|
+
signal: :logs,
|
|
69
|
+
option_name: :endpoint,
|
|
70
|
+
computed_default: default_logs_endpoint
|
|
71
|
+
)
|
|
72
|
+
timeout = config_or_exporter_fallback(signal: :logs, option_name: :timeout_millis)
|
|
73
|
+
headers = config_or_exporter_fallback(signal: :logs, option_name: :headers)
|
|
74
|
+
# opentelemetry-logs-sdk only supports http/protobuf protocol as of 0.5.0.
|
|
75
|
+
config_or_exporter_fallback(signal: :logs, option_name: :protocol)
|
|
76
|
+
|
|
77
|
+
exporter = Datadog::OpenTelemetry::SDK::LogsExporter.new(
|
|
78
|
+
endpoint: endpoint,
|
|
79
|
+
timeout: timeout / 1000.0,
|
|
80
|
+
headers: headers
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
processor = ::OpenTelemetry::SDK::Logs::Export::BatchLogRecordProcessor.new(
|
|
84
|
+
exporter,
|
|
85
|
+
max_queue_size: logs_config.max_queue_size,
|
|
86
|
+
schedule_delay: logs_config.schedule_delay_millis,
|
|
87
|
+
exporter_timeout: logs_config.export_timeout_millis,
|
|
88
|
+
max_export_batch_size: logs_config.max_export_batch_size
|
|
89
|
+
)
|
|
90
|
+
provider.add_log_record_processor(processor)
|
|
91
|
+
true
|
|
92
|
+
rescue LoadError => e
|
|
93
|
+
@logger.warn("Could not load OTLP logs exporter: #{e.class}: #{e.message}")
|
|
94
|
+
false
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative '../core/configuration/ext'
|
|
4
|
+
require_relative 'ext'
|
|
5
|
+
require_relative 'signal_configuration'
|
|
4
6
|
|
|
5
7
|
module Datadog
|
|
6
8
|
module OpenTelemetry
|
|
7
9
|
class Metrics
|
|
8
|
-
|
|
10
|
+
include SignalConfiguration
|
|
9
11
|
|
|
10
12
|
def self.initialize!(components)
|
|
11
13
|
new(components).configure_metrics_sdk
|
|
12
14
|
true
|
|
13
15
|
rescue => exc
|
|
14
|
-
components.logger.
|
|
16
|
+
components.logger.warn("Failed to initialize OpenTelemetry metrics: #{exc.class}: #{exc.message}: #{exc.backtrace.join("\n")}")
|
|
15
17
|
false
|
|
16
18
|
end
|
|
17
19
|
|
|
@@ -40,30 +42,9 @@ module Datadog
|
|
|
40
42
|
|
|
41
43
|
private
|
|
42
44
|
|
|
43
|
-
def create_resource
|
|
44
|
-
resource_attributes = {}
|
|
45
|
-
resource_attributes['host.name'] = Datadog::Core::Environment::Socket.hostname if @settings.tracing.report_hostname
|
|
46
|
-
|
|
47
|
-
@settings.tags&.each do |key, value|
|
|
48
|
-
otel_key = case key
|
|
49
|
-
when 'service' then 'service.name'
|
|
50
|
-
when 'env' then 'deployment.environment'
|
|
51
|
-
when 'version' then 'service.version'
|
|
52
|
-
else key
|
|
53
|
-
end
|
|
54
|
-
resource_attributes[otel_key] = value
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
resource_attributes['service.name'] = @settings.service_without_fallback || resource_attributes['service.name'] || Datadog::Core::Environment::Ext::FALLBACK_SERVICE_NAME
|
|
58
|
-
resource_attributes['deployment.environment'] = @settings.env if @settings.env
|
|
59
|
-
resource_attributes['service.version'] = @settings.version if @settings.version
|
|
60
|
-
|
|
61
|
-
::OpenTelemetry::SDK::Resources::Resource.create(resource_attributes)
|
|
62
|
-
end
|
|
63
|
-
|
|
64
45
|
def configure_metric_reader(provider)
|
|
65
46
|
exporter_name = @settings.opentelemetry.metrics.exporter
|
|
66
|
-
return if exporter_name == EXPORTER_NONE
|
|
47
|
+
return if exporter_name == Ext::EXPORTER_NONE
|
|
67
48
|
|
|
68
49
|
configure_otlp_exporter(provider)
|
|
69
50
|
rescue => e
|
|
@@ -79,15 +60,16 @@ module Datadog
|
|
|
79
60
|
require_relative 'sdk/metrics_exporter'
|
|
80
61
|
|
|
81
62
|
metrics_config = @settings.opentelemetry.metrics
|
|
82
|
-
endpoint =
|
|
63
|
+
endpoint = config_or_exporter_fallback(
|
|
64
|
+
signal: :metrics,
|
|
83
65
|
option_name: :endpoint,
|
|
84
66
|
computed_default: default_metrics_endpoint
|
|
85
67
|
)
|
|
86
|
-
timeout =
|
|
87
|
-
headers =
|
|
68
|
+
timeout = config_or_exporter_fallback(signal: :metrics, option_name: :timeout_millis)
|
|
69
|
+
headers = config_or_exporter_fallback(signal: :metrics, option_name: :headers)
|
|
88
70
|
# OpenTelemetry SDK only supports http/protobuf protocol.
|
|
89
71
|
# TODO: Add support for http/json and grpc.
|
|
90
|
-
# protocol =
|
|
72
|
+
# protocol = config_or_exporter_fallback(signal: :metrics, option_name: :protocol)
|
|
91
73
|
exporter = Datadog::OpenTelemetry::SDK::MetricsExporter.new(
|
|
92
74
|
endpoint: endpoint,
|
|
93
75
|
timeout: timeout / 1000.0,
|
|
@@ -103,15 +85,6 @@ module Datadog
|
|
|
103
85
|
rescue LoadError => e
|
|
104
86
|
@logger.warn("Could not load OTLP metrics exporter: #{e.class}: #{e.message}")
|
|
105
87
|
end
|
|
106
|
-
|
|
107
|
-
# Returns metrics config value if explicitly set, otherwise falls back to exporter config or computed default value.
|
|
108
|
-
def get_metrics_config_with_fallback(option_name:, computed_default: nil)
|
|
109
|
-
if @settings.opentelemetry.metrics.using_default?(option_name)
|
|
110
|
-
@settings.opentelemetry.exporter.public_send(option_name) || computed_default
|
|
111
|
-
else
|
|
112
|
-
@settings.opentelemetry.metrics.public_send(option_name)
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
88
|
end
|
|
116
89
|
end
|
|
117
90
|
end
|
|
@@ -30,6 +30,16 @@ module Datadog
|
|
|
30
30
|
[SpanProcessor.new]
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
+
# SDK 1.6.0+ calls logs_configuration_hook from configure.
|
|
34
|
+
# https://github.com/open-telemetry/opentelemetry-ruby/blob/opentelemetry-sdk/v1.6.0/sdk/lib/opentelemetry/sdk/configurator.rb#L152
|
|
35
|
+
# Older supported SDK versions do not, so we call it explicitly as a fallback.
|
|
36
|
+
# The flag prevents double-calling on newer SDK versions.
|
|
37
|
+
def configure
|
|
38
|
+
@datadog_logs_hook_called = false
|
|
39
|
+
super
|
|
40
|
+
logs_configuration_hook unless @datadog_logs_hook_called
|
|
41
|
+
end
|
|
42
|
+
|
|
33
43
|
def metrics_configuration_hook
|
|
34
44
|
components = Datadog.send(:components)
|
|
35
45
|
return super unless components.settings.opentelemetry.metrics.enabled
|
|
@@ -45,15 +55,45 @@ module Datadog
|
|
|
45
55
|
super unless success
|
|
46
56
|
end
|
|
47
57
|
|
|
58
|
+
def logs_configuration_hook
|
|
59
|
+
@datadog_logs_hook_called = true
|
|
60
|
+
components = Datadog.send(:components)
|
|
61
|
+
unless components.settings.opentelemetry.logs.enabled
|
|
62
|
+
super if defined?(super)
|
|
63
|
+
return
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
begin
|
|
67
|
+
require 'opentelemetry-logs-sdk'
|
|
68
|
+
rescue LoadError => exc
|
|
69
|
+
components.logger.warn("Failed to load OpenTelemetry logs gems: #{exc.class}: #{exc.message}")
|
|
70
|
+
return
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
success = Datadog::OpenTelemetry::Logs.initialize!(components)
|
|
74
|
+
unless success
|
|
75
|
+
components.logger.warn('Falling back to OpenTelemetry default logs configuration')
|
|
76
|
+
super if defined?(super)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
48
80
|
# Prepend to ConfiguratorPatch (not Configurator) so our hook runs first.
|
|
49
81
|
begin
|
|
50
82
|
require 'opentelemetry-metrics-sdk' if defined?(OpenTelemetry::SDK) && !defined?(OpenTelemetry::SDK::Metrics::ConfiguratorPatch)
|
|
51
83
|
rescue LoadError
|
|
52
84
|
end
|
|
53
85
|
|
|
86
|
+
begin
|
|
87
|
+
require 'opentelemetry-logs-sdk' if defined?(OpenTelemetry::SDK) && !defined?(OpenTelemetry::SDK::Logs::ConfiguratorPatch)
|
|
88
|
+
rescue LoadError
|
|
89
|
+
end
|
|
90
|
+
|
|
54
91
|
if defined?(::OpenTelemetry::SDK::Metrics::ConfiguratorPatch)
|
|
55
92
|
::OpenTelemetry::SDK::Metrics::ConfiguratorPatch.prepend(self) unless ::OpenTelemetry::SDK::Metrics::ConfiguratorPatch.ancestors.include?(self)
|
|
56
93
|
end
|
|
94
|
+
if defined?(::OpenTelemetry::SDK::Logs::ConfiguratorPatch)
|
|
95
|
+
::OpenTelemetry::SDK::Logs::ConfiguratorPatch.prepend(self) unless ::OpenTelemetry::SDK::Logs::ConfiguratorPatch.ancestors.include?(self)
|
|
96
|
+
end
|
|
57
97
|
::OpenTelemetry::SDK::Configurator.prepend(self) unless ::OpenTelemetry::SDK::Configurator.ancestors.include?(self)
|
|
58
98
|
end
|
|
59
99
|
end
|
|
@@ -1,23 +1,29 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative '../../tracing/utils'
|
|
4
|
+
|
|
3
5
|
module Datadog
|
|
4
6
|
module OpenTelemetry
|
|
5
7
|
module SDK
|
|
6
|
-
# Generates Datadog-compatible IDs for OpenTelemetry
|
|
7
|
-
#
|
|
8
|
+
# Generates Datadog-compatible trace IDs for OpenTelemetry spans.
|
|
9
|
+
#
|
|
10
|
+
# Reuses the same 128-bit ID format as non-OTel Datadog tracing:
|
|
11
|
+
# [32-bit seconds since Epoch | 32 zero bits | 64 random bits]
|
|
12
|
+
#
|
|
13
|
+
# When DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED is false the high 64
|
|
14
|
+
# bits are zero, preserving the OTel 16-byte wire format while keeping
|
|
15
|
+
# backward compatibility with 64-bit Datadog trace IDs.
|
|
8
16
|
class IdGenerator
|
|
9
17
|
class << self
|
|
10
18
|
include ::OpenTelemetry::Trace
|
|
11
19
|
|
|
12
|
-
#
|
|
13
|
-
# non-zero byte.
|
|
14
|
-
#
|
|
15
|
-
# @return [String] a valid trace ID.
|
|
20
|
+
# @return [String] a valid 16-byte trace ID.
|
|
16
21
|
def generate_trace_id
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
trace_id = Tracing::Utils::TraceId.next_id
|
|
23
|
+
[
|
|
24
|
+
Tracing::Utils::TraceId.to_high_order(trace_id),
|
|
25
|
+
Tracing::Utils::TraceId.to_low_order(trace_id),
|
|
26
|
+
].pack('Q>Q>')
|
|
21
27
|
end
|
|
22
28
|
end
|
|
23
29
|
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'opentelemetry/exporter/otlp_logs'
|
|
4
|
+
|
|
5
|
+
module Datadog
|
|
6
|
+
module OpenTelemetry
|
|
7
|
+
module SDK
|
|
8
|
+
class LogsExporter < ::OpenTelemetry::Exporter::OTLP::Logs::LogsExporter
|
|
9
|
+
METRIC_EXPORT_ATTEMPTS = 'otel.logs_export_attempts'
|
|
10
|
+
METRIC_EXPORT_SUCCESSES = 'otel.logs_export_successes'
|
|
11
|
+
METRIC_EXPORT_FAILURES = 'otel.logs_export_failures'
|
|
12
|
+
METRIC_LOG_RECORDS = 'otel.log_records'
|
|
13
|
+
TELEMETRY_NAMESPACE = 'tracers'
|
|
14
|
+
TELEMETRY_TAGS = {'protocol' => 'http', 'encoding' => 'protobuf'}.freeze
|
|
15
|
+
|
|
16
|
+
def export(log_records, timeout: nil)
|
|
17
|
+
telemetry&.inc(TELEMETRY_NAMESPACE, METRIC_EXPORT_ATTEMPTS, 1, tags: TELEMETRY_TAGS)
|
|
18
|
+
telemetry&.inc(TELEMETRY_NAMESPACE, METRIC_LOG_RECORDS, log_records.size, tags: TELEMETRY_TAGS)
|
|
19
|
+
result = super
|
|
20
|
+
metric_name = (result == 0) ? METRIC_EXPORT_SUCCESSES : METRIC_EXPORT_FAILURES
|
|
21
|
+
telemetry&.inc(TELEMETRY_NAMESPACE, metric_name, 1, tags: TELEMETRY_TAGS)
|
|
22
|
+
result
|
|
23
|
+
rescue => e
|
|
24
|
+
Datadog.logger.warn("Failed to export OpenTelemetry Logs: #{e.class}: #{e.message}")
|
|
25
|
+
telemetry&.inc(TELEMETRY_NAMESPACE, METRIC_EXPORT_FAILURES, 1, tags: TELEMETRY_TAGS)
|
|
26
|
+
raise
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def telemetry
|
|
32
|
+
Datadog.send(:components).telemetry
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../core/configuration/ext'
|
|
4
|
+
require_relative '../core/environment/socket'
|
|
5
|
+
|
|
6
|
+
module Datadog
|
|
7
|
+
module OpenTelemetry
|
|
8
|
+
# Shared resource building and signal-specific config fallback logic for Logs and Metrics.
|
|
9
|
+
module SignalConfiguration
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def create_resource
|
|
13
|
+
resource_attributes = {}
|
|
14
|
+
|
|
15
|
+
@settings.tags&.each do |key, value| # steep:ignore
|
|
16
|
+
otel_key = case key
|
|
17
|
+
when 'service' then 'service.name'
|
|
18
|
+
when 'env' then 'deployment.environment'
|
|
19
|
+
when 'version' then 'service.version'
|
|
20
|
+
else key
|
|
21
|
+
end
|
|
22
|
+
resource_attributes[otel_key] = value
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
resource_attributes['service.name'] = @settings.service_without_fallback || resource_attributes['service.name'] || Datadog::Core::Environment::Ext::FALLBACK_SERVICE_NAME # steep:ignore
|
|
26
|
+
resource_attributes['deployment.environment'] = @settings.env if @settings.env # steep:ignore
|
|
27
|
+
resource_attributes['service.version'] = @settings.version if @settings.version # steep:ignore
|
|
28
|
+
|
|
29
|
+
hostname = Datadog::Core::Environment::Socket.resolved_hostname(@settings) # steep:ignore
|
|
30
|
+
if hostname
|
|
31
|
+
if hostname == @settings.hostname # steep:ignore
|
|
32
|
+
resource_attributes['host.name'] = hostname
|
|
33
|
+
elsif !resource_attributes.key?('host.name')
|
|
34
|
+
resource_attributes['host.name'] = hostname
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
::OpenTelemetry::SDK::Resources::Resource.create(resource_attributes)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Returns the signal-specific option value when explicitly set,
|
|
42
|
+
# otherwise falls back to the general OTLP exporter config or computed_default.
|
|
43
|
+
def config_or_exporter_fallback(signal:, option_name:, computed_default: nil)
|
|
44
|
+
signal_settings = @settings.opentelemetry.public_send(signal) # steep:ignore
|
|
45
|
+
if signal_settings.using_default?(option_name)
|
|
46
|
+
@settings.opentelemetry.exporter.public_send(option_name) || computed_default # steep:ignore
|
|
47
|
+
else
|
|
48
|
+
signal_settings.public_send(option_name)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -23,6 +23,7 @@ require_relative 'opentelemetry/sdk/configurator' if defined?(OpenTelemetry::SDK
|
|
|
23
23
|
require_relative 'opentelemetry/sdk/trace/span' if defined?(OpenTelemetry::SDK)
|
|
24
24
|
|
|
25
25
|
require_relative 'opentelemetry/metrics' if defined?(OpenTelemetry::SDK::Metrics)
|
|
26
|
+
require_relative 'opentelemetry/logs' if defined?(OpenTelemetry::SDK::Logs)
|
|
26
27
|
|
|
27
28
|
module Datadog
|
|
28
29
|
# Datadog OpenTelemetry integration.
|
|
@@ -49,7 +49,6 @@ module Datadog
|
|
|
49
49
|
valid_cpu_sampling_interval(settings.profiling.advanced.experimental_cpu_sampling_interval_ms, logger)
|
|
50
50
|
|
|
51
51
|
recorder = Datadog::Profiling::StackRecorder.new(
|
|
52
|
-
cpu_time_enabled: RUBY_PLATFORM.include?("linux"), # Only supported on Linux currently
|
|
53
52
|
alloc_samples_enabled: allocation_profiling_enabled,
|
|
54
53
|
heap_samples_enabled: heap_profiling_enabled,
|
|
55
54
|
heap_size_enabled: heap_size_profiling_enabled,
|
|
@@ -9,7 +9,6 @@ module Datadog
|
|
|
9
9
|
# Methods prefixed with _native_ are implemented in `stack_recorder.c`
|
|
10
10
|
class StackRecorder
|
|
11
11
|
def initialize(
|
|
12
|
-
cpu_time_enabled:,
|
|
13
12
|
alloc_samples_enabled:,
|
|
14
13
|
heap_samples_enabled:,
|
|
15
14
|
heap_size_enabled:,
|
|
@@ -27,7 +26,6 @@ module Datadog
|
|
|
27
26
|
|
|
28
27
|
self.class._native_initialize(
|
|
29
28
|
self_instance: self,
|
|
30
|
-
cpu_time_enabled: cpu_time_enabled,
|
|
31
29
|
alloc_samples_enabled: alloc_samples_enabled,
|
|
32
30
|
heap_samples_enabled: heap_samples_enabled,
|
|
33
31
|
heap_size_enabled: heap_size_enabled,
|
|
@@ -38,7 +36,6 @@ module Datadog
|
|
|
38
36
|
end
|
|
39
37
|
|
|
40
38
|
def self.for_testing(
|
|
41
|
-
cpu_time_enabled: true,
|
|
42
39
|
alloc_samples_enabled: false,
|
|
43
40
|
heap_samples_enabled: false,
|
|
44
41
|
heap_size_enabled: false,
|
|
@@ -48,7 +45,6 @@ module Datadog
|
|
|
48
45
|
**options
|
|
49
46
|
)
|
|
50
47
|
new(
|
|
51
|
-
cpu_time_enabled: cpu_time_enabled,
|
|
52
48
|
alloc_samples_enabled: alloc_samples_enabled,
|
|
53
49
|
heap_samples_enabled: heap_samples_enabled,
|
|
54
50
|
heap_size_enabled: heap_size_enabled,
|