diff --git a/lib/datadog/core/utils.rb b/lib/datadog/core/utils.rb index 0969ed5498..a38640bb3d 100644 --- a/lib/datadog/core/utils.rb +++ b/lib/datadog/core/utils.rb @@ -1,7 +1,6 @@ # typed: true require_relative 'utils/forking' -require_relative '../tracing/span' module Datadog module Core @@ -11,26 +10,6 @@ module Utils extend Forking EMPTY_STRING = ''.encode(::Encoding::UTF_8).freeze - # We use a custom random number generator because we want no interference - # with the default one. Using the default prng, we could break code that - # would rely on srand/rand sequences. - - # Return a randomly generated integer, valid as a Span ID or Trace ID. - # This method is thread-safe and fork-safe. - def self.next_id - after_fork! { reset! } - id_rng.rand(Tracing::Span::RUBY_ID_RANGE) - end - - def self.id_rng - @id_rng ||= Random.new - end - - def self.reset! - @id_rng = Random.new - end - - private_class_method :id_rng, :reset! # Stringifies `value` and ensures the outcome is # string is no longer than `size`. diff --git a/lib/datadog/opentracer/distributed_headers.rb b/lib/datadog/opentracer/distributed_headers.rb index 0043832ce3..9f42c8aef0 100644 --- a/lib/datadog/opentracer/distributed_headers.rb +++ b/lib/datadog/opentracer/distributed_headers.rb @@ -1,7 +1,7 @@ # typed: true -require_relative '../tracing/span' require_relative '../tracing/distributed/datadog' +require_relative '../tracing/utils' module Datadog module OpenTracer @@ -47,7 +47,7 @@ def origin def id(header) value = @carrier[header].to_i - return if value.zero? || value >= Datadog::Tracing::Span::EXTERNAL_MAX_ID + return if value.zero? || value >= Datadog::Tracing::Utils::EXTERNAL_MAX_ID value < 0 ? value + 0x1_0000_0000_0000_0000 : value end diff --git a/lib/datadog/tracing/distributed/helpers.rb b/lib/datadog/tracing/distributed/helpers.rb index 8839c92698..e0d5d10f9f 100644 --- a/lib/datadog/tracing/distributed/helpers.rb +++ b/lib/datadog/tracing/distributed/helpers.rb @@ -2,6 +2,7 @@ # typed: true require_relative '../sampling/ext' +require_relative '../utils' module Datadog module Tracing @@ -47,7 +48,7 @@ def self.value_to_id(value, base = 10) return if id.nil? # Zero or greater than max allowed value of 2**64 - return if id.zero? || id > Span::EXTERNAL_MAX_ID + return if id.zero? || id > Tracing::Utils::EXTERNAL_MAX_ID id < 0 ? id + (2**64) : id end diff --git a/lib/datadog/tracing/sampling/rate_sampler.rb b/lib/datadog/tracing/sampling/rate_sampler.rb index 7f5bb2910c..b1ac4ae382 100644 --- a/lib/datadog/tracing/sampling/rate_sampler.rb +++ b/lib/datadog/tracing/sampling/rate_sampler.rb @@ -3,7 +3,7 @@ require_relative '../../core' require_relative 'sampler' -require_relative '../span' +require_relative '../utils' module Datadog module Tracing @@ -49,11 +49,11 @@ def sample_rate(*_) def sample_rate=(sample_rate) @sample_rate = sample_rate - @sampling_id_threshold = sample_rate * Tracing::Span::EXTERNAL_MAX_ID + @sampling_id_threshold = sample_rate * Tracing::Utils::EXTERNAL_MAX_ID end def sample?(trace) - ((trace.id * KNUTH_FACTOR) % Tracing::Span::EXTERNAL_MAX_ID) <= @sampling_id_threshold + ((trace.id * KNUTH_FACTOR) % Tracing::Utils::EXTERNAL_MAX_ID) <= @sampling_id_threshold end def sample!(trace) diff --git a/lib/datadog/tracing/span.rb b/lib/datadog/tracing/span.rb index ee0ce054f8..ed9c697cdd 100644 --- a/lib/datadog/tracing/span.rb +++ b/lib/datadog/tracing/span.rb @@ -2,8 +2,8 @@ # typed: true -require_relative '../core/utils' require_relative '../core/utils/safe_dup' +require_relative 'utils' require_relative 'metadata/ext' require_relative 'metadata' @@ -19,22 +19,6 @@ module Tracing class Span include Metadata - # The max value for a {Datadog::Tracing::Span} identifier. - # Span and trace identifiers should be strictly positive and strictly inferior to this limit. - # - # Limited to +2<<62-1+ positive integers, as Ruby is able to represent such numbers "inline", - # inside a +VALUE+ scalar, thus not requiring memory allocation. - # - # The range of IDs also has to consider portability across different languages and platforms. - RUBY_MAX_ID = (1 << 62) - 1 - - # Excludes zero from possible values - RUBY_ID_RANGE = (1..RUBY_MAX_ID).freeze - - # While we only generate 63-bit integers due to limitations in other languages, we support - # parsing 64-bit integers for distributed tracing since an upstream system may generate one - EXTERNAL_MAX_ID = 1 << 64 - attr_accessor \ :end_time, :id, @@ -90,9 +74,9 @@ def initialize( @resource = Core::Utils::SafeDup.frozen_or_dup(resource) @type = Core::Utils::SafeDup.frozen_or_dup(type) - @id = id || Core::Utils.next_id + @id = id || Tracing::Utils.next_id @parent_id = parent_id || 0 - @trace_id = trace_id || Core::Utils.next_id + @trace_id = trace_id || Tracing::Utils.next_id @meta = meta || {} @metrics = metrics || {} diff --git a/lib/datadog/tracing/span_operation.rb b/lib/datadog/tracing/span_operation.rb index 0df9829cd3..66fbb0a1d9 100644 --- a/lib/datadog/tracing/span_operation.rb +++ b/lib/datadog/tracing/span_operation.rb @@ -7,10 +7,11 @@ require_relative '../core/utils' require_relative '../core/utils/time' -require_relative 'metadata/ext' require_relative 'event' -require_relative 'span' require_relative 'metadata' +require_relative 'metadata/ext' +require_relative 'span' +require_relative 'utils' module Datadog module Tracing @@ -61,9 +62,9 @@ def initialize( self.type = type self.resource = resource - @id = Core::Utils.next_id + @id = Tracing::Utils.next_id @parent_id = parent_id || 0 - @trace_id = trace_id || Core::Utils.next_id + @trace_id = trace_id || Tracing::Utils.next_id @status = 0 diff --git a/lib/datadog/tracing/trace_operation.rb b/lib/datadog/tracing/trace_operation.rb index f12e7098b1..518ce58f78 100644 --- a/lib/datadog/tracing/trace_operation.rb +++ b/lib/datadog/tracing/trace_operation.rb @@ -4,12 +4,13 @@ require_relative '../core/environment/identity' require_relative '../core/utils' -require_relative 'sampling/ext' require_relative 'event' +require_relative 'metadata/tagging' +require_relative 'sampling/ext' require_relative 'span_operation' -require_relative 'trace_segment' require_relative 'trace_digest' -require_relative 'metadata/tagging' +require_relative 'trace_segment' +require_relative 'utils' module Datadog module Tracing @@ -70,7 +71,7 @@ def initialize( metrics: nil ) # Attributes - @id = id || Core::Utils.next_id + @id = id || Tracing::Utils.next_id @max_length = max_length || DEFAULT_MAX_LENGTH @parent_span_id = parent_span_id @sampled = sampled.nil? ? true : sampled diff --git a/lib/datadog/tracing/utils.rb b/lib/datadog/tracing/utils.rb new file mode 100644 index 0000000000..230ba2d73b --- /dev/null +++ b/lib/datadog/tracing/utils.rb @@ -0,0 +1,50 @@ +# typed: true + +require_relative '../core/utils/forking' + +module Datadog + module Tracing + # Utils contains low-level tracing utility functions. + # @public_api + module Utils + extend Datadog::Core::Utils::Forking + + # The max value for a {Datadog::Tracing::Span} identifier. + # Span and trace identifiers should be strictly positive and strictly inferior to this limit. + # + # Limited to +2<<62-1+ positive integers, as Ruby is able to represent such numbers "inline", + # inside a +VALUE+ scalar, thus not requiring memory allocation. + # + # The range of IDs also has to consider portability across different languages and platforms. + RUBY_MAX_ID = (1 << 62) - 1 + + # Excludes zero from possible values + RUBY_ID_RANGE = (1..RUBY_MAX_ID).freeze + + # While we only generate 63-bit integers due to limitations in other languages, we support + # parsing 64-bit integers for distributed tracing since an upstream system may generate one + EXTERNAL_MAX_ID = 1 << 64 + + # We use a custom random number generator because we want no interference + # with the default one. Using the default prng, we could break code that + # would rely on srand/rand sequences. + + # Return a randomly generated integer, valid as a Span ID or Trace ID. + # This method is thread-safe and fork-safe. + def self.next_id + after_fork! { reset! } + id_rng.rand(RUBY_ID_RANGE) + end + + def self.id_rng + @id_rng ||= Random.new + end + + def self.reset! + @id_rng = Random.new + end + + private_class_method :id_rng, :reset! + end + end +end diff --git a/spec/datadog/core/utils_spec.rb b/spec/datadog/core/utils_spec.rb index 13d33ee4b0..9bdba06c34 100644 --- a/spec/datadog/core/utils_spec.rb +++ b/spec/datadog/core/utils_spec.rb @@ -6,34 +6,6 @@ require 'datadog/core/utils' RSpec.describe Datadog::Core::Utils do - describe '.next_id' do - subject(:next_id) { described_class.next_id } - - it 'returns a positive integer smaller than 2**62' do - is_expected.to be_a(Integer) - is_expected.to be_between(1, 2**62 - 1) - end - - it 'fits in a CRuby VALUE slot', if: ObjectSpaceHelper.estimate_bytesize_supported? do - expect(ObjectSpaceHelper.estimate_bytesize(next_id)).to eq(0) - end - - it 'returns unique numbers on successive calls' do - is_expected.to_not eq(described_class.next_id) - end - - context 'after forking', if: PlatformHelpers.supports_fork? do - it 'generates unique ids across forks' do - ids = Array.new(3) do - result = expect_in_fork { puts next_id } - Integer(result[:stdout]) - end.uniq - - expect(ids).to have(3).items - end - end - end - describe '.truncate' do subject(:truncate) { described_class.truncate(value, size, omission) } let(:value) { 123456 } diff --git a/spec/datadog/opentracer/distributed_headers_spec.rb b/spec/datadog/opentracer/distributed_headers_spec.rb index fefeff106b..33e30ffd6e 100644 --- a/spec/datadog/opentracer/distributed_headers_spec.rb +++ b/spec/datadog/opentracer/distributed_headers_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -require 'datadog/tracing/span' +require 'datadog/tracing/utils' require 'datadog/opentracer' RSpec.describe Datadog::OpenTracer::DistributedHeaders do @@ -25,21 +25,21 @@ context 'when #trace_id is missing' do let(:trace_id) { nil } - let(:parent_id) { (Datadog::Tracing::Span::EXTERNAL_MAX_ID + 1).to_s } + let(:parent_id) { (Datadog::Tracing::Utils::EXTERNAL_MAX_ID + 1).to_s } it { is_expected.to be false } end context 'when #parent_id is missing' do - let(:trace_id) { (Datadog::Tracing::Span::EXTERNAL_MAX_ID + 1).to_s } + let(:trace_id) { (Datadog::Tracing::Utils::EXTERNAL_MAX_ID + 1).to_s } let(:parent_id) { nil } it { is_expected.to be false } end context 'when both #trace_id and #parent_id are present' do - let(:trace_id) { (Datadog::Tracing::Span::EXTERNAL_MAX_ID - 1).to_s } - let(:parent_id) { (Datadog::Tracing::Span::EXTERNAL_MAX_ID - 1).to_s } + let(:trace_id) { (Datadog::Tracing::Utils::EXTERNAL_MAX_ID - 1).to_s } + let(:parent_id) { (Datadog::Tracing::Utils::EXTERNAL_MAX_ID - 1).to_s } it { is_expected.to be true } end @@ -60,13 +60,13 @@ context 'when the header is present' do context 'but the value is out of range' do - let(:value) { (Datadog::Tracing::Span::EXTERNAL_MAX_ID + 1).to_s } + let(:value) { (Datadog::Tracing::Utils::EXTERNAL_MAX_ID + 1).to_s } it { is_expected.to be nil } end context 'and the value is in range' do - let(:value) { (Datadog::Tracing::Span::EXTERNAL_MAX_ID - 1).to_s } + let(:value) { (Datadog::Tracing::Utils::EXTERNAL_MAX_ID - 1).to_s } it { is_expected.to eq value.to_i } @@ -95,13 +95,13 @@ context 'when the header is present' do context 'but the value is out of range' do - let(:value) { (Datadog::Tracing::Span::EXTERNAL_MAX_ID + 1).to_s } + let(:value) { (Datadog::Tracing::Utils::EXTERNAL_MAX_ID + 1).to_s } it { is_expected.to be nil } end context 'and the value is in range' do - let(:value) { (Datadog::Tracing::Span::EXTERNAL_MAX_ID - 1).to_s } + let(:value) { (Datadog::Tracing::Utils::EXTERNAL_MAX_ID - 1).to_s } it { is_expected.to eq value.to_i } diff --git a/spec/datadog/opentracer/propagation_integration_spec.rb b/spec/datadog/opentracer/propagation_integration_spec.rb index c6b217dec0..9ec568ac97 100644 --- a/spec/datadog/opentracer/propagation_integration_spec.rb +++ b/spec/datadog/opentracer/propagation_integration_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -require 'datadog/tracing/span' +require 'datadog/tracing/utils' require 'datadog/opentracer' RSpec.describe 'OpenTracer context propagation' do @@ -80,8 +80,8 @@ def baggage_to_carrier_format(baggage) ) end - let(:trace_id) { Datadog::Tracing::Span::EXTERNAL_MAX_ID - 1 } - let(:parent_id) { Datadog::Tracing::Span::EXTERNAL_MAX_ID - 2 } + let(:trace_id) { Datadog::Tracing::Utils::EXTERNAL_MAX_ID - 1 } + let(:parent_id) { Datadog::Tracing::Utils::EXTERNAL_MAX_ID - 2 } let(:sampling_priority) { 2 } let(:origin) { 'synthetics' } @@ -272,8 +272,8 @@ def baggage_to_carrier_format(baggage) ) end - let(:trace_id) { Datadog::Tracing::Span::EXTERNAL_MAX_ID - 1 } - let(:parent_id) { Datadog::Tracing::Span::EXTERNAL_MAX_ID - 2 } + let(:trace_id) { Datadog::Tracing::Utils::EXTERNAL_MAX_ID - 1 } + let(:parent_id) { Datadog::Tracing::Utils::EXTERNAL_MAX_ID - 2 } let(:sampling_priority) { 2 } let(:origin) { 'synthetics' } diff --git a/spec/datadog/tracing/correlation_spec.rb b/spec/datadog/tracing/correlation_spec.rb index 162b46e3d8..289d50d78d 100644 --- a/spec/datadog/tracing/correlation_spec.rb +++ b/spec/datadog/tracing/correlation_spec.rb @@ -3,9 +3,9 @@ require 'spec_helper' require 'datadog/core' -require 'datadog/core/utils' require 'datadog/tracing/correlation' require 'datadog/tracing/trace_digest' +require 'datadog/tracing/utils' RSpec.describe Datadog::Tracing::Correlation do let(:default_env) { 'default-env' } @@ -22,12 +22,12 @@ shared_context 'correlation data' do let(:env) { 'dev' } let(:service) { 'acme-api' } - let(:span_id) { Datadog::Core::Utils.next_id } + let(:span_id) { Datadog::Tracing::Utils.next_id } let(:span_name) { 'active_record.sql' } let(:span_resource) { 'SELECT * FROM users;' } let(:span_service) { 'acme-mysql' } let(:span_type) { 'db' } - let(:trace_id) { Datadog::Core::Utils.next_id } + let(:trace_id) { Datadog::Tracing::Utils.next_id } let(:trace_name) { 'rack.request' } let(:trace_resource) { 'GET /users' } let(:trace_service) { 'acme-api' } @@ -212,8 +212,8 @@ ) end - let(:trace_id) { Datadog::Core::Utils.next_id } - let(:span_id) { Datadog::Core::Utils.next_id } + let(:trace_id) { Datadog::Tracing::Utils.next_id } + let(:span_id) { Datadog::Tracing::Utils.next_id } let(:env) { 'dev' } let(:service) { 'acme-api' } let(:version) { '1.0' } @@ -232,7 +232,7 @@ def have_attribute(attribute) context 'when #trace_id' do context 'is defined' do it_behaves_like 'a log format string' do - let(:trace_id) { Datadog::Core::Utils.next_id } + let(:trace_id) { Datadog::Tracing::Utils.next_id } it do is_expected.to have_attribute( "#{Datadog::Tracing::Correlation::Identifier::LOG_ATTR_TRACE_ID}=#{trace_id}" @@ -256,7 +256,7 @@ def have_attribute(attribute) context 'when #span_id' do context 'is defined' do it_behaves_like 'a log format string' do - let(:span_id) { Datadog::Core::Utils.next_id } + let(:span_id) { Datadog::Tracing::Utils.next_id } it do is_expected.to have_attribute( "#{Datadog::Tracing::Correlation::Identifier::LOG_ATTR_SPAN_ID}=#{span_id}" diff --git a/spec/datadog/tracing/distributed/helpers_spec.rb b/spec/datadog/tracing/distributed/helpers_spec.rb index 233148bddb..b0ffad6c2f 100644 --- a/spec/datadog/tracing/distributed/helpers_spec.rb +++ b/spec/datadog/tracing/distributed/helpers_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' require 'datadog/tracing/distributed/helpers' -require 'datadog/tracing/span' +require 'datadog/tracing/utils' RSpec.describe Datadog::Tracing::Distributed::Helpers do describe '#clamp_sampling_priority' do @@ -45,10 +45,10 @@ [((2**64) - 1).to_s(16), 'ffffffffffffffff'], # Our max generated id - [Datadog::Tracing::Span::RUBY_MAX_ID.to_s(16), '3fffffffffffffff'], + [Datadog::Tracing::Utils::RUBY_MAX_ID.to_s(16), '3fffffffffffffff'], # Our max external id # DEV: This is the same as (2**64) above, but use the constant to be sure - [Datadog::Tracing::Span::EXTERNAL_MAX_ID.to_s(16), '0'], + [Datadog::Tracing::Utils::EXTERNAL_MAX_ID.to_s(16), '0'], # 128-bit max, which is 32 characters long, so we truncate to the last 16, which is all zeros [(2**128).to_s(16), '0'], @@ -79,14 +79,14 @@ ['', nil], # Larger than we allow - [(Datadog::Tracing::Span::EXTERNAL_MAX_ID + 1).to_s, nil], + [(Datadog::Tracing::Utils::EXTERNAL_MAX_ID + 1).to_s, nil], # Negative number ['-100', -100 + (2**64)], # Allowed values - [Datadog::Tracing::Span::RUBY_MAX_ID.to_s, Datadog::Tracing::Span::RUBY_MAX_ID], - [Datadog::Tracing::Span::EXTERNAL_MAX_ID.to_s, Datadog::Tracing::Span::EXTERNAL_MAX_ID], + [Datadog::Tracing::Utils::RUBY_MAX_ID.to_s, Datadog::Tracing::Utils::RUBY_MAX_ID], + [Datadog::Tracing::Utils::EXTERNAL_MAX_ID.to_s, Datadog::Tracing::Utils::EXTERNAL_MAX_ID], ['1', 1], ['123456789', 123456789] ].each do |value, expected| @@ -99,11 +99,11 @@ [ # Larger than we allow # DEV: We truncate to 64-bit for base16 - [(Datadog::Tracing::Span::EXTERNAL_MAX_ID + 1).to_s(16), 1], - [Datadog::Tracing::Span::EXTERNAL_MAX_ID.to_s(16), nil], + [(Datadog::Tracing::Utils::EXTERNAL_MAX_ID + 1).to_s(16), 1], + [Datadog::Tracing::Utils::EXTERNAL_MAX_ID.to_s(16), nil], - [Datadog::Tracing::Span::RUBY_MAX_ID.to_s(16), Datadog::Tracing::Span::RUBY_MAX_ID], - [(Datadog::Tracing::Span::EXTERNAL_MAX_ID - 1).to_s(16), Datadog::Tracing::Span::EXTERNAL_MAX_ID - 1], + [Datadog::Tracing::Utils::RUBY_MAX_ID.to_s(16), Datadog::Tracing::Utils::RUBY_MAX_ID], + [(Datadog::Tracing::Utils::EXTERNAL_MAX_ID - 1).to_s(16), Datadog::Tracing::Utils::EXTERNAL_MAX_ID - 1], ['3e8', 1000], ['3E8', 1000], @@ -138,10 +138,10 @@ ['2', 2], # Allowed values - [Datadog::Tracing::Span::RUBY_MAX_ID.to_s, Datadog::Tracing::Span::RUBY_MAX_ID], - [(Datadog::Tracing::Span::RUBY_MAX_ID + 1).to_s, Datadog::Tracing::Span::RUBY_MAX_ID + 1], - [Datadog::Tracing::Span::EXTERNAL_MAX_ID.to_s, Datadog::Tracing::Span::EXTERNAL_MAX_ID], - [(Datadog::Tracing::Span::EXTERNAL_MAX_ID + 1).to_s, Datadog::Tracing::Span::EXTERNAL_MAX_ID + 1], + [Datadog::Tracing::Utils::RUBY_MAX_ID.to_s, Datadog::Tracing::Utils::RUBY_MAX_ID], + [(Datadog::Tracing::Utils::RUBY_MAX_ID + 1).to_s, Datadog::Tracing::Utils::RUBY_MAX_ID + 1], + [Datadog::Tracing::Utils::EXTERNAL_MAX_ID.to_s, Datadog::Tracing::Utils::EXTERNAL_MAX_ID], + [(Datadog::Tracing::Utils::EXTERNAL_MAX_ID + 1).to_s, Datadog::Tracing::Utils::EXTERNAL_MAX_ID + 1], ['-100', -100], ['100', 100], ].each do |value, expected| @@ -156,11 +156,11 @@ [ # Larger than we allow # DEV: We truncate to 64-bit for base16, so the - [Datadog::Tracing::Span::EXTERNAL_MAX_ID.to_s(16), 0], - [(Datadog::Tracing::Span::EXTERNAL_MAX_ID + 1).to_s(16), 1], + [Datadog::Tracing::Utils::EXTERNAL_MAX_ID.to_s(16), 0], + [(Datadog::Tracing::Utils::EXTERNAL_MAX_ID + 1).to_s(16), 1], - [Datadog::Tracing::Span::RUBY_MAX_ID.to_s(16), Datadog::Tracing::Span::RUBY_MAX_ID], - [(Datadog::Tracing::Span::RUBY_MAX_ID + 1).to_s(16), Datadog::Tracing::Span::RUBY_MAX_ID + 1], + [Datadog::Tracing::Utils::RUBY_MAX_ID.to_s(16), Datadog::Tracing::Utils::RUBY_MAX_ID], + [(Datadog::Tracing::Utils::RUBY_MAX_ID + 1).to_s(16), Datadog::Tracing::Utils::RUBY_MAX_ID + 1], ['3e8', 1000], ['3E8', 1000], diff --git a/spec/datadog/tracing/span_operation_spec.rb b/spec/datadog/tracing/span_operation_spec.rb index f0f2f86655..11f330cd55 100644 --- a/spec/datadog/tracing/span_operation_spec.rb +++ b/spec/datadog/tracing/span_operation_spec.rb @@ -7,11 +7,11 @@ require 'datadog/core' require 'datadog/core/logger' -require 'datadog/core/utils' -require 'datadog/core/utils/time' + require 'datadog/tracing/metadata/ext' require 'datadog/tracing/span_operation' require 'datadog/tracing/span' +require 'datadog/tracing/utils' RSpec.describe Datadog::Tracing::SpanOperation do subject(:span_op) { described_class.new(name, **options) } @@ -361,7 +361,7 @@ end context 'that is an Integer' do - let(:trace_id) { Datadog::Core::Utils.next_id } + let(:trace_id) { Datadog::Tracing::Utils.next_id } it { is_expected.to have_attributes(trace_id: trace_id) } end end diff --git a/spec/datadog/tracing/trace_digest_spec.rb b/spec/datadog/tracing/trace_digest_spec.rb index 54700024ac..fbb59b319a 100644 --- a/spec/datadog/tracing/trace_digest_spec.rb +++ b/spec/datadog/tracing/trace_digest_spec.rb @@ -3,9 +3,10 @@ require 'spec_helper' require 'datadog/core/environment/identity' -require 'datadog/core/utils' + require 'datadog/tracing/sampling/ext' require 'datadog/tracing/trace_digest' +require 'datadog/tracing/utils' RSpec.describe Datadog::Tracing::TraceDigest do subject(:trace_digest) { described_class.new(**options) } @@ -42,7 +43,7 @@ context 'given' do context ':span_id' do let(:options) { { span_id: span_id } } - let(:span_id) { Datadog::Core::Utils.next_id } + let(:span_id) { Datadog::Tracing::Utils.next_id } it { is_expected.to have_attributes(span_id: span_id) } end @@ -91,7 +92,7 @@ context ':trace_id' do let(:options) { { trace_id: trace_id } } - let(:trace_id) { Datadog::Core::Utils.next_id } + let(:trace_id) { Datadog::Tracing::Utils.next_id } it { is_expected.to have_attributes(trace_id: trace_id) } end diff --git a/spec/datadog/tracing/trace_operation_spec.rb b/spec/datadog/tracing/trace_operation_spec.rb index b2bd7f2ee4..977e9fcce3 100644 --- a/spec/datadog/tracing/trace_operation_spec.rb +++ b/spec/datadog/tracing/trace_operation_spec.rb @@ -6,11 +6,12 @@ require 'datadog/core' require 'datadog/core/environment/identity' -require 'datadog/core/utils' + require 'datadog/tracing/sampling/ext' require 'datadog/tracing/span_operation' require 'datadog/tracing/trace_operation' require 'datadog/tracing/trace_segment' +require 'datadog/tracing/utils' RSpec.describe Datadog::Tracing::TraceOperation do subject(:trace_op) { described_class.new(**options) } @@ -106,7 +107,7 @@ context ':id' do subject(:options) { { id: id } } - let(:id) { Datadog::Core::Utils.next_id } + let(:id) { Datadog::Tracing::Utils.next_id } it { expect(trace_op.id).to eq(id) } end @@ -134,7 +135,7 @@ context ':parent_span_id' do subject(:options) { { parent_span_id: parent_span_id } } - let(:parent_span_id) { Datadog::Core::Utils.next_id } + let(:parent_span_id) { Datadog::Tracing::Utils.next_id } it { expect(trace_op.parent_span_id).to eq(parent_span_id) } end @@ -1806,7 +1807,7 @@ def span context 'but :parent_span_id has been defined' do let(:options) { { parent_span_id: parent_span_id } } - let(:parent_span_id) { Datadog::Core::Utils.next_id } + let(:parent_span_id) { Datadog::Tracing::Utils.next_id } it { expect(digest.span_id).to eq(parent_span_id) } end @@ -1856,7 +1857,7 @@ def span context 'and :parent_span_id has been defined' do let(:options) { { parent_span_id: parent_span_id } } - let(:parent_span_id) { Datadog::Core::Utils.next_id } + let(:parent_span_id) { Datadog::Tracing::Utils.next_id } it { expect(digest.span_id).to eq(@parent.id) } end @@ -2008,7 +2009,7 @@ def span context 'and :parent_span_id has been defined' do let(:options) { { parent_span_id: parent_span_id } } - let(:parent_span_id) { Datadog::Core::Utils.next_id } + let(:parent_span_id) { Datadog::Tracing::Utils.next_id } it { expect(digest.span_id).to be nil } end @@ -2069,7 +2070,7 @@ def span context 'but :parent_span_id has been defined' do let(:options) { { parent_span_id: parent_span_id } } - let(:parent_span_id) { Datadog::Core::Utils.next_id } + let(:parent_span_id) { Datadog::Tracing::Utils.next_id } it { expect(new_trace_op.parent_span_id).to eq(parent_span_id) } end @@ -2125,7 +2126,7 @@ def span context 'and :parent_span_id has been defined' do let(:options) { { parent_span_id: parent_span_id } } - let(:parent_span_id) { Datadog::Core::Utils.next_id } + let(:parent_span_id) { Datadog::Tracing::Utils.next_id } it { expect(new_trace_op.parent_span_id).to eq(@parent.id) } end @@ -2305,7 +2306,7 @@ def span context 'and :parent_span_id has been defined' do let(:options) { { parent_span_id: parent_span_id } } - let(:parent_span_id) { Datadog::Core::Utils.next_id } + let(:parent_span_id) { Datadog::Tracing::Utils.next_id } it { expect(new_trace_op.parent_span_id).to be parent_span_id } end diff --git a/spec/datadog/tracing/tracer_integration_spec.rb b/spec/datadog/tracing/tracer_integration_spec.rb index c25099d71b..d33727c6fa 100644 --- a/spec/datadog/tracing/tracer_integration_spec.rb +++ b/spec/datadog/tracing/tracer_integration_spec.rb @@ -3,11 +3,12 @@ require 'spec_helper' require 'datadog/core/runtime/ext' -require 'datadog/core/utils' + require 'datadog/tracing/propagation/http' require 'datadog/tracing/sampling/ext' require 'datadog/tracing/trace_digest' require 'datadog/tracing/tracer' +require 'datadog/tracing/utils' RSpec.describe Datadog::Tracing::Tracer do subject(:tracer) { described_class.new(writer: FauxWriter.new) } @@ -218,8 +219,8 @@ def lang_tag(span) context 'with state' do let(:digest) do Datadog::Tracing::TraceDigest.new( - span_id: Datadog::Core::Utils.next_id, - trace_id: Datadog::Core::Utils.next_id, + span_id: Datadog::Tracing::Utils.next_id, + trace_id: Datadog::Tracing::Utils.next_id, trace_origin: 'synthetics', trace_sampling_priority: Datadog::Tracing::Sampling::Ext::Priority::USER_KEEP ) diff --git a/spec/datadog/tracing/tracer_spec.rb b/spec/datadog/tracing/tracer_spec.rb index 874644728b..29aa98f8b1 100644 --- a/spec/datadog/tracing/tracer_spec.rb +++ b/spec/datadog/tracing/tracer_spec.rb @@ -7,7 +7,7 @@ require 'datadog/core' require 'datadog/core/environment/identity' require 'datadog/core/environment/socket' -require 'datadog/core/utils' + require 'datadog/tracing' require 'datadog/tracing/context' require 'datadog/tracing/correlation' @@ -16,6 +16,7 @@ require 'datadog/tracing/span_operation' require 'datadog/tracing/trace_operation' require 'datadog/tracing/tracer' +require 'datadog/tracing/utils' require 'datadog/tracing/writer' RSpec.describe Datadog::Tracing::Tracer do @@ -799,9 +800,9 @@ context 'given a TraceDigest' do let(:digest) do Datadog::Tracing::TraceDigest.new( - span_id: Datadog::Core::Utils.next_id, + span_id: Datadog::Tracing::Utils.next_id, trace_distributed_tags: { '_dd.p.test' => 'value' }, - trace_id: Datadog::Core::Utils.next_id, + trace_id: Datadog::Tracing::Utils.next_id, trace_origin: 'synthetics', trace_sampling_priority: Datadog::Tracing::Sampling::Ext::Priority::USER_KEEP, ) diff --git a/spec/datadog/tracing/utils_spec.rb b/spec/datadog/tracing/utils_spec.rb new file mode 100644 index 0000000000..2587f6e345 --- /dev/null +++ b/spec/datadog/tracing/utils_spec.rb @@ -0,0 +1,35 @@ +# typed: false + +require 'spec_helper' + +require 'datadog/tracing/utils' + +RSpec.describe Datadog::Tracing::Utils do + describe '.next_id' do + subject(:next_id) { described_class.next_id } + + it 'returns a positive integer smaller than 2**62' do + is_expected.to be_a(Integer) + is_expected.to be_between(1, 2**62 - 1) + end + + it 'fits in a CRuby VALUE slot', if: ObjectSpaceHelper.estimate_bytesize_supported? do + expect(ObjectSpaceHelper.estimate_bytesize(next_id)).to eq(0) + end + + it 'returns unique numbers on successive calls' do + is_expected.to_not eq(described_class.next_id) + end + + context 'after forking', if: PlatformHelpers.supports_fork? do + it 'generates unique ids across forks' do + ids = Array.new(3) do + result = expect_in_fork { puts next_id } + Integer(result[:stdout]) + end.uniq + + expect(ids).to have(3).items + end + end + end +end diff --git a/spec/ddtrace/transport/trace_formatter_spec.rb b/spec/ddtrace/transport/trace_formatter_spec.rb index 9f06089ffe..730e471264 100644 --- a/spec/ddtrace/transport/trace_formatter_spec.rb +++ b/spec/ddtrace/transport/trace_formatter_spec.rb @@ -4,11 +4,12 @@ require 'datadog/core/environment/identity' require 'datadog/core/runtime/ext' -require 'datadog/core/utils' + require 'datadog/tracing/metadata/ext' require 'datadog/tracing/sampling/ext' require 'datadog/tracing/span' require 'datadog/tracing/trace_segment' +require 'datadog/tracing/utils' require 'ddtrace/transport/trace_formatter' RSpec.describe Datadog::Transport::TraceFormatter do @@ -69,7 +70,13 @@ end shared_context 'missing root span' do - let(:trace) { Datadog::Tracing::TraceSegment.new(spans, root_span_id: Datadog::Core::Utils.next_id, **trace_options) } + let(:trace) do + Datadog::Tracing::TraceSegment.new( + spans, + root_span_id: Datadog::Tracing::Utils.next_id, + **trace_options + ) + end let(:spans) { Array.new(3) { Datadog::Tracing::Span.new('my.job') } } let(:root_span) { spans.last } end