Skip to content

Commit

Permalink
add new setting get_time_provider that allows redefining Core::Util…
Browse files Browse the repository at this point in the history
…s::Time.get_time method
  • Loading branch information
anmarchenko committed Sep 25, 2024
1 parent 2209a7c commit 64f1297
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 0 deletions.
15 changes: 15 additions & 0 deletions lib/datadog/core/configuration/settings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,21 @@ def initialize(*_)
end
end

option :get_time_provider do |o|
o.default_proc { |unit| ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, unit) }
o.type :proc

o.after_set do |get_time_provider|
Core::Utils::Time.get_time_provider = get_time_provider
end

o.resetter do |_value|
lambda { |unit| ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, unit)}.tap do |default|
Core::Utils::Time.get_time_provider = default
end
end
end

# The `version` tag in Datadog. Use it to enable [Deployment Tracking](https://docs.datadoghq.com/tracing/deployment_tracking/).
# @see https://docs.datadoghq.com/getting_started/tagging/unified_service_tagging
# @default `DD_VERSION` environment variable, otherwise `nils`
Expand Down
13 changes: 13 additions & 0 deletions lib/datadog/core/utils/time.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,19 @@ def now_provider=(block)
define_singleton_method(:now, &block)
end


# Overrides the implementation of `#get_time
# with the provided callable.
#
# Overriding the method `#get_time` instead of
# indirectly calling `block` removes
# one level of method call overhead.
#
# @param block [Proc] block that accepts unit and returns timestamp in the requested unit, since some unspecified starting point
def get_time_provider=(block)
define_singleton_method(:get_time, &block)
end

def measure(unit = :float_second)
before = get_time(unit)
yield
Expand Down
1 change: 1 addition & 0 deletions sig/datadog/core/utils/time.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module Datadog
def self?.get_time: (?::Symbol unit) -> ::Numeric
def self?.now: () -> ::Time
def self?.now_provider=: (^() -> ::Time block) -> void
def self?.get_time_provider=: (^(?::Symbol unit) -> ::Numeric block) -> void
def self?.measure: (?::Symbol unit) { () -> void } -> ::Numeric
def self?.as_utc_epoch_ns: (::Time time) -> ::Integer
end
Expand Down
67 changes: 67 additions & 0 deletions spec/datadog/core/configuration/settings_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1392,6 +1392,73 @@
end
end

describe '#get_time_provider=' do
subject(:set_get_time_provider) { settings.get_time_provider = get_time_provider }

after { settings.reset! }

let(:get_time) { 1 }

let(:get_time_new_milliseconds) { 42 }
let(:get_time_new_seconds) { 0.042 }

let(:unit) { :float_second }
let(:get_time_provider) do
new_milliseconds = get_time_new_milliseconds # Capture for closure
new_seconds = get_time_new_seconds # Capture for closure

lambda { |unit| if unit == :float_millisecond then new_milliseconds else new_seconds end}
end

context 'when default' do
before { allow(Process).to receive(:clock_gettime).with(Process::CLOCK_MONOTONIC, unit).and_return(1) }

it 'delegates to Process.clock_gettime' do
expect(settings.get_time_provider.call(unit)).to eq(get_time)
expect(Datadog::Core::Utils::Time.get_time(unit)).to eq(get_time)
end
end

context 'when given a value' do
before { set_get_time_provider }

context "when unit is :float_second" do
it 'returns the provided time in float seconds' do
expect(settings.get_time_provider.call(unit)).to eq(get_time_new_seconds)
expect(Datadog::Core::Utils::Time.get_time(unit)).to eq(get_time_new_seconds)
end
end

context "when unit is :float_millisecond" do
let(:unit) { :float_millisecond }

it 'returns the provided time in float milliseconds' do
expect(settings.get_time_provider.call(unit)).to eq(get_time_new_milliseconds)
expect(Datadog::Core::Utils::Time.get_time(unit)).to eq(get_time_new_milliseconds)
end
end
end

context 'then reset' do
let(:original_get_time) { 1 }

before do
set_get_time_provider
allow(Process).to receive(:clock_gettime).with(Process::CLOCK_MONOTONIC, unit).and_return(original_get_time)
end

it 'returns the provided time' do
expect(settings.get_time_provider.call(unit)).to eq(get_time_new_seconds)
expect(Datadog::Core::Utils::Time.get_time(unit)).to eq(get_time_new_seconds)

settings.reset!

expect(settings.get_time_provider.call(unit)).to eq(original_get_time)
expect(Datadog::Core::Utils::Time.get_time(unit)).to eq(original_get_time)
end
end
end

# Important note: These settings are used as inputs of the AgentSettingsResolver and are used by all components
# that consume its result (e.g. tracing, profiling, and telemetry, as of January 2023).
describe '#agent' do
Expand Down

0 comments on commit 64f1297

Please sign in to comment.