Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move Utils#next_id and constants to Tracing::Utils #2463

Merged
merged 1 commit into from
Dec 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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