diff --git a/README.md b/README.md index 07ec990..a6c3cea 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,11 @@ Configuration is provided via environment variables: |JAMBONES_RECORD_ALL_CALLS| enable auto record calls |no| |K8S| service running as kubernetes service |no| |K8S_RTPENGINE_SERVICE_NAME| rtpengine service name(required for K8S) |no| +|JAMBONES_OTEL_ENABLED| set to 1 to enable otel tracing |no| +|JAMBONES_OTEL_SERVICE_NAME| app name |no| +|OTEL_EXPORTER_JAEGER_ENDPOINT| jaeger endpoint url 'http://127.0.0.1:14268/api/traces' |no| + + ### running under pm2 Typically, this application runs under [pm2](https://pm2.io) using an [ecosystem.config.js](https://pm2.keymetrics.io/docs/usage/application-declaration/) file similar to this: diff --git a/app.js b/app.js index 796fd22..28d0c77 100644 --- a/app.js +++ b/app.js @@ -14,7 +14,9 @@ const srf = new Srf('sbc-outbound'); const CIDRMatcher = require('cidr-matcher'); const {equalsIgnoreOrder, pingMsTeamsGateways, createHealthCheckApp, systemHealth} = require('./lib/utils'); const opts = Object.assign({ - timestamp: () => {return `, "time": "${new Date().toISOString()}"`;} + timestamp: () => { + return `, "time": "${new Date().toISOString()}"`; + }, }, {level: process.env.JAMBONES_LOGLEVEL || 'info'}); const logger = require('pino')(opts); const { @@ -24,11 +26,11 @@ const { writeCdrs, queryCdrs, writeAlerts, - AlertType + AlertType, } = require('@jambonz/time-series')(logger, { host: process.env.JAMBONES_TIME_SERIES_HOST, commitSize: 50, - commitInterval: 'test' === process.env.NODE_ENV ? 7 : 20 + commitInterval: 'test' === process.env.NODE_ENV ? 7 : 20, }); const StatsCollector = require('@jambonz/stats-collector'); const stats = new StatsCollector(logger); @@ -44,14 +46,14 @@ const { lookupAccountCapacitiesBySid, lookupSipGatewaysByCarrier, lookupCarrierBySid, - queryCallLimits + queryCallLimits, } = require('@jambonz/db-helpers')({ host: process.env.JAMBONES_MYSQL_HOST, port: process.env.JAMBONES_MYSQL_PORT || 3306, user: process.env.JAMBONES_MYSQL_USER, password: process.env.JAMBONES_MYSQL_PASSWORD, database: process.env.JAMBONES_MYSQL_DATABASE, - connectionLimit: process.env.JAMBONES_MYSQL_CONNECTION_LIMIT || 10 + connectionLimit: process.env.JAMBONES_MYSQL_CONNECTION_LIMIT || 10, }, logger); const { client: redisClient, @@ -60,17 +62,31 @@ const { incrKey, decrKey, retrieveSet, - isMemberOfSet + isMemberOfSet, } = require('@jambonz/realtimedb-helpers')({ host: process.env.JAMBONES_REDIS_HOST, - port: process.env.JAMBONES_REDIS_PORT || 6379 + port: process.env.JAMBONES_REDIS_PORT || 6379, }, logger); const activeCallIds = new Map(); const Emitter = require('events'); const idleEmitter = new Emitter(); -srf.locals = {...srf.locals, +const {version} = require('./package.json'); +const {JambonzTracer} = require('@jambonz/tracing'); +const {tracer} = new JambonzTracer({ + version, + name: process.env.JAMBONES_OTEL_SERVICE_NAME || 'jambonz-sbc-outbound', + enabled: process.env.JAMBONES_OTEL_ENABLED, + jaegerHost: process.env.OTEL_EXPORTER_JAEGER_AGENT_HOST, + jaegerEndpoint: process.env.OTEL_EXPORTER_JAEGER_ENDPOINT, + zipkinUrl: process.env.OTEL_EXPORTER_ZIPKIN_URL, + collectorUrl: process.env.OTEL_EXPORTER_COLLECTOR_URL, + logLevel: process.env.JAMBONES_LOGLEVEL, +}); + +srf.locals = { + ...srf.locals, stats, writeCallCount, writeCallCountSP, @@ -90,26 +106,29 @@ srf.locals = {...srf.locals, lookupAccountCapacitiesBySid, lookupSipGatewaysByCarrier, lookupCarrierBySid, - queryCallLimits + queryCallLimits, }, realtimeDbHelpers: { createHash, retrieveHash, incrKey, decrKey, - isMemberOfSet - } + isMemberOfSet, + }, + otel: { + tracer, + }, }; -const {initLocals, checkLimits, route} = require('./lib/middleware')(srf, logger, { +const {initLocals, createRootSpan, checkLimits, route} = require('./lib/middleware')(srf, logger, { host: process.env.JAMBONES_REDIS_HOST, - port: process.env.JAMBONES_REDIS_PORT || 6379 + port: process.env.JAMBONES_REDIS_PORT || 6379, }); const ngProtocol = process.env.JAMBONES_NG_PROTOCOL || 'udp'; const ngPort = process.env.RTPENGINE_PORT || ('udp' === ngProtocol ? 22222 : 8080); const {getRtpEngine, setRtpEngines} = require('@jambonz/rtpengine-utils')([], logger, { //emitter: stats, dtmfListenPort: process.env.DTMF_LISTEN_PORT || 22225, - protocol: ngProtocol + protocol: ngProtocol, }); srf.locals.getRtpEngine = getRtpEngine; @@ -120,7 +139,7 @@ if (process.env.DRACHTIO_HOST && !process.env.K8S) { logger.info({cidrs}, 'internal network CIDRs'); const matcher = new CIDRMatcher(cidrs); - srf.connect({host: process.env.DRACHTIO_HOST, port: process.env.DRACHTIO_PORT, secret: process.env.DRACHTIO_SECRET }); + srf.connect({host: process.env.DRACHTIO_HOST, port: process.env.DRACHTIO_PORT, secret: process.env.DRACHTIO_SECRET}); srf.on('connect', (err, hp) => { logger.info(`connected to drachtio listening on ${hp}`); @@ -130,16 +149,14 @@ if (process.env.DRACHTIO_HOST && !process.env.K8S) { if (arr && 'udp' === arr[1] && !matcher.contains(arr[2])) { logger.info(`sbc public address: ${arr[2]}`); srf.locals.sipAddress = arr[2]; - } - else if (arr && 'tcp' === arr[1] && matcher.contains(arr[2])) { + } else if (arr && 'tcp' === arr[1] && matcher.contains(arr[2])) { const hostport = `${arr[2]}:${arr[3]}`; logger.info(`sbc private address: ${hostport}`); srf.locals.privateSipAddress = hostport; } } }); -} -else { +} else { logger.info(`listening in outbound mode on port ${process.env.DRACHTIO_PORT}`); srf.listen({port: process.env.DRACHTIO_PORT, secret: process.env.DRACHTIO_SECRET}); } @@ -149,7 +166,7 @@ if (process.env.NODE_ENV === 'test') { }); } -srf.use('invite', [initLocals, checkLimits, route]); +srf.use('invite', [initLocals, createRootSpan, checkLimits, route]); srf.invite((req, res) => { const session = new CallSession(logger, req, res); session.connect(); @@ -167,13 +184,13 @@ if (process.env.K8S || process.env.HTTP_PORT) { app, logger, path: '/', - fn: getCount + fn: getCount, }); healthCheck({ app, logger, path: '/system-health', - fn: systemHealth.bind(null, redisClient, ping, getCount) + fn: systemHealth.bind(null, redisClient, ping, getCount), }); return; }) @@ -214,12 +231,10 @@ if (process.env.K8S_RTPENGINE_SERVICE_NAME) { const {lookup} = require('dns'); lookupRtpServiceEndpoints(lookup, svc); setInterval(lookupRtpServiceEndpoints.bind(null, lookup, svc), process.env.RTPENGINE_DNS_POLL_INTERVAL || 10000); -} -else if (process.env.JAMBONES_RTPENGINES) { +} else if (process.env.JAMBONES_RTPENGINES) { /* static list of rtpengines */ setRtpEngines([process.env.JAMBONES_RTPENGINES]); -} -else { +} else { /* poll redis periodically for rtpengines that have registered via OPTIONS ping */ const getActiveRtpServers = async() => { try { @@ -253,8 +268,7 @@ function handle(signal) { if (0 === activeCallIds.size) { logger.info('exiting immediately since we have no calls in progress'); process.exit(0); - } - else { + } else { idleEmitter.once('idle', () => process.exit(0)); } } diff --git a/lib/call-session.js b/lib/call-session.js index 5dc1a16..abb6551 100644 --- a/lib/call-session.js +++ b/lib/call-session.js @@ -18,8 +18,7 @@ const createBLegFromHeader = (req, teams) => { let host = 'localhost'; if (teams) { host = req.get('X-MS-Teams-Tenant-FQDN'); - } - else if (req.has('X-Preferred-From-User') || req.has('X-Preferred-From-Host')) { + } else if (req.has('X-Preferred-From-User') || req.has('X-Preferred-From-Host')) { user = req.get('X-Preferred-From-User') || user; host = req.get('X-Preferred-From-Host') || host; } @@ -55,7 +54,7 @@ const initCdr = (srf, req) => { direction: 'outbound', host: srf.locals.sipAddress, remote_host: uri.host, - trace_id: req.get('X-Trace-ID') || '00000000000000000000000000000000' + trace_id: req.get('X-Trace-ID') || '00000000000000000000000000000000', }; }; @@ -64,7 +63,8 @@ const updateRtpEngineFlags = (sdp, opts) => { const parsed = sdpTransform.parse(sdp); const codec = parsed.media[0].rtp[0].codec; if (['PCMU', 'PCMA'].includes(codec)) opts.flags.push(`codec-accept-${codec}`); - } catch (err) {} + } catch (err) { + } return opts; }; @@ -119,6 +119,7 @@ class CallSession extends Emitter { this._onDTMF.bind(this, dlg)); } } + unsubscribeForDTMF() { if (this._subscribedForDTMF) { this._subscribedForDTMF = false; @@ -127,9 +128,12 @@ class CallSession extends Emitter { } async connect() { + const {rootSpan, ...locals} = this.req.locals; + const childSpan = rootSpan.startChildSpan('outbound:connect', {}); const teams = this.teams = this.req.locals.target === 'teams'; const engine = this.srf.locals.getRtpEngine(); if (!engine) { + childSpan.endWithError('no rtp engines'); this.logger.info('No available rtpengines, rejecting call!'); return this.res.send(480); } @@ -147,7 +151,7 @@ class CallSession extends Emitter { unsubscribeDTMF, subscribeRequest, subscribeAnswer, - unsubscribe + unsubscribe, } = engine; const {createHash, retrieveHash} = this.srf.locals.realtimeDbHelpers; this.offer = offer; @@ -171,16 +175,17 @@ class CallSession extends Emitter { try { // determine where to send the call - debug(`connecting call: ${JSON.stringify(this.req.locals)}`); + debug(`connecting call: ${JSON.stringify(locals)}`); let headers = { 'From': createBLegFromHeader(this.req, teams), 'Contact': createBLegFromHeader(this.req, teams), 'To': createBLegToHeader(this.req, teams), Allow: 'INVITE, ACK, OPTIONS, CANCEL, BYE, NOTIFY, UPDATE, PRACK', - 'X-Account-Sid': this.account_sid + 'X-Account-Sid': this.account_sid, }; - + childSpan.setAttributes(headers); if (this.req.locals.registration) { + childSpan.setAttributes({callType: 'user'}); debug(`sending call to registered user ${JSON.stringify(this.req.locals.registration)}`); const contact = this.req.locals.registration.contact; let destUri = contact; @@ -190,28 +195,27 @@ class CallSession extends Emitter { uri.user = dest; destUri = stringifyUri(uri); this.logger.info(`overriding destination user with ${dest}, so final uri is ${destUri}`); + childSpan.setAttributes({'X-Override-To': dest}); } uris = [destUri]; if (!contact.includes('transport=ws')) { proxy = this.req.locals.registration.proxy; } - } - else if (this.req.locals.target === 'forward') { + } else if (this.req.locals.target === 'forward') { uris = [this.req.uri]; - } - else if (teams) { + } else if (teams) { const vmailParam = 'opaque=app:voicemail'; proxy = `sip:${this.req.calledNumber}@sip.pstnhub.microsoft.com:5061;transport=tls`; if (this.req.uri.includes(vmailParam)) { uris = [`sip:${this.req.calledNumber}@sip.pstnhub.microsoft.com;${vmailParam}`]; - } - else uris = [`sip:${this.req.calledNumber}@sip.pstnhub.microsoft.com`]; + } else uris = [`sip:${this.req.calledNumber}@sip.pstnhub.microsoft.com`]; headers = { ...headers, - Contact: `sip:${this.req.calledNumber}@${this.req.get('X-MS-Teams-Tenant-FQDN')}:5061;transport=tls` + Contact: `sip:${this.req.calledNumber}@${this.req.get('X-MS-Teams-Tenant-FQDN')}:5061;transport=tls`, }; - } - else { + childSpan.setAttributes(headers); + } else { + childSpan.setAttributes({lcr: 'true'}); debug('calling lcr'); try { /* was a specific carrier requested */ @@ -231,20 +235,19 @@ class CallSession extends Emitter { const obj = { name: vc.name, diversion: vc.diversion, - hostport + hostport, }; if (vc.register_username && vc.register_password) { obj.auth = { username: vc.register_username, - password: vc.register_password + password: vc.register_password, }; } mapGateways.set(u, obj); uris.push(u); }); this.logger.debug({uris, voip_carrier_sid}, 'selected outbound gateways for requested carrier'); - } - else { + } else { this.logger.info({voip_carrier_sid}, 'no outbound gateways found for requested carrier'); } } @@ -263,7 +266,7 @@ class CallSession extends Emitter { name: gw.name, auth: gw.auth, diversion: gw.diversion, - hostport: gw.hostport + hostport: gw.hostport, })); uris = gateways.map((gw) => gw.uri); } @@ -281,24 +284,28 @@ class CallSession extends Emitter { ...this.rtpEngineOpts.common, ...this.rtpEngineOpts.uac.mediaOpts, 'from-tag': this.rtpEngineOpts.uas.tag, - direction: ['private', 'public'], - sdp: this.req.body + direction: ['private', 'public'], + sdp: this.req.body, }); const response = await this.offer(opts); debug(`response from rtpengine to offer ${JSON.stringify(response)}`); this.logger.debug({offer: opts, response}, 'initial offer to rtpengine'); if ('ok' !== response.result) { this.logger.error(`rtpengine offer failed with ${JSON.stringify(response)}`); + childSpan.endWithError('rtpengine failed: answer'); throw new Error('rtpengine failed: answer'); } /* check if call was abandoned */ - if (this.req.canceled) throw new Error('abandoned'); + if (this.req.canceled) { + childSpan.endWithError('abandoned'); + throw new Error('abandoned'); + } // crank through the list of gateways until connected, exhausted or caller hangs up let earlyMedia = false; while (uris.length) { - let hdrs = { ...headers}; + let hdrs = {...headers}; const uri = uris.shift(); const gw = mapGateways.get(uri); const passFailure = 0 === uris.length; // only a single target @@ -310,7 +317,7 @@ class CallSession extends Emitter { hdrs = { ...hdrs, 'Call-ID': obj.callId, - 'CSeq': `${obj.cseq} INVITE` + 'CSeq': `${obj.cseq} INVITE`, }; } } catch (err) { @@ -324,15 +331,13 @@ class CallSession extends Emitter { let div = gw.diversion; if (div.startsWith('+')) { div = `;reason=unknown;counter=1;privacy=off`; - } - else div = `;reason=unknown;counter=1;privacy=off`; + } else div = `;reason=unknown;counter=1;privacy=off`; hdrs = { ...hdrs, - 'Diversion': div + 'Diversion': div, }; } - } - else this.logger.info(`sending INVITE to ${uri} via proxy ${proxy})`); + } else this.logger.info(`sending INVITE to ${uri} via proxy ${proxy})`); try { const responseHeaders = this.privateSipAddress ? {Contact: ``} : {}; @@ -356,7 +361,7 @@ class CallSession extends Emitter { proxyResponseHeaders: [ 'all', '-Allow', - '-Session-Expires' + '-Session-Expires', ], headers: hdrs, responseHeaders, @@ -370,17 +375,18 @@ class CallSession extends Emitter { 'from-tag': this.rtpEngineOpts.uas.tag, 'to-tag': this.rtpEngineOpts.uac.tag, flags: ['single codec'], - sdp + sdp, }; const response = await this.answer(opts); this.logger.debug({answer: opts, response}, 'rtpengine answer'); if ('ok' !== response.result) { /* note: this can happen if call was abandoned while we were waiting for B leg to answer */ + childSpan.endWithError(`rtpengine failed: ${response['error-reason']}`); this.logger.info(`rtpengine answer failed with ${JSON.stringify(response)}`); throw new Error(`rtpengine failed: ${response['error-reason']}`); } return response.sdp; - } + }, }, { cbRequest: async(err, inv) => { if (err) return this.logger.info({err}, 'CallSession error sending INVITE'); @@ -392,19 +398,18 @@ class CallSession extends Emitter { } if (this.req.locals.account?.disable_cdrs) { this.logger.debug('cdrs disabled for this account'); - } - else { + } else { this.req.locals.cdr = { ...initCdr(this.req.srf, inv), service_provider_sid: this.req.locals.service_provider_sid, account_sid: this.req.locals.account_sid, ...(this.req.locals.application_sid && {application_sid: this.req.locals.application_sid}), - trunk + trunk, }; } const opts = { callId: inv.get('Call-ID'), - cseq: ++inv.getParsedHeader('CSeq').seq + cseq: ++inv.getParsedHeader('CSeq').seq, }; try { const key = makeInviteInProgressKey(this.req.get('Call-ID')); @@ -415,7 +420,7 @@ class CallSession extends Emitter { }, cbProvisional: (response) => { if (!earlyMedia && [180, 183].includes(response.status) && response.body) earlyMedia = true; - } + }, }); // successfully connected @@ -448,25 +453,27 @@ class CallSession extends Emitter { this.stats.increment('sbc.originations', tags); if (this.req.locals.cdr && ![401, 407].includes(status)) { - this.writeCdrs({...this.req.locals.cdr, + this.writeCdrs({ + ...this.req.locals.cdr, terminated_at: Date.now(), termination_reason: 487 === status ? 'caller abandoned' : 'failed', - sip_status: status + sip_status: status, }).catch((err) => this.logger.error({err}, 'Error writing cdr for call failure')); } return; - } - else { + } else { this.logger.info(`got ${err.status}, cranking back to next destination`); } } } } catch (err) { + childSpan.endWithError('Error setting up outbound'); if ('abandonded' !== err.message) this.logger.error(err, `Error setting up outbound call to: ${uris}`); this.emit('failed'); this.srf.endSession(this.req); this.rtpEngineResource.destroy(); } + childSpan.end(); } _setHandlers({uas, uac}) { @@ -478,7 +485,7 @@ class CallSession extends Emitter { this.req.locals.cdr = { ...this.req.locals.cdr, answered: true, - answered_at: callStart + answered_at: callStart, }; } this.uas = uas; @@ -492,7 +499,8 @@ class CallSession extends Emitter { //this.unsubscribeDTMF(this.logger, this.req.get('Call-ID'), this.rtpEngineOpts.uac.tag); try { await other.destroy(); - } catch (err) {} + } catch (err) { + } const trackingOn = process.env.JAMBONES_TRACK_ACCOUNT_CALLS || process.env.JAMBONES_TRACK_SP_CALLS || @@ -503,7 +511,7 @@ class CallSession extends Emitter { await nudgeCallCounts(this.logger, { service_provider_sid: this.service_provider_sid, account_sid: this.account_sid, - application_sid: this.application_sid + application_sid: this.application_sid, }, this.decrKey, {writeCallCountSP, writeCallCount, writeCallCountApp}) .catch((err) => this.logger.error(err, 'Error decrementing call counts')); } @@ -511,12 +519,13 @@ class CallSession extends Emitter { /* write cdr for connected call */ if (this.req.locals.cdr) { const now = Date.now(); - this.writeCdrs({...this.req.locals.cdr, + this.writeCdrs({ + ...this.req.locals.cdr, terminated_at: now, termination_reason: dlg.type === 'uas' ? 'caller hungup' : 'called party hungup', sip_status: 200, answered: true, - duration: Math.floor((now - callStart) / 1000) + duration: Math.floor((now - callStart) / 1000), }).catch((err) => this.logger.error({err}, 'Error writing cdr for completed call')); } /* de-link the 2 Dialogs for GC */ @@ -550,7 +559,7 @@ class CallSession extends Emitter { uac.on('info', this._onInfo.bind(this, uac)); // default forwarding of other request types - forwardInDialogRequests(uac, ['notify', 'options', 'message']); + forwardInDialogRequests(uac, ['notify', 'options', 'message']); } async _onRefer(dlg, req, res) { @@ -561,8 +570,8 @@ class CallSession extends Emitter { headers: { 'Refer-To': req.get('Refer-To'), 'Referred-By': req.get('Referred-By'), - 'User-Agent': req.get('User-Agent') - } + 'User-Agent': req.get('User-Agent'), + }, }); res.send(response.status, response.reason); } catch (err) { @@ -588,10 +597,10 @@ class CallSession extends Emitter { await dlg.request({ method: 'INFO', headers: { - 'Content-Type': 'application/dtmf-relay' + 'Content-Type': 'application/dtmf-relay', }, body: `Signal=${dtmf} -Duration=${payload.duration} ` +Duration=${payload.duration} `, }); } catch (err) { this.logger.info({err}, 'Error sending INFO application/dtmf-relay'); @@ -606,7 +615,7 @@ Duration=${payload.duration} ` const toTag = dlg.type === 'uas' ? this.rtpEngineOpts.uac.tag : this.rtpEngineOpts.uas.tag; const offerMedia = dlg.type === 'uas' ? this.rtpEngineOpts.uac.mediaOpts : this.rtpEngineOpts.uas.mediaOpts; const answerMedia = dlg.type === 'uas' ? this.rtpEngineOpts.uas.mediaOpts : this.rtpEngineOpts.uac.mediaOpts; - const direction = dlg.type === 'uas' ? ['private', 'public'] : ['public', 'private']; + const direction = dlg.type === 'uas' ? ['private', 'public'] : ['public', 'private']; if (isReleasingMedia) { if (!offerMedia.flags.includes('port latching')) offerMedia.flags.push('port latching'); if (!offerMedia.flags.includes('asymmetric')) offerMedia.flags.push('asymmetric'); @@ -639,8 +648,7 @@ Duration=${payload.duration} ` if (!answerMedia.flags.includes('asymmetric')) answerMedia.flags.push('asymmetric'); answerMedia.flags = answerMedia.flags.filter((f) => f !== 'media handover'); this._mediaReleased = 'release-media' === reason; - } - else { + } else { sdp = await dlg.other.modify(response.sdp); this.logger.info({sdp}, 'CallSession:_onReinvite: got sdp from 200 OK to invite we sent'); } @@ -649,7 +657,7 @@ Duration=${payload.duration} ` ...answerMedia, 'from-tag': fromTag, 'to-tag': toTag, - sdp + sdp, }; response = await this.answer(opts); if ('ok' !== response.result) { @@ -671,7 +679,7 @@ Duration=${payload.duration} ` const reason = req.get('X-Reason'); const opts = { ...this.rtpEngineOpts.common, - 'from-tag': toTag + 'from-tag': toTag, }; this.logger.info(`_onInfo: got request ${reason}`); res.send(200); @@ -679,12 +687,10 @@ Duration=${payload.duration} ` if (reason.startsWith('mute')) { const response = Promise.all([this.blockMedia(opts), this.blockDTMF(opts)]); this.logger.info({response}, `_onInfo: response to rtpengine command for ${reason}`); - } - else if (reason.startsWith('unmute')) { + } else if (reason.startsWith('unmute')) { const response = Promise.all([this.unblockMedia(opts), this.unblockDTMF(opts)]); this.logger.info({response}, `_onInfo: response to rtpengine command for ${reason}`); - } - else if (reason.includes('CallRecording')) { + } else if (reason.includes('CallRecording')) { let succeeded = false; if (reason === 'startCallRecording') { const from = this.req.getParsedHeader('From'); @@ -728,15 +734,14 @@ Duration=${payload.duration} ` del: this.del, blockMedia: this.blockMedia, unblockMedia: this.unblockMedia, - unsubscribe: this.unsubscribe + unsubscribe: this.unsubscribe, }); try { succeeded = await this.srsClient.start(); } catch (err) { this.logger.error({err}, 'Error starting SipRec call recording'); } - } - else if (reason === 'stopCallRecording') { + } else if (reason === 'stopCallRecording') { if (!this.srsClient) { res.send(400); this.logger.info('discarding stopCallRecording request because we are not recording'); @@ -748,16 +753,14 @@ Duration=${payload.duration} ` this.logger.error({err}, 'Error stopping SipRec call recording'); } this.srsClient = null; - } - else if (reason === 'pauseCallRecording') { + } else if (reason === 'pauseCallRecording') { if (!this.srsClient || this.srsClient.paused) { this.logger.info('discarding invalid pauseCallRecording request'); res.send(400); return; } succeeded = await this.srsClient.pause(); - } - else if (reason === 'resumeCallRecording') { + } else if (reason === 'resumeCallRecording') { if (!this.srsClient || !this.srsClient.paused) { res.send(400); this.logger.info('discarding invalid resumeCallRecording request'); @@ -767,8 +770,7 @@ Duration=${payload.duration} ` } res.send(succeeded ? 200 : 503); } - } - else if (dlg.type === 'uac' && ['application/dtmf-relay', 'application/dtmf'].includes(contentType)) { + } else if (dlg.type === 'uac' && ['application/dtmf-relay', 'application/dtmf'].includes(contentType)) { const arr = /Signal=\s*([0-9#*])/.exec(req.body); if (!arr) { this.logger.info({body: req.body}, '_onInfo: invalid INFO dtmf request'); @@ -784,15 +786,14 @@ Duration=${payload.duration} ` this._onDTMF(dlg.other, {event: code, duration}) .catch((err) => this.logger.info({err}, 'Error relaying DTMF to feature server')); res.send(200); - } - else { + } else { /* else convert SIP INFO to RFC 2833 telephony events */ this.logger.info({code, duration}, 'got SIP INFO DTMF from caller, converting to RFC 2833'); const opts = { ...this.rtpEngineOpts.common, 'from-tag': this.rtpEngineOpts.uac.tag, code, - duration + duration, }; const response = await this.playDTMF(opts); if ('ok' !== response.result) { @@ -801,16 +802,15 @@ Duration=${payload.duration} ` } res.send(200); } - } - else { + } else { const response = await dlg.other.request({ method: 'INFO', headers: req.headers, - body: req.body + body: req.body, }); res.send(response.status, { headers: response.headers, - body: response.body + body: response.body, }); } } catch (err) { @@ -837,8 +837,8 @@ Duration=${payload.duration} ` method: 'REFER', headers: { 'Refer-To': stringifyUri(uri), - 'Referred-By': stringifyUri(u) - } + 'Referred-By': stringifyUri(u), + }, }); return res.send(response.status); } @@ -847,7 +847,7 @@ Duration=${payload.duration} ` // invite to new fs const headers = { ...(req.has('X-Retain-Call-Sid') && {'X-Retain-Call-Sid': req.get('X-Retain-Call-Sid')}), - ...(req.has('X-Account-Sid') && {'X-Account-Sid': req.get('X-Account-Sid')}) + ...(req.has('X-Account-Sid') && {'X-Account-Sid': req.get('X-Account-Sid')}), }; const dlg = await this.srf.createUAC(referTo.uri, {localSdp: dlg.local.sdp, headers}); this.uas = dlg; diff --git a/lib/middleware.js b/lib/middleware.js index 0fe6724..6de1bc0 100644 --- a/lib/middleware.js +++ b/lib/middleware.js @@ -2,7 +2,8 @@ const debug = require('debug')('jambonz:sbc-outbound'); const parseUri = require('drachtio-srf').parseUri; const Registrar = require('@jambonz/mw-registrar'); const {selectHostPort, nudgeCallCounts} = require('./utils'); -const FS_UUID_SET_NAME = 'fsUUIDs'; +const FS_UUID_SET_NAME = 'fsUUIDs'; +const {RootSpan} = require('@jambonz/tracing'); module.exports = (srf, logger, opts) => { const {incrKey, decrKey, isMemberOfSet} = srf.locals.realtimeDbHelpers; @@ -11,8 +12,8 @@ module.exports = (srf, logger, opts) => { const { lookupAccountCapacitiesBySid, lookupAccountBySid, - queryCallLimits - } = srf.locals.dbHelpers; + queryCallLimits, + } = srf.locals.dbHelpers; const initLocals = async(req, res, next) => { req.locals = req.locals || {}; @@ -24,14 +25,15 @@ module.exports = (srf, logger, opts) => { callId, traceId, account_sid: - req.locals.account_sid}); + req.locals.account_sid, + }); if (!req.locals.account_sid) { logger.info('missing X-Account-Sid on outbound call'); res.send(403, { headers: { - 'X-Reason': 'missing X-Account-Sid' - } + 'X-Reason': 'missing X-Account-Sid', + }, }); return req.srf.endSession(req); } @@ -41,8 +43,8 @@ module.exports = (srf, logger, opts) => { logger.info({msg: req.msg}, 'missing X-Jambonz-Routing header'); res.send(403, { headers: { - 'X-Reason': 'missing required jambonz headers' - } + 'X-Reason': 'missing required jambonz headers', + }, }); return req.srf.endSession(req); } @@ -54,8 +56,8 @@ module.exports = (srf, logger, opts) => { if (!exists || !fsUUID) { res.send(403, { headers: { - 'X-Reason': `missing or invalid FS-UUID ${fsUUID}` - } + 'X-Reason': `missing or invalid FS-UUID ${fsUUID}`, + }, }); return req.srf.endSession(req); } @@ -86,12 +88,41 @@ module.exports = (srf, logger, opts) => { next(); }; + const createRootSpan = (req, res, next) => { + const {tracer} = req.srf.locals.otel; + const rootSpan = new RootSpan('sbc:outgoing-call', req.get('X-Trace-ID'), req.get('X-Span-ID'), {}, tracer, logger); + const traceId = rootSpan.traceId; + req.locals = { + ...req.locals, + traceId, + rootSpan, + }; + /** + * end the span on final failure or cancel from caller; + * otherwise it will be closed when sip dialog is destroyed + */ + req.once('cancel', () => { + logger.info('cancel'); + rootSpan.setAttributes({finalStatus: 487}); + rootSpan.end(); + }); + res.once('finish', () => { + logger.info('finish'); + rootSpan.setAttributes({finalStatus: res.statusCode}); + res.statusCode >= 300 && rootSpan.end(); + }); + next(); + }; + const checkLimits = async(req, res, next) => { - const {logger, account_sid, service_provider_sid, application_sid} = req.locals; + const {logger, account_sid, service_provider_sid, application_sid, rootSpan} = req.locals; const trackingOn = process.env.JAMBONES_TRACK_ACCOUNT_CALLS || process.env.JAMBONES_TRACK_SP_CALLS || process.env.JAMBONES_TRACK_APP_CALLS; + const childSpan = rootSpan.startChildSpan('outbound:checkLimits'); if (!process.env.JAMBONES_HOSTING && !trackingOn) { + childSpan.setAttributes({trackingOn: 'false'}); + childSpan.end(); logger.debug('tracking is off, skipping call limit checks'); return next(); // skip } @@ -105,23 +136,22 @@ module.exports = (srf, logger, opts) => { nudgeCallCounts(logger, { service_provider_sid, account_sid, - application_sid + application_sid, }, decrKey, {writeCallCountSP, writeCallCount, writeCallCountApp}) .catch((err) => logger.error(err, 'Error decrementing call counts')); const tags = ['accepted:no', `sipStatus:${status}`]; stats.increment('sbc.originations', tags); - } - else { + } else { const tags = ['accepted:yes', 'sipStatus:200']; stats.increment('sbc.originations', tags); } }); /* increment the call count */ - const {callsSP, calls} = await nudgeCallCounts(logger, { + const {callsSP, calls} = await nudgeCallCounts(logger, { service_provider_sid, account_sid, - application_sid + application_sid, }, incrKey, {writeCallCountSP, writeCallCount, writeCallCountApp}); /* compare to account's limit, though avoid db hit when call count is low */ @@ -136,56 +166,63 @@ module.exports = (srf, logger, opts) => { const limit_sessions = limit.quantity; if (calls > limit_sessions) { + childSpan.setAttributes({calls, limit_sessions}); + childSpan.endWithError('call limit exceeded'); logger.info({calls, limit_sessions}, 'checkLimits: limits exceeded'); writeAlerts({ alert_type: AlertType.ACCOUNT_CALL_LIMIT, service_provider_sid, account_sid, - count: limit_sessions + count: limit_sessions, }).catch((err) => logger.info({err}, 'checkLimits: error writing alert')); res.send(503, 'Maximum Calls In Progress'); return req.srf.endSession(req); } - } - else if (trackingOn) { + } else if (trackingOn) { const {account_limit, sp_limit} = await queryCallLimits(service_provider_sid, account_sid); if (process.env.JAMBONES_TRACK_ACCOUNT_CALLS && account_limit > 0 && calls > account_limit) { + childSpan.setAttributes({calls, account_limit}); + childSpan.endWithError('account limit exceeded'); logger.info({calls, account_limit}, 'checkLimits: account limits exceeded'); writeAlerts({ alert_type: AlertType.ACCOUNT_CALL_LIMIT, service_provider_sid: service_provider_sid, account_sid, - count: calls + count: calls, }).catch((err) => logger.info({err}, 'checkLimits: error writing alert')); res.send(503, 'Max Account Calls In Progress', { headers: { 'X-Account-Sid': account_sid, - 'X-Call-Limit': account_limit - } + 'X-Call-Limit': account_limit, + }, }); return req.srf.endSession(req); } if (process.env.JAMBONES_TRACK_SP_CALLS && sp_limit > 0 && callsSP > sp_limit) { + childSpan.setAttributes({callsSP, sp_limit}); + childSpan.endWithError('service provider limit exceeded'); logger.info({callsSP, sp_limit}, 'checkLimits: service provider limits exceeded'); writeAlerts({ alert_type: AlertType.SP_CALL_LIMIT, service_provider_sid: service_provider_sid, - count: callsSP + count: callsSP, }).catch((err) => logger.info({err}, 'checkLimits: error writing alert')); res.send(503, 'Max Service Provider Calls In Progress', { headers: { 'X-Service-Provider-Sid': service_provider_sid, - 'X-Call-Limit': sp_limit - } + 'X-Call-Limit': sp_limit, + }, }); return req.srf.endSession(req); } } next(); } catch (err) { + childSpan.endWithError('error checking limits'); logger.error({err}, 'error checking limits error for inbound call'); res.send(500); } + childSpan.end(); }; const route = async(req, res, next) => { @@ -199,8 +236,8 @@ module.exports = (srf, logger, opts) => { logger.info({uri: req.uri}, 'invalid request-uri on outbound call, rejecting'); res.send(400, { headers: { - 'X-Reason': 'invalid request-uri' - } + 'X-Reason': 'invalid request-uri', + }, }); return req.srf.endSession(req); } @@ -209,8 +246,7 @@ module.exports = (srf, logger, opts) => { if ('teams' === desiredRouting) { logger.debug('This is a call to ms teams'); req.locals.target = 'teams'; - } - else if ('user' === desiredRouting) { + } else if ('user' === desiredRouting) { const aor = `${uri.user}@${uri.host}`; const reg = await registrar.query(aor); if (reg) { @@ -221,31 +257,27 @@ module.exports = (srf, logger, opts) => { if (req.server.hostport !== reg.sbcAddress) { /* redirect to the correct SBC where this user is connected */ const proxyAddress = selectHostPort(reg.sbcAddress, 'tcp'); - const redirectUri = ``; + const redirectUri = ``; logger.info(`redirecting call to SBC at ${redirectUri}`); return res.send(302, {headers: {Contact: redirectUri}}); } req.locals.registration = reg; req.locals.target = 'user'; - } - else { + } else { const account = await lookupAccountBySipRealm(uri.host); if (account) { logger.info({host: uri.host, account}, `returning 404 to unregistered user in valid domain: ${req.uri}`); - } - else { + } else { logger.info({host: uri.host, account}, `returning 404 to user in invalid domain: ${req.uri}`); } res.send(404); return req.srf.endSession(req); } - } - else if ('sip' === desiredRouting) { + } else if ('sip' === desiredRouting) { // call that needs to be forwarded to a sip endpoint logger.info(`forwarding call to sip endpoint ${req.uri}`); req.locals.target = 'forward'; - } - else if ('phone' === desiredRouting) { + } else if ('phone' === desiredRouting) { debug('sending call to LCR'); req.locals.target = 'lcr'; } @@ -254,7 +286,8 @@ module.exports = (srf, logger, opts) => { return { initLocals, + createRootSpan, checkLimits, - route + route, }; }; diff --git a/package-lock.json b/package-lock.json index ee0b25f..3f1bff9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "@jambonz/siprec-client-utils": "^0.2.4", "@jambonz/stats-collector": "^0.1.8", "@jambonz/time-series": "^0.2.5", + "@jambonz/tracing": "^0.1.9", "cidr-matcher": "^2.1.1", "debug": "^4.3.4", "drachtio-fn-b2b-sugar": "^0.0.12", @@ -663,6 +664,21 @@ "influx": "^5.9.3" } }, + "node_modules/@jambonz/tracing": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@jambonz/tracing/-/tracing-0.1.9.tgz", + "integrity": "sha512-pkAMe/KNnS/v7uM2xZyrYy2VWF38KMe1cDzf9zkQ6IhQL5KC8ey0hBXZ83bHPoymOqRwzKUfTpMLdtv1dzWRig==", + "dependencies": { + "@opentelemetry/api": "^1.4.0", + "@opentelemetry/exporter-jaeger": "^1.9.0", + "@opentelemetry/exporter-trace-otlp-http": "^0.35.0", + "@opentelemetry/exporter-zipkin": "^1.9.0", + "@opentelemetry/resources": "^1.9.0", + "@opentelemetry/sdk-trace-base": "^1.9.0", + "@opentelemetry/sdk-trace-node": "^1.9.0", + "@opentelemetry/semantic-conventions": "^1.9.0" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", @@ -710,6 +726,389 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, + "node_modules/@opentelemetry/api": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.4.1.tgz", + "integrity": "sha512-O2yRJce1GOc6PAy3QxFM4NzFiWzvScDC1/5ihYBL6BUEVdq0XMWN01sppE+H6bBXbaFYipjwFLEWLg5PaSOThA==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/context-async-hooks": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-1.12.0.tgz", + "integrity": "sha512-PmwAanPNWCyS9JYFzhzVzHgviLhc0UHjOwdth+hp3HgQQ9XZZNE635P8JhAUHZmbghW9/qQFafRWOS4VN9VVnQ==", + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.5.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.12.0.tgz", + "integrity": "sha512-4DWYNb3dLs2mSCGl65jY3aEgbvPWSHVQV/dmDWiYeWUrMakZQFcymqZOSUNZO0uDrEJoxMu8O5tZktX6UKFwag==", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.12.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.5.0" + } + }, + "node_modules/@opentelemetry/exporter-jaeger": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-jaeger/-/exporter-jaeger-1.12.0.tgz", + "integrity": "sha512-MGWslvok6tlNCHexHGnfXrSyobBqUDh4YOLENt2MeQ/F974SyVG4e73TD/CDM+227/rRM587hJ8dQBzvwUac/g==", + "dependencies": { + "@opentelemetry/core": "1.12.0", + "@opentelemetry/sdk-trace-base": "1.12.0", + "@opentelemetry/semantic-conventions": "1.12.0", + "jaeger-client": "^3.15.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http": { + "version": "0.35.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.35.1.tgz", + "integrity": "sha512-EJgAsrvscKsqb/GzF1zS74vM+Z/aQRhrFE7hs/1GK1M9bLixaVyMGwg2pxz1wdYdjxS1mqpHMhXU+VvMvFCw1w==", + "dependencies": { + "@opentelemetry/core": "1.9.1", + "@opentelemetry/otlp-exporter-base": "0.35.1", + "@opentelemetry/otlp-transformer": "0.35.1", + "@opentelemetry/resources": "1.9.1", + "@opentelemetry/sdk-trace-base": "1.9.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/core": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.9.1.tgz", + "integrity": "sha512-6/qon6tw2I8ZaJnHAQUUn4BqhTbTNRS0WP8/bA0ynaX+Uzp/DDbd0NS0Cq6TMlh8+mrlsyqDE7mO50nmv2Yvlg==", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.9.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.5.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/resources": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.9.1.tgz", + "integrity": "sha512-VqBGbnAfubI+l+yrtYxeLyOoL358JK57btPMJDd3TCOV3mV5TNBmzvOfmesM4NeTyXuGJByd3XvOHvFezLn3rQ==", + "dependencies": { + "@opentelemetry/core": "1.9.1", + "@opentelemetry/semantic-conventions": "1.9.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.5.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/sdk-trace-base": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.9.1.tgz", + "integrity": "sha512-Y9gC5M1efhDLYHeeo2MWcDDMmR40z6QpqcWnPCm4Dmh+RHAMf4dnEBBntIe1dDpor686kyU6JV1D29ih1lZpsQ==", + "dependencies": { + "@opentelemetry/core": "1.9.1", + "@opentelemetry/resources": "1.9.1", + "@opentelemetry/semantic-conventions": "1.9.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.5.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.9.1.tgz", + "integrity": "sha512-oPQdbFDmZvjXk5ZDoBGXG8B4tSB/qW5vQunJWQMFUBp7Xe8O1ByPANueJ+Jzg58esEBegyyxZ7LRmfJr7kFcFg==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/exporter-zipkin": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-zipkin/-/exporter-zipkin-1.12.0.tgz", + "integrity": "sha512-HJ4ww7OjVIV4x5ZGgY+h+D1JS0GsCtnHuqZUVHl7EFFQxMGpbQcf5eISRtwqgQwlQKh2iqrEbiHdDyzbgA/7XQ==", + "dependencies": { + "@opentelemetry/core": "1.12.0", + "@opentelemetry/resources": "1.12.0", + "@opentelemetry/sdk-trace-base": "1.12.0", + "@opentelemetry/semantic-conventions": "1.12.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.35.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.35.1.tgz", + "integrity": "sha512-Sc0buJIs8CfUeQCL/12vDDjBREgsqHdjboBa/kPQDgMf008OBJSM02Ijj6T1TH+QVHl/VHBBEVJF+FTf0EH9Vg==", + "dependencies": { + "@opentelemetry/core": "1.9.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/otlp-exporter-base/node_modules/@opentelemetry/core": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.9.1.tgz", + "integrity": "sha512-6/qon6tw2I8ZaJnHAQUUn4BqhTbTNRS0WP8/bA0ynaX+Uzp/DDbd0NS0Cq6TMlh8+mrlsyqDE7mO50nmv2Yvlg==", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.9.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.5.0" + } + }, + "node_modules/@opentelemetry/otlp-exporter-base/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.9.1.tgz", + "integrity": "sha512-oPQdbFDmZvjXk5ZDoBGXG8B4tSB/qW5vQunJWQMFUBp7Xe8O1ByPANueJ+Jzg58esEBegyyxZ7LRmfJr7kFcFg==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/otlp-transformer": { + "version": "0.35.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.35.1.tgz", + "integrity": "sha512-c0HXcJ49MKoWSaA49J8PXlVx48CeEFpL0odP6KBkVT+Bw6kAe8JlI3mIezyN05VCDJGtS2I5E6WEsE+DJL1t9A==", + "dependencies": { + "@opentelemetry/core": "1.9.1", + "@opentelemetry/resources": "1.9.1", + "@opentelemetry/sdk-metrics": "1.9.1", + "@opentelemetry/sdk-trace-base": "1.9.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.5.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/core": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.9.1.tgz", + "integrity": "sha512-6/qon6tw2I8ZaJnHAQUUn4BqhTbTNRS0WP8/bA0ynaX+Uzp/DDbd0NS0Cq6TMlh8+mrlsyqDE7mO50nmv2Yvlg==", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.9.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.5.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/resources": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.9.1.tgz", + "integrity": "sha512-VqBGbnAfubI+l+yrtYxeLyOoL358JK57btPMJDd3TCOV3mV5TNBmzvOfmesM4NeTyXuGJByd3XvOHvFezLn3rQ==", + "dependencies": { + "@opentelemetry/core": "1.9.1", + "@opentelemetry/semantic-conventions": "1.9.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.5.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/sdk-trace-base": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.9.1.tgz", + "integrity": "sha512-Y9gC5M1efhDLYHeeo2MWcDDMmR40z6QpqcWnPCm4Dmh+RHAMf4dnEBBntIe1dDpor686kyU6JV1D29ih1lZpsQ==", + "dependencies": { + "@opentelemetry/core": "1.9.1", + "@opentelemetry/resources": "1.9.1", + "@opentelemetry/semantic-conventions": "1.9.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.5.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.9.1.tgz", + "integrity": "sha512-oPQdbFDmZvjXk5ZDoBGXG8B4tSB/qW5vQunJWQMFUBp7Xe8O1ByPANueJ+Jzg58esEBegyyxZ7LRmfJr7kFcFg==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/propagator-b3": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-b3/-/propagator-b3-1.12.0.tgz", + "integrity": "sha512-WFcn98075QPc2zE1obhKydJHUehI5/HuLoelPEVwATj+487hjCwjHj9r2fgmQkWpvuNSB7CJaA0ys6qqq1N6lg==", + "dependencies": { + "@opentelemetry/core": "1.12.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.5.0" + } + }, + "node_modules/@opentelemetry/propagator-jaeger": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-jaeger/-/propagator-jaeger-1.12.0.tgz", + "integrity": "sha512-ugtWF7GC6X5RIJ0+iMwW2iVAGNs206CAeq8XQ8OkJRg+v0lp4H0/i+gJ4hubTT8NIL5a3IxtIrAENPLIGdLucQ==", + "dependencies": { + "@opentelemetry/core": "1.12.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.5.0" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.12.0.tgz", + "integrity": "sha512-gunMKXG0hJrR0LXrqh7BVbziA/+iJBL3ZbXCXO64uY+SrExkwoyJkpiq9l5ismkGF/A20mDEV7tGwh+KyPw00Q==", + "dependencies": { + "@opentelemetry/core": "1.12.0", + "@opentelemetry/semantic-conventions": "1.12.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.5.0" + } + }, + "node_modules/@opentelemetry/sdk-metrics": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.9.1.tgz", + "integrity": "sha512-AyhKDcA8NuV7o1+9KvzRMxNbATJ8AcrutKilJ6hWSo9R5utnzxgffV4y+Hp4mJn84iXxkv+CBb99GOJ2A5OMzA==", + "dependencies": { + "@opentelemetry/core": "1.9.1", + "@opentelemetry/resources": "1.9.1", + "lodash.merge": "4.6.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.5.0" + } + }, + "node_modules/@opentelemetry/sdk-metrics/node_modules/@opentelemetry/core": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.9.1.tgz", + "integrity": "sha512-6/qon6tw2I8ZaJnHAQUUn4BqhTbTNRS0WP8/bA0ynaX+Uzp/DDbd0NS0Cq6TMlh8+mrlsyqDE7mO50nmv2Yvlg==", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.9.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.5.0" + } + }, + "node_modules/@opentelemetry/sdk-metrics/node_modules/@opentelemetry/resources": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.9.1.tgz", + "integrity": "sha512-VqBGbnAfubI+l+yrtYxeLyOoL358JK57btPMJDd3TCOV3mV5TNBmzvOfmesM4NeTyXuGJByd3XvOHvFezLn3rQ==", + "dependencies": { + "@opentelemetry/core": "1.9.1", + "@opentelemetry/semantic-conventions": "1.9.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.5.0" + } + }, + "node_modules/@opentelemetry/sdk-metrics/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.9.1.tgz", + "integrity": "sha512-oPQdbFDmZvjXk5ZDoBGXG8B4tSB/qW5vQunJWQMFUBp7Xe8O1ByPANueJ+Jzg58esEBegyyxZ7LRmfJr7kFcFg==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/sdk-trace-base": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.12.0.tgz", + "integrity": "sha512-pfCOB3tNDlYVoWuz4D7Ji+Jmy9MHnATWHVpkERdCEiwUGEZ+4IvNPXUcPc37wJVmMpjGLeaWgPPrie0KIpWf1A==", + "dependencies": { + "@opentelemetry/core": "1.12.0", + "@opentelemetry/resources": "1.12.0", + "@opentelemetry/semantic-conventions": "1.12.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.5.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-node": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-1.12.0.tgz", + "integrity": "sha512-PxpDemnNZLLeFNLAu95/K3QubjlaScXVjVQPlwPui65VRxIvxGVysnN7DFfsref+qoh1hI6nlrYSij43vxdm2w==", + "dependencies": { + "@opentelemetry/context-async-hooks": "1.12.0", + "@opentelemetry/core": "1.12.0", + "@opentelemetry/propagator-b3": "1.12.0", + "@opentelemetry/propagator-jaeger": "1.12.0", + "@opentelemetry/sdk-trace-base": "1.12.0", + "semver": "^7.3.5" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.5.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.12.0.tgz", + "integrity": "sha512-hO+bdeGOlJwqowUBoZF5LyP3ORUFOP1G0GRv8N45W/cztXbT2ZEXaAzfokRS9Xc9FWmYrDj32mF6SzH6wuoIyA==", + "engines": { + "node": ">=14" + } + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -772,6 +1171,14 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ansi-color": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ansi-color/-/ansi-color-0.2.1.tgz", + "integrity": "sha512-bF6xLaZBLpOQzgYUtYEhJx090nPSZk1BQ/q2oyBK9aMMcJHzx9uXGCjI2Y+LebsN4Jwoykr0V9whbPiogdyHoQ==", + "engines": { + "node": "*" + } + }, "node_modules/ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -1002,6 +1409,20 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/bufrw": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/bufrw/-/bufrw-1.3.0.tgz", + "integrity": "sha512-jzQnSbdJqhIltU9O5KUiTtljP9ccw2u5ix59McQy4pV2xGhVLhRZIndY8GIrgh5HjXa6+QJ9AQhOd2QWQizJFQ==", + "dependencies": { + "ansi-color": "^0.2.1", + "error": "^7.0.0", + "hexer": "^1.5.0", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 0.10.x" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -1454,6 +1875,15 @@ "node": ">=8.6" } }, + "node_modules/error": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/error/-/error-7.0.2.tgz", + "integrity": "sha512-UtVv4l5MhijsYUxPJo4390gzfZvAnTHreNnDjnTZaKIiZ/SemXxAhBkYSKtWa5RtBXbLP8tMgn/n0RUa/H7jXw==", + "dependencies": { + "string-template": "~0.2.1", + "xtend": "~4.0.0" + } + }, "node_modules/es-abstract": { "version": "1.21.1", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz", @@ -2357,6 +2787,23 @@ "node": ">=8" } }, + "node_modules/hexer": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/hexer/-/hexer-1.5.0.tgz", + "integrity": "sha512-dyrPC8KzBzUJ19QTIo1gXNqIISRXQ0NwteW6OeQHRN4ZuZeHkdODfj0zHBdOlHbRY8GqbqK57C9oWSvQZizFsg==", + "dependencies": { + "ansi-color": "^0.2.1", + "minimist": "^1.1.0", + "process": "^0.10.0", + "xtend": "^4.0.0" + }, + "bin": { + "hexer": "cli.js" + }, + "engines": { + "node": ">= 0.10.x" + } + }, "node_modules/hot-shots": { "version": "8.5.2", "resolved": "https://registry.npmjs.org/hot-shots/-/hot-shots-8.5.2.tgz", @@ -2918,6 +3365,21 @@ "node": ">=8" } }, + "node_modules/jaeger-client": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/jaeger-client/-/jaeger-client-3.19.0.tgz", + "integrity": "sha512-M0c7cKHmdyEUtjemnJyx/y9uX16XHocL46yQvyqDlPdvAcwPDbHrIbKjQdBqtiE4apQ/9dmr+ZLJYYPGnurgpw==", + "dependencies": { + "node-int64": "^0.4.0", + "opentracing": "^0.14.4", + "thriftrw": "^3.5.0", + "uuid": "^8.3.2", + "xorshift": "^1.1.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -3026,8 +3488,7 @@ "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, "node_modules/lodash.truncate": { "version": "4.4.2", @@ -3142,7 +3603,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -3220,6 +3680,11 @@ "node": ">= 0.6" } }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" + }, "node_modules/node-noop": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/node-noop/-/node-noop-0.0.1.tgz", @@ -3447,6 +3912,14 @@ "resolved": "https://registry.npmjs.org/only/-/only-0.0.2.tgz", "integrity": "sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ==" }, + "node_modules/opentracing": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/opentracing/-/opentracing-0.14.7.tgz", + "integrity": "sha512-vz9iS7MJ5+Bp1URw8Khvdyw1H/hGvzHWlKQ7eRrQojSCDL1/SrWfrY9QebLw97n2deyRtzHRC3MkQfVNUCo91Q==", + "engines": { + "node": ">=0.10" + } + }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -3647,6 +4120,14 @@ "node": ">= 0.8.0" } }, + "node_modules/process": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/process/-/process-0.10.1.tgz", + "integrity": "sha512-dyIett8dgGIZ/TXKUzeYExt7WA6ldDzys9vTDU/cCA9L17Ypme+KzS+NjQCjpn9xsvi/shbMC+yP/BcFMBz0NA==", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/process-on-spawn": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", @@ -4009,7 +4490,6 @@ "version": "7.3.8", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -4259,6 +4739,11 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/string-template": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", + "integrity": "sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw==" + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -4476,6 +4961,30 @@ "real-require": "^0.1.0" } }, + "node_modules/thriftrw": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/thriftrw/-/thriftrw-3.12.0.tgz", + "integrity": "sha512-4YZvR4DPEI41n4Opwr4jmrLGG4hndxr7387kzRFIIzxHQjarPusH4lGXrugvgb7TtPrfZVTpZCVe44/xUxowEw==", + "dependencies": { + "bufrw": "^1.3.0", + "error": "7.0.2", + "long": "^2.4.0" + }, + "bin": { + "thrift2json": "thrift2json.js" + }, + "engines": { + "node": ">= 0.10.x" + } + }, + "node_modules/thriftrw/node_modules/long": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/long/-/long-2.4.0.tgz", + "integrity": "sha512-ijUtjmO/n2A5PaosNG9ZGDsQ3vxJg7ZW8vsY8Kp0f2yIZWhSJvjmegV7t+9RPQKxKrvj8yKGehhS+po14hPLGQ==", + "engines": { + "node": ">=0.6" + } + }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -4801,6 +5310,19 @@ } } }, + "node_modules/xorshift": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/xorshift/-/xorshift-1.2.0.tgz", + "integrity": "sha512-iYgNnGyeeJ4t6U11NpA/QiKy+PXn5Aa3Azg5qkwIFz1tBLllQrjjsk9yzD7IAK0naNU4JxdeDgqW9ov4u/hc4g==" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -5319,6 +5841,21 @@ "influx": "^5.9.3" } }, + "@jambonz/tracing": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@jambonz/tracing/-/tracing-0.1.9.tgz", + "integrity": "sha512-pkAMe/KNnS/v7uM2xZyrYy2VWF38KMe1cDzf9zkQ6IhQL5KC8ey0hBXZ83bHPoymOqRwzKUfTpMLdtv1dzWRig==", + "requires": { + "@opentelemetry/api": "^1.4.0", + "@opentelemetry/exporter-jaeger": "^1.9.0", + "@opentelemetry/exporter-trace-otlp-http": "^0.35.0", + "@opentelemetry/exporter-zipkin": "^1.9.0", + "@opentelemetry/resources": "^1.9.0", + "@opentelemetry/sdk-trace-base": "^1.9.0", + "@opentelemetry/sdk-trace-node": "^1.9.0", + "@opentelemetry/semantic-conventions": "^1.9.0" + } + }, "@jridgewell/gen-mapping": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", @@ -5357,6 +5894,248 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, + "@opentelemetry/api": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.4.1.tgz", + "integrity": "sha512-O2yRJce1GOc6PAy3QxFM4NzFiWzvScDC1/5ihYBL6BUEVdq0XMWN01sppE+H6bBXbaFYipjwFLEWLg5PaSOThA==" + }, + "@opentelemetry/context-async-hooks": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-1.12.0.tgz", + "integrity": "sha512-PmwAanPNWCyS9JYFzhzVzHgviLhc0UHjOwdth+hp3HgQQ9XZZNE635P8JhAUHZmbghW9/qQFafRWOS4VN9VVnQ==", + "requires": {} + }, + "@opentelemetry/core": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.12.0.tgz", + "integrity": "sha512-4DWYNb3dLs2mSCGl65jY3aEgbvPWSHVQV/dmDWiYeWUrMakZQFcymqZOSUNZO0uDrEJoxMu8O5tZktX6UKFwag==", + "requires": { + "@opentelemetry/semantic-conventions": "1.12.0" + } + }, + "@opentelemetry/exporter-jaeger": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-jaeger/-/exporter-jaeger-1.12.0.tgz", + "integrity": "sha512-MGWslvok6tlNCHexHGnfXrSyobBqUDh4YOLENt2MeQ/F974SyVG4e73TD/CDM+227/rRM587hJ8dQBzvwUac/g==", + "requires": { + "@opentelemetry/core": "1.12.0", + "@opentelemetry/sdk-trace-base": "1.12.0", + "@opentelemetry/semantic-conventions": "1.12.0", + "jaeger-client": "^3.15.0" + } + }, + "@opentelemetry/exporter-trace-otlp-http": { + "version": "0.35.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.35.1.tgz", + "integrity": "sha512-EJgAsrvscKsqb/GzF1zS74vM+Z/aQRhrFE7hs/1GK1M9bLixaVyMGwg2pxz1wdYdjxS1mqpHMhXU+VvMvFCw1w==", + "requires": { + "@opentelemetry/core": "1.9.1", + "@opentelemetry/otlp-exporter-base": "0.35.1", + "@opentelemetry/otlp-transformer": "0.35.1", + "@opentelemetry/resources": "1.9.1", + "@opentelemetry/sdk-trace-base": "1.9.1" + }, + "dependencies": { + "@opentelemetry/core": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.9.1.tgz", + "integrity": "sha512-6/qon6tw2I8ZaJnHAQUUn4BqhTbTNRS0WP8/bA0ynaX+Uzp/DDbd0NS0Cq6TMlh8+mrlsyqDE7mO50nmv2Yvlg==", + "requires": { + "@opentelemetry/semantic-conventions": "1.9.1" + } + }, + "@opentelemetry/resources": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.9.1.tgz", + "integrity": "sha512-VqBGbnAfubI+l+yrtYxeLyOoL358JK57btPMJDd3TCOV3mV5TNBmzvOfmesM4NeTyXuGJByd3XvOHvFezLn3rQ==", + "requires": { + "@opentelemetry/core": "1.9.1", + "@opentelemetry/semantic-conventions": "1.9.1" + } + }, + "@opentelemetry/sdk-trace-base": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.9.1.tgz", + "integrity": "sha512-Y9gC5M1efhDLYHeeo2MWcDDMmR40z6QpqcWnPCm4Dmh+RHAMf4dnEBBntIe1dDpor686kyU6JV1D29ih1lZpsQ==", + "requires": { + "@opentelemetry/core": "1.9.1", + "@opentelemetry/resources": "1.9.1", + "@opentelemetry/semantic-conventions": "1.9.1" + } + }, + "@opentelemetry/semantic-conventions": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.9.1.tgz", + "integrity": "sha512-oPQdbFDmZvjXk5ZDoBGXG8B4tSB/qW5vQunJWQMFUBp7Xe8O1ByPANueJ+Jzg58esEBegyyxZ7LRmfJr7kFcFg==" + } + } + }, + "@opentelemetry/exporter-zipkin": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-zipkin/-/exporter-zipkin-1.12.0.tgz", + "integrity": "sha512-HJ4ww7OjVIV4x5ZGgY+h+D1JS0GsCtnHuqZUVHl7EFFQxMGpbQcf5eISRtwqgQwlQKh2iqrEbiHdDyzbgA/7XQ==", + "requires": { + "@opentelemetry/core": "1.12.0", + "@opentelemetry/resources": "1.12.0", + "@opentelemetry/sdk-trace-base": "1.12.0", + "@opentelemetry/semantic-conventions": "1.12.0" + } + }, + "@opentelemetry/otlp-exporter-base": { + "version": "0.35.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.35.1.tgz", + "integrity": "sha512-Sc0buJIs8CfUeQCL/12vDDjBREgsqHdjboBa/kPQDgMf008OBJSM02Ijj6T1TH+QVHl/VHBBEVJF+FTf0EH9Vg==", + "requires": { + "@opentelemetry/core": "1.9.1" + }, + "dependencies": { + "@opentelemetry/core": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.9.1.tgz", + "integrity": "sha512-6/qon6tw2I8ZaJnHAQUUn4BqhTbTNRS0WP8/bA0ynaX+Uzp/DDbd0NS0Cq6TMlh8+mrlsyqDE7mO50nmv2Yvlg==", + "requires": { + "@opentelemetry/semantic-conventions": "1.9.1" + } + }, + "@opentelemetry/semantic-conventions": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.9.1.tgz", + "integrity": "sha512-oPQdbFDmZvjXk5ZDoBGXG8B4tSB/qW5vQunJWQMFUBp7Xe8O1ByPANueJ+Jzg58esEBegyyxZ7LRmfJr7kFcFg==" + } + } + }, + "@opentelemetry/otlp-transformer": { + "version": "0.35.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.35.1.tgz", + "integrity": "sha512-c0HXcJ49MKoWSaA49J8PXlVx48CeEFpL0odP6KBkVT+Bw6kAe8JlI3mIezyN05VCDJGtS2I5E6WEsE+DJL1t9A==", + "requires": { + "@opentelemetry/core": "1.9.1", + "@opentelemetry/resources": "1.9.1", + "@opentelemetry/sdk-metrics": "1.9.1", + "@opentelemetry/sdk-trace-base": "1.9.1" + }, + "dependencies": { + "@opentelemetry/core": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.9.1.tgz", + "integrity": "sha512-6/qon6tw2I8ZaJnHAQUUn4BqhTbTNRS0WP8/bA0ynaX+Uzp/DDbd0NS0Cq6TMlh8+mrlsyqDE7mO50nmv2Yvlg==", + "requires": { + "@opentelemetry/semantic-conventions": "1.9.1" + } + }, + "@opentelemetry/resources": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.9.1.tgz", + "integrity": "sha512-VqBGbnAfubI+l+yrtYxeLyOoL358JK57btPMJDd3TCOV3mV5TNBmzvOfmesM4NeTyXuGJByd3XvOHvFezLn3rQ==", + "requires": { + "@opentelemetry/core": "1.9.1", + "@opentelemetry/semantic-conventions": "1.9.1" + } + }, + "@opentelemetry/sdk-trace-base": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.9.1.tgz", + "integrity": "sha512-Y9gC5M1efhDLYHeeo2MWcDDMmR40z6QpqcWnPCm4Dmh+RHAMf4dnEBBntIe1dDpor686kyU6JV1D29ih1lZpsQ==", + "requires": { + "@opentelemetry/core": "1.9.1", + "@opentelemetry/resources": "1.9.1", + "@opentelemetry/semantic-conventions": "1.9.1" + } + }, + "@opentelemetry/semantic-conventions": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.9.1.tgz", + "integrity": "sha512-oPQdbFDmZvjXk5ZDoBGXG8B4tSB/qW5vQunJWQMFUBp7Xe8O1ByPANueJ+Jzg58esEBegyyxZ7LRmfJr7kFcFg==" + } + } + }, + "@opentelemetry/propagator-b3": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-b3/-/propagator-b3-1.12.0.tgz", + "integrity": "sha512-WFcn98075QPc2zE1obhKydJHUehI5/HuLoelPEVwATj+487hjCwjHj9r2fgmQkWpvuNSB7CJaA0ys6qqq1N6lg==", + "requires": { + "@opentelemetry/core": "1.12.0" + } + }, + "@opentelemetry/propagator-jaeger": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-jaeger/-/propagator-jaeger-1.12.0.tgz", + "integrity": "sha512-ugtWF7GC6X5RIJ0+iMwW2iVAGNs206CAeq8XQ8OkJRg+v0lp4H0/i+gJ4hubTT8NIL5a3IxtIrAENPLIGdLucQ==", + "requires": { + "@opentelemetry/core": "1.12.0" + } + }, + "@opentelemetry/resources": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.12.0.tgz", + "integrity": "sha512-gunMKXG0hJrR0LXrqh7BVbziA/+iJBL3ZbXCXO64uY+SrExkwoyJkpiq9l5ismkGF/A20mDEV7tGwh+KyPw00Q==", + "requires": { + "@opentelemetry/core": "1.12.0", + "@opentelemetry/semantic-conventions": "1.12.0" + } + }, + "@opentelemetry/sdk-metrics": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.9.1.tgz", + "integrity": "sha512-AyhKDcA8NuV7o1+9KvzRMxNbATJ8AcrutKilJ6hWSo9R5utnzxgffV4y+Hp4mJn84iXxkv+CBb99GOJ2A5OMzA==", + "requires": { + "@opentelemetry/core": "1.9.1", + "@opentelemetry/resources": "1.9.1", + "lodash.merge": "4.6.2" + }, + "dependencies": { + "@opentelemetry/core": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.9.1.tgz", + "integrity": "sha512-6/qon6tw2I8ZaJnHAQUUn4BqhTbTNRS0WP8/bA0ynaX+Uzp/DDbd0NS0Cq6TMlh8+mrlsyqDE7mO50nmv2Yvlg==", + "requires": { + "@opentelemetry/semantic-conventions": "1.9.1" + } + }, + "@opentelemetry/resources": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.9.1.tgz", + "integrity": "sha512-VqBGbnAfubI+l+yrtYxeLyOoL358JK57btPMJDd3TCOV3mV5TNBmzvOfmesM4NeTyXuGJByd3XvOHvFezLn3rQ==", + "requires": { + "@opentelemetry/core": "1.9.1", + "@opentelemetry/semantic-conventions": "1.9.1" + } + }, + "@opentelemetry/semantic-conventions": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.9.1.tgz", + "integrity": "sha512-oPQdbFDmZvjXk5ZDoBGXG8B4tSB/qW5vQunJWQMFUBp7Xe8O1ByPANueJ+Jzg58esEBegyyxZ7LRmfJr7kFcFg==" + } + } + }, + "@opentelemetry/sdk-trace-base": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.12.0.tgz", + "integrity": "sha512-pfCOB3tNDlYVoWuz4D7Ji+Jmy9MHnATWHVpkERdCEiwUGEZ+4IvNPXUcPc37wJVmMpjGLeaWgPPrie0KIpWf1A==", + "requires": { + "@opentelemetry/core": "1.12.0", + "@opentelemetry/resources": "1.12.0", + "@opentelemetry/semantic-conventions": "1.12.0" + } + }, + "@opentelemetry/sdk-trace-node": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-1.12.0.tgz", + "integrity": "sha512-PxpDemnNZLLeFNLAu95/K3QubjlaScXVjVQPlwPui65VRxIvxGVysnN7DFfsref+qoh1hI6nlrYSij43vxdm2w==", + "requires": { + "@opentelemetry/context-async-hooks": "1.12.0", + "@opentelemetry/core": "1.12.0", + "@opentelemetry/propagator-b3": "1.12.0", + "@opentelemetry/propagator-jaeger": "1.12.0", + "@opentelemetry/sdk-trace-base": "1.12.0", + "semver": "^7.3.5" + } + }, + "@opentelemetry/semantic-conventions": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.12.0.tgz", + "integrity": "sha512-hO+bdeGOlJwqowUBoZF5LyP3ORUFOP1G0GRv8N45W/cztXbT2ZEXaAzfokRS9Xc9FWmYrDj32mF6SzH6wuoIyA==" + }, "accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -5401,6 +6180,11 @@ "uri-js": "^4.2.2" } }, + "ansi-color": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ansi-color/-/ansi-color-0.2.1.tgz", + "integrity": "sha512-bF6xLaZBLpOQzgYUtYEhJx090nPSZk1BQ/q2oyBK9aMMcJHzx9uXGCjI2Y+LebsN4Jwoykr0V9whbPiogdyHoQ==" + }, "ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -5577,6 +6361,17 @@ "update-browserslist-db": "^1.0.10" } }, + "bufrw": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/bufrw/-/bufrw-1.3.0.tgz", + "integrity": "sha512-jzQnSbdJqhIltU9O5KUiTtljP9ccw2u5ix59McQy4pV2xGhVLhRZIndY8GIrgh5HjXa6+QJ9AQhOd2QWQizJFQ==", + "requires": { + "ansi-color": "^0.2.1", + "error": "^7.0.0", + "hexer": "^1.5.0", + "xtend": "^4.0.0" + } + }, "bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -5928,6 +6723,15 @@ "ansi-colors": "^4.1.1" } }, + "error": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/error/-/error-7.0.2.tgz", + "integrity": "sha512-UtVv4l5MhijsYUxPJo4390gzfZvAnTHreNnDjnTZaKIiZ/SemXxAhBkYSKtWa5RtBXbLP8tMgn/n0RUa/H7jXw==", + "requires": { + "string-template": "~0.2.1", + "xtend": "~4.0.0" + } + }, "es-abstract": { "version": "1.21.1", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz", @@ -6614,6 +7418,17 @@ } } }, + "hexer": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/hexer/-/hexer-1.5.0.tgz", + "integrity": "sha512-dyrPC8KzBzUJ19QTIo1gXNqIISRXQ0NwteW6OeQHRN4ZuZeHkdODfj0zHBdOlHbRY8GqbqK57C9oWSvQZizFsg==", + "requires": { + "ansi-color": "^0.2.1", + "minimist": "^1.1.0", + "process": "^0.10.0", + "xtend": "^4.0.0" + } + }, "hot-shots": { "version": "8.5.2", "resolved": "https://registry.npmjs.org/hot-shots/-/hot-shots-8.5.2.tgz", @@ -7018,6 +7833,18 @@ "istanbul-lib-report": "^3.0.0" } }, + "jaeger-client": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/jaeger-client/-/jaeger-client-3.19.0.tgz", + "integrity": "sha512-M0c7cKHmdyEUtjemnJyx/y9uX16XHocL46yQvyqDlPdvAcwPDbHrIbKjQdBqtiE4apQ/9dmr+ZLJYYPGnurgpw==", + "requires": { + "node-int64": "^0.4.0", + "opentracing": "^0.14.4", + "thriftrw": "^3.5.0", + "uuid": "^8.3.2", + "xorshift": "^1.1.1" + } + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -7102,8 +7929,7 @@ "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, "lodash.truncate": { "version": "4.4.2", @@ -7186,8 +8012,7 @@ "minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" }, "ms": { "version": "2.1.2", @@ -7251,6 +8076,11 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" + }, "node-noop": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/node-noop/-/node-noop-0.0.1.tgz", @@ -7435,6 +8265,11 @@ "resolved": "https://registry.npmjs.org/only/-/only-0.0.2.tgz", "integrity": "sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ==" }, + "opentracing": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/opentracing/-/opentracing-0.14.7.tgz", + "integrity": "sha512-vz9iS7MJ5+Bp1URw8Khvdyw1H/hGvzHWlKQ7eRrQojSCDL1/SrWfrY9QebLw97n2deyRtzHRC3MkQfVNUCo91Q==" + }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -7590,6 +8425,11 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, + "process": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/process/-/process-0.10.1.tgz", + "integrity": "sha512-dyIett8dgGIZ/TXKUzeYExt7WA6ldDzys9vTDU/cCA9L17Ypme+KzS+NjQCjpn9xsvi/shbMC+yP/BcFMBz0NA==" + }, "process-on-spawn": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", @@ -7837,7 +8677,6 @@ "version": "7.3.8", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, "requires": { "lru-cache": "^6.0.0" } @@ -8043,6 +8882,11 @@ "safe-buffer": "~5.2.0" } }, + "string-template": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", + "integrity": "sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw==" + }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -8210,6 +9054,23 @@ "real-require": "^0.1.0" } }, + "thriftrw": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/thriftrw/-/thriftrw-3.12.0.tgz", + "integrity": "sha512-4YZvR4DPEI41n4Opwr4jmrLGG4hndxr7387kzRFIIzxHQjarPusH4lGXrugvgb7TtPrfZVTpZCVe44/xUxowEw==", + "requires": { + "bufrw": "^1.3.0", + "error": "7.0.2", + "long": "^2.4.0" + }, + "dependencies": { + "long": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/long/-/long-2.4.0.tgz", + "integrity": "sha512-ijUtjmO/n2A5PaosNG9ZGDsQ3vxJg7ZW8vsY8Kp0f2yIZWhSJvjmegV7t+9RPQKxKrvj8yKGehhS+po14hPLGQ==" + } + } + }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -8441,6 +9302,16 @@ "integrity": "sha512-1qo+M9Ba+xNhPB+YTWUlK6M17brTut5EXbcBaMRN5pH5dFrXz7lzz1ChFSUq3bOUl8yEvSenhHmYUNJxFzdJew==", "requires": {} }, + "xorshift": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/xorshift/-/xorshift-1.2.0.tgz", + "integrity": "sha512-iYgNnGyeeJ4t6U11NpA/QiKy+PXn5Aa3Azg5qkwIFz1tBLllQrjjsk9yzD7IAK0naNU4JxdeDgqW9ov4u/hc4g==" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", diff --git a/package.json b/package.json index a98ce6c..5b2eb44 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "@jambonz/siprec-client-utils": "^0.2.4", "@jambonz/stats-collector": "^0.1.8", "@jambonz/time-series": "^0.2.5", + "@jambonz/tracing": "^0.1.9", "cidr-matcher": "^2.1.1", "debug": "^4.3.4", "drachtio-fn-b2b-sugar": "^0.0.12",