# Licensed to Elasticsearch B.V. under one or more contributor# license agreements. See the NOTICE file distributed with# this work for additional information regarding copyright# ownership. Elasticsearch B.V. licenses this file to you under# the Apache License, Version 2.0 (the "License"); you may# not use this file except in compliance with the License.# You may obtain a copy of the License at## http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing,# software distributed under the License is distributed on an# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY# KIND, either express or implied. See the License for the# specific language governing permissions and limitations# under the License.# 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_contextenddefset_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.labels[key]=valendelseelastic_span.context.labels[key]=valendselfenddefset_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(agent=ElasticAPM.agent)elastic_span.doneclock_end: Util.micros(end_time)caseelastic_spanwhenElasticAPM::Transactionagent.instrumenter.current_transaction=nilwhenElasticAPM::Spanagent.instrumenter.current_spans.delete(elastic_span)endagent.enqueueelastic_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 privateclassSpanContextextendForwardabledefinitialize(trace_context:,baggage: nil)ifbaggageElasticAPM.agent.config.logger.warn('Baggage is not supported by ElasticAPM')end@trace_context=trace_contextendattr_accessor:trace_contextdef_delegators:trace_context,:trace_id,:id,:parent_iddefself.from_header(header)returnunlessheadertrace_context=TraceContext.new(traceparent: TraceContext::Traceparent.parse(header))trace_context.traceparent.id=trace_context.parent_idtrace_context.traceparent.parent_id=nilfrom_trace_context(trace_context)enddefself.from_trace_context(trace_context)new(trace_context: trace_context)enddefchildself.class.from_trace_context(trace_context.child)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# A custom tracer to use the OpenTracing API with ElasticAPMclassTracerdefinitialize@scope_manager=ScopeManager.newendattr_reader:scope_managerdefactive_spanscope_manager.active&.spanend# rubocop:disable 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?beginreturnyieldscopeensurescope.closeendendscopeend# rubocop:enable Metrics/ParameterLists# rubocop:disable Metrics/ParameterListsdefstart_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.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.labels[key]=valueendelastic_span.startUtil.micros(start_time)Span.new(elastic_span,span_context)end# rubocop:enable Metrics/ParameterListsdefinject(span_context,format,carrier)caseformatwhen::OpenTracing::FORMAT_RACK,::OpenTracing::FORMAT_TEXT_MAPcarrier['elastic-apm-traceparent']=span_context.traceparent.to_headerelsewarn'Only injection via HTTP headers and Rack is available'endenddefextract(format,carrier)caseformatwhen::OpenTracing::FORMAT_RACKSpanContext.from_header(carrier['HTTP_ELASTIC_APM_TRACEPARENT'])when::OpenTracing::FORMAT_TEXT_MAPSpanContext.from_header(carrier['elastic-apm-traceparent'])elsewarn'Only extraction from HTTP headers via Rack or in '\'text map format are available'nilendrescueElasticAPM::TraceContext::InvalidTraceparentHeadernilendprivatedefprepare_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)returncontext.childifcontext.respond_to?(:child)contextenddefcontext_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 unexpected results')returnend@scope_manager.active&.span&.contextendendendend