Skip to content

Commit

Permalink
Merge pull request #2463 from DataDog/refactor/extract_utils_tracing_…
Browse files Browse the repository at this point in the history
…next_id

Move Utils#next_id and constants to Tracing::Utils
  • Loading branch information
delner authored Dec 5, 2022
2 parents 3424345 + 88af816 commit d2fc40f
Show file tree
Hide file tree
Showing 20 changed files with 178 additions and 144 deletions.
21 changes: 0 additions & 21 deletions lib/datadog/core/utils.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# typed: true

require_relative 'utils/forking'
require_relative '../tracing/span'

module Datadog
module Core
Expand All @@ -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`.
Expand Down
4 changes: 2 additions & 2 deletions lib/datadog/opentracer/distributed_headers.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# typed: true

require_relative '../tracing/span'
require_relative '../tracing/distributed/datadog'
require_relative '../tracing/utils'

module Datadog
module OpenTracer
Expand Down Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion lib/datadog/tracing/distributed/helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# typed: true

require_relative '../sampling/ext'
require_relative '../utils'

module Datadog
module Tracing
Expand Down Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions lib/datadog/tracing/sampling/rate_sampler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
require_relative '../../core'

require_relative 'sampler'
require_relative '../span'
require_relative '../utils'

module Datadog
module Tracing
Expand Down Expand Up @@ -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)
Expand Down
22 changes: 3 additions & 19 deletions lib/datadog/tracing/span.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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,
Expand Down Expand Up @@ -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 || {}
Expand Down
9 changes: 5 additions & 4 deletions lib/datadog/tracing/span_operation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
9 changes: 5 additions & 4 deletions lib/datadog/tracing/trace_operation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
50 changes: 50 additions & 0 deletions lib/datadog/tracing/utils.rb
Original file line number Diff line number Diff line change
@@ -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
28 changes: 0 additions & 28 deletions spec/datadog/core/utils_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
18 changes: 9 additions & 9 deletions spec/datadog/opentracer/distributed_headers_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

require 'spec_helper'

require 'datadog/tracing/span'
require 'datadog/tracing/utils'
require 'datadog/opentracer'

RSpec.describe Datadog::OpenTracer::DistributedHeaders do
Expand All @@ -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
Expand All @@ -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 }

Expand Down Expand Up @@ -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 }

Expand Down
10 changes: 5 additions & 5 deletions spec/datadog/opentracer/propagation_integration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

require 'spec_helper'

require 'datadog/tracing/span'
require 'datadog/tracing/utils'
require 'datadog/opentracer'

RSpec.describe 'OpenTracer context propagation' do
Expand Down Expand Up @@ -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' }

Expand Down Expand Up @@ -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' }

Expand Down
Loading

0 comments on commit d2fc40f

Please sign in to comment.