module Traces

def self.Provider(klass, &block)

Extend the specified class in order to emit traces.
def self.Provider(klass, &block)
	klass.extend(Singleton)
	provider = klass.traces_provider
	klass.prepend(provider)
	
	provider.module_exec(&block) if block_given?
	
	return provider
end

def self.Provider(klass, &block)

def self.Provider(klass, &block)
	# Tracing disabled.
end

def self.active?

@returns [Boolean] Whether there is an active trace.

This is a default implementation, which can be replaced by the backend.

Whether there is an active trace context.
def self.active?
	!!self.trace_context
end

def self.current_context

@returns [Context | Nil] The current trace context, or nil if no active trace.

This is a default implementation, which can be replaced by the backend.

The returned object is opaque, in other words, you should not make assumptions about its structure.

This method returns the current trace context that can be safely passed between threads, fibers, or other execution contexts within the same process.

Capture the current trace context for local propagation between execution contexts.
def self.current_context
	trace_context
end

def self.enabled?

@returns [Boolean] Whether there is an active backend.
def self.enabled?
	Backend.const_defined?(:Interface)
end

def self.extract(headers)

@returns [Context, nil] The extracted trace context, or nil if no valid context found.
@parameter headers [Hash] The headers object containing trace context.

This is a default implementation, which can be replaced by the backend.

The returned object is opaque, in other words, you should not make assumptions about its structure.

Extract trace context from headers for distributed propagation.
def self.extract(headers)
	Context.extract(headers)
end

def self.inject(headers = nil, context = nil)

@returns [Hash | Nil] The headers hash, or nil if no context is available.
@parameter context [Context] A trace context, or nil to use current context.
@parameter headers [Hash] The headers object to mutate with trace context headers.

This is a default implementation, which can be replaced by the backend.

This method adds W3C Trace Context headers (traceparent, tracestate) and W3C Baggage headers to the provided headers hash, enabling distributed tracing across service boundaries. The headers hash is mutated in place.

Inject trace context into a headers hash for distributed propagation.
def self.inject(headers = nil, context = nil)
	context ||= self.trace_context
	
	if context
		headers ||= Hash.new
		context.inject(headers)
	else
		headers = nil
	end
	
	return headers
end

def self.trace_context

@returns [Object] The current trace context.

You should prefer to use the new `Traces.current_context` family of methods.

This is a default implementation, which can be replaced by the backend.

Capture the current trace context for remote propagation.
def self.trace_context
	nil
end

def self.with_context(context)

@yields {...} If a block is given, the block is executed within the specified trace context.
@parameter context [Context] A trace context obtained from `Traces.current_context`.

This is a default implementation, which can be replaced by the backend.

When called without a block, permanently switches to the specified context. This enables manual context management for scenarios where automatic restoration isn't desired.

This method is designed for propagating trace context between execution contexts within the same process (threads, fibers, etc.). It temporarily switches to the specified trace context for the duration of the block execution, then restores the previous context.

Execute a block within a specific trace context for local execution.
def self.with_context(context)
	if block_given?
		# This implementation is not ideal but the best we can do with the current interface.
		previous_context = self.trace_context
		begin
			self.trace_context = context
			yield
		ensure
			self.trace_context = previous_context
		end
	else
		self.trace_context = context
	end
end