datadog 2.23.0 → 2.28.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 +132 -2
- data/ext/datadog_profiling_native_extension/clock_id_from_pthread.c +2 -1
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +100 -29
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +2 -2
- data/ext/datadog_profiling_native_extension/collectors_gc_profiling_helper.c +3 -2
- data/ext/datadog_profiling_native_extension/collectors_stack.c +23 -10
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +16 -12
- data/ext/datadog_profiling_native_extension/crashtracking_runtime_stacks.c +239 -0
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +48 -1
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +41 -0
- data/ext/datadog_profiling_native_extension/encoded_profile.c +2 -1
- data/ext/datadog_profiling_native_extension/extconf.rb +4 -1
- data/ext/datadog_profiling_native_extension/heap_recorder.c +24 -24
- data/ext/datadog_profiling_native_extension/http_transport.c +10 -4
- data/ext/datadog_profiling_native_extension/libdatadog_helpers.c +3 -22
- data/ext/datadog_profiling_native_extension/libdatadog_helpers.h +0 -5
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +21 -8
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +4 -0
- data/ext/datadog_profiling_native_extension/profiling.c +22 -15
- data/ext/datadog_profiling_native_extension/ruby_helpers.c +55 -44
- data/ext/datadog_profiling_native_extension/ruby_helpers.h +17 -5
- data/ext/datadog_profiling_native_extension/setup_signal_handler.c +8 -2
- data/ext/datadog_profiling_native_extension/setup_signal_handler.h +3 -0
- data/ext/datadog_profiling_native_extension/stack_recorder.c +16 -16
- data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.c +2 -1
- data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h +5 -2
- data/ext/libdatadog_api/crashtracker.c +5 -8
- data/ext/libdatadog_api/datadog_ruby_common.c +48 -1
- data/ext/libdatadog_api/datadog_ruby_common.h +41 -0
- data/ext/libdatadog_api/ddsketch.c +4 -8
- data/ext/libdatadog_api/feature_flags.c +5 -5
- data/ext/libdatadog_api/helpers.h +27 -0
- data/ext/libdatadog_api/init.c +4 -0
- data/ext/libdatadog_extconf_helpers.rb +1 -1
- data/lib/datadog/ai_guard/api_client.rb +82 -0
- data/lib/datadog/ai_guard/component.rb +42 -0
- data/lib/datadog/ai_guard/configuration/ext.rb +17 -0
- data/lib/datadog/ai_guard/configuration/settings.rb +110 -0
- data/lib/datadog/ai_guard/configuration.rb +11 -0
- data/lib/datadog/ai_guard/contrib/integration.rb +37 -0
- data/lib/datadog/ai_guard/contrib/ruby_llm/chat_instrumentation.rb +42 -0
- data/lib/datadog/ai_guard/contrib/ruby_llm/integration.rb +41 -0
- data/lib/datadog/ai_guard/contrib/ruby_llm/patcher.rb +30 -0
- data/lib/datadog/ai_guard/evaluation/message.rb +25 -0
- data/lib/datadog/ai_guard/evaluation/no_op_result.rb +34 -0
- data/lib/datadog/ai_guard/evaluation/request.rb +81 -0
- data/lib/datadog/ai_guard/evaluation/result.rb +43 -0
- data/lib/datadog/ai_guard/evaluation/tool_call.rb +18 -0
- data/lib/datadog/ai_guard/evaluation.rb +72 -0
- data/lib/datadog/ai_guard/ext.rb +16 -0
- data/lib/datadog/ai_guard.rb +155 -0
- data/lib/datadog/appsec/api_security/endpoint_collection/rails_collector.rb +8 -1
- data/lib/datadog/appsec/api_security/endpoint_collection/rails_route_serializer.rb +9 -2
- data/lib/datadog/appsec/component.rb +1 -1
- data/lib/datadog/appsec/context.rb +5 -4
- data/lib/datadog/appsec/contrib/active_record/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/active_record/patcher.rb +1 -1
- data/lib/datadog/appsec/contrib/excon/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/excon/patcher.rb +1 -1
- data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +47 -12
- data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +32 -15
- data/lib/datadog/appsec/contrib/rails/patcher.rb +10 -2
- data/lib/datadog/appsec/contrib/rest_client/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/rest_client/patcher.rb +1 -1
- data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +50 -14
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +5 -4
- data/lib/datadog/appsec/contrib/sinatra/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/sinatra/patcher.rb +4 -4
- data/lib/datadog/appsec/contrib/sinatra/patches/json_patch.rb +1 -1
- data/lib/datadog/appsec/ext.rb +2 -0
- data/lib/datadog/appsec/metrics/collector.rb +8 -3
- data/lib/datadog/appsec/metrics/exporter.rb +7 -0
- data/lib/datadog/appsec/metrics/telemetry.rb +7 -2
- data/lib/datadog/appsec/metrics.rb +5 -5
- data/lib/datadog/appsec/remote.rb +7 -14
- data/lib/datadog/appsec/security_engine/engine.rb +3 -3
- data/lib/datadog/appsec/security_engine/result.rb +2 -1
- data/lib/datadog/appsec/security_engine/runner.rb +2 -2
- data/lib/datadog/appsec/utils/http/media_type.rb +37 -23
- data/lib/datadog/appsec.rb +7 -1
- data/lib/datadog/core/configuration/components.rb +7 -0
- data/lib/datadog/core/configuration/config_helper.rb +1 -1
- data/lib/datadog/core/configuration/deprecations.rb +2 -2
- data/lib/datadog/core/configuration/option_definition.rb +4 -2
- data/lib/datadog/core/configuration/options.rb +8 -5
- data/lib/datadog/core/configuration/settings.rb +31 -3
- data/lib/datadog/core/configuration/supported_configurations.rb +10 -1
- data/lib/datadog/core/crashtracking/tag_builder.rb +6 -0
- data/lib/datadog/core/environment/cgroup.rb +52 -25
- data/lib/datadog/core/environment/container.rb +140 -46
- data/lib/datadog/core/environment/ext.rb +1 -0
- data/lib/datadog/core/environment/process.rb +9 -1
- data/lib/datadog/core/error.rb +6 -6
- data/lib/datadog/core/knuth_sampler.rb +57 -0
- data/lib/datadog/core/pin.rb +4 -0
- data/lib/datadog/core/rate_limiter.rb +9 -1
- data/lib/datadog/core/remote/client.rb +14 -6
- data/lib/datadog/core/remote/component.rb +6 -4
- data/lib/datadog/core/remote/configuration/content.rb +15 -2
- data/lib/datadog/core/remote/configuration/digest.rb +14 -7
- data/lib/datadog/core/remote/configuration/repository.rb +1 -1
- data/lib/datadog/core/remote/configuration/target.rb +13 -6
- data/lib/datadog/core/remote/transport/config.rb +3 -16
- data/lib/datadog/core/remote/transport/http/config.rb +4 -44
- data/lib/datadog/core/remote/transport/http/negotiation.rb +0 -39
- data/lib/datadog/core/remote/transport/http.rb +13 -24
- data/lib/datadog/core/remote/transport/negotiation.rb +7 -16
- data/lib/datadog/core/runtime/metrics.rb +11 -1
- data/lib/datadog/core/semaphore.rb +1 -4
- data/lib/datadog/core/telemetry/component.rb +52 -13
- data/lib/datadog/core/telemetry/event/app_started.rb +36 -1
- data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +27 -4
- data/lib/datadog/core/telemetry/logger.rb +2 -0
- data/lib/datadog/core/telemetry/logging.rb +20 -2
- data/lib/datadog/core/telemetry/metrics_manager.rb +9 -0
- data/lib/datadog/core/telemetry/request.rb +17 -3
- data/lib/datadog/core/telemetry/transport/http/telemetry.rb +2 -32
- data/lib/datadog/core/telemetry/transport/http.rb +21 -16
- data/lib/datadog/core/telemetry/transport/telemetry.rb +3 -10
- data/lib/datadog/core/telemetry/worker.rb +88 -32
- data/lib/datadog/core/transport/ext.rb +2 -0
- data/lib/datadog/core/transport/http/api/endpoint.rb +9 -4
- data/lib/datadog/core/transport/http/api/instance.rb +4 -21
- data/lib/datadog/core/transport/http/builder.rb +9 -5
- data/lib/datadog/core/transport/http/client.rb +19 -8
- data/lib/datadog/core/transport/http.rb +22 -19
- data/lib/datadog/core/transport/response.rb +12 -1
- data/lib/datadog/core/transport/transport.rb +90 -0
- data/lib/datadog/core/utils/only_once_successful.rb +2 -0
- data/lib/datadog/core/utils/safe_dup.rb +2 -2
- data/lib/datadog/core/utils/sequence.rb +2 -0
- data/lib/datadog/core/utils/time.rb +1 -1
- data/lib/datadog/core/workers/async.rb +10 -1
- data/lib/datadog/core/workers/interval_loop.rb +44 -3
- data/lib/datadog/core/workers/polling.rb +2 -0
- data/lib/datadog/core/workers/queue.rb +100 -1
- data/lib/datadog/data_streams/processor.rb +1 -1
- data/lib/datadog/data_streams/transport/http/stats.rb +1 -36
- data/lib/datadog/data_streams/transport/http.rb +5 -6
- data/lib/datadog/data_streams/transport/stats.rb +3 -17
- data/lib/datadog/di/boot.rb +4 -2
- data/lib/datadog/di/configuration/settings.rb +22 -0
- data/lib/datadog/di/contrib/active_record.rb +30 -5
- data/lib/datadog/di/el/compiler.rb +8 -4
- data/lib/datadog/di/error.rb +5 -0
- data/lib/datadog/di/instrumenter.rb +26 -7
- data/lib/datadog/di/logger.rb +2 -2
- data/lib/datadog/di/probe_builder.rb +2 -1
- data/lib/datadog/di/probe_file_loader/railtie.rb +1 -1
- data/lib/datadog/di/probe_manager.rb +37 -31
- data/lib/datadog/di/probe_notification_builder.rb +15 -2
- data/lib/datadog/di/probe_notifier_worker.rb +5 -5
- data/lib/datadog/di/redactor.rb +8 -1
- data/lib/datadog/di/remote.rb +89 -84
- data/lib/datadog/di/transport/diagnostics.rb +7 -35
- data/lib/datadog/di/transport/http/diagnostics.rb +1 -31
- data/lib/datadog/di/transport/http/input.rb +1 -31
- data/lib/datadog/di/transport/http.rb +28 -17
- data/lib/datadog/di/transport/input.rb +7 -34
- data/lib/datadog/di.rb +61 -5
- data/lib/datadog/error_tracking/filters.rb +2 -2
- data/lib/datadog/kit/appsec/events/v2.rb +2 -3
- data/lib/datadog/open_feature/evaluation_engine.rb +2 -1
- data/lib/datadog/open_feature/remote.rb +3 -10
- data/lib/datadog/open_feature/transport.rb +9 -11
- data/lib/datadog/opentelemetry/api/baggage.rb +1 -1
- data/lib/datadog/opentelemetry/configuration/settings.rb +2 -2
- data/lib/datadog/opentelemetry/metrics.rb +21 -14
- data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +5 -8
- data/lib/datadog/profiling/collectors/code_provenance.rb +27 -2
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +3 -2
- data/lib/datadog/profiling/collectors/info.rb +5 -4
- data/lib/datadog/profiling/component.rb +25 -11
- data/lib/datadog/profiling/exporter.rb +4 -0
- data/lib/datadog/profiling/ext/dir_monkey_patches.rb +18 -0
- data/lib/datadog/profiling/ext/exec_monkey_patch.rb +32 -0
- data/lib/datadog/profiling/flush.rb +3 -0
- data/lib/datadog/profiling/http_transport.rb +4 -1
- data/lib/datadog/profiling/profiler.rb +3 -5
- data/lib/datadog/profiling/scheduler.rb +8 -7
- data/lib/datadog/profiling/tag_builder.rb +1 -0
- data/lib/datadog/tracing/contrib/extensions.rb +10 -2
- data/lib/datadog/tracing/contrib/karafka/patcher.rb +31 -32
- data/lib/datadog/tracing/contrib/status_range_matcher.rb +2 -1
- data/lib/datadog/tracing/contrib/utils/quantization/hash.rb +3 -1
- data/lib/datadog/tracing/contrib/waterdrop/patcher.rb +6 -3
- data/lib/datadog/tracing/contrib/waterdrop.rb +4 -0
- data/lib/datadog/tracing/diagnostics/environment_logger.rb +1 -1
- data/lib/datadog/tracing/distributed/baggage.rb +3 -2
- data/lib/datadog/tracing/remote.rb +1 -9
- data/lib/datadog/tracing/sampling/priority_sampler.rb +3 -1
- data/lib/datadog/tracing/sampling/rate_sampler.rb +8 -19
- data/lib/datadog/tracing/span.rb +1 -1
- data/lib/datadog/tracing/span_event.rb +2 -2
- data/lib/datadog/tracing/span_operation.rb +20 -9
- data/lib/datadog/tracing/trace_operation.rb +44 -6
- data/lib/datadog/tracing/tracer.rb +42 -16
- data/lib/datadog/tracing/transport/http/traces.rb +2 -50
- data/lib/datadog/tracing/transport/http.rb +15 -9
- data/lib/datadog/tracing/transport/io/client.rb +1 -1
- data/lib/datadog/tracing/transport/traces.rb +6 -66
- data/lib/datadog/tracing/workers/trace_writer.rb +5 -0
- data/lib/datadog/tracing/writer.rb +1 -0
- data/lib/datadog/version.rb +2 -2
- data/lib/datadog.rb +1 -0
- metadata +33 -19
- data/lib/datadog/core/remote/transport/http/api.rb +0 -53
- data/lib/datadog/core/telemetry/transport/http/api.rb +0 -43
- data/lib/datadog/core/transport/http/api/spec.rb +0 -36
- data/lib/datadog/data_streams/transport/http/api.rb +0 -33
- data/lib/datadog/data_streams/transport/http/client.rb +0 -21
- data/lib/datadog/di/transport/http/api.rb +0 -42
- data/lib/datadog/opentelemetry/api/baggage.rbs +0 -26
- data/lib/datadog/tracing/transport/http/api.rb +0 -44
|
@@ -13,6 +13,7 @@ module Datadog
|
|
|
13
13
|
:duration_ns,
|
|
14
14
|
:duration_ext_ns,
|
|
15
15
|
:inputs_truncated,
|
|
16
|
+
:downstream_requests,
|
|
16
17
|
keyword_init: true
|
|
17
18
|
)
|
|
18
19
|
|
|
@@ -22,10 +23,13 @@ module Datadog
|
|
|
22
23
|
@mutex = Mutex.new
|
|
23
24
|
|
|
24
25
|
@waf = Store.new(
|
|
25
|
-
evals: 0, matches: 0, errors: 0, timeouts: 0, duration_ns: 0,
|
|
26
|
+
evals: 0, matches: 0, errors: 0, timeouts: 0, duration_ns: 0,
|
|
27
|
+
duration_ext_ns: 0, inputs_truncated: 0, downstream_requests: 0
|
|
26
28
|
)
|
|
29
|
+
|
|
27
30
|
@rasp = Store.new(
|
|
28
|
-
evals: 0, matches: 0, errors: 0, timeouts: 0, duration_ns: 0,
|
|
31
|
+
evals: 0, matches: 0, errors: 0, timeouts: 0, duration_ns: 0,
|
|
32
|
+
duration_ext_ns: 0, inputs_truncated: 0, downstream_requests: 0
|
|
29
33
|
)
|
|
30
34
|
end
|
|
31
35
|
|
|
@@ -41,7 +45,7 @@ module Datadog
|
|
|
41
45
|
end
|
|
42
46
|
end
|
|
43
47
|
|
|
44
|
-
def record_rasp(result)
|
|
48
|
+
def record_rasp(result, type:, phase: nil)
|
|
45
49
|
@mutex.synchronize do
|
|
46
50
|
@rasp.evals += 1
|
|
47
51
|
@waf.matches += 1 if result.match?
|
|
@@ -50,6 +54,7 @@ module Datadog
|
|
|
50
54
|
@rasp.duration_ns += result.duration_ns
|
|
51
55
|
@rasp.duration_ext_ns += result.duration_ext_ns
|
|
52
56
|
@rasp.inputs_truncated += 1 if result.input_truncated?
|
|
57
|
+
@rasp.downstream_requests += 1 if type == Ext::RASP_SSRF && phase == Ext::RASP_REQUEST_PHASE
|
|
53
58
|
end
|
|
54
59
|
end
|
|
55
60
|
end
|
|
@@ -22,6 +22,13 @@ module Datadog
|
|
|
22
22
|
span.set_tag('_dd.appsec.rasp.timeout', 1) unless metrics.timeouts.zero?
|
|
23
23
|
span.set_tag('_dd.appsec.rasp.duration', convert_ns_to_us(metrics.duration_ns))
|
|
24
24
|
span.set_tag('_dd.appsec.rasp.duration_ext', convert_ns_to_us(metrics.duration_ext_ns))
|
|
25
|
+
|
|
26
|
+
# NOTE: In case of downstream requests being analyzed additionally
|
|
27
|
+
# with `Context.run_waf` method, we would need to share it
|
|
28
|
+
# between two exporting methods
|
|
29
|
+
unless metrics.downstream_requests.zero?
|
|
30
|
+
span.set_tag('_dd.appsec.downstream_request', metrics.downstream_requests)
|
|
31
|
+
end
|
|
25
32
|
end
|
|
26
33
|
|
|
27
34
|
# private
|
|
@@ -7,10 +7,15 @@ module Datadog
|
|
|
7
7
|
module Telemetry
|
|
8
8
|
module_function
|
|
9
9
|
|
|
10
|
-
def report_rasp(type, result)
|
|
10
|
+
def report_rasp(type, result, phase: nil)
|
|
11
11
|
return if result.error?
|
|
12
12
|
|
|
13
|
-
tags = {rule_type: type, waf_version:
|
|
13
|
+
tags = {rule_type: type, waf_version: WAF::VERSION::BASE_STRING}
|
|
14
|
+
tags[:rule_variant] = phase if phase
|
|
15
|
+
|
|
16
|
+
context = AppSec.active_context
|
|
17
|
+
tags[:event_rules_version] = context.waf_runner_ruleset_version if context
|
|
18
|
+
|
|
14
19
|
namespace = Ext::TELEMETRY_METRICS_NAMESPACE
|
|
15
20
|
|
|
16
21
|
AppSec.telemetry.inc(namespace, 'rasp.rule.eval', 1, tags: tags)
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative 'metrics/collector'
|
|
4
|
+
require_relative 'metrics/exporter'
|
|
5
|
+
require_relative 'metrics/telemetry'
|
|
6
|
+
require_relative 'metrics/telemetry_exporter'
|
|
7
|
+
|
|
3
8
|
module Datadog
|
|
4
9
|
module AppSec
|
|
5
10
|
# This namespace contains classes related to metrics collection and exportation.
|
|
@@ -7,8 +12,3 @@ module Datadog
|
|
|
7
12
|
end
|
|
8
13
|
end
|
|
9
14
|
end
|
|
10
|
-
|
|
11
|
-
require_relative 'metrics/collector'
|
|
12
|
-
require_relative 'metrics/exporter'
|
|
13
|
-
require_relative 'metrics/telemetry'
|
|
14
|
-
require_relative 'metrics/telemetry_exporter'
|
|
@@ -7,8 +7,6 @@ module Datadog
|
|
|
7
7
|
module AppSec
|
|
8
8
|
# Remote
|
|
9
9
|
module Remote
|
|
10
|
-
class ReadError < StandardError; end
|
|
11
|
-
|
|
12
10
|
class NoRulesError < StandardError; end
|
|
13
11
|
|
|
14
12
|
class << self
|
|
@@ -77,7 +75,8 @@ module Datadog
|
|
|
77
75
|
|
|
78
76
|
matcher = Core::Remote::Dispatcher::Matcher::Product.new(ASM_PRODUCTS)
|
|
79
77
|
receiver = Core::Remote::Dispatcher::Receiver.new(matcher) do |repository, changes|
|
|
80
|
-
|
|
78
|
+
engine = AppSec.security_engine
|
|
79
|
+
next unless engine
|
|
81
80
|
|
|
82
81
|
changes.each do |change|
|
|
83
82
|
content = repository[change.path]
|
|
@@ -85,11 +84,11 @@ module Datadog
|
|
|
85
84
|
|
|
86
85
|
case change.type
|
|
87
86
|
when :insert, :update
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
content.applied
|
|
87
|
+
# @type var content: Core::Remote::Configuration::Content
|
|
88
|
+
engine.add_or_update_config(parse_content(content), path: change.path.to_s)
|
|
89
|
+
content.applied
|
|
91
90
|
when :delete
|
|
92
|
-
|
|
91
|
+
engine.remove_config_at_path(change.path.to_s)
|
|
93
92
|
end
|
|
94
93
|
end
|
|
95
94
|
|
|
@@ -109,13 +108,7 @@ module Datadog
|
|
|
109
108
|
end
|
|
110
109
|
|
|
111
110
|
def parse_content(content)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
content.data.rewind
|
|
115
|
-
|
|
116
|
-
raise ReadError, 'EOF reached' if data.nil?
|
|
117
|
-
|
|
118
|
-
JSON.parse(data)
|
|
111
|
+
JSON.parse(content.data)
|
|
119
112
|
end
|
|
120
113
|
end
|
|
121
114
|
end
|
|
@@ -54,17 +54,17 @@ module Datadog
|
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
def add_or_update_config(config, path:)
|
|
57
|
-
|
|
57
|
+
is_ruleset_update = path.include?('ASM_DD')
|
|
58
58
|
|
|
59
59
|
# default config has to be removed when adding an ASM_DD config
|
|
60
|
-
remove_config_at_path(DEFAULT_RULES_CONFIG_PATH) if
|
|
60
|
+
remove_config_at_path(DEFAULT_RULES_CONFIG_PATH) if is_ruleset_update
|
|
61
61
|
|
|
62
62
|
diagnostics = @waf_builder.add_or_update_config(config, path: path)
|
|
63
63
|
@reconfigured_ruleset_version = diagnostics['ruleset_version'] if diagnostics.key?('ruleset_version')
|
|
64
64
|
report_configuration_diagnostics(diagnostics, action: 'update', telemetry: AppSec.telemetry)
|
|
65
65
|
|
|
66
66
|
# we need to load default config if diagnostics contains top-level error for rules or processors
|
|
67
|
-
if
|
|
67
|
+
if is_ruleset_update &&
|
|
68
68
|
(diagnostics.key?('error') ||
|
|
69
69
|
diagnostics.dig('rules', 'error') ||
|
|
70
70
|
diagnostics.dig('processors', 'errors'))
|
|
@@ -70,7 +70,8 @@ module Datadog
|
|
|
70
70
|
|
|
71
71
|
def initialize(duration_ext_ns:, input_truncated:)
|
|
72
72
|
@events = []
|
|
73
|
-
@actions =
|
|
73
|
+
@actions = {}.freeze
|
|
74
|
+
@attributes = {}.freeze
|
|
74
75
|
@duration_ns = 0
|
|
75
76
|
@duration_ext_ns = duration_ext_ns
|
|
76
77
|
@input_truncated = !!input_truncated
|
|
@@ -27,13 +27,13 @@ module Datadog
|
|
|
27
27
|
persistent_data.reject! do |_, v|
|
|
28
28
|
next false if v.is_a?(TrueClass) || v.is_a?(FalseClass)
|
|
29
29
|
|
|
30
|
-
v.nil? || v.empty?
|
|
30
|
+
v.nil? || (v.respond_to?(:empty?) && v.empty?)
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
ephemeral_data.reject! do |_, v|
|
|
34
34
|
next false if v.is_a?(TrueClass) || v.is_a?(FalseClass)
|
|
35
35
|
|
|
36
|
-
v.nil? || v.empty?
|
|
36
|
+
v.nil? || (v.respond_to?(:empty?) && v.empty?)
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
result = try_run(persistent_data, ephemeral_data, timeout)
|
|
@@ -4,14 +4,13 @@ module Datadog
|
|
|
4
4
|
module AppSec
|
|
5
5
|
module Utils
|
|
6
6
|
module HTTP
|
|
7
|
-
# Implementation of media type for
|
|
7
|
+
# Implementation of media type for HTTP headers
|
|
8
8
|
#
|
|
9
9
|
# See:
|
|
10
10
|
# - https://www.rfc-editor.org/rfc/rfc7231#section-5.3.1
|
|
11
11
|
# - https://www.rfc-editor.org/rfc/rfc7231#section-5.3.2
|
|
12
12
|
class MediaType
|
|
13
|
-
|
|
14
|
-
end
|
|
13
|
+
ParseError = Class.new(StandardError) # steep:ignore IncompatibleAssignment
|
|
15
14
|
|
|
16
15
|
WILDCARD = '*'
|
|
17
16
|
|
|
@@ -19,7 +18,7 @@ module Datadog
|
|
|
19
18
|
TOKEN_RE = /[-#$%&'*+.^_`|~A-Za-z0-9]+/.freeze
|
|
20
19
|
|
|
21
20
|
# See: https://www.rfc-editor.org/rfc/rfc7231#section-3.1.1.1
|
|
22
|
-
PARAMETER_RE = %r{
|
|
21
|
+
PARAMETER_RE = %r{
|
|
23
22
|
(?:
|
|
24
23
|
(?<parameter_name>#{TOKEN_RE})
|
|
25
24
|
=
|
|
@@ -46,39 +45,54 @@ module Datadog
|
|
|
46
45
|
|
|
47
46
|
attr_reader :type, :subtype, :parameters
|
|
48
47
|
|
|
49
|
-
def
|
|
50
|
-
|
|
48
|
+
def self.json?(media_type)
|
|
49
|
+
return false if media_type.nil? || media_type.empty?
|
|
51
50
|
|
|
52
|
-
|
|
51
|
+
match = MEDIA_TYPE_RE.match(media_type)
|
|
52
|
+
return false if match.nil?
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
@parameters = {}
|
|
54
|
+
subtype = match['subtype']
|
|
55
|
+
return false if subtype.nil? || subtype.empty?
|
|
57
56
|
|
|
58
|
-
|
|
57
|
+
subtype.downcase!
|
|
58
|
+
subtype == 'json' || subtype.end_with?('+json')
|
|
59
|
+
end
|
|
59
60
|
|
|
60
|
-
|
|
61
|
+
def initialize(media_type)
|
|
62
|
+
match = MEDIA_TYPE_RE.match(media_type)
|
|
63
|
+
raise ParseError, media_type.inspect if match.nil?
|
|
61
64
|
|
|
62
|
-
|
|
63
|
-
|
|
65
|
+
@type = match['type'] || WILDCARD
|
|
66
|
+
@type.downcase!
|
|
64
67
|
|
|
65
|
-
|
|
68
|
+
@subtype = match['subtype'] || WILDCARD
|
|
69
|
+
@subtype.downcase!
|
|
66
70
|
|
|
67
|
-
|
|
68
|
-
|
|
71
|
+
@parameters = {}
|
|
72
|
+
|
|
73
|
+
parameters = match['parameters']
|
|
74
|
+
return if parameters.nil? || parameters.empty?
|
|
69
75
|
|
|
70
|
-
|
|
76
|
+
parameters.scan(PARAMETER_RE) do |name, unquoted_value, quoted_value|
|
|
77
|
+
# NOTE: Order of unquoted_value and quoted_value does not matter,
|
|
78
|
+
# as they are mutually exclusive by the regex.
|
|
79
|
+
# @type var value: ::String?
|
|
80
|
+
value = unquoted_value || quoted_value
|
|
81
|
+
next if name.nil? || value.nil?
|
|
71
82
|
|
|
72
|
-
|
|
83
|
+
# See https://github.com/soutaro/steep/issues/2051
|
|
84
|
+
name.downcase! # steep:ignore NoMethod
|
|
85
|
+
value.downcase!
|
|
86
|
+
|
|
87
|
+
# See https://github.com/soutaro/steep/issues/2051
|
|
88
|
+
@parameters[name] = value # steep:ignore ArgumentTypeMismatch
|
|
73
89
|
end
|
|
74
90
|
end
|
|
75
91
|
|
|
76
92
|
def to_s
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
s << ';' << @parameters.map { |k, v| "#{k}=#{v}" }.join(';') if @parameters.count > 0
|
|
93
|
+
return "#{@type}/#{@subtype}" if @parameters.empty?
|
|
80
94
|
|
|
81
|
-
|
|
95
|
+
"#{@type}/#{@subtype};#{@parameters.map { |k, v| "#{k}=#{v}" }.join(";")}"
|
|
82
96
|
end
|
|
83
97
|
end
|
|
84
98
|
end
|
data/lib/datadog/appsec.rb
CHANGED
|
@@ -22,8 +22,14 @@ module Datadog
|
|
|
22
22
|
Datadog::AppSec::Context.active
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
+
# NOTE: This is a temporary workaround for type checking.
|
|
26
|
+
#
|
|
27
|
+
# We want to move from possible nil-component to the disabled-component
|
|
28
|
+
# on an initialization error. Technically, telemetry will be never
|
|
29
|
+
# used if AppSec was not able to initialize, so it's safe to assume
|
|
30
|
+
# that telemetry will never be used and will be nil at the same time.
|
|
25
31
|
def telemetry
|
|
26
|
-
components.appsec&.telemetry
|
|
32
|
+
components.appsec&.telemetry || components.telemetry
|
|
27
33
|
end
|
|
28
34
|
|
|
29
35
|
def security_engine
|
|
@@ -14,6 +14,7 @@ require_relative '../remote/component'
|
|
|
14
14
|
require_relative '../../tracing/component'
|
|
15
15
|
require_relative '../../profiling/component'
|
|
16
16
|
require_relative '../../appsec/component'
|
|
17
|
+
require_relative '../../ai_guard/component'
|
|
17
18
|
require_relative '../../di/component'
|
|
18
19
|
require_relative '../../open_feature/component'
|
|
19
20
|
require_relative '../../error_tracking/component'
|
|
@@ -48,6 +49,7 @@ module Datadog
|
|
|
48
49
|
options[:statsd] = settings.runtime_metrics.statsd unless settings.runtime_metrics.statsd.nil?
|
|
49
50
|
options[:services] = [settings.service] unless settings.service.nil?
|
|
50
51
|
options[:experimental_runtime_id_enabled] = settings.runtime_metrics.experimental_runtime_id_enabled
|
|
52
|
+
options[:experimental_propagate_process_tags_enabled] = settings.experimental_propagate_process_tags_enabled
|
|
51
53
|
|
|
52
54
|
Core::Runtime::Metrics.new(logger: logger, telemetry: telemetry, **options)
|
|
53
55
|
end
|
|
@@ -107,6 +109,7 @@ module Datadog
|
|
|
107
109
|
:error_tracking,
|
|
108
110
|
:dynamic_instrumentation,
|
|
109
111
|
:appsec,
|
|
112
|
+
:ai_guard,
|
|
110
113
|
:agent_info,
|
|
111
114
|
:data_streams,
|
|
112
115
|
:open_feature
|
|
@@ -143,6 +146,7 @@ module Datadog
|
|
|
143
146
|
@runtime_metrics = self.class.build_runtime_metrics_worker(settings, @logger, telemetry)
|
|
144
147
|
@health_metrics = self.class.build_health_metrics(settings, @logger, telemetry)
|
|
145
148
|
@appsec = Datadog::AppSec::Component.build_appsec_component(settings, telemetry: telemetry)
|
|
149
|
+
@ai_guard = Datadog::AIGuard::Component.build(settings, logger: @logger, telemetry: telemetry)
|
|
146
150
|
@open_feature = OpenFeature::Component.build(settings, agent_settings, logger: @logger, telemetry: telemetry)
|
|
147
151
|
@dynamic_instrumentation = Datadog::DI::Component.build(settings, agent_settings, @logger, telemetry: telemetry)
|
|
148
152
|
@error_tracking = Datadog::ErrorTracking::Component.build(settings, @tracer, @logger)
|
|
@@ -209,6 +213,9 @@ module Datadog
|
|
|
209
213
|
# Decommission AppSec
|
|
210
214
|
appsec&.shutdown!
|
|
211
215
|
|
|
216
|
+
# Shutdown AIGuard component
|
|
217
|
+
ai_guard&.shutdown!
|
|
218
|
+
|
|
212
219
|
# Shutdown the old tracer, unless it's still being used.
|
|
213
220
|
# (e.g. a custom tracer instance passed in.)
|
|
214
221
|
tracer.shutdown! unless replacement && tracer.equal?(replacement.tracer)
|
|
@@ -9,7 +9,7 @@ module Datadog
|
|
|
9
9
|
class ConfigHelper
|
|
10
10
|
def initialize(
|
|
11
11
|
source_env: ENV,
|
|
12
|
-
supported_configurations:
|
|
12
|
+
supported_configurations: SUPPORTED_CONFIGURATION_NAMES,
|
|
13
13
|
aliases: ALIASES,
|
|
14
14
|
alias_to_canonical: ALIAS_TO_CANONICAL,
|
|
15
15
|
raise_on_unknown_env_var: false
|
|
@@ -21,12 +21,12 @@ module Datadog
|
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
private_class_method def self.log_deprecated_environment_variables(logger, source_env, source_name, deprecations, alias_to_canonical)
|
|
24
|
-
deprecations.each do |deprecated_env_var
|
|
24
|
+
deprecations.each do |deprecated_env_var|
|
|
25
25
|
next unless source_env.key?(deprecated_env_var)
|
|
26
26
|
|
|
27
27
|
Datadog::Core.log_deprecation(disallowed_next_major: false, logger: logger) do
|
|
28
28
|
"#{deprecated_env_var} #{source_name} variable is deprecated" +
|
|
29
|
-
(alias_to_canonical[deprecated_env_var] ? ", use #{alias_to_canonical[deprecated_env_var]} instead." : ".
|
|
29
|
+
(alias_to_canonical[deprecated_env_var] ? ", use #{alias_to_canonical[deprecated_env_var]} instead." : ".")
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
32
|
end
|
|
@@ -42,7 +42,8 @@ module Datadog
|
|
|
42
42
|
# Acts as DSL for building OptionDefinitions
|
|
43
43
|
# @public_api
|
|
44
44
|
class Builder
|
|
45
|
-
|
|
45
|
+
# Steep: https://github.com/soutaro/steep/issues/1880
|
|
46
|
+
InvalidOptionError = Class.new(StandardError) # steep:ignore IncompatibleAssignment
|
|
46
47
|
|
|
47
48
|
attr_reader \
|
|
48
49
|
:helpers
|
|
@@ -119,7 +120,8 @@ module Datadog
|
|
|
119
120
|
env_parser(&options[:env_parser]) if options.key?(:env_parser)
|
|
120
121
|
after_set(&options[:after_set]) if options.key?(:after_set)
|
|
121
122
|
resetter(&options[:resetter]) if options.key?(:resetter)
|
|
122
|
-
|
|
123
|
+
# Steep: https://github.com/soutaro/steep/issues/1979
|
|
124
|
+
setter(&options[:setter]) if options.key?(:setter) # steep:ignore BlockTypeMismatch
|
|
123
125
|
type(options[:type], **(options[:type_options] || {})) if options.key?(:type)
|
|
124
126
|
end
|
|
125
127
|
|
|
@@ -40,14 +40,16 @@ module Datadog
|
|
|
40
40
|
|
|
41
41
|
def default_helpers(name)
|
|
42
42
|
option_name = name.to_sym
|
|
43
|
-
#
|
|
44
|
-
|
|
43
|
+
# Steep: https://github.com/soutaro/steep/issues/335
|
|
44
|
+
# @type var opt_getter: Configuration::OptionDefinition::generic_proc
|
|
45
|
+
opt_getter = proc do # steep:ignore IncompatibleAssignment
|
|
45
46
|
# These Procs uses `get/set_option`, but we only add them to the OptionDefinition helpers here.
|
|
46
47
|
# Steep is right that these methods are not defined, but we only run these Procs in instance context.
|
|
47
48
|
get_option(option_name) # steep:ignore NoMethod
|
|
48
49
|
end
|
|
49
|
-
#
|
|
50
|
-
|
|
50
|
+
# Steep: https://github.com/soutaro/steep/issues/335
|
|
51
|
+
# @type var opt_setter: Configuration::OptionDefinition::generic_proc
|
|
52
|
+
opt_setter = proc do |value| # steep:ignore IncompatibleAssignment
|
|
51
53
|
set_option(option_name, value) # steep:ignore NoMethod
|
|
52
54
|
end
|
|
53
55
|
{
|
|
@@ -127,7 +129,8 @@ module Datadog
|
|
|
127
129
|
end
|
|
128
130
|
end
|
|
129
131
|
|
|
130
|
-
|
|
132
|
+
# Steep: https://github.com/soutaro/steep/issues/1880
|
|
133
|
+
InvalidOptionError = Class.new(StandardError) # steep:ignore IncompatibleAssignment
|
|
131
134
|
end
|
|
132
135
|
end
|
|
133
136
|
end
|
|
@@ -170,6 +170,20 @@ module Datadog
|
|
|
170
170
|
o.env Core::Environment::Ext::ENV_ENVIRONMENT
|
|
171
171
|
end
|
|
172
172
|
|
|
173
|
+
# Configuration for container environments. For internal use only.
|
|
174
|
+
# @!visibility private
|
|
175
|
+
settings :container do
|
|
176
|
+
# Data supplied by the container runner to assist in uniquely identifying this process.
|
|
177
|
+
# Used in [Origin Detection](https://docs.datadoghq.com/developers/dogstatsd/unix_socket/?tab=host#origin-detection)
|
|
178
|
+
#
|
|
179
|
+
# @default `DD_EXTERNAL_ENV` environment variable, otherwise `nil`
|
|
180
|
+
# @return [String,nil]
|
|
181
|
+
option :external_env do |o|
|
|
182
|
+
o.type :string, nilable: true
|
|
183
|
+
o.env Core::Environment::Ext::ENV_EXTERNAL_ENV
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
173
187
|
# Internal {Datadog::Statsd} metrics collection.
|
|
174
188
|
#
|
|
175
189
|
# @public_api
|
|
@@ -293,9 +307,6 @@ module Datadog
|
|
|
293
307
|
# for Ruby versions 2.x, 3.1.4+, 3.2.3+ and 3.3.0+
|
|
294
308
|
# (more details in {Datadog::Profiling::Component.enable_gc_profiling?})
|
|
295
309
|
#
|
|
296
|
-
# @warn Due to a VM bug in the Ractor implementation (https://bugs.ruby-lang.org/issues/19112) this feature
|
|
297
|
-
# stops working when Ractors get garbage collected.
|
|
298
|
-
#
|
|
299
310
|
# @default `DD_PROFILING_GC_ENABLED` environment variable, otherwise `true`
|
|
300
311
|
option :gc_enabled do |o|
|
|
301
312
|
o.type :bool
|
|
@@ -425,6 +436,23 @@ module Datadog
|
|
|
425
436
|
o.default true
|
|
426
437
|
end
|
|
427
438
|
|
|
439
|
+
# The profiler gathers data by sending `SIGPROF` unix signals to Ruby application threads.
|
|
440
|
+
#
|
|
441
|
+
# When using `Kernel#exec` on Linux, it can happen that a signal sent before calling `exec` arrives after
|
|
442
|
+
# the new process is running, causing it to fail with the `Profiling timer expired` error message.
|
|
443
|
+
# To avoid this, the profiler installs a monkey patch on `Kernel#exec` to stop profiling before actually
|
|
444
|
+
# calling `exec`.
|
|
445
|
+
# This monkey patch is available for Ruby 2.7+; let us know if you need it on earlier Rubies.
|
|
446
|
+
# For more details see https://github.com/DataDog/dd-trace-rb/issues/5101 .
|
|
447
|
+
#
|
|
448
|
+
# @default `DD_PROFILING_SHUTDOWN_ON_EXEC_ENABLED` environment variable as a boolean,
|
|
449
|
+
# otherwise `true`
|
|
450
|
+
option :shutdown_on_exec_enabled do |o|
|
|
451
|
+
o.env 'DD_PROFILING_SHUTDOWN_ON_EXEC_ENABLED'
|
|
452
|
+
o.type :bool
|
|
453
|
+
o.default true
|
|
454
|
+
end
|
|
455
|
+
|
|
428
456
|
# Configures how much wall-time overhead the profiler targets. The profiler will dynamically adjust the
|
|
429
457
|
# interval between samples it takes so as to try and maintain the property that it spends no longer than
|
|
430
458
|
# this amount of wall-clock time profiling. For example, with the default value of 2%, the profiler will
|
|
@@ -8,8 +8,13 @@ require 'set'
|
|
|
8
8
|
module Datadog
|
|
9
9
|
module Core
|
|
10
10
|
module Configuration
|
|
11
|
-
|
|
11
|
+
SUPPORTED_CONFIGURATION_NAMES =
|
|
12
12
|
Set["DD_AGENT_HOST",
|
|
13
|
+
"DD_AI_GUARD_ENABLED",
|
|
14
|
+
"DD_AI_GUARD_ENDPOINT",
|
|
15
|
+
"DD_AI_GUARD_MAX_CONTENT_SIZE",
|
|
16
|
+
"DD_AI_GUARD_MAX_MESSAGES_LENGTH",
|
|
17
|
+
"DD_AI_GUARD_TIMEOUT",
|
|
13
18
|
"DD_API_KEY",
|
|
14
19
|
"DD_API_SECURITY_ENABLED",
|
|
15
20
|
"DD_API_SECURITY_ENDPOINT_COLLECTION_ENABLED",
|
|
@@ -34,6 +39,7 @@ module Datadog
|
|
|
34
39
|
"DD_APPSEC_TRACE_RATE_LIMIT",
|
|
35
40
|
"DD_APPSEC_WAF_DEBUG",
|
|
36
41
|
"DD_APPSEC_WAF_TIMEOUT",
|
|
42
|
+
"DD_APP_KEY",
|
|
37
43
|
"DD_CRASHTRACKING_ENABLED",
|
|
38
44
|
"DD_DATA_STREAMS_ENABLED",
|
|
39
45
|
"DD_DBM_PROPAGATION_MODE",
|
|
@@ -42,11 +48,13 @@ module Datadog
|
|
|
42
48
|
"DD_DYNAMIC_INSTRUMENTATION_PROBE_FILE",
|
|
43
49
|
"DD_DYNAMIC_INSTRUMENTATION_REDACTED_IDENTIFIERS",
|
|
44
50
|
"DD_DYNAMIC_INSTRUMENTATION_REDACTED_TYPES",
|
|
51
|
+
"DD_DYNAMIC_INSTRUMENTATION_REDACTION_EXCLUDED_IDENTIFIERS",
|
|
45
52
|
"DD_ENV",
|
|
46
53
|
"DD_ERROR_TRACKING_HANDLED_ERRORS",
|
|
47
54
|
"DD_ERROR_TRACKING_HANDLED_ERRORS_INCLUDE",
|
|
48
55
|
"DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED",
|
|
49
56
|
"DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED",
|
|
57
|
+
"DD_EXTERNAL_ENV",
|
|
50
58
|
"DD_GIT_COMMIT_SHA",
|
|
51
59
|
"DD_GIT_REPOSITORY_URL",
|
|
52
60
|
"DD_HEALTH_METRICS_ENABLED",
|
|
@@ -74,6 +82,7 @@ module Datadog
|
|
|
74
82
|
"DD_PROFILING_NO_SIGNALS_WORKAROUND_ENABLED",
|
|
75
83
|
"DD_PROFILING_OVERHEAD_TARGET_PERCENTAGE",
|
|
76
84
|
"DD_PROFILING_PREVIEW_OTEL_CONTEXT_ENABLED",
|
|
85
|
+
"DD_PROFILING_SHUTDOWN_ON_EXEC_ENABLED",
|
|
77
86
|
"DD_PROFILING_SIGHANDLER_SAMPLING_ENABLED",
|
|
78
87
|
"DD_PROFILING_SKIP_MYSQL2_CHECK",
|
|
79
88
|
"DD_PROFILING_TIMELINE_ENABLED",
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative '../tag_builder'
|
|
4
4
|
require_relative '../utils'
|
|
5
|
+
require_relative '../environment/process'
|
|
5
6
|
|
|
6
7
|
module Datadog
|
|
7
8
|
module Core
|
|
@@ -13,6 +14,11 @@ module Datadog
|
|
|
13
14
|
'is_crash' => 'true',
|
|
14
15
|
)
|
|
15
16
|
|
|
17
|
+
if settings.experimental_propagate_process_tags_enabled
|
|
18
|
+
process_tags = Environment::Process.serialized
|
|
19
|
+
hash['process_tags'] = process_tags unless process_tags.empty?
|
|
20
|
+
end
|
|
21
|
+
|
|
16
22
|
Utils.encode_tags(hash)
|
|
17
23
|
end
|
|
18
24
|
end
|
|
@@ -10,40 +10,67 @@ module Datadog
|
|
|
10
10
|
# about the current Linux container identity.
|
|
11
11
|
# @see https://man7.org/linux/man-pages/man7/cgroups.7.html
|
|
12
12
|
module Cgroup
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
:
|
|
17
|
-
:groups,
|
|
13
|
+
# A parsed cgroup entry from /proc/<pid>/cgroup
|
|
14
|
+
Entry = Struct.new(
|
|
15
|
+
:hierarchy,
|
|
16
|
+
:controllers,
|
|
18
17
|
:path,
|
|
19
|
-
:
|
|
18
|
+
:inode
|
|
20
19
|
)
|
|
21
20
|
|
|
22
21
|
module_function
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
end
|
|
34
|
-
rescue => e
|
|
35
|
-
Datadog.logger.error(
|
|
36
|
-
"Error while parsing cgroup. Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
|
|
37
|
-
)
|
|
23
|
+
# Parses the /proc/self/cgroup file,
|
|
24
|
+
# @return [Array<Entry>] one entry for each valid cgroup line
|
|
25
|
+
def entries
|
|
26
|
+
filepath = '/proc/self/cgroup'
|
|
27
|
+
return [] unless File.exist?(filepath)
|
|
28
|
+
|
|
29
|
+
ret = []
|
|
30
|
+
File.foreach(filepath) do |entry_line|
|
|
31
|
+
ret << parse(entry_line) unless entry_line.empty?
|
|
38
32
|
end
|
|
33
|
+
ret
|
|
39
34
|
end
|
|
40
35
|
|
|
41
|
-
|
|
42
|
-
|
|
36
|
+
# Parses a single cgroup entry from /proc/<pid>/cgroup.
|
|
37
|
+
#
|
|
38
|
+
# Files can have cgroup v1 and v2 entries mixed. Their format is the same.
|
|
39
|
+
#
|
|
40
|
+
# Each entry has 3 colon-separated fields:
|
|
41
|
+
# hierarchy-ID:controllers:path
|
|
42
|
+
# Examples:
|
|
43
|
+
# 10:memory:/docker/1234567890abcdef (cgroup v1)
|
|
44
|
+
# 0::/docker/1234567890abcdef (cgroup v2)
|
|
45
|
+
#
|
|
46
|
+
# @see https://man7.org/linux/man-pages/man7/cgroups.7.html#:~:text=%2Fproc%2Fpid%2Fcgroup
|
|
47
|
+
# @return [Entry]
|
|
48
|
+
def parse(entry_line)
|
|
49
|
+
hierarchy, controllers, path = entry_line.split(':', 3)
|
|
43
50
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
51
|
+
Entry.new(
|
|
52
|
+
hierarchy,
|
|
53
|
+
controllers,
|
|
54
|
+
path,
|
|
55
|
+
inode_for(controllers, path)
|
|
56
|
+
)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# We can find the container inode by running a file stat on the cgroup filesystem path.
|
|
60
|
+
# Example:
|
|
61
|
+
# For the entry `0:cpu:/docker/abc123`,
|
|
62
|
+
# we read `stat -c '%i' /sys/fs/cgroup/cpu/docker/abc123`
|
|
63
|
+
def inode_for(controllers, path)
|
|
64
|
+
return if controllers.nil? || path.nil?
|
|
65
|
+
|
|
66
|
+
# In cgroup v1, when multiple controllers are co-mounted, the controllers
|
|
67
|
+
# becomes part of the directory name (with commas preserved).
|
|
68
|
+
# Example entry:
|
|
69
|
+
# For the line "10:cpu,cpuacct:/docker/abc123", the path is
|
|
70
|
+
# "/sys/fs/cgroup/cpu,cpuacct/docker/abc123"
|
|
71
|
+
inode_path = File.join('/sys/fs/cgroup', controllers, path)
|
|
72
|
+
|
|
73
|
+
File.stat(inode_path).ino if File.exist?(inode_path)
|
|
47
74
|
end
|
|
48
75
|
end
|
|
49
76
|
end
|