datadog 2.14.0 → 2.15.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 +24 -2
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +7 -6
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +3 -0
- data/ext/datadog_profiling_native_extension/encoded_profile.c +69 -0
- data/ext/datadog_profiling_native_extension/encoded_profile.h +7 -0
- data/ext/datadog_profiling_native_extension/http_transport.c +25 -32
- data/ext/datadog_profiling_native_extension/profiling.c +2 -0
- data/ext/datadog_profiling_native_extension/stack_recorder.c +22 -21
- data/ext/libdatadog_api/datadog_ruby_common.h +3 -0
- data/lib/datadog/appsec/assets/waf_rules/README.md +50 -5
- data/lib/datadog/appsec/assets/waf_rules/processors.json +239 -10
- data/lib/datadog/appsec/assets/waf_rules/recommended.json +0 -1344
- data/lib/datadog/appsec/assets/waf_rules/scanners.json +926 -17
- data/lib/datadog/appsec/assets/waf_rules/strict.json +0 -1344
- data/lib/datadog/appsec/component.rb +19 -17
- data/lib/datadog/appsec/compressed_json.rb +40 -0
- data/lib/datadog/appsec/contrib/active_record/integration.rb +1 -1
- data/lib/datadog/appsec/event.rb +21 -50
- data/lib/datadog/appsec/remote.rb +4 -0
- data/lib/datadog/core/diagnostics/environment_logger.rb +1 -1
- data/lib/datadog/core/telemetry/metric.rb +5 -5
- data/lib/datadog/core/telemetry/request.rb +1 -1
- data/lib/datadog/di/probe_notification_builder.rb +1 -1
- data/lib/datadog/di/transport/http/diagnostics.rb +0 -1
- data/lib/datadog/di/transport/http/input.rb +0 -1
- data/lib/datadog/di/transport/http.rb +0 -6
- data/lib/datadog/profiling/collectors/info.rb +3 -0
- data/lib/datadog/profiling/encoded_profile.rb +11 -0
- data/lib/datadog/profiling/exporter.rb +2 -3
- data/lib/datadog/profiling/ext.rb +0 -1
- data/lib/datadog/profiling/flush.rb +4 -7
- data/lib/datadog/profiling/http_transport.rb +10 -59
- data/lib/datadog/profiling/stack_recorder.rb +4 -4
- data/lib/datadog/profiling.rb +1 -0
- data/lib/datadog/tracing/contrib/active_record/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/opensearch/configuration/settings.rb +17 -0
- data/lib/datadog/tracing/contrib/opensearch/ext.rb +9 -0
- data/lib/datadog/tracing/contrib/opensearch/patcher.rb +5 -1
- data/lib/datadog/tracing/contrib/rack/request_queue.rb +1 -1
- data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +1 -1
- data/lib/datadog/tracing/span_event.rb +1 -1
- data/lib/datadog/version.rb +1 -1
- metadata +10 -6
@@ -12,7 +12,25 @@ module Datadog
|
|
12
12
|
class << self
|
13
13
|
def build_appsec_component(settings, telemetry:)
|
14
14
|
return if !settings.respond_to?(:appsec) || !settings.appsec.enabled
|
15
|
-
|
15
|
+
|
16
|
+
ffi_version = Gem.loaded_specs['ffi'] && Gem.loaded_specs['ffi'].version
|
17
|
+
unless ffi_version
|
18
|
+
Datadog.logger.warn('FFI gem is not loaded, AppSec will be disabled.')
|
19
|
+
telemetry.error('AppSec: Component not loaded, due to missing FFI gem')
|
20
|
+
|
21
|
+
return
|
22
|
+
end
|
23
|
+
|
24
|
+
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.3') && ffi_version < Gem::Version.new('1.16.0')
|
25
|
+
Datadog.logger.warn(
|
26
|
+
'AppSec is not supported in Ruby versions above 3.3.0 when using `ffi` versions older than 1.16.0, ' \
|
27
|
+
'and will be forcibly disabled due to a memory leak in `ffi`. ' \
|
28
|
+
'Please upgrade your `ffi` version to 1.16.0 or higher.'
|
29
|
+
)
|
30
|
+
telemetry.error('AppSec: Component not loaded, ffi version is leaky with ruby > 3.3.0')
|
31
|
+
|
32
|
+
return
|
33
|
+
end
|
16
34
|
|
17
35
|
processor = create_processor(settings, telemetry)
|
18
36
|
|
@@ -29,22 +47,6 @@ module Datadog
|
|
29
47
|
|
30
48
|
private
|
31
49
|
|
32
|
-
def incompatible_ffi_version?
|
33
|
-
ffi_version = Gem.loaded_specs['ffi'] && Gem.loaded_specs['ffi'].version
|
34
|
-
return true unless ffi_version
|
35
|
-
|
36
|
-
return false unless Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.3') &&
|
37
|
-
ffi_version < Gem::Version.new('1.16.0')
|
38
|
-
|
39
|
-
Datadog.logger.warn(
|
40
|
-
'AppSec is not supported in Ruby versions above 3.3.0 when using `ffi` versions older than 1.16.0, ' \
|
41
|
-
'and will be forcibly disabled due to a memory leak in `ffi`. ' \
|
42
|
-
'Please upgrade your `ffi` version to 1.16.0 or higher.'
|
43
|
-
)
|
44
|
-
|
45
|
-
true
|
46
|
-
end
|
47
|
-
|
48
50
|
def create_processor(settings, telemetry)
|
49
51
|
rules = AppSec::Processor::RuleLoader.load_rules(
|
50
52
|
telemetry: telemetry,
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'zlib'
|
5
|
+
require 'stringio'
|
6
|
+
|
7
|
+
require_relative '../core/utils/base64'
|
8
|
+
|
9
|
+
module Datadog
|
10
|
+
module AppSec
|
11
|
+
# Converts derivative schema payloads into JSON and compresses them into a
|
12
|
+
# base64 encoded string if the payload is worth compressing.
|
13
|
+
#
|
14
|
+
# See: https://github.com/DataDog/dd-trace-rb/pull/3177#issuecomment-1747221082
|
15
|
+
module CompressedJson
|
16
|
+
MIN_SIZE_FOR_COMPRESSION = 260
|
17
|
+
|
18
|
+
def self.dump(payload)
|
19
|
+
value = JSON.dump(payload)
|
20
|
+
return value if value.bytesize < MIN_SIZE_FOR_COMPRESSION
|
21
|
+
|
22
|
+
compress_and_encode(value)
|
23
|
+
rescue ArgumentError, Encoding::UndefinedConversionError, JSON::JSONError => e
|
24
|
+
AppSec.telemetry.report(e, description: 'AppSec: Failed to convert value into JSON')
|
25
|
+
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
|
29
|
+
private_class_method def self.compress_and_encode(payload)
|
30
|
+
Core::Utils::Base64.strict_encode64(
|
31
|
+
Zlib.gzip(payload, level: Zlib::BEST_SPEED, strategy: Zlib::DEFAULT_STRATEGY)
|
32
|
+
)
|
33
|
+
rescue Zlib::Error, TypeError => e
|
34
|
+
AppSec.telemetry.report(e, description: 'AppSec: Failed to compress and encode value')
|
35
|
+
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -13,7 +13,7 @@ module Datadog
|
|
13
13
|
|
14
14
|
MINIMUM_VERSION = Gem::Version.new('4')
|
15
15
|
|
16
|
-
register_as :active_record, auto_patch:
|
16
|
+
register_as :active_record, auto_patch: true
|
17
17
|
|
18
18
|
def self.version
|
19
19
|
Gem.loaded_specs['activerecord'] && Gem.loaded_specs['activerecord'].version
|
data/lib/datadog/appsec/event.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'json'
|
4
|
-
require 'zlib'
|
5
|
-
|
6
4
|
require_relative 'rate_limiter'
|
7
|
-
require_relative '
|
5
|
+
require_relative 'compressed_json'
|
8
6
|
|
9
7
|
module Datadog
|
10
8
|
module AppSec
|
11
9
|
# AppSec event
|
12
10
|
module Event
|
11
|
+
DERIVATIVE_SCHEMA_KEY_PREFIX = '_dd.appsec.s.'
|
12
|
+
DERIVATIVE_SCHEMA_MAX_COMPRESSED_SIZE = 25000
|
13
13
|
ALLOWED_REQUEST_HEADERS = %w[
|
14
14
|
X-Forwarded-For
|
15
15
|
X-Client-IP
|
@@ -38,11 +38,6 @@ module Datadog
|
|
38
38
|
Content-Language
|
39
39
|
].map!(&:downcase).freeze
|
40
40
|
|
41
|
-
MAX_ENCODED_SCHEMA_SIZE = 25000
|
42
|
-
# For more information about this number
|
43
|
-
# please check https://github.com/DataDog/dd-trace-rb/pull/3177#issuecomment-1747221082
|
44
|
-
MIN_SCHEMA_SIZE_FOR_COMPRESSION = 260
|
45
|
-
|
46
41
|
# Record events for a trace
|
47
42
|
#
|
48
43
|
# This is expected to be called only once per trace for the rate limiter
|
@@ -80,7 +75,6 @@ module Datadog
|
|
80
75
|
end
|
81
76
|
end
|
82
77
|
|
83
|
-
# rubocop:disable Metrics/MethodLength
|
84
78
|
def build_service_entry_tags(event_group)
|
85
79
|
waf_events = []
|
86
80
|
entry_tags = event_group.each_with_object({ '_dd.origin' => 'appsec' }) do |event, tags|
|
@@ -106,26 +100,17 @@ module Datadog
|
|
106
100
|
waf_events += waf_result.events
|
107
101
|
|
108
102
|
waf_result.derivatives.each do |key, value|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
else
|
117
|
-
parsed_value
|
118
|
-
end
|
119
|
-
next unless schema_value
|
120
|
-
|
121
|
-
if schema_value.size >= MAX_ENCODED_SCHEMA_SIZE
|
122
|
-
Datadog.logger.debug do
|
123
|
-
"Schema key: #{key} exceeds the max size value. It will not be included as part of the span tags"
|
124
|
-
end
|
103
|
+
next tags[key] = value unless key.start_with?(DERIVATIVE_SCHEMA_KEY_PREFIX)
|
104
|
+
|
105
|
+
value = CompressedJson.dump(value)
|
106
|
+
next if value.nil?
|
107
|
+
|
108
|
+
if value.size >= DERIVATIVE_SCHEMA_MAX_COMPRESSED_SIZE
|
109
|
+
Datadog.logger.debug { "AppSec: Schema key '#{key}' will not be included into span tags due to it's size" }
|
125
110
|
next
|
126
111
|
end
|
127
112
|
|
128
|
-
tags[key] =
|
113
|
+
tags[key] = value
|
129
114
|
end
|
130
115
|
|
131
116
|
tags
|
@@ -135,14 +120,16 @@ module Datadog
|
|
135
120
|
entry_tags['_dd.appsec.json'] = appsec_events if appsec_events
|
136
121
|
entry_tags
|
137
122
|
end
|
138
|
-
# rubocop:enable Metrics/MethodLength
|
139
123
|
|
140
124
|
def tag_and_keep!(context, waf_result)
|
141
125
|
# We want to keep the trace in case of security event
|
142
126
|
context.trace.keep! if context.trace
|
143
127
|
|
144
128
|
if context.span
|
145
|
-
|
129
|
+
if waf_result.actions.key?('block_request') || waf_result.actions.key?('redirect_request')
|
130
|
+
context.span.set_tag('appsec.blocked', 'true')
|
131
|
+
end
|
132
|
+
|
146
133
|
context.span.set_tag('appsec.event', 'true')
|
147
134
|
end
|
148
135
|
|
@@ -151,31 +138,15 @@ module Datadog
|
|
151
138
|
|
152
139
|
private
|
153
140
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
Datadog.logger.debug do
|
158
|
-
"Failed to compress and encode value when populating AppSec::Event. Error: #{e.message}"
|
159
|
-
end
|
160
|
-
nil
|
161
|
-
end
|
162
|
-
|
141
|
+
# NOTE: Handling of Encoding::UndefinedConversionError is added as a quick fix to
|
142
|
+
# the issue between Ruby encoded strings and libddwaf produced events and now
|
143
|
+
# is under investigation.
|
163
144
|
def json_parse(value)
|
164
145
|
JSON.dump(value)
|
165
|
-
rescue ArgumentError => e
|
166
|
-
|
167
|
-
"Failed to parse value to JSON when populating AppSec::Event. Error: #{e.message}"
|
168
|
-
end
|
169
|
-
nil
|
170
|
-
end
|
146
|
+
rescue ArgumentError, Encoding::UndefinedConversionError, JSON::JSONError => e
|
147
|
+
AppSec.telemetry.report(e, description: 'AppSec: Failed to convert value into JSON')
|
171
148
|
|
172
|
-
|
173
|
-
sio = StringIO.new
|
174
|
-
# For an in depth comparison of Zlib options check https://github.com/DataDog/dd-trace-rb/pull/3177#issuecomment-1747215473
|
175
|
-
gz = Zlib::GzipWriter.new(sio, Zlib::BEST_SPEED, Zlib::DEFAULT_STRATEGY)
|
176
|
-
gz.write(value)
|
177
|
-
gz.close
|
178
|
-
sio.string
|
149
|
+
nil
|
179
150
|
end
|
180
151
|
|
181
152
|
# Propagate to downstream services the information that the current distributed trace is
|
@@ -23,6 +23,8 @@ module Datadog
|
|
23
23
|
CAP_ASM_CUSTOM_RULES = 1 << 8 # accept custom rules
|
24
24
|
CAP_ASM_CUSTOM_BLOCKING_RESPONSE = 1 << 9 # supports custom http code or redirect sa blocking response
|
25
25
|
CAP_ASM_TRUSTED_IPS = 1 << 10 # supports trusted ip
|
26
|
+
CAP_ASM_RASP_SSRF = 1 << 23 # support for server-side request forgery exploit prevention rules
|
27
|
+
CAP_ASM_RASP_SQLI = 1 << 21 # support for SQL injection exploit prevention rules
|
26
28
|
|
27
29
|
# TODO: we need to dynamically add CAP_ASM_ACTIVATION once we support it
|
28
30
|
ASM_CAPABILITIES = [
|
@@ -35,6 +37,8 @@ module Datadog
|
|
35
37
|
CAP_ASM_CUSTOM_RULES,
|
36
38
|
CAP_ASM_CUSTOM_BLOCKING_RESPONSE,
|
37
39
|
CAP_ASM_TRUSTED_IPS,
|
40
|
+
CAP_ASM_RASP_SSRF,
|
41
|
+
CAP_ASM_RASP_SQLI,
|
38
42
|
].freeze
|
39
43
|
|
40
44
|
ASM_PRODUCTS = [
|
@@ -108,9 +108,9 @@ module Datadog
|
|
108
108
|
value = value.to_i
|
109
109
|
|
110
110
|
if values.empty?
|
111
|
-
values << [Time.now.to_i, value]
|
111
|
+
values << [Core::Utils::Time.now.to_i, value]
|
112
112
|
else
|
113
|
-
values[0][0] = Time.now.to_i
|
113
|
+
values[0][0] = Core::Utils::Time.now.to_i
|
114
114
|
values[0][1] += value
|
115
115
|
end
|
116
116
|
nil
|
@@ -129,9 +129,9 @@ module Datadog
|
|
129
129
|
|
130
130
|
def track(value)
|
131
131
|
if values.empty?
|
132
|
-
values << [Time.now.to_i, value]
|
132
|
+
values << [Core::Utils::Time.now.to_i, value]
|
133
133
|
else
|
134
|
-
values[0][0] = Time.now.to_i
|
134
|
+
values[0][0] = Core::Utils::Time.now.to_i
|
135
135
|
values[0][1] = value
|
136
136
|
end
|
137
137
|
nil
|
@@ -155,7 +155,7 @@ module Datadog
|
|
155
155
|
|
156
156
|
def track(value = 1.0)
|
157
157
|
@value += value
|
158
|
-
@values = [[Time.now.to_i, @value / interval]]
|
158
|
+
@values = [[Core::Utils::Time.now.to_i, @value / interval]]
|
159
159
|
nil
|
160
160
|
end
|
161
161
|
end
|
@@ -1,15 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'uri'
|
4
|
-
|
5
|
-
require_relative '../../core/environment/container'
|
6
|
-
require_relative '../../core/environment/ext'
|
7
|
-
require_relative '../../core/transport/ext'
|
8
3
|
require_relative 'diagnostics'
|
9
4
|
require_relative 'input'
|
10
5
|
require_relative 'http/api'
|
11
6
|
require_relative '../../core/transport/http'
|
12
|
-
require_relative '../../../datadog/version'
|
13
7
|
|
14
8
|
module Datadog
|
15
9
|
module DI
|
@@ -31,6 +31,9 @@ module Datadog
|
|
31
31
|
# Instead of trying to figure out real process start time by checking
|
32
32
|
# /proc or some other complex/non-portable way, approximate start time
|
33
33
|
# by time of requirement of this file.
|
34
|
+
#
|
35
|
+
# Note: this does not use Core::Utils::Time.now because this constant
|
36
|
+
# gets initialized before a user has a chance to configure the library.
|
34
37
|
START_TIME = Time.now.utc.freeze
|
35
38
|
|
36
39
|
def collect_platform_info
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module Profiling
|
5
|
+
# This class exists to wrap a ddog_prof_EncodedProfile into a Ruby object
|
6
|
+
#
|
7
|
+
# This class is not empty; all of this class is implemented as native code.
|
8
|
+
class EncodedProfile # rubocop:disable Lint/EmptyClass
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -57,7 +57,7 @@ module Datadog
|
|
57
57
|
serialization_result = pprof_recorder.serialize
|
58
58
|
return if serialization_result.nil?
|
59
59
|
|
60
|
-
start, finish,
|
60
|
+
start, finish, encoded_profile, profile_stats = serialization_result
|
61
61
|
@last_flush_finish_at = finish
|
62
62
|
|
63
63
|
if duration_below_threshold?(start, finish)
|
@@ -70,8 +70,7 @@ module Datadog
|
|
70
70
|
Flush.new(
|
71
71
|
start: start,
|
72
72
|
finish: finish,
|
73
|
-
|
74
|
-
pprof_data: compressed_pprof.to_s,
|
73
|
+
encoded_profile: encoded_profile,
|
75
74
|
code_provenance_file_name: Datadog::Profiling::Ext::Transport::HTTP::CODE_PROVENANCE_FILENAME,
|
76
75
|
code_provenance_data: uncompressed_code_provenance,
|
77
76
|
tags_as_array: Datadog::Profiling::TagBuilder.call(settings: Datadog.configuration).to_a,
|
@@ -9,10 +9,9 @@ module Datadog
|
|
9
9
|
attr_reader \
|
10
10
|
:start,
|
11
11
|
:finish,
|
12
|
-
:
|
13
|
-
:pprof_data, # gzipped pprof bytes
|
12
|
+
:encoded_profile,
|
14
13
|
:code_provenance_file_name,
|
15
|
-
:code_provenance_data,
|
14
|
+
:code_provenance_data,
|
16
15
|
:tags_as_array,
|
17
16
|
:internal_metadata_json,
|
18
17
|
:info_json
|
@@ -20,8 +19,7 @@ module Datadog
|
|
20
19
|
def initialize(
|
21
20
|
start:,
|
22
21
|
finish:,
|
23
|
-
|
24
|
-
pprof_data:,
|
22
|
+
encoded_profile:,
|
25
23
|
code_provenance_file_name:,
|
26
24
|
code_provenance_data:,
|
27
25
|
tags_as_array:,
|
@@ -30,8 +28,7 @@ module Datadog
|
|
30
28
|
)
|
31
29
|
@start = start
|
32
30
|
@finish = finish
|
33
|
-
@
|
34
|
-
@pprof_data = pprof_data
|
31
|
+
@encoded_profile = encoded_profile
|
35
32
|
@code_provenance_file_name = code_provenance_file_name
|
36
33
|
@code_provenance_data = code_provenance_data
|
37
34
|
@tags_as_array = tags_as_array
|
@@ -20,34 +20,21 @@ module Datadog
|
|
20
20
|
[:agent, agent_settings.url].freeze
|
21
21
|
end
|
22
22
|
|
23
|
-
status, result =
|
23
|
+
status, result = self.class._native_validate_exporter(exporter_configuration)
|
24
24
|
|
25
25
|
raise(ArgumentError, "Failed to initialize transport: #{result}") if status == :error
|
26
26
|
end
|
27
27
|
|
28
28
|
def export(flush)
|
29
|
-
status, result =
|
30
|
-
exporter_configuration
|
31
|
-
|
32
|
-
|
33
|
-
#
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
start_timespec_nanoseconds: flush.start.tv_nsec,
|
39
|
-
finish_timespec_seconds: flush.finish.tv_sec,
|
40
|
-
finish_timespec_nanoseconds: flush.finish.tv_nsec,
|
41
|
-
|
42
|
-
pprof_file_name: flush.pprof_file_name,
|
43
|
-
pprof_data: flush.pprof_data,
|
44
|
-
code_provenance_file_name: flush.code_provenance_file_name,
|
45
|
-
code_provenance_data: flush.code_provenance_data,
|
46
|
-
|
47
|
-
tags_as_array: flush.tags_as_array,
|
48
|
-
internal_metadata_json: flush.internal_metadata_json,
|
49
|
-
|
50
|
-
info_json: flush.info_json
|
29
|
+
status, result = self.class._native_do_export(
|
30
|
+
exporter_configuration,
|
31
|
+
@upload_timeout_milliseconds,
|
32
|
+
flush,
|
33
|
+
# TODO: This is going to be removed once we move to libdatadog 17
|
34
|
+
flush.start.tv_sec,
|
35
|
+
flush.start.tv_nsec,
|
36
|
+
flush.finish.tv_sec,
|
37
|
+
flush.finish.tv_nsec,
|
51
38
|
)
|
52
39
|
|
53
40
|
if status == :ok
|
@@ -77,42 +64,6 @@ module Datadog
|
|
77
64
|
site && api_key && Core::Environment::VariableHelpers.env_to_bool(Profiling::Ext::ENV_AGENTLESS, false)
|
78
65
|
end
|
79
66
|
|
80
|
-
def validate_exporter(exporter_configuration)
|
81
|
-
self.class._native_validate_exporter(exporter_configuration)
|
82
|
-
end
|
83
|
-
|
84
|
-
def do_export(
|
85
|
-
exporter_configuration:,
|
86
|
-
upload_timeout_milliseconds:,
|
87
|
-
start_timespec_seconds:,
|
88
|
-
start_timespec_nanoseconds:,
|
89
|
-
finish_timespec_seconds:,
|
90
|
-
finish_timespec_nanoseconds:,
|
91
|
-
pprof_file_name:,
|
92
|
-
pprof_data:,
|
93
|
-
code_provenance_file_name:,
|
94
|
-
code_provenance_data:,
|
95
|
-
tags_as_array:,
|
96
|
-
internal_metadata_json:,
|
97
|
-
info_json:
|
98
|
-
)
|
99
|
-
self.class._native_do_export(
|
100
|
-
exporter_configuration,
|
101
|
-
upload_timeout_milliseconds,
|
102
|
-
start_timespec_seconds,
|
103
|
-
start_timespec_nanoseconds,
|
104
|
-
finish_timespec_seconds,
|
105
|
-
finish_timespec_nanoseconds,
|
106
|
-
pprof_file_name,
|
107
|
-
pprof_data,
|
108
|
-
code_provenance_file_name,
|
109
|
-
code_provenance_data,
|
110
|
-
tags_as_array,
|
111
|
-
internal_metadata_json,
|
112
|
-
info_json,
|
113
|
-
)
|
114
|
-
end
|
115
|
-
|
116
67
|
def config_without_api_key
|
117
68
|
"#{exporter_configuration[0]}: #{exporter_configuration[1]}"
|
118
69
|
end
|
@@ -63,11 +63,11 @@ module Datadog
|
|
63
63
|
status, result = @no_concurrent_synchronize_mutex.synchronize { self.class._native_serialize(self) }
|
64
64
|
|
65
65
|
if status == :ok
|
66
|
-
start, finish,
|
66
|
+
start, finish, encoded_profile, profile_stats = result
|
67
67
|
|
68
68
|
Datadog.logger.debug { "Encoded profile covering #{start.iso8601} to #{finish.iso8601}" }
|
69
69
|
|
70
|
-
[start, finish,
|
70
|
+
[start, finish, encoded_profile, profile_stats]
|
71
71
|
else
|
72
72
|
error_message = result
|
73
73
|
|
@@ -82,9 +82,9 @@ module Datadog
|
|
82
82
|
status, result = @no_concurrent_synchronize_mutex.synchronize { self.class._native_serialize(self) }
|
83
83
|
|
84
84
|
if status == :ok
|
85
|
-
_start, _finish,
|
85
|
+
_start, _finish, encoded_profile = result
|
86
86
|
|
87
|
-
|
87
|
+
encoded_profile
|
88
88
|
else
|
89
89
|
error_message = result
|
90
90
|
|
data/lib/datadog/profiling.rb
CHANGED
@@ -149,6 +149,7 @@ module Datadog
|
|
149
149
|
require_relative 'profiling/collectors/thread_context'
|
150
150
|
require_relative 'profiling/stack_recorder'
|
151
151
|
require_relative 'profiling/exporter'
|
152
|
+
require_relative 'profiling/encoded_profile'
|
152
153
|
require_relative 'profiling/flush'
|
153
154
|
require_relative 'profiling/scheduler'
|
154
155
|
require_relative 'profiling/tasks/setup'
|
@@ -46,6 +46,23 @@ module Datadog
|
|
46
46
|
o.type :string, nilable: true
|
47
47
|
o.env Ext::ENV_PEER_SERVICE
|
48
48
|
end
|
49
|
+
|
50
|
+
option :resource_pattern do |o|
|
51
|
+
o.type :string
|
52
|
+
o.env Ext::ENV_RESOURCE_PATTERN
|
53
|
+
o.default Ext::DEFAULT_RESOURCE_PATTERN
|
54
|
+
o.setter do |value|
|
55
|
+
next value if Ext::VALID_RESOURCE_PATTERNS.include?(value)
|
56
|
+
|
57
|
+
Datadog.logger.warn(
|
58
|
+
"Invalid resource pattern: #{value}. " \
|
59
|
+
"Supported values are: #{Ext::VALID_RESOURCE_PATTERNS.join(' | ')}. " \
|
60
|
+
"Using default value: #{Ext::DEFAULT_RESOURCE_PATTERN}."
|
61
|
+
)
|
62
|
+
|
63
|
+
Ext::DEFAULT_RESOURCE_PATTERN
|
64
|
+
end
|
65
|
+
end
|
49
66
|
end
|
50
67
|
end
|
51
68
|
end
|
@@ -13,6 +13,15 @@ module Datadog
|
|
13
13
|
# @!visibility private
|
14
14
|
ENV_ANALYTICS_ENABLED = 'DD_TRACE_OPENSEARCH_ANALYTICS_ENABLED'
|
15
15
|
ENV_ANALYTICS_SAMPLE_RATE = 'DD_TRACE_OPENSEARCH_ANALYTICS_SAMPLE_RATE'
|
16
|
+
ENV_RESOURCE_PATTERN = 'DD_TRACE_OPENSEARCH_RESOURCE_PATTERN'
|
17
|
+
ABSOLUTE_RESOURCE_PATTERN = 'absolute'
|
18
|
+
RELATIVE_RESOURCE_PATTERN = 'relative'
|
19
|
+
VALID_RESOURCE_PATTERNS = [
|
20
|
+
ABSOLUTE_RESOURCE_PATTERN,
|
21
|
+
RELATIVE_RESOURCE_PATTERN
|
22
|
+
].freeze
|
23
|
+
# Default should be changed to RELATIVE in 3.0 to match the Elasticsearch integration
|
24
|
+
DEFAULT_RESOURCE_PATTERN = ABSOLUTE_RESOURCE_PATTERN
|
16
25
|
DEFAULT_PEER_SERVICE_NAME = 'opensearch'
|
17
26
|
SPAN_QUERY = 'opensearch.query'
|
18
27
|
SPAN_TYPE_QUERY = 'opensearch'
|
@@ -77,7 +77,11 @@ module Datadog
|
|
77
77
|
span.set_tag(Tracing::Metadata::Ext::TAG_PEER_HOSTNAME, host) if host
|
78
78
|
|
79
79
|
# Define span resource
|
80
|
-
quantized_url =
|
80
|
+
quantized_url = if datadog_configuration[:resource_pattern] == Ext::RELATIVE_RESOURCE_PATTERN
|
81
|
+
OpenSearch::Quantize.format_url(url.path)
|
82
|
+
else # Default to Ext::ABSOLUTE_RESOURCE_PATTERN
|
83
|
+
OpenSearch::Quantize.format_url(url)
|
84
|
+
end
|
81
85
|
span.resource = "#{method} #{quantized_url}"
|
82
86
|
Contrib::SpanAttributeSchema.set_peer_service!(span, Ext::PEER_SERVICE_SOURCES)
|
83
87
|
rescue StandardError => e
|
@@ -61,7 +61,7 @@ module Datadog
|
|
61
61
|
span.set_tag(Ext::TAG_JOB_RETRY_COUNT, job['retry_count'])
|
62
62
|
span.set_tag(Ext::TAG_JOB_QUEUE, job['queue'])
|
63
63
|
span.set_tag(Ext::TAG_JOB_WRAPPER, job['class']) if job['wrapped']
|
64
|
-
span.set_tag(Ext::TAG_JOB_DELAY, 1000.0 * (Time.now.utc.to_f - job['enqueued_at'].to_f))
|
64
|
+
span.set_tag(Ext::TAG_JOB_DELAY, 1000.0 * (Core::Utils::Time.now.utc.to_f - job['enqueued_at'].to_f))
|
65
65
|
|
66
66
|
args = job['args']
|
67
67
|
if args && !args.empty?
|
@@ -33,7 +33,7 @@ module Datadog
|
|
33
33
|
|
34
34
|
# OpenTelemetry SDK stores span event timestamps in nanoseconds (not seconds).
|
35
35
|
# We will do the same here to avoid unnecessary conversions and inconsistencies.
|
36
|
-
@time_unix_nano = time_unix_nano || (Time.now.to_r * 1_000_000_000).to_i
|
36
|
+
@time_unix_nano = time_unix_nano || (Core::Utils::Time.now.to_r * 1_000_000_000).to_i
|
37
37
|
end
|
38
38
|
|
39
39
|
# Converts the span event into a hash to be used by with the span tag serialization
|