diff --git a/.github/workflows/test-memory-leaks.yaml b/.github/workflows/test-memory-leaks.yaml index 95453a5d3a0..a80a55da14d 100644 --- a/.github/workflows/test-memory-leaks.yaml +++ b/.github/workflows/test-memory-leaks.yaml @@ -11,7 +11,7 @@ jobs: bundler-cache: true # runs 'bundle install' and caches installed gems automatically bundler: latest cache-version: v1 # bump this to invalidate cache - - run: sudo apt update && sudo apt install -y valgrind && valgrind --version + - run: sudo apt-get update && (sudo apt-get install -y valgrind || sleep 5 && sudo apt-get install -y valgrind) && valgrind --version - run: bundle exec rake compile spec:profiling:memcheck test-asan: # Temporarily disabled on 2024-09-17 until ruby-asan builds are available again on diff --git a/Gemfile b/Gemfile index 38384131c01..d25788ece52 100644 --- a/Gemfile +++ b/Gemfile @@ -82,8 +82,8 @@ end group :check do if RUBY_VERSION >= '3.0.0' && RUBY_PLATFORM != 'java' - gem 'rbs', '~> 3.2.0', require: false - gem 'steep', '~> 1.6.0', require: false + gem 'rbs', '~> 3.5.0', require: false + gem 'steep', '~> 1.7.0', require: false end gem 'ruby_memcheck', '>= 3' if RUBY_VERSION >= '3.4.0' && RUBY_PLATFORM != 'java' gem 'standard', require: false diff --git a/Steepfile b/Steepfile index dfae78bba26..853aa813e01 100644 --- a/Steepfile +++ b/Steepfile @@ -5,6 +5,8 @@ target :datadog do ignore 'lib/datadog/appsec.rb' ignore 'lib/datadog/appsec/component.rb' + # Excluded due to https://github.com/soutaro/steep/issues/1232 + ignore 'lib/datadog/appsec/configuration/settings.rb' ignore 'lib/datadog/appsec/contrib/' ignore 'lib/datadog/appsec/contrib/auto_instrument.rb' ignore 'lib/datadog/appsec/contrib/integration.rb' @@ -69,6 +71,8 @@ target :datadog do ignore 'lib/datadog/core/metrics/options.rb' ignore 'lib/datadog/core/pin.rb' ignore 'lib/datadog/core/rate_limiter.rb' + # steep fails in this file due to https://github.com/soutaro/steep/issues/1231 + ignore 'lib/datadog/core/remote/tie.rb' ignore 'lib/datadog/core/runtime/ext.rb' ignore 'lib/datadog/core/runtime/metrics.rb' ignore 'lib/datadog/core/transport/ext.rb' diff --git a/lib/datadog/core/configuration/settings.rb b/lib/datadog/core/configuration/settings.rb index 45835ddcdcf..31cddb33bf4 100644 --- a/lib/datadog/core/configuration/settings.rb +++ b/lib/datadog/core/configuration/settings.rb @@ -654,6 +654,33 @@ def initialize(*_) end end + # The monotonic clock time provider used by Datadog. This option is internal and is used by `datadog-ci` + # gem to avoid traces' durations being skewed by timecop. + # + # It must respect the interface of [Datadog::Core::Utils::Time#get_time] method. + # + # For [Timecop](https://rubygems.org/gems/timecop), for example, + # `->(unit = :float_second) { ::Process.clock_gettime_without_mock(::Process::CLOCK_MONOTONIC, unit) }` + # allows Datadog features to use the real monotonic time when time is frozen with + # `Timecop.mock_process_clock = true`. + # + # @default `->(unit = :float_second) { ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, unit)}` + # @return [Proc] + option :get_time_provider do |o| + o.default_proc { |unit = :float_second| ::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| + ->(unit = :float_second) { ::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` diff --git a/lib/datadog/core/environment/execution.rb b/lib/datadog/core/environment/execution.rb index 2049773a8d4..6d4a084ebec 100644 --- a/lib/datadog/core/environment/execution.rb +++ b/lib/datadog/core/environment/execution.rb @@ -25,9 +25,9 @@ def development? # 2. Checking if `Net::HTTP` is referring to the original one # => ::Net::HTTP.equal?(::WebMock::HttpLibAdapters::NetHttpAdapter::OriginalNetHTTP) def webmock_enabled? - defined?(::WebMock::HttpLibAdapters::NetHttpAdapter) && + !!(defined?(::WebMock::HttpLibAdapters::NetHttpAdapter) && defined?(::Net::HTTP) && - ::Net::HTTP.equal?(::WebMock::HttpLibAdapters::NetHttpAdapter.instance_variable_get(:@webMockNetHTTP)) + ::Net::HTTP.equal?(::WebMock::HttpLibAdapters::NetHttpAdapter.instance_variable_get(:@webMockNetHTTP))) end private @@ -68,7 +68,7 @@ def minitest? # Check if we are running from `bin/cucumber` or `cucumber/rake/task`. def cucumber? - defined?(::Cucumber::Cli) + !!defined?(::Cucumber::Cli) end # If this is a Rails application, use different heuristics to detect @@ -80,7 +80,7 @@ def rails_development? # detecting its presence is enough to deduct if this is a development environment. # # @see https://github.com/rails/spring/blob/48b299348ace2188444489a0c216a6f3e9687281/README.md?plain=1#L204-L207 - defined?(::Spring) || rails_env_development? + !!defined?(::Spring) || rails_env_development? end RAILS_ENV_DEVELOPMENT = Set['development', 'test'].freeze @@ -94,7 +94,7 @@ def rails_development? # it's common to have a custom "staging" environment, and such environment normally want to run as close # to production as possible. def rails_env_development? - defined?(::Rails.env) && RAILS_ENV_DEVELOPMENT.include?(::Rails.env) + !!defined?(::Rails.env) && RAILS_ENV_DEVELOPMENT.include?(::Rails.env) end end end diff --git a/lib/datadog/core/remote/tie.rb b/lib/datadog/core/remote/tie.rb index f4279a471ba..ef0d331529a 100644 --- a/lib/datadog/core/remote/tie.rb +++ b/lib/datadog/core/remote/tie.rb @@ -19,6 +19,8 @@ def self.boot barrier = Datadog::Core::Remote.active_remote.barrier(:once) end + # steep does not permit the next line due to + # https://github.com/soutaro/steep/issues/1231 Boot.new(barrier, t) end end diff --git a/lib/datadog/core/utils/time.rb b/lib/datadog/core/utils/time.rb index 20b1c473914..79367097e05 100644 --- a/lib/datadog/core/utils/time.rb +++ b/lib/datadog/core/utils/time.rb @@ -34,6 +34,18 @@ 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 + def get_time_provider=(block) + define_singleton_method(:get_time, &block) + end + def measure(unit = :float_second) before = get_time(unit) yield diff --git a/lib/datadog/tracing/contrib/active_record/events/instantiation.rb b/lib/datadog/tracing/contrib/active_record/events/instantiation.rb index 0d0cf07b6cc..fb0d4465f53 100644 --- a/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +++ b/lib/datadog/tracing/contrib/active_record/events/instantiation.rb @@ -4,6 +4,7 @@ require_relative '../../analytics' require_relative '../ext' require_relative '../event' +require_relative '../../../../core/telemetry/logger' module Datadog module Tracing @@ -48,7 +49,8 @@ def on_start(span, event, _id, payload) span.set_tag(Ext::TAG_INSTANTIATION_CLASS_NAME, payload.fetch(:class_name)) span.set_tag(Ext::TAG_INSTANTIATION_RECORD_COUNT, payload.fetch(:record_count)) rescue StandardError => e - Datadog.logger.debug(e.message) + Datadog.logger.error(e.message) + Datadog::Core::Telemetry::Logger.report(e) end end end diff --git a/lib/datadog/tracing/contrib/active_record/events/sql.rb b/lib/datadog/tracing/contrib/active_record/events/sql.rb index 1e1c1a87382..8640ac43aa9 100644 --- a/lib/datadog/tracing/contrib/active_record/events/sql.rb +++ b/lib/datadog/tracing/contrib/active_record/events/sql.rb @@ -6,6 +6,7 @@ require_relative '../ext' require_relative '../../analytics' require_relative '../../utils/database' +require_relative '../../../../core/telemetry/logger' module Datadog module Tracing @@ -68,7 +69,8 @@ def on_start(span, event, _id, payload) span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_HOST, config[:host]) if config[:host] span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_PORT, config[:port]) if config[:port] rescue StandardError => e - Datadog.logger.debug(e.message) + Datadog.logger.error(e.message) + Datadog::Core::Telemetry::Logger.report(e) end end end diff --git a/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb b/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb index 2abec4c1d26..0b8820c8fec 100644 --- a/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +++ b/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb @@ -2,6 +2,7 @@ require_relative '../../ext' require_relative '../event' +require_relative '../../../../../core/telemetry/logger' module Datadog module Tracing @@ -64,7 +65,7 @@ def on_start(span, event, _id, payload) key = payload[:key] store = payload[:store] - mapping = MAPPING[event] + mapping = MAPPING.fetch(event) span.service = configuration[:cache_service] span.resource = mapping[:resource] @@ -81,6 +82,9 @@ def on_start(span, event, _id, payload) span.set_tag('EVENT', event) set_cache_key(span, key, mapping[:multi_key]) + rescue StandardError => e + Datadog.logger.error(e.message) + Datadog::Core::Telemetry::Logger.report(e) end def set_cache_key(span, key, multi_key) diff --git a/lib/datadog/tracing/contrib/aws/instrumentation.rb b/lib/datadog/tracing/contrib/aws/instrumentation.rb index 7194ef9ae01..a19ea684877 100644 --- a/lib/datadog/tracing/contrib/aws/instrumentation.rb +++ b/lib/datadog/tracing/contrib/aws/instrumentation.rb @@ -29,6 +29,7 @@ def call(context) private # rubocop:disable Metrics/AbcSize + # rubocop:disable Metrics/MethodLength def annotate!(span, context) span.service = configuration[:service_name] span.type = Tracing::Metadata::Ext::HTTP::TYPE_OUTBOUND @@ -76,7 +77,11 @@ def annotate!(span, context) span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_STATUS_CODE, context.safely(:status_code)) Contrib::SpanAttributeSchema.set_peer_service!(span, Ext::PEER_SERVICE_SOURCES) + rescue StandardError => e + Datadog.logger.error(e.message) + Datadog::Core::Telemetry::Logger.report(e) end + # rubocop:enable Metrics/MethodLength # rubocop:enable Metrics/AbcSize def configuration diff --git a/lib/datadog/tracing/contrib/faraday/middleware.rb b/lib/datadog/tracing/contrib/faraday/middleware.rb index 1134fb9379a..9bdea9c364b 100644 --- a/lib/datadog/tracing/contrib/faraday/middleware.rb +++ b/lib/datadog/tracing/contrib/faraday/middleware.rb @@ -7,6 +7,7 @@ require_relative '../analytics' require_relative 'ext' require_relative '../http_annotation_helper' +require_relative '../../../core/telemetry/logger' module Datadog module Tracing @@ -37,6 +38,7 @@ def call(env) attr_reader :app + # rubocop:disable Metrics/AbcSize def annotate!(span, env, options) span.resource = resource_name(env) span.service = service_name(env[:url].host, options) @@ -75,7 +77,11 @@ def annotate!(span, env, options) ) Contrib::SpanAttributeSchema.set_peer_service!(span, Ext::PEER_SERVICE_SOURCES) + rescue StandardError => e + Datadog.logger.error(e.message) + Datadog::Core::Telemetry::Logger.report(e) end + # rubocop:enable Metrics/AbcSize def handle_response(span, env, options) span.set_error(["Error #{env[:status]}", env[:body]]) if options[:error_status_codes].include? env[:status] @@ -85,6 +91,9 @@ def handle_response(span, env, options) span.set_tags( Datadog.configuration.tracing.header_tags.response_tags(env[:response_headers]) ) + rescue StandardError => e + Datadog.logger.error(e.message) + Datadog::Core::Telemetry::Logger.report(e) end def propagate!(trace, span, env) diff --git a/lib/datadog/tracing/contrib/httpclient/instrumentation.rb b/lib/datadog/tracing/contrib/httpclient/instrumentation.rb index 5a600970870..5cbc784bf59 100644 --- a/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +++ b/lib/datadog/tracing/contrib/httpclient/instrumentation.rb @@ -102,6 +102,9 @@ def annotate_span_with_response!(span, response, request_options) span.set_tags( Datadog.configuration.tracing.header_tags.response_tags(response.header) ) + rescue StandardError => e + Datadog.logger.error("error preparing span from httpclient response: #{e}, Source: #{e.backtrace}") + Datadog::Core::Telemetry::Logger.report(e) end def annotate_span_with_error!(span, error) diff --git a/lib/datadog/tracing/contrib/httprb/instrumentation.rb b/lib/datadog/tracing/contrib/httprb/instrumentation.rb index b935d3bd14b..c39916ebb4a 100644 --- a/lib/datadog/tracing/contrib/httprb/instrumentation.rb +++ b/lib/datadog/tracing/contrib/httprb/instrumentation.rb @@ -110,6 +110,9 @@ def annotate_span_with_response!(span, response, request_options) span.set_tags( Datadog.configuration.tracing.header_tags.response_tags(response.headers) ) + rescue StandardError => e + logger.error("error preparing span from http.rb response: #{e}, Source: #{e.backtrace}") + Datadog::Core::Telemetry::Logger.report(e) end def annotate_span_with_error!(span, error) diff --git a/lib/datadog/tracing/contrib/mongodb/subscribers.rb b/lib/datadog/tracing/contrib/mongodb/subscribers.rb index 06e67add3ef..fe34da1ad9e 100644 --- a/lib/datadog/tracing/contrib/mongodb/subscribers.rb +++ b/lib/datadog/tracing/contrib/mongodb/subscribers.rb @@ -70,6 +70,8 @@ def started(event) # set the resource with the quantized query span.resource = serialized_query + rescue StandardError => e + Datadog.logger.debug("error when handling MongoDB 'started' event: #{e}") end # rubocop:enable Metrics/AbcSize diff --git a/lib/datadog/tracing/contrib/redis/tags.rb b/lib/datadog/tracing/contrib/redis/tags.rb index 6e8feb49029..98de54f41a9 100644 --- a/lib/datadog/tracing/contrib/redis/tags.rb +++ b/lib/datadog/tracing/contrib/redis/tags.rb @@ -4,6 +4,7 @@ require_relative '../analytics' require_relative 'ext' require_relative '../ext' +require_relative '../../../core/telemetry/logger' module Datadog module Tracing @@ -45,6 +46,9 @@ def set_common_tags(client, span, raw_command) span.set_tag Ext::TAG_RAW_COMMAND, raw_command Contrib::SpanAttributeSchema.set_peer_service!(span, Ext::PEER_SERVICE_SOURCES) + rescue StandardError => e + Datadog.logger.error(e.message) + Datadog::Core::Telemetry::Logger.report(e) end private diff --git a/sig/datadog/core/remote/tie.rbs b/sig/datadog/core/remote/tie.rbs index b4af9d4f2d4..793db6c802d 100644 --- a/sig/datadog/core/remote/tie.rbs +++ b/sig/datadog/core/remote/tie.rbs @@ -2,14 +2,14 @@ module Datadog module Core module Remote module Tie - class Boot < ::Struct[untyped] + class Boot < ::Struct[[Component::Barrier, Numeric]] def initialize: (Component::Barrier? barrier, Numeric? time) -> void attr_reader barrier: Component::Barrier attr_reader time: Numeric end - def self.boot: () -> (nil | Boot) + def self.boot: () -> Boot? end end end diff --git a/sig/datadog/core/telemetry/event.rbs b/sig/datadog/core/telemetry/event.rbs index 12fd27713c1..4818992176f 100644 --- a/sig/datadog/core/telemetry/event.rbs +++ b/sig/datadog/core/telemetry/event.rbs @@ -24,7 +24,7 @@ module Datadog def agent_transport: (untyped config) -> String - def conf_value: (String name, Object value, Integer seq_id, ?String origin) -> Hash[Symbol, untyped] + def conf_value: (String name, untyped value, Integer seq_id, ?String origin) -> Hash[Symbol, untyped] def to_value: (Object value) -> Object diff --git a/sig/datadog/core/utils/time.rbs b/sig/datadog/core/utils/time.rbs index 74aeb383b29..39a01face69 100644 --- a/sig/datadog/core/utils/time.rbs +++ b/sig/datadog/core/utils/time.rbs @@ -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 diff --git a/spec/datadog/core/configuration/settings_spec.rb b/spec/datadog/core/configuration/settings_spec.rb index a9c12188b95..8703f477afc 100644 --- a/spec/datadog/core/configuration/settings_spec.rb +++ b/spec/datadog/core/configuration/settings_spec.rb @@ -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 + + ->(unit) { unit == :float_millisecond ? new_milliseconds : new_seconds } + 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 diff --git a/spec/datadog/tracing/contrib/active_record/events/instantiation_spec.rb b/spec/datadog/tracing/contrib/active_record/events/instantiation_spec.rb new file mode 100644 index 00000000000..c0a08a0ec39 --- /dev/null +++ b/spec/datadog/tracing/contrib/active_record/events/instantiation_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' +require 'datadog/tracing/contrib/active_record/events/instantiation' +require 'datadog/tracing/span_operation' + +RSpec.describe Datadog::Tracing::Contrib::ActiveRecord::Events::Instantiation do + describe '.event_name' do + it 'returns the correct event name' do + expect(described_class.event_name).to eq('instantiation.active_record') + end + end + + describe '.span_name' do + it 'returns the correct span name' do + expect(described_class.span_name).to eq('active_record.instantiation') + end + end + + describe '.on_start' do + context 'when an error occurs' do + let(:span) { Datadog::Tracing::SpanOperation.new('fake') } + + it 'logs the error' do + expect(Datadog.logger).to receive(:error).with(/key not found/) + expect(Datadog::Core::Telemetry::Logger).to receive(:report).with(a_kind_of(StandardError)) + + expect do + described_class.on_start(span, double, double, {}) + end.not_to raise_error + end + end + end +end diff --git a/spec/datadog/tracing/contrib/active_record/events/sql_spec.rb b/spec/datadog/tracing/contrib/active_record/events/sql_spec.rb new file mode 100644 index 00000000000..7bacaac6d25 --- /dev/null +++ b/spec/datadog/tracing/contrib/active_record/events/sql_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' +require 'datadog/tracing/contrib/active_record/events/sql' +require 'datadog/tracing/span_operation' + +require 'active_record' + +RSpec.describe Datadog::Tracing::Contrib::ActiveRecord::Events::SQL do + describe '.event_name' do + it 'returns the correct event name' do + expect(described_class.event_name).to eq('sql.active_record') + end + end + + describe '.span_name' do + it 'returns the correct span name' do + expect(described_class.span_name).to eq('active_record.sql') + end + end + + describe '.on_start' do + context 'when an error occurs' do + let(:span) { Datadog::Tracing::SpanOperation.new('fake') } + + it 'logs the error' do + expect(Datadog.logger).to receive(:error).with(/key not found/) + expect(Datadog::Core::Telemetry::Logger).to receive(:report).with(a_kind_of(StandardError)) + + expect do + described_class.on_start(span, double, double, {}) + end.not_to raise_error + end + end + end +end diff --git a/spec/datadog/tracing/contrib/active_support/cache/events/cache_spec.rb b/spec/datadog/tracing/contrib/active_support/cache/events/cache_spec.rb new file mode 100644 index 00000000000..f0df41028b5 --- /dev/null +++ b/spec/datadog/tracing/contrib/active_support/cache/events/cache_spec.rb @@ -0,0 +1,20 @@ +require 'spec_helper' +require 'datadog/tracing/contrib/active_support/cache/events/cache' +require 'datadog/tracing/span_operation' + +RSpec.describe Datadog::Tracing::Contrib::ActiveSupport::Cache::Events::Cache do + describe '.on_start' do + context 'when an error occurs' do + let(:span) { Datadog::Tracing::SpanOperation.new('fake') } + + it 'logs the error' do + expect(Datadog.logger).to receive(:error).with(/key not found/) + expect(Datadog::Core::Telemetry::Logger).to receive(:report).with(a_kind_of(StandardError)) + + expect do + described_class.on_start(span, double, double, {}) + end.not_to raise_error + end + end + end +end diff --git a/spec/datadog/tracing/contrib/redis/tags_spec.rb b/spec/datadog/tracing/contrib/redis/tags_spec.rb new file mode 100644 index 00000000000..895ab09361a --- /dev/null +++ b/spec/datadog/tracing/contrib/redis/tags_spec.rb @@ -0,0 +1,24 @@ +require 'spec_helper' +require 'datadog/tracing/contrib/redis/tags' + +require 'datadog/tracing/span_operation' + +RSpec.describe Datadog::Tracing::Contrib::Redis::Tags do + let(:client) { double('client') } + let(:span) { Datadog::Tracing::SpanOperation.new('fake') } + let(:raw_command) { 'SET key value' } + + describe '.set_common_tags' do + context 'when an error occurs' do + it 'logs the error' do + allow(client).to receive(:host).and_raise(StandardError.new('Oops...')) + expect(Datadog.logger).to receive(:error).with('Oops...') + expect(Datadog::Core::Telemetry::Logger).to receive(:report).with(a_kind_of(StandardError)) + + expect do + described_class.set_common_tags(client, span, raw_command) + end.not_to raise_error + end + end + end +end diff --git a/spec/datadog/tracing/span_operation_spec.rb b/spec/datadog/tracing/span_operation_spec.rb index 6b10bebeb22..5eef0d6a69c 100644 --- a/spec/datadog/tracing/span_operation_spec.rb +++ b/spec/datadog/tracing/span_operation_spec.rb @@ -872,6 +872,27 @@ expect(span_op.end_time - span_op.start_time).to eq 0 end end + + context 'with get_time_provider set' do + let(:clock_increment) { 0.42 } + before do + incr = clock_increment + clock_time = clock_increment + Datadog.configure do |c| + # Use a custom clock provider that increments by `clock_increment` + c.get_time_provider = ->(_unit = :float_second) { clock_time += incr } + end + end + + after { without_warnings { Datadog.configuration.reset! } } + + it 'sets the duration to the provider increment' do + span_op.start + span_op.stop + + expect(span_op.duration).to be_within(0.01).of(clock_increment) + end + end end context 'with start_time provided' do