# frozen_string_literal: truerequire'elastic_apm'require'opentracing'moduleElasticAPMmoduleOpenTracing# @api privateclassSpandefinitialize(elastic_span,span_context)@elastic_span=elastic_span@span_context=span_contextendattr_reader:elastic_spandefoperation_name=(name)elastic_span.name=nameenddefcontext@span_contextend# rubocop:disable Metrics/MethodLengthdefset_tag(key,val)ifelastic_span.is_a?(Transaction)casekey.to_swhen'type'elastic_span.type=valwhen'result'elastic_span.result=valwhen/user\.(\w+)/set_user_value($1,val)elseelastic_span.context.tags[key]=valendelseelastic_span.context.tags[key]=valendend# rubocop:enable Metrics/MethodLengthdefset_baggage_item(_key,_value)ElasticAPM.agent.config.logger.warn('Baggage is not supported by ElasticAPM')enddefget_baggage_item(_key)ElasticAPM.agent.config.logger.warn('Baggage is not supported by ElasticAPM')nilend# rubocop:disable Lint/UnusedMethodArgumentdeflog_kv(timestamp: nil,**fields)if(exception=fields[:'error.object'])ElasticAPM.reportexceptionelsif(message=fields[:message])ElasticAPM.report_messagemessageendend# rubocop:enable Lint/UnusedMethodArgumentdeffinish(end_time: Time.now)returnunless(instrumenter=ElasticAPM.agent&.instrumenter)elastic_span.doneend_time: Util.micros(end_time)caseelastic_spanwhenElasticAPM::Transactioninstrumenter.current_transaction=nilwhenElasticAPM::Spaninstrumenter.current_spans.delete(elastic_span)endinstrumenter.enqueue.callelastic_spanendprivatedefset_user_value(key,value)returnunlesselastic_span.is_a?(Transaction)setter=:"#{key}="returnunlesselastic_span.context.user.respond_to?(setter)elastic_span.context.user.send(setter,value)endend# @api privateclassSpanContextdefinitialize(trace_context:,baggage: nil)ifbaggageElasticAPM.agent.config.logger.warn('Baggage is not supported by ElasticAPM')end@trace_context=trace_contextendattr_accessor:trace_contextdefself.from_trace_context(trace_context)new(trace_context: trace_context)endend# @api privateclassScopedefinitialize(span,scope_stack,finish_on_close:)@span=span@scope_stack=scope_stack@finish_on_close=finish_on_closeendattr_reader:spandefelastic_spanspan.elastic_spanenddefclose@span.finishif@finish_on_close@scope_stack.popendend# @api privateclassScopeStackKEY=:__elastic_apm_ot_scope_stackdefpush(scope)scopes<<scopeenddefpopscopes.popenddeflastscopes.lastendprivatedefscopesThread.current[KEY]||=[]endend# @api privateclassScopeManagerdefinitialize@scope_stack=ScopeStack.newenddefactivate(span,finish_on_close: true)returnactiveifactive&&active.span==spanscope=Scope.new(span,@scope_stack,finish_on_close: finish_on_close)@scope_stack.pushscopescopeenddefactive@scope_stack.lastendend# rubocop:disable Metrics/ClassLength# A custom tracer to use the OpenTracing API with ElasticAPMclassTracerdefinitialize@scope_manager=ScopeManager.newendattr_reader:scope_managerdefactive_spanscope_manager.active&.spanend# rubocop:disable Metrics/MethodLength, Metrics/ParameterListsdefstart_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)ifblock_given?beginyieldscopeensurescope.closeendendscopeend# rubocop:enable Metrics/MethodLength, Metrics/ParameterLists# rubocop:disable Metrics/MethodLength, Metrics/ParameterLists# rubocop:disable Metrics/AbcSizedefstart_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)ifspan_contexttrace_context=span_context&&span_context.respond_to?(:trace_context)&&span_context.trace_contextendelastic_span=ifElasticAPM.current_transactionElasticAPM.start_span(operation_name,trace_context: trace_context)elseElasticAPM.start_transaction(operation_name,trace_context: trace_context)end# if no Elastic APM agent is running or transaction not sampledunlesselastic_spanreturn::OpenTracing::Span::NOOP_INSTANCEendspan_context||=SpanContext.from_trace_context(elastic_span.trace_context)tags.eachdo|key,value|elastic_span.context.tags[key]=valueendelastic_span.startUtil.micros(start_time)Span.new(elastic_span,span_context)end# rubocop:enable Metrics/AbcSize# rubocop:enable Metrics/MethodLength, Metrics/ParameterListsdefinject(span_context,format,carrier)caseformatwhen::OpenTracing::FORMAT_RACKcarrier['elastic-apm-traceparent']=span_context.to_headerelsewarn'Only injection via HTTP headers and Rack is available'endenddefextract(format,carrier)caseformatwhen::OpenTracing::FORMAT_RACKElasticAPM::TraceContext.parse(carrier['HTTP_ELASTIC_APM_TRACEPARENT'])elsewarn'Only extraction from HTTP headers via Rack is available'nilendrescueElasticAPM::TraceContext::InvalidTraceparentHeadernilendprivatedefprepare_span_context(child_of:,references:,ignore_active_scope:
)context_from_child_of(child_of)||context_from_references(references)||context_from_active_scope(ignore_active_scope)enddefcontext_from_child_of(child_of)returnunlesschild_ofchild_of.respond_to?(:context)?child_of.context:child_ofenddefcontext_from_references(references)returnif!references||references.none?child_of=references.finddo|reference|reference.type==::OpenTracing::Reference::CHILD_OFend(child_of||references.first).contextenddefcontext_from_active_scope(ignore_active_scope)ifignore_active_scopeElasticAPM.agent&.config&.logger&.warn('ignore_active_scope might lead to unexpeced results')returnend@scope_manager.active&.span&.contextendend# rubocop:enable Metrics/ClassLengthendend