Skip to content

Commit

Permalink
Implement a hierarchical sampler
Browse files Browse the repository at this point in the history
  • Loading branch information
gillesbergerp committed Nov 11, 2023
1 parent 6878b48 commit a40750d
Show file tree
Hide file tree
Showing 5 changed files with 223 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@
# The OpenTelemetry module provides global accessors for telemetry objects.
# See the documentation for the `opentelemetry-api` gem for details.

require_relative('hierarchical/sampler')
require_relative('hierarchical/version')
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# frozen_string_literal: true

# Copyright The OpenTelemetry Authors
#
# SPDX-License-Identifier: Apache-2.0

module OpenTelemetry
module Sampling
module Hierarchical
class Sampler
# @param [Array<OpenTelemetry::SDK::Trace::Samplers>] samplers
def initialize(*samplers)
@samplers = samplers
end

# @param [String] trace_id
# @param [OpenTelemetry::Context] parent_context
# @param [Enumerable<Link>] links
# @param [String] name
# @param [Symbol] kind
# @param [Hash<String, Object>] attributes
# @return [OpenTelemetry::SDK::Trace::Samplers::Result] The sampling result.
def should_sample?(trace_id:, parent_context:, links:, name:, kind:, attributes:)
@samplers.each do |sampler|
result = sampler.should_sample?(trace_id: trace_id, parent_context: parent_context, links: links, name: name, kind: kind, attributes: attributes)
return result if result.sampled?
end

OpenTelemetry::SDK::Trace::Samplers::Result.new(
decision: OpenTelemetry::SDK::Trace::Samplers::Decision::DROP,
tracestate: OpenTelemetry::Trace.current_span(parent_context).context.tracestate
)
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
# frozen_string_literal: true

# Copyright The OpenTelemetry Authors
#
# SPDX-License-Identifier: Apache-2.0

require('test_helper')

describe(OpenTelemetry::Sampling::Hierarchical::Sampler) do
describe('#should_sample?') do
it('returns DROP if it has no samplers') do
sampler = OpenTelemetry::Sampling::Hierarchical::Sampler.new([])

_(
sampler.should_sample?(
trace_id: SecureRandom.uuid.to_s,
parent_context: nil,
links: [],
name: SecureRandom.uuid.to_s,
kind: :internal,
attributes: {}
).sampled?
).must_equal(false)
end

it('returns RECORD_AND_SAMPLE if the first sampler returns RECORD_AND_SAMPLE') do
trace_id = SecureRandom.uuid.to_s
name = SecureRandom.uuid.to_s

first_sampler = Minitest::Mock.new
second_sampler = Minitest::Mock.new

first_sampler.expect(
:should_sample?,
OpenTelemetry::SDK::Trace::Samplers::Result.new(
decision: OpenTelemetry::SDK::Trace::Samplers::Decision::RECORD_AND_SAMPLE,
tracestate: OpenTelemetry::Trace::Tracestate.from_hash({})
),
[],
trace_id: trace_id,
parent_context: nil,
links: [],
name: name,
kind: :internal,
attributes: {}
)

sampler = OpenTelemetry::Sampling::Hierarchical::Sampler.new([first_sampler, second_sampler])
_(
sampler.should_sample?(
trace_id: trace_id,
parent_context: nil,
links: [],
name: name,
kind: :internal,
attributes: {}
).sampled?
).must_equal(true)

first_sampler.verify
second_sampler.verify
end

it('returns RECORD_AND_SAMPLE if the second sampler returns RECORD_AND_SAMPLE') do
trace_id = SecureRandom.uuid.to_s
name = SecureRandom.uuid.to_s

first_sampler = Minitest::Mock.new
second_sampler = Minitest::Mock.new

first_sampler.expect(
:should_sample?,
OpenTelemetry::SDK::Trace::Samplers::Result.new(
decision: OpenTelemetry::SDK::Trace::Samplers::Decision::DROP,
tracestate: OpenTelemetry::Trace::Tracestate.from_hash({})
),
[],
trace_id: trace_id,
parent_context: nil,
links: [],
name: name,
kind: :internal,
attributes: {}
)
second_sampler.expect(
:should_sample?,
OpenTelemetry::SDK::Trace::Samplers::Result.new(
decision: OpenTelemetry::SDK::Trace::Samplers::Decision::RECORD_AND_SAMPLE,
tracestate: OpenTelemetry::Trace::Tracestate.from_hash({})
),
[],
trace_id: trace_id,
parent_context: nil,
links: [],
name: name,
kind: :internal,
attributes: {}
)

sampler = OpenTelemetry::Sampling::Hierarchical::Sampler.new([first_sampler, second_sampler])
_(
sampler.should_sample?(
trace_id: trace_id,
parent_context: nil,
links: [],
name: name,
kind: :internal,
attributes: {}
).sampled?
).must_equal(true)

first_sampler.verify
second_sampler.verify
end

it('returns DROP if both samplers return DROP') do
trace_id = SecureRandom.uuid.to_s
name = SecureRandom.uuid.to_s

first_sampler = Minitest::Mock.new
second_sampler = Minitest::Mock.new

first_sampler.expect(
:should_sample?,
OpenTelemetry::SDK::Trace::Samplers::Result.new(
decision: OpenTelemetry::SDK::Trace::Samplers::Decision::DROP,
tracestate: OpenTelemetry::Trace::Tracestate.from_hash({})
),
[],
trace_id: trace_id,
parent_context: nil,
links: [],
name: name,
kind: :internal,
attributes: {}
)
second_sampler.expect(
:should_sample?,
OpenTelemetry::SDK::Trace::Samplers::Result.new(
decision: OpenTelemetry::SDK::Trace::Samplers::Decision::DROP,
tracestate: OpenTelemetry::Trace::Tracestate.from_hash({})
),
[],
trace_id: trace_id,
parent_context: nil,
links: [],
name: name,
kind: :internal,
attributes: {}
)

sampler = OpenTelemetry::Sampling::Hierarchical::Sampler.new([first_sampler, second_sampler])
_(
sampler.should_sample?(
trace_id: trace_id,
parent_context: nil,
links: [],
name: name,
kind: :internal,
attributes: {}
).sampled?
).must_equal(false)

first_sampler.verify
second_sampler.verify
end
end
end
17 changes: 17 additions & 0 deletions sampling/hierarchical/test/opentelemetry/test_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true

# Copyright The OpenTelemetry Authors
#
# SPDX-License-Identifier: Apache-2.0

require('bundler/setup')
Bundler.require(:default, :development, :test)

SimpleCov.minimum_coverage(85)
SimpleCov.start

require('opentelemetry-sampling-hierarchical')
require('minitest/autorun')
require('webmock/minitest')

OpenTelemetry.logger = Logger.new($stderr, level: ENV.fetch('OTEL_LOG_LEVEL', 'error').to_sym)
1 change: 0 additions & 1 deletion sampling/hierarchical/test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,5 @@

require('opentelemetry-sampling-hierarchical')
require('minitest/autorun')
require('webmock/minitest')

OpenTelemetry.logger = Logger.new($stderr, level: ENV.fetch('OTEL_LOG_LEVEL', 'debug').to_sym)

0 comments on commit a40750d

Please sign in to comment.