lib/opentelemetry/sdk/trace/tracer_provider.rb in opentelemetry-sdk-1.0.0.rc1 vs lib/opentelemetry/sdk/trace/tracer_provider.rb in opentelemetry-sdk-1.0.0.rc2
- old
+ new
@@ -6,28 +6,39 @@
module OpenTelemetry
module SDK
module Trace
# {TracerProvider} is the SDK implementation of {OpenTelemetry::Trace::TracerProvider}.
- class TracerProvider < OpenTelemetry::Trace::TracerProvider
+ class TracerProvider < OpenTelemetry::Trace::TracerProvider # rubocop:disable Metrics/ClassLength
Key = Struct.new(:name, :version)
private_constant(:Key)
- attr_accessor :active_trace_config, :id_generator
- attr_reader :active_span_processor, :stopped, :resource
- alias stopped? stopped
+ attr_accessor :span_limits, :id_generator, :sampler
+ attr_reader :resource
# Returns a new {TracerProvider} instance.
#
+ # @param [optional Sampler] sampler The sampling policy for new spans
+ # @param [optional Resource] resource The resource to associate with spans
+ # created by Tracers created by this TracerProvider
+ # @param [optional IDGenerator] id_generator The trace and span ID generation
+ # policy
+ # @param [optional SpanLimits] span_limits The limits to apply to attribute,
+ # event and link counts for Spans created by Tracers created by this
+ # TracerProvider
+ #
# @return [TracerProvider]
- def initialize(resource = OpenTelemetry::SDK::Resources::Resource.create)
+ def initialize(sampler: sampler_from_environment(Samplers.parent_based(root: Samplers::ALWAYS_ON)),
+ resource: OpenTelemetry::SDK::Resources::Resource.create,
+ id_generator: OpenTelemetry::Trace,
+ span_limits: SpanLimits::DEFAULT)
@mutex = Mutex.new
@registry = {}
- @active_span_processor = NoopSpanProcessor.instance
- @active_trace_config = Config::TraceConfig::DEFAULT
- @id_generator = OpenTelemetry::Trace
- @registered_span_processors = []
+ @span_processors = []
+ @span_limits = span_limits
+ @sampler = sampler
+ @id_generator = id_generator
@stopped = false
@resource = resource
end
# Returns a {Tracer} instance.
@@ -37,10 +48,11 @@
#
# @return [Tracer]
def tracer(name = nil, version = nil)
name ||= ''
version ||= ''
+ OpenTelemetry.logger.warn 'calling TracerProvider#tracer without providing a tracer name.' if name.empty?
@mutex.synchronize { @registry[Key.new(name, version)] ||= Tracer.new(name, version, self) }
end
# Attempts to stop all the activity for this {TracerProvider}. Calls
# SpanProcessor#shutdown for all registered SpanProcessors.
@@ -50,18 +62,28 @@
# processed and exported.
#
# After this is called all the newly created {Span}s will be no-op.
#
# @param [optional Numeric] timeout An optional timeout in seconds.
+ # @return [Integer] Export::SUCCESS if no error occurred, Export::FAILURE if
+ # a non-specific failure occurred, Export::TIMEOUT if a timeout occurred.
def shutdown(timeout: nil)
@mutex.synchronize do
if @stopped
OpenTelemetry.logger.warn('calling Tracer#shutdown multiple times.')
- return
+ return Export::FAILURE
end
- @active_span_processor.shutdown(timeout: timeout)
+
+ start_time = OpenTelemetry::Common::Utilities.timeout_timestamp
+ results = @span_processors.map do |processor|
+ remaining_timeout = OpenTelemetry::Common::Utilities.maybe_timeout(timeout, start_time)
+ break [Export::TIMEOUT] if remaining_timeout&.zero?
+
+ processor.shutdown(timeout: remaining_timeout)
+ end
@stopped = true
+ results.max || Export::SUCCESS
end
end
# Immediately export all spans that have not yet been exported for all the
# registered SpanProcessors.
@@ -76,11 +98,18 @@
# a non-specific failure occurred, Export::TIMEOUT if a timeout occurred.
def force_flush(timeout: nil)
@mutex.synchronize do
return Export::SUCCESS if @stopped
- @active_span_processor.force_flush(timeout: timeout)
+ start_time = OpenTelemetry::Common::Utilities.timeout_timestamp
+ results = @span_processors.map do |processor|
+ remaining_timeout = OpenTelemetry::Common::Utilities.maybe_timeout(timeout, start_time)
+ return Export::TIMEOUT if remaining_timeout&.zero?
+
+ processor.force_flush(timeout: remaining_timeout)
+ end
+ results.max || Export::SUCCESS
end
end
# Adds a new SpanProcessor to this {Tracer}.
#
@@ -89,16 +118,56 @@
@mutex.synchronize do
if @stopped
OpenTelemetry.logger.warn('calling Tracer#add_span_processor after shutdown.')
return
end
- @registered_span_processors << span_processor
- @active_span_processor = if @registered_span_processors.size == 1
- span_processor
- else
- MultiSpanProcessor.new(@registered_span_processors.dup)
- end
+ @span_processors = @span_processors.dup.push(span_processor)
end
+ end
+
+ # @api private
+ def internal_create_span(name, kind, trace_id, parent_span_id, attributes, links, start_timestamp, parent_context, instrumentation_library) # rubocop:disable Metrics/MethodLength
+ trace_id ||= @id_generator.generate_trace_id
+ result = @sampler.should_sample?(trace_id: trace_id, parent_context: parent_context, links: links, name: name, kind: kind, attributes: attributes)
+ span_id = @id_generator.generate_span_id
+ if result.recording? && !@stopped
+ trace_flags = result.sampled? ? OpenTelemetry::Trace::TraceFlags::SAMPLED : OpenTelemetry::Trace::TraceFlags::DEFAULT
+ context = OpenTelemetry::Trace::SpanContext.new(trace_id: trace_id, span_id: span_id, trace_flags: trace_flags, tracestate: result.tracestate)
+ attributes = attributes&.merge(result.attributes) || result.attributes
+ Span.new(
+ context,
+ parent_context,
+ name,
+ kind,
+ parent_span_id,
+ @span_limits,
+ @span_processors,
+ attributes,
+ links,
+ start_timestamp,
+ @resource,
+ instrumentation_library
+ )
+ else
+ OpenTelemetry::Trace.non_recording_span(OpenTelemetry::Trace::SpanContext.new(trace_id: trace_id, span_id: span_id, tracestate: result.tracestate))
+ end
+ end
+
+ private
+
+ def sampler_from_environment(default_sampler) # rubocop:disable Metrics/CyclomaticComplexity
+ case ENV['OTEL_TRACES_SAMPLER']
+ when 'always_on' then Samplers::ALWAYS_ON
+ when 'always_off' then Samplers::ALWAYS_OFF
+ when 'traceidratio' then Samplers.trace_id_ratio_based(Float(ENV.fetch('OTEL_TRACES_SAMPLER_ARG', 1.0)))
+ when 'parentbased_always_on' then Samplers.parent_based(root: Samplers::ALWAYS_ON)
+ when 'parentbased_always_off' then Samplers.parent_based(root: Samplers::ALWAYS_OFF)
+ when 'parentbased_traceidratio' then Samplers.parent_based(root: Samplers.trace_id_ratio_based(Float(ENV.fetch('OTEL_TRACES_SAMPLER_ARG', 1.0))))
+ else default_sampler
+ end
+ rescue StandardError => e
+ OpenTelemetry.handle_error(exception: e, message: "installing default sampler #{default_sampler.description}")
+ default_sampler
end
end
end
end
end