Skip to content

Instantly share code, notes, and snippets.

@iaintshine
Last active August 2, 2017 22:48
Show Gist options
  • Save iaintshine/25112fe7d66e9c885e30589b949b9673 to your computer and use it in GitHub Desktop.
Save iaintshine/25112fe7d66e9c885e30589b949b9673 to your computer and use it in GitHub Desktop.
Ruby OpenTracing current span propagation proposal
class ActiveSpan
def span
end
# Mark the end of the active period for the ActiveSpan
def deactivate
end
end
class ActiveSpanSource
# Wraps and makes the span active
# @param span [OpenTracing::Span]
# @return ActiveSpan
def activate(span)
end
# Retrieves the current active span
# @return ActiveSpan
def active_span
end
end
class AutoReleasingActiveSpan < OpenTracing::Span
extend Forwardable
def_delegators :@span, :context, :operation_name=, :set_tag, :set_baggage_item, :get_baggage_item, :log, :finish
def initialize(active_span)
@active_span = active_span
@span = active_span.span
end
def finish
@span.finish
@active_span.deactivate
end
end
class AutoReleasingTracer < OpenTracing::Tracer
CURRENT_ACTIVE_SPAN = OpenTracing::Span.new.freeze
extend Forwardable
def_delegators :@tracer, :inject, :extract
def initialize(tracer, active_span_source)
@tracer = tracer
@active_span_source = active_span_source
end
def start_span(operation_name, child_of: CURRENT_ACTIVE_SPAN, **args)
parent_span = child_of == CURRENT_ACTIVE_SPAN ? active_span_source.current_span : child_of
new_span = @tracer.start_span(operation_name, child_of: parent_span, **args)
active_span = @active_span_source.activate(new_span)
AutoReleasingActiveSpan.new(active_span)
end
end
active_span_source = ThreadLocalActiveSpanSource.new
tracer = AutoReleasingTracer.new(Jaeger::Client.build(...), active_span_source)
root = tracer.start_span("GET", tags: {'component' => 'rack'})
# notice that we might leave child_of empty, use root, or active_span_source.current_span
http_call = tracer.start_span("POST /auth", tags: {'component' => 'faraday'})
http_call.finish
root.finish
class ThreadLocalActiveSpan < ActiveSpan
def initialize(trace_context, span)
@trace_context = trace_context
@span = span
end
def deactivate
@trace_context.pop
end
end
class ThreadLocalActiveSpanSource < ActiveSourceSpan
def initialize
@trace_context = ThreadLocalTraceContext.new
end
def activate(span)
active_span = ThreadLocalActiveSpan.new(@trace_context, span)
@trace_context.push(span)
active_span
end
def current_span
@trace_context.current_span
end
end
# ThreadLocalTraceContext allows an application access and manipulation of the current span state on per thread basis.
class ThreadLocalTraceContext
# Adds the given span to the TraceContext
#
# @param span [Span] The span to be pushed
def push(span)
local_stack << span
self
end
# Removes a span from the TraceContext
#
# @return [Span] returns and removes the current span from the top of the stack
def pop
local_stack.pop
end
# Retrieves the current span withouth modifying the TraceContext
#
# @return returns the current span of the local stack without removing from the stack.
def current_span
local_stack.last
end
# Checks if there is any span set in the current TraceContext
#
# @return returns a boolean saying whether or not the stack is empty
def empty?
local_stack.empty?
end
private
def local_stack
Thread.current[:___trace_context__] ||= []
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment