datadog 2.39.0 → 2.40.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 +27 -1
- data/ext/datadog_profiling_native_extension/collectors_stack.c +218 -147
- data/ext/datadog_profiling_native_extension/collectors_stack.h +16 -2
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +12 -7
- data/ext/datadog_profiling_native_extension/crashtracking_runtime_stacks.c +5 -4
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +19 -11
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +7 -0
- data/ext/datadog_profiling_native_extension/extconf.rb +12 -7
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +259 -65
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +16 -10
- data/ext/libdatadog_api/datadog_ruby_common.c +19 -11
- data/ext/libdatadog_api/datadog_ruby_common.h +7 -0
- data/ext/libdatadog_api/init.c +4 -0
- data/ext/libdatadog_api/trace_exporter.c +974 -0
- data/ext/libdatadog_api/trace_exporter.h +5 -0
- data/lib/datadog/ai_guard/evaluation.rb +1 -0
- data/lib/datadog/ai_guard/ext.rb +2 -0
- data/lib/datadog/appsec/configuration.rb +9 -0
- data/lib/datadog/appsec/contrib/devise/patcher.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/patcher.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +6 -3
- data/lib/datadog/appsec/contrib/rails/request_middleware.rb +2 -1
- data/lib/datadog/appsec/contrib/sinatra/request_middleware.rb +2 -1
- data/lib/datadog/core/configuration/settings.rb +33 -41
- data/lib/datadog/core/configuration/supported_configurations.rb +3 -0
- data/lib/datadog/core/environment/gc.rb +1 -1
- data/lib/datadog/core/environment/vm_cache.rb +1 -1
- data/lib/datadog/core/environment/yjit.rb +2 -2
- data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +1 -1
- data/lib/datadog/core/utils/at_fork_monkey_patch.rb +80 -12
- data/lib/datadog/core/utils/sequence.rb +3 -6
- data/lib/datadog/core/utils/time.rb +16 -54
- data/lib/datadog/di/el/compiler.rb +65 -12
- data/lib/datadog/di/el/evaluator.rb +82 -2
- data/lib/datadog/di/el/expression.rb +10 -2
- data/lib/datadog/di/probe_builder.rb +6 -6
- data/lib/datadog/profiling/collectors/thread_context.rb +6 -13
- data/lib/datadog/profiling/component.rb +1 -0
- data/lib/datadog/profiling.rb +4 -0
- data/lib/datadog/tracing/component.rb +21 -0
- data/lib/datadog/tracing/configuration/ext.rb +1 -0
- data/lib/datadog/tracing/configuration/settings.rb +16 -0
- data/lib/datadog/tracing/contrib/hanami/router_tracing.rb +2 -1
- data/lib/datadog/tracing/contrib/kafka/events/connection/request.rb +4 -0
- data/lib/datadog/tracing/contrib/kafka/events/produce_operation/send_messages.rb +7 -2
- data/lib/datadog/tracing/contrib/kafka/events/producer/deliver_messages.rb +7 -2
- data/lib/datadog/tracing/contrib/sequel/database.rb +1 -5
- data/lib/datadog/tracing/distributed/propagation_policy.rb +5 -0
- data/lib/datadog/tracing/sync_writer.rb +8 -3
- data/lib/datadog/tracing/tracer.rb +8 -0
- data/lib/datadog/tracing/transport/native/response.rb +71 -0
- data/lib/datadog/tracing/transport/native.rb +363 -0
- data/lib/datadog/tracing/transport/trace_formatter.rb +1 -1
- data/lib/datadog/tracing/writer.rb +16 -3
- data/lib/datadog/version.rb +1 -1
- metadata +9 -5
|
@@ -15,6 +15,7 @@ module Datadog
|
|
|
15
15
|
Tracing::Metadata::Ext::Distributed::TAG_DECISION_MAKER,
|
|
16
16
|
Tracing::Sampling::Ext::Decision::AI_GUARD
|
|
17
17
|
)
|
|
18
|
+
trace.set_distributed_source(Ext::PRODUCT_BIT)
|
|
18
19
|
trace.set_tag(Ext::EVENT_TAG, true)
|
|
19
20
|
trace.set_tag(Ext::TRACE_EXECUTED_TAG, "1")
|
|
20
21
|
|
data/lib/datadog/ai_guard/ext.rb
CHANGED
|
@@ -52,6 +52,15 @@ module Datadog
|
|
|
52
52
|
o.default false
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
+
# NOTE: Marker set by the agentic onboarding tooling.
|
|
56
|
+
# Has no effect here — we just report its value in telemetry,
|
|
57
|
+
# so onboarding can be detected at runtime
|
|
58
|
+
option :agentic_onboarding do |o|
|
|
59
|
+
o.type :string
|
|
60
|
+
o.env "DD_APPSEC_AGENTIC_ONBOARDING"
|
|
61
|
+
o.default ""
|
|
62
|
+
end
|
|
63
|
+
|
|
55
64
|
define_method(:instrument) do |integration_name|
|
|
56
65
|
if enabled
|
|
57
66
|
registered_integration = Datadog::AppSec::Contrib::Integration.registry[integration_name]
|
|
@@ -12,7 +12,8 @@ module Datadog
|
|
|
12
12
|
# This should be inserted just below Rack::JSONBodyParser or
|
|
13
13
|
# legacy Rack::PostBodyContentTypeParser from rack-contrib
|
|
14
14
|
class RequestBodyMiddleware
|
|
15
|
-
|
|
15
|
+
# TODO: opt is never used, it can probably be safely removed
|
|
16
|
+
def initialize(app, opt = {}) # steep:ignore DifferentMethodParameterKind
|
|
16
17
|
@app = app
|
|
17
18
|
end
|
|
18
19
|
|
|
@@ -23,7 +24,7 @@ module Datadog
|
|
|
23
24
|
|
|
24
25
|
# TODO: handle exceptions, except for @app.call
|
|
25
26
|
|
|
26
|
-
http_response = nil
|
|
27
|
+
http_response = nil #: Rack::response?
|
|
27
28
|
interrupt_params = catch(::Datadog::AppSec::Ext::INTERRUPT) do
|
|
28
29
|
http_response, _request = Instrumentation.gateway.push("rack.request.body", Gateway::Request.new(env)) do
|
|
29
30
|
@app.call(env)
|
|
@@ -34,7 +35,9 @@ module Datadog
|
|
|
34
35
|
|
|
35
36
|
return AppSec::Response.from_interrupt_params(interrupt_params, env["HTTP_ACCEPT"]).to_rack if interrupt_params
|
|
36
37
|
|
|
37
|
-
http_response
|
|
38
|
+
# Steep can't see that the catch block always populates http_response
|
|
39
|
+
# when no interrupt is thrown.
|
|
40
|
+
http_response #: Rack::response
|
|
38
41
|
end
|
|
39
42
|
end
|
|
40
43
|
end
|
|
@@ -6,7 +6,8 @@ module Datadog
|
|
|
6
6
|
module Rails
|
|
7
7
|
# Rack middleware for AppSec on Rails
|
|
8
8
|
class RequestMiddleware
|
|
9
|
-
|
|
9
|
+
# TODO: opt is never used, it can probably be safely removed
|
|
10
|
+
def initialize(app, opt = {}) # steep:ignore DifferentMethodParameterKind
|
|
10
11
|
@app = app
|
|
11
12
|
end
|
|
12
13
|
|
|
@@ -6,7 +6,8 @@ module Datadog
|
|
|
6
6
|
module Sinatra
|
|
7
7
|
# Rack middleware for AppSec on Sinatra
|
|
8
8
|
class RequestMiddleware
|
|
9
|
-
|
|
9
|
+
# TODO: opt is never used, it can probably be safely removed
|
|
10
|
+
def initialize(app, opt = {}) # steep:ignore DifferentMethodParameterKind
|
|
10
11
|
@app = app
|
|
11
12
|
end
|
|
12
13
|
|
|
@@ -644,6 +644,13 @@ module Datadog
|
|
|
644
644
|
o.env "DD_PROFILING_EXPERIMENTAL_USE_SYSTEM_DNS"
|
|
645
645
|
o.default true
|
|
646
646
|
end
|
|
647
|
+
|
|
648
|
+
# Whether the profiler samples include the class/module name in stack frames, like `Foo::Bar#baz`, or not (`baz`)
|
|
649
|
+
option :experimental_show_classes_enabled do |o|
|
|
650
|
+
o.type :bool
|
|
651
|
+
o.env "DD_PROFILING_EXPERIMENTAL_SHOW_CLASSES_ENABLED"
|
|
652
|
+
o.default false
|
|
653
|
+
end
|
|
647
654
|
end
|
|
648
655
|
|
|
649
656
|
# @public_api
|
|
@@ -792,55 +799,40 @@ module Datadog
|
|
|
792
799
|
end
|
|
793
800
|
end
|
|
794
801
|
|
|
795
|
-
#
|
|
796
|
-
#
|
|
797
|
-
#
|
|
798
|
-
#
|
|
799
|
-
# For [Timecop](https://rubygems.org/gems/timecop), for example, `->{ Time.now_without_mock_time }`
|
|
800
|
-
# allows Datadog features to use the real wall time when time is frozen.
|
|
801
|
-
#
|
|
802
|
-
# @default `->{ Time.now }`
|
|
803
|
-
# @return [Proc<Time>]
|
|
802
|
+
# Deprecated and no longer does anything.
|
|
803
|
+
# This gem already takes care to not be affected by timecop.
|
|
804
|
+
# DEV-3.0: Remove `time_now_provider` option
|
|
804
805
|
option :time_now_provider do |o|
|
|
805
|
-
o.default_proc { ::Time.now }
|
|
806
|
+
o.default_proc { Datadog::Core::Utils::Time.now }
|
|
806
807
|
o.type :proc
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
Core::Utils::Time.now_provider = default
|
|
808
|
+
o.after_set do |_, _, precedence|
|
|
809
|
+
unless precedence == Datadog::Core::Configuration::Option::Precedence::DEFAULT
|
|
810
|
+
unless defined?(Datadog::CI) # the datadog-ci gem needs to work with any datadog gem version and not warn
|
|
811
|
+
Core.log_deprecation(key: :time_now_provider) do
|
|
812
|
+
"The time_now_provider setting has been deprecated for removal " \
|
|
813
|
+
"and no longer does anything. Please remove it from your Datadog.configure block. " \
|
|
814
|
+
"The datadog gem always uses the real non-mocked time, even when the timecop gem monkey-patches Time."
|
|
815
|
+
end
|
|
816
|
+
end
|
|
817
817
|
end
|
|
818
818
|
end
|
|
819
819
|
end
|
|
820
820
|
|
|
821
|
-
#
|
|
822
|
-
# gem
|
|
823
|
-
#
|
|
824
|
-
# It must respect the interface of [Datadog::Core::Utils::Time#get_time] method.
|
|
825
|
-
#
|
|
826
|
-
# For [Timecop](https://rubygems.org/gems/timecop), for example,
|
|
827
|
-
# `->(unit = :float_second) { ::Process.clock_gettime_without_mock(Datadog::Core::Utils::Time::MONOTONIC_CLOCK_ID, unit) }`
|
|
828
|
-
# allows Datadog features to use the real monotonic time when time is frozen with
|
|
829
|
-
# `Timecop.mock_process_clock = true`.
|
|
830
|
-
#
|
|
831
|
-
# @default `->(unit = :float_second) { ::Process.clock_gettime(Core::Utils::Time::MONOTONIC_CLOCK_ID, unit) }`
|
|
832
|
-
# @return [Proc<Numeric>]
|
|
821
|
+
# Deprecated and no longer does anything.
|
|
822
|
+
# This gem already takes care to not be affected by timecop.
|
|
823
|
+
# DEV-3.0: Remove `get_time_provider` option
|
|
833
824
|
option :get_time_provider do |o|
|
|
834
|
-
o.default_proc { |unit = :float_second| ::
|
|
825
|
+
o.default_proc { |unit = :float_second| Datadog::Core::Utils::Time.get_time(unit) }
|
|
835
826
|
o.type :proc
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
827
|
+
o.after_set do |_, _, precedence|
|
|
828
|
+
unless precedence == Datadog::Core::Configuration::Option::Precedence::DEFAULT
|
|
829
|
+
unless defined?(Datadog::CI) # the datadog-ci gem needs to work with any datadog gem version and not warn
|
|
830
|
+
Core.log_deprecation(key: :get_time_provider) do
|
|
831
|
+
"The get_time_provider setting has been deprecated for removal " \
|
|
832
|
+
"and no longer does anything. Please remove it from your Datadog.configure block. " \
|
|
833
|
+
"The datadog gem always uses the real non-mocked time, even when the timecop gem monkey-patches Process.clock_gettime."
|
|
834
|
+
end
|
|
835
|
+
end
|
|
844
836
|
end
|
|
845
837
|
end
|
|
846
838
|
end
|
|
@@ -24,6 +24,7 @@ module Datadog
|
|
|
24
24
|
"DD_API_SECURITY_REQUEST_SAMPLE_RATE",
|
|
25
25
|
"DD_API_SECURITY_SAMPLE_DELAY",
|
|
26
26
|
"DD_APM_TRACING_ENABLED",
|
|
27
|
+
"DD_APPSEC_AGENTIC_ONBOARDING",
|
|
27
28
|
"DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING",
|
|
28
29
|
"DD_APPSEC_AUTO_USER_INSTRUMENTATION_MODE",
|
|
29
30
|
"DD_APPSEC_BODY_PARSING_SIZE_LIMIT",
|
|
@@ -60,6 +61,7 @@ module Datadog
|
|
|
60
61
|
"DD_ERROR_TRACKING_HANDLED_ERRORS_INCLUDE",
|
|
61
62
|
"DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED",
|
|
62
63
|
"DD_EXPERIMENTAL_FLAGGING_PROVIDER_SPAN_ENRICHMENT_ENABLED",
|
|
64
|
+
"DD_EXPERIMENTAL_NATIVE_TRANSPORT_ENABLED",
|
|
63
65
|
"DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED",
|
|
64
66
|
"DD_EXTERNAL_ENV",
|
|
65
67
|
"DD_FLAGGING_EVALUATION_COUNTS_ENABLED",
|
|
@@ -85,6 +87,7 @@ module Datadog
|
|
|
85
87
|
"DD_PROFILING_EXPERIMENTAL_HEAP_ENABLED",
|
|
86
88
|
"DD_PROFILING_EXPERIMENTAL_HEAP_SAMPLE_RATE",
|
|
87
89
|
"DD_PROFILING_EXPERIMENTAL_HEAP_SIZE_ENABLED",
|
|
90
|
+
"DD_PROFILING_EXPERIMENTAL_SHOW_CLASSES_ENABLED",
|
|
88
91
|
"DD_PROFILING_EXPERIMENTAL_USE_SYSTEM_DNS",
|
|
89
92
|
"DD_PROFILING_GC_ENABLED",
|
|
90
93
|
"DD_PROFILING_GVL_ENABLED",
|
|
@@ -59,9 +59,9 @@ module Datadog
|
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
def available?
|
|
62
|
-
defined?(::RubyVM::YJIT) \
|
|
62
|
+
!!(defined?(::RubyVM::YJIT) \
|
|
63
63
|
&& ::RubyVM::YJIT.enabled? \
|
|
64
|
-
&& ::RubyVM::YJIT.respond_to?(:runtime_stats)
|
|
64
|
+
&& ::RubyVM::YJIT.respond_to?(:runtime_stats))
|
|
65
65
|
end
|
|
66
66
|
end
|
|
67
67
|
end
|
|
@@ -6,6 +6,12 @@ module Datadog
|
|
|
6
6
|
# Monkey patches `Kernel#fork` and similar functions, adding an `at_fork` callback mechanism which
|
|
7
7
|
# is used to restart observability after the VM forks (e.g. in multiprocess Ruby apps).
|
|
8
8
|
module AtForkMonkeyPatch
|
|
9
|
+
AT_FORK_BEFORE_BLOCKS = [] # rubocop:disable Style/MutableConstant -- Used to store blocks to run, mutable by design.
|
|
10
|
+
private_constant :AT_FORK_BEFORE_BLOCKS
|
|
11
|
+
|
|
12
|
+
AT_FORK_PARENT_BLOCKS = [] # rubocop:disable Style/MutableConstant -- Used to store blocks to run, mutable by design.
|
|
13
|
+
private_constant :AT_FORK_PARENT_BLOCKS
|
|
14
|
+
|
|
9
15
|
AT_FORK_CHILD_BLOCKS = [] # rubocop:disable Style/MutableConstant -- Used to store blocks to run, mutable by design.
|
|
10
16
|
private_constant :AT_FORK_CHILD_BLOCKS
|
|
11
17
|
|
|
@@ -32,19 +38,41 @@ module Datadog
|
|
|
32
38
|
end
|
|
33
39
|
|
|
34
40
|
def self.run_at_fork_blocks(stage)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
AT_FORK_CHILD_BLOCKS.each(&:call)
|
|
41
|
+
blocks_for(stage).each(&:call)
|
|
38
42
|
end
|
|
39
43
|
|
|
44
|
+
# Registers a block to run at the given fork +stage+ (+:before+,
|
|
45
|
+
# +:parent+, or +:child+).
|
|
46
|
+
#
|
|
47
|
+
# Returns the registered block so callers can keep a handle to it and
|
|
48
|
+
# later deregister it via {.remove_at_fork}.
|
|
40
49
|
def self.at_fork(stage, &block)
|
|
41
|
-
raise(ArgumentError, "Unsupported stage #{stage}") unless stage == :child
|
|
42
50
|
raise(ArgumentError, "Missing block argument") unless block
|
|
43
51
|
|
|
44
|
-
|
|
52
|
+
blocks_for(stage) << block
|
|
45
53
|
|
|
46
|
-
|
|
54
|
+
block
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Deregisters a block previously registered with {.at_fork} for the given
|
|
58
|
+
# +stage+. It is a no-op (does not raise) when +block+ was never
|
|
59
|
+
# registered (or was already removed). Raises +ArgumentError+ for an
|
|
60
|
+
# unknown stage, matching the {.at_fork} contract.
|
|
61
|
+
def self.remove_at_fork(stage, block)
|
|
62
|
+
blocks_for(stage).delete(block)
|
|
63
|
+
|
|
64
|
+
nil
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def self.blocks_for(stage)
|
|
68
|
+
case stage
|
|
69
|
+
when :before then AT_FORK_BEFORE_BLOCKS
|
|
70
|
+
when :parent then AT_FORK_PARENT_BLOCKS
|
|
71
|
+
when :child then AT_FORK_CHILD_BLOCKS
|
|
72
|
+
else raise(ArgumentError, "Unsupported stage #{stage}")
|
|
73
|
+
end
|
|
47
74
|
end
|
|
75
|
+
private_class_method :blocks_for
|
|
48
76
|
|
|
49
77
|
# Adds `at_fork` behavior; see parent module for details.
|
|
50
78
|
module KernelMonkeyPatch
|
|
@@ -59,15 +87,29 @@ module Datadog
|
|
|
59
87
|
end
|
|
60
88
|
end
|
|
61
89
|
|
|
90
|
+
# Run pre-fork callbacks in the parent, just before forking.
|
|
91
|
+
AtForkMonkeyPatch.run_at_fork_blocks(:before)
|
|
92
|
+
|
|
62
93
|
# Start fork
|
|
63
94
|
# If a block is provided, use the wrapped version.
|
|
64
|
-
|
|
95
|
+
begin
|
|
96
|
+
result = child_block.nil? ? super : super(&child_block)
|
|
97
|
+
rescue Exception # rubocop:disable Lint/RescueException -- re-raised unchanged; we only need to run parent cleanup first
|
|
98
|
+
# The fork failed and we are still in the parent; run `:parent` to
|
|
99
|
+
# restore any state the `:before` blocks set up, then re-raise.
|
|
100
|
+
AtForkMonkeyPatch.run_at_fork_blocks(:parent)
|
|
101
|
+
raise
|
|
102
|
+
end
|
|
65
103
|
|
|
66
104
|
# When fork gets called without a block, it returns twice:
|
|
67
105
|
# If we're in the fork, result = nil: trigger child callbacks.
|
|
68
|
-
# If we're in the parent, result = pid:
|
|
106
|
+
# If we're in the parent, result = pid: trigger parent callbacks.
|
|
69
107
|
# (If it gets called with a block, it only returns on the parent)
|
|
70
|
-
|
|
108
|
+
if result.nil?
|
|
109
|
+
AtForkMonkeyPatch.run_at_fork_blocks(:child)
|
|
110
|
+
else
|
|
111
|
+
AtForkMonkeyPatch.run_at_fork_blocks(:parent)
|
|
112
|
+
end
|
|
71
113
|
|
|
72
114
|
result
|
|
73
115
|
end
|
|
@@ -78,9 +120,24 @@ module Datadog
|
|
|
78
120
|
# Hook provided by Ruby 3.1+ for observability libraries that want to know about fork, see
|
|
79
121
|
# https://github.com/ruby/ruby/pull/5017 and https://bugs.ruby-lang.org/issues/17795
|
|
80
122
|
def _fork
|
|
81
|
-
|
|
123
|
+
AtForkMonkeyPatch.run_at_fork_blocks(:before)
|
|
124
|
+
|
|
125
|
+
begin
|
|
126
|
+
pid = super
|
|
127
|
+
rescue Exception # rubocop:disable Lint/RescueException -- re-raised unchanged; we only need to run parent cleanup first
|
|
128
|
+
# The fork failed, so no child was created and we are still in the
|
|
129
|
+
# parent. The `:before` blocks already ran (and may hold resources,
|
|
130
|
+
# e.g. a locked mutex); run the `:parent` blocks so that state is
|
|
131
|
+
# restored, then re-raise.
|
|
132
|
+
AtForkMonkeyPatch.run_at_fork_blocks(:parent)
|
|
133
|
+
raise
|
|
134
|
+
end
|
|
82
135
|
|
|
83
|
-
|
|
136
|
+
if pid == 0
|
|
137
|
+
AtForkMonkeyPatch.run_at_fork_blocks(:child)
|
|
138
|
+
else
|
|
139
|
+
AtForkMonkeyPatch.run_at_fork_blocks(:parent)
|
|
140
|
+
end
|
|
84
141
|
|
|
85
142
|
pid
|
|
86
143
|
end
|
|
@@ -89,8 +146,19 @@ module Datadog
|
|
|
89
146
|
# keeps executing code in the child process, killing off the parent, thus effectively replacing it.
|
|
90
147
|
# This is not covered by `_fork` and thus we have some extra code for it.
|
|
91
148
|
def daemon(*args)
|
|
92
|
-
|
|
149
|
+
AtForkMonkeyPatch.run_at_fork_blocks(:before)
|
|
150
|
+
|
|
151
|
+
begin
|
|
152
|
+
result = super
|
|
153
|
+
rescue Exception # rubocop:disable Lint/RescueException -- re-raised unchanged; we only need to run parent cleanup first
|
|
154
|
+
# `daemon` failed, so the original process survives; run `:parent`
|
|
155
|
+
# to restore state the `:before` blocks set up, then re-raise.
|
|
156
|
+
AtForkMonkeyPatch.run_at_fork_blocks(:parent)
|
|
157
|
+
raise
|
|
158
|
+
end
|
|
93
159
|
|
|
160
|
+
# `daemon` kills the parent, so there is no surviving parent to run
|
|
161
|
+
# `:parent` callbacks in; only the child continues executing.
|
|
94
162
|
AtForkMonkeyPatch.run_at_fork_blocks(:child)
|
|
95
163
|
|
|
96
164
|
result
|
|
@@ -5,18 +5,15 @@ module Datadog
|
|
|
5
5
|
module Utils
|
|
6
6
|
# Generates values from a consistent sequence
|
|
7
7
|
class Sequence
|
|
8
|
-
def initialize(seed = 0
|
|
8
|
+
def initialize(seed = 0)
|
|
9
9
|
@seed = seed
|
|
10
10
|
@current = seed
|
|
11
|
-
@next_item = block
|
|
12
11
|
end
|
|
13
12
|
|
|
14
13
|
def next
|
|
15
|
-
|
|
16
|
-
# @type ivar @next_item: ^(::Integer) -> Integer
|
|
17
|
-
next_item = @next_item ? @next_item.call(@current) : @current
|
|
14
|
+
current = @current
|
|
18
15
|
@current += 1
|
|
19
|
-
|
|
16
|
+
current
|
|
20
17
|
end
|
|
21
18
|
|
|
22
19
|
def reset!
|
|
@@ -5,7 +5,16 @@ module Datadog
|
|
|
5
5
|
module Utils
|
|
6
6
|
# Common database-related utility functions.
|
|
7
7
|
module Time
|
|
8
|
-
|
|
8
|
+
# timecop monkey-patches Time.now, Process.clock_gettime, etc:
|
|
9
|
+
# https://github.com/travisjeffery/timecop/blob/v0.9.11/lib/timecop/time_extensions.rb
|
|
10
|
+
# It keeps the original methods as aliases.
|
|
11
|
+
# We want the real not-mocked time here, so we use those aliases to the original method if present.
|
|
12
|
+
# If not present we assume these methods have not been monkey-patched and are the original.
|
|
13
|
+
|
|
14
|
+
original_clock_gettime_name = Process.respond_to?(:clock_gettime_without_mock) ? :clock_gettime_without_mock : :clock_gettime
|
|
15
|
+
define_singleton_method(:original_clock_gettime, &Process.method(original_clock_gettime_name))
|
|
16
|
+
|
|
17
|
+
MONOTONIC_CLOCK_ID = RUBY_PLATFORM.include?("darwin") ? Process::CLOCK_MONOTONIC_RAW : Process::CLOCK_MONOTONIC
|
|
9
18
|
|
|
10
19
|
# Current monotonic time
|
|
11
20
|
# On macOS, CLOCK_MONOTONIC only has microsecond precision,
|
|
@@ -13,71 +22,24 @@ module Datadog
|
|
|
13
22
|
#
|
|
14
23
|
# @param unit [Symbol] unit for the resulting value, same as ::Process#clock_gettime, defaults to :float_second
|
|
15
24
|
# @return [Float|Integer] timestamp in the requested unit, since some unspecified starting point
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def get_time(unit = :float_second)
|
|
19
|
-
Process.clock_gettime(MONOTONIC_CLOCK_ID, unit)
|
|
25
|
+
def self.get_time(unit = :float_second)
|
|
26
|
+
original_clock_gettime(MONOTONIC_CLOCK_ID, unit)
|
|
20
27
|
end
|
|
21
28
|
|
|
22
29
|
# Current wall time.
|
|
23
30
|
#
|
|
24
31
|
# @return [Time] current time object
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# Overrides the implementation of `#now
|
|
30
|
-
# with the provided callable.
|
|
31
|
-
#
|
|
32
|
-
# Overriding the method `#now` instead of
|
|
33
|
-
# indirectly calling `block` removes
|
|
34
|
-
# one level of method call overhead.
|
|
35
|
-
#
|
|
36
|
-
# @param block [Proc] block that returns a `Time` object representing the current wall time
|
|
37
|
-
def now_provider=(block)
|
|
38
|
-
class << self
|
|
39
|
-
# Avoid method redefinition warning.
|
|
40
|
-
# `rescue nil` is added in case customers remove the method
|
|
41
|
-
# themselves to squelch the warning.
|
|
42
|
-
begin
|
|
43
|
-
remove_method(:now)
|
|
44
|
-
rescue
|
|
45
|
-
nil
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
define_singleton_method(:now, &block)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# Overrides the implementation of `#get_time
|
|
52
|
-
# with the provided callable.
|
|
53
|
-
#
|
|
54
|
-
# Overriding the method `#get_time` instead of
|
|
55
|
-
# indirectly calling `block` removes
|
|
56
|
-
# one level of method call overhead.
|
|
57
|
-
#
|
|
58
|
-
# @param block [Proc] block that accepts unit and returns timestamp in the requested unit
|
|
59
|
-
def get_time_provider=(block)
|
|
60
|
-
class << self
|
|
61
|
-
# Avoid method redefinition warning
|
|
62
|
-
# `rescue nil` is added in case customers remove the method
|
|
63
|
-
# themselves to squelch the warning.
|
|
64
|
-
begin
|
|
65
|
-
remove_method(:get_time)
|
|
66
|
-
rescue
|
|
67
|
-
nil
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
define_singleton_method(:get_time, &block)
|
|
71
|
-
end
|
|
32
|
+
original_time_now_name = ::Time.respond_to?(:now_without_mock_time) ? :now_without_mock_time : :now
|
|
33
|
+
define_singleton_method(:now, &::Time.method(original_time_now_name))
|
|
72
34
|
|
|
73
|
-
def measure(unit = :float_second)
|
|
35
|
+
def self.measure(unit = :float_second)
|
|
74
36
|
before = get_time(unit)
|
|
75
37
|
yield
|
|
76
38
|
after = get_time(unit)
|
|
77
39
|
after - before
|
|
78
40
|
end
|
|
79
41
|
|
|
80
|
-
def as_utc_epoch_ns(time)
|
|
42
|
+
def self.as_utc_epoch_ns(time)
|
|
81
43
|
# we use #to_r instead of #to_f because Float doesn't have enough precision to represent exact nanoseconds, see
|
|
82
44
|
# https://rubyapi.org/3.0/o/time#method-i-to_f
|
|
83
45
|
(time.to_r * 1_000_000_000).to_i
|