diff --git a/lib/middleware.js b/lib/middleware.js index a8ef630c..c581c60f 100644 --- a/lib/middleware.js +++ b/lib/middleware.js @@ -28,6 +28,7 @@ module.exports = function(srf, logger) { registrar, lookupClientByAccountAndUsername } = srf.locals.dbHelpers; + const {addKey} = srf.locals.dbHelpers; const { writeAlerts, AlertType @@ -142,6 +143,14 @@ module.exports = function(srf, logger) { rootSpan }; + /* write a short-lived Redis key mapping the original Call-ID (X-CID) to the traceId, + so sbc-inbound can look it up for CDRs even when a CANCEL is sent to sbc-inbound */ + const externalCallId = req.get('X-CID'); + if (externalCallId) { + addKey(`callid:${externalCallId}`, traceId, 300) + .catch((err) => logger.error(err, 'createRootSpan: error writing traceId to Redis')); + } + /** * end the span on final failure or cancel from caller; * otherwise it will be closed when sip dialog is destroyed diff --git a/lib/session/call-session.js b/lib/session/call-session.js index 099325c5..d1bc8cd9 100644 --- a/lib/session/call-session.js +++ b/lib/session/call-session.js @@ -1495,7 +1495,12 @@ class CallSession extends Emitter { else if (opts.call_status === CallStatus.NoAnswer) { if (this.direction === CallDirection.Inbound) { if (this.res && !this.res.finalResponseSent) { - this.res.send(503); + const traceId = this.req?.locals?.traceId; + this.res.send(503, { + headers: { + ...(traceId && {'X-Trace-ID': traceId}) + } + }); this._callReleased(); } } @@ -2530,10 +2535,12 @@ Duration=${duration} ` // Send SIP error response immediately for inbound calls if (this.res && !this.res.finalResponseSent) { this.logger.info(`Sending ${err.status} response to SBC due to SipError`); + const traceId = this.req?.locals?.traceId; this.res.send(err.status, { headers: { 'X-Reason': `endpoint allocation failure: ${err.reason || 'Endpoint Allocation Failed'}`, - ...(sipReasonHeader && {'Reason': sipReasonHeader}) + ...(sipReasonHeader && {'Reason': sipReasonHeader}), + ...(traceId && {'X-Trace-ID': traceId}) } }); this._notifyCallStatusChange({ diff --git a/lib/session/inbound-call-session.js b/lib/session/inbound-call-session.js index a905f4bd..ef69c556 100644 --- a/lib/session/inbound-call-session.js +++ b/lib/session/inbound-call-session.js @@ -51,12 +51,14 @@ class InboundCallSession extends CallSession { _onTasksDone() { if (!this.res.finalResponseSent) { + const traceId = this.req.locals.traceId; if (this._mediaServerFailure) { this.rootSpan.setAttributes({'call.termination': 'media server failure'}); this.logger.info('InboundCallSession:_onTasksDone generating 480 due to media server failure'); this.res.send(480, { headers: { - 'X-Reason': 'crankback: media server failure' + 'X-Reason': 'crankback: media server failure', + ...(traceId && {'X-Trace-ID': traceId}) } }); } @@ -69,14 +71,19 @@ class InboundCallSession extends CallSession { this.res.send(status, { headers: { 'X-Reason': `endpoint allocation failure: ${reason}`, - ...(sipReasonHeader && {'Reason': sipReasonHeader}) + ...(sipReasonHeader && {'Reason': sipReasonHeader}), + ...(traceId && {'X-Trace-ID': traceId}) } }); } else { this.rootSpan.setAttributes({'call.termination': 'tasks completed without answering call'}); this.logger.info('InboundCallSession:_onTasksDone auto-generating non-success response to invite'); - this.res.send(603); + this.res.send(603, { + headers: { + ...(traceId && {'X-Trace-ID': traceId}) + } + }); } } this.req.removeAllListeners('cancel');