class ElasticAPM::OpenTracing::Tracer
A custom tracer to use the OpenTracing API with ElasticAPM
def active_span
def active_span scope_manager.active&.span end
def context_from_active_scope(ignore_active_scope)
def context_from_active_scope(ignore_active_scope) if ignore_active_scope ElasticAPM.agent&.config&.logger&.warn( 'ignore_active_scope might lead to unexpected results' ) return end @scope_manager.active&.span&.context end
def context_from_child_of(child_of)
def context_from_child_of(child_of) return unless child_of child_of.respond_to?(:context) ? child_of.context : child_of end
def context_from_references(references)
def context_from_references(references) return if !references || references.none? child_of = references.find do |reference| reference.type == ::OpenTracing::Reference::CHILD_OF end (child_of || references.first).context end
def extract(format, carrier)
def extract(format, carrier) case format when ::OpenTracing::FORMAT_RACK SpanContext.from_header( carrier['HTTP_ELASTIC_APM_TRACEPARENT'] ) when ::OpenTracing::FORMAT_TEXT_MAP SpanContext.from_header( carrier['elastic-apm-traceparent'] ) else warn 'Only extraction from HTTP headers via Rack or in ' \ 'text map format are available' nil end rescue ElasticAPM::TraceContext::InvalidTraceparentHeader nil end
def initialize
def initialize @scope_manager = ScopeManager.new end
def inject(span_context, format, carrier)
def inject(span_context, format, carrier) case format when ::OpenTracing::FORMAT_RACK, ::OpenTracing::FORMAT_TEXT_MAP carrier['elastic-apm-traceparent'] = span_context.traceparent.to_header else warn 'Only injection via HTTP headers and Rack is available' end end
def prepare_span_context(
def prepare_span_context( child_of:, references:, ignore_active_scope: ) context = context_from_child_of(child_of) || context_from_references(references) || context_from_active_scope(ignore_active_scope) return context.child if context.respond_to?(:child) context end
def start_active_span(
def start_active_span( operation_name, child_of: nil, references: nil, start_time: Time.now, tags: {}, ignore_active_scope: false, finish_on_close: true, ** ) span = start_span( operation_name, child_of: child_of, references: references, start_time: start_time, tags: tags, ignore_active_scope: ignore_active_scope ) scope = scope_manager.activate(span, finish_on_close: finish_on_close) if block_given? begin return yield scope ensure scope.close end end scope end
def start_span(
def start_span( operation_name, child_of: nil, references: nil, start_time: Time.now, tags: {}, ignore_active_scope: false, ** ) span_context = prepare_span_context( child_of: child_of, references: references, ignore_active_scope: ignore_active_scope ) if span_context trace_context = span_context.respond_to?(:trace_context) && span_context.trace_context end elastic_span = if ElasticAPM.current_transaction ElasticAPM.start_span( operation_name, trace_context: trace_context ) else ElasticAPM.start_transaction( operation_name, trace_context: trace_context ) end # if no Elastic APM agent is running or transaction not sampled unless elastic_span return ::OpenTracing::Span::NOOP_INSTANCE end span_context ||= SpanContext.from_trace_context(elastic_span.trace_context) tags.each do |key, value| elastic_span.context.labels[key] = value end elastic_span.start Util.micros(start_time) Span.new(elastic_span, span_context) end