diff --git a/lib/utils/call-tracer.js b/lib/utils/call-tracer.js index b6b229e83..bebb06914 100644 --- a/lib/utils/call-tracer.js +++ b/lib/utils/call-tracer.js @@ -1,39 +1,42 @@ -const {context, trace} = require('@opentelemetry/api'); + +const {trace, context, SpanKind} = require('@opentelemetry/api'); const {Dialog} = require('drachtio-srf'); +const {SipPropagator} = require('./sip-propagator'); + class RootSpan { constructor(callType, req) { - let tracer, callSid, linkedSpanId; + const tracer = req.srf.locals.otel.tracer; + const propagator = new SipPropagator(); + const ctx = propagator.extract(context.active(), req); + this._span = tracer.startSpan(callType || 'incoming-call', { + kind: SpanKind.CONSUMER, + attributes: this.getSpanAttributes(req), + root: false + }, ctx); + this._ctx = trace.setSpan(ctx, this._span); + this.tracer = tracer; + } + getSpanAttributes(req) { if (req instanceof Dialog) { - const dlg = req; - tracer = dlg.srf.locals.otel.tracer; - callSid = dlg.callSid; - linkedSpanId = dlg.linkedSpanId; - } - else { - tracer = req.srf.locals.otel.tracer; - callSid = req.locals.callSid; - } - this._span = tracer.startSpan(callType || 'incoming-call'); - if (req instanceof Dialog) { - const dlg = req; - this._span.setAttributes({ + const {sip, callSid, linkedSpanId} = req; + const {callId} = sip; + return { linkedSpanId, - callId: dlg.sip.callId - }); - } - else { - this._span.setAttributes({ + callId, + callSid + }; + } else { + const {locals} = req; + const {callSid} = locals; + return { callSid, accountSid: req.get('X-Account-Sid'), - applicationSid: req.locals.application_sid, + applicationSid: locals.application_sid, callId: req.get('Call-ID'), externalCallId: req.get('X-CID') - }); + }; } - - this._ctx = trace.setSpan(context.active(), this._span); - this.tracer = tracer; } get context() { @@ -54,7 +57,7 @@ class RootSpan { getTracingPropagation(encoding) { // TODO: support encodings beyond b3 https://github.com/openzipkin/b3-propagation - if (this._span && this.traceId !== '00000000000000000000000000000000') { + if (this._span && this.traceId !== '00000000000000000000000000000000') { return `${this.traceId}-${this.spanId}-1`; } } @@ -69,10 +72,9 @@ class RootSpan { startChildSpan(name, attributes) { const span = this.tracer.startSpan(name, attributes, this._ctx); - const ctx = trace.setSpan(context.active(), span); + const ctx = trace.setSpan(this._ctx, span); return {span, ctx}; } } module.exports = RootSpan; - diff --git a/lib/utils/sip-propagator.js b/lib/utils/sip-propagator.js new file mode 100644 index 000000000..c51a44219 --- /dev/null +++ b/lib/utils/sip-propagator.js @@ -0,0 +1,50 @@ +const {TraceFlags, trace, isSpanContextValid, isValidTraceId, isValidSpanId} = require('@opentelemetry/api'); +const {isTracingSuppressed} = require('@opentelemetry/core'); +const {Dialog} = require('drachtio-srf'); + +class SipPropagator { + constructor() { + } + + inject(context, carrier, setter) { + const spanContext = trace.getSpanContext(context); + if (!spanContext || !isSpanContextValid(spanContext) || isTracingSuppressed(context)) { + return; + } + setter.set(carrier, 'traceId', spanContext.traceId); + setter.set(carrier, 'spanId', spanContext.spanId); + } + + extract(context, carrier) { + const callSid = this.getCallSidFromCarrier(carrier); + const traceId = this.getHexValue(callSid); + const spanId = traceId.substring(0, 16); + if (!isValidTraceId(traceId) || !isValidSpanId(spanId)) { + return context; + } + return trace.setSpanContext(context, { + traceId, + spanId, + isRemote: true, + traceFlags: TraceFlags.SAMPLED + }); + } + + fields() { + return ['traceId', 'spanId']; + } + + getCallSidFromCarrier(carrier) { + if (carrier instanceof Dialog) { + return carrier.callSid; + } else { + return carrier.locals.callSid; + } + } + + getHexValue(callSid) { + return callSid.replaceAll('-', ''); + } +} + +exports.SipPropagator = SipPropagator;