mirror of
https://github.com/jambonz/sbc-inbound.git
synced 2026-10-09 21:14:09 +00:00
add metrics
This commit is contained in:
@@ -5,6 +5,7 @@ assert.ok(process.env.JAMBONES_MYSQL_HOST &&
|
||||
process.env.JAMBONES_MYSQL_DATABASE, 'missing JAMBONES_MYSQL_XXX env vars');
|
||||
assert.ok(process.env.DRACHTIO_PORT || process.env.DRACHTIO_HOST, 'missing DRACHTIO_PORT env var');
|
||||
assert.ok(process.env.DRACHTIO_SECRET, 'missing DRACHTIO_SECRET env var');
|
||||
assert.ok(process.env.JAMBONES_RTPENGINES, 'missing DRACHTIO_SECRET env var');
|
||||
|
||||
const Srf = require('drachtio-srf');
|
||||
const srf = new Srf();
|
||||
@@ -12,7 +13,16 @@ const opts = Object.assign({
|
||||
timestamp: () => {return `, "time": "${new Date().toISOString()}"`;}
|
||||
}, {level: process.env.JAMBONES_LOGLEVEL || 'info'});
|
||||
const logger = require('pino')(opts);
|
||||
const StatsCollector = require('jambonz-stats-collector');
|
||||
srf.locals.stats = new StatsCollector(logger);
|
||||
srf.locals.getFeatureServer = require('./lib/fs-tracking')(srf, logger);
|
||||
const {getRtpEngine} = require('jambonz-rtpengine-utils')(process.env.JAMBONES_RTPENGINES.split(','), {
|
||||
emitter: srf.locals.stats
|
||||
});
|
||||
srf.locals.getRtpEngine = getRtpEngine;
|
||||
srf.locals.activeCallIds = new Set();
|
||||
logger.info('starting..');
|
||||
|
||||
const {
|
||||
lookupAuthHook,
|
||||
lookupSipGatewayBySignalingAddress
|
||||
@@ -28,7 +38,7 @@ srf.locals.dbHelpers = {
|
||||
lookupAuthHook,
|
||||
lookupSipGatewayBySignalingAddress
|
||||
};
|
||||
const {challengeDeviceCalls} = require('./lib/middleware')(srf, logger);
|
||||
const {challengeDeviceCalls, initLocals} = require('./lib/middleware')(srf, logger);
|
||||
const CallSession = require('./lib/call-session');
|
||||
|
||||
if (process.env.DRACHTIO_HOST) {
|
||||
@@ -47,11 +57,16 @@ if (process.env.NODE_ENV === 'test') {
|
||||
}
|
||||
|
||||
// challenge calls from devices, let calls from sip gateways through
|
||||
srf.use('invite', [challengeDeviceCalls]);
|
||||
srf.use('invite', [initLocals, challengeDeviceCalls]);
|
||||
|
||||
srf.invite((req, res) => {
|
||||
const session = new CallSession(logger, req, res);
|
||||
session.connect();
|
||||
});
|
||||
|
||||
module.exports = {srf};
|
||||
srf.use((req, res, next, err) => {
|
||||
logger.error(err, 'hit top-level error handler');
|
||||
res.send(500);
|
||||
});
|
||||
|
||||
module.exports = {srf, logger};
|
||||
|
||||
+25
-4
@@ -1,8 +1,7 @@
|
||||
const Emitter = require('events');
|
||||
const {getAppserver, isWSS, makeRtpEngineOpts} = require('./utils');
|
||||
const {isWSS, makeRtpEngineOpts} = require('./utils');
|
||||
const {forwardInDialogRequests} = require('drachtio-fn-b2b-sugar');
|
||||
const {parseUri, SipError} = require('drachtio-srf');
|
||||
const {getRtpEngine} = require('jambonz-rtpengine-utils')(process.env.JAMBONES_RTPENGINES.split(','));
|
||||
const debug = require('debug')('jambonz:sbc-inbound');
|
||||
|
||||
class CallSession extends Emitter {
|
||||
@@ -13,13 +12,21 @@ class CallSession extends Emitter {
|
||||
this.srf = req.srf;
|
||||
this.logger = logger.child({callId: req.get('Call-ID')});
|
||||
|
||||
this.getRtpEngine = req.srf.locals.getRtpEngine;
|
||||
this.getFeatureServer = req.srf.locals.getFeatureServer;
|
||||
this.stats = this.srf.locals.stats;
|
||||
this.activeCallIds = this.srf.locals.activeCallIds;
|
||||
|
||||
}
|
||||
|
||||
async connect() {
|
||||
const engine = getRtpEngine(this.logger);
|
||||
this.activeCallIds.add(this.req.get('Call-ID'));
|
||||
this.stats.gauge('sbc.sip.calls.count', this.activeCallIds.size);
|
||||
const engine = this.getRtpEngine(this.logger);
|
||||
if (!engine) {
|
||||
this.logger.info('No available rtpengines, rejecting call!');
|
||||
const tags = ['accepted:no', 'sipStatus:480', `originator:${this.req.locals.originator}`];
|
||||
this.stats.increment('sbc.terminations', tags);
|
||||
return this.res.send(480);
|
||||
}
|
||||
debug(`got engine: ${JSON.stringify(engine)}`);
|
||||
@@ -31,6 +38,8 @@ class CallSession extends Emitter {
|
||||
const featureServer = this.getFeatureServer();
|
||||
if (!featureServer) {
|
||||
this.logger.info('No available feature servers, rejecting call!');
|
||||
const tags = ['accepted:no', 'sipStatus:480', `originator:${this.req.locals.originator}`];
|
||||
this.stats.increment('sbc.terminations', tags);
|
||||
return this.res.send(480);
|
||||
}
|
||||
this.logger.debug(`using feature server ${featureServer}`);
|
||||
@@ -79,6 +88,8 @@ class CallSession extends Emitter {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.req.canceled) throw new Error('call canceled');
|
||||
|
||||
debug(`sending INVITE to ${proxy} with ${uri}`);
|
||||
const {uas, uac} = await this.srf.createB2BUA(this.req, this.res, uri, {
|
||||
proxy,
|
||||
@@ -102,16 +113,24 @@ class CallSession extends Emitter {
|
||||
this.logger.info('call connected');
|
||||
debug('call connected');
|
||||
this.emit('connected');
|
||||
const tags = ['accepted:yes', 'sipStatus:200', `originator:${this.req.locals.originator}`];
|
||||
this.stats.increment('sbc.terminations', tags);
|
||||
|
||||
this._setHandlers({uas, uac});
|
||||
return;
|
||||
} catch (err) {
|
||||
this.rtpEngineResource.destroy();
|
||||
this.activeCallIds.delete(this.req.get('Call-ID'));
|
||||
this.stats.gauge('sbc.sip.calls.count', this.activeCallIds.size);
|
||||
if (err instanceof SipError) {
|
||||
const tags = ['accepted:no', `sipStatus:${err.status}`, `originator:${this.req.locals.originator}`];
|
||||
this.stats.increment('sbc.terminations', tags);
|
||||
this.logger.info(`call failed with ${err.status}`);
|
||||
return this.emit('failed');
|
||||
}
|
||||
this.logger.error(err, 'unexpected error routing inbound call');
|
||||
else if (err.message !== 'call canceled') {
|
||||
this.logger.error(err, 'unexpected error routing inbound call');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,6 +142,8 @@ class CallSession extends Emitter {
|
||||
dlg.on('destroy', () => {
|
||||
this.logger.info('call ended');
|
||||
this.rtpEngineResource.destroy();
|
||||
this.activeCallIds.delete(this.req.get('Call-ID'));
|
||||
this.stats.gauge('sbc.sip.calls.count', this.activeCallIds.size);
|
||||
});
|
||||
|
||||
//re-invite
|
||||
|
||||
+5
-4
@@ -6,6 +6,7 @@ module.exports = (srf, logger) => {
|
||||
logger = logger || noopLogger;
|
||||
let dynamic = true;
|
||||
let idx = 0;
|
||||
const stats = srf.locals.stats;
|
||||
|
||||
srf.options((req, res) => {
|
||||
res.send(200);
|
||||
@@ -14,9 +15,9 @@ module.exports = (srf, logger) => {
|
||||
const status = req.get('X-FS-Status');
|
||||
const calls = req.has('X-FS-Calls') ? parseInt(req.get('X-FS-Calls')) : 0;
|
||||
if (status === 'open') {
|
||||
if (!contacts) {
|
||||
if (!contacts.has(uri)) {
|
||||
logger.info(`adding feature server at ${uri}`);
|
||||
//stats.gauge('sbc.featureservers', contacts.size + 1);
|
||||
stats.gauge('sbc.featureservers.count', contacts.size + 1);
|
||||
}
|
||||
logger.debug(`Feature server at ${uri} has ${calls} calls`);
|
||||
contacts.set(uri, {pingTime: new Date(), calls: calls});
|
||||
@@ -25,7 +26,7 @@ module.exports = (srf, logger) => {
|
||||
if (contacts.includes(uri)) {
|
||||
logger.info(`removing feature server at ${uri}`);
|
||||
contacts.delete(uri);
|
||||
//stats.gauge('sbc.featureservers', contacts.size + 1);
|
||||
stats.gauge('sbc.featureservers.count', contacts.size + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,7 +56,7 @@ module.exports = (srf, logger) => {
|
||||
|
||||
const keys = [ ...contacts.keys() ];
|
||||
logger.debug({keys}, `there are ${keys.length} feature servers online`);
|
||||
//stats.gauge('sbc.featureservers', contacts.size);
|
||||
stats.gauge('sbc.featureservers.count', contacts.size);
|
||||
}, CHECK_INTERVAL * 1000);
|
||||
}
|
||||
|
||||
|
||||
+19
-1
@@ -3,9 +3,25 @@ const debug = require('debug')('jambonz:sbc-inbound');
|
||||
module.exports = function(srf, logger) {
|
||||
const {lookupSipGatewayBySignalingAddress, lookupAuthHook} = srf.locals.dbHelpers;
|
||||
const authenticator = require('jambonz-http-authenticator')(lookupAuthHook, logger, {blacklistUnknownRealms: true});
|
||||
const {stats, activeCallIds} = srf.locals;
|
||||
|
||||
function initLocals(req, res, next) {
|
||||
req.locals = req.locals || {};
|
||||
const callId = req.get('Call-ID');
|
||||
req.on('cancel', () => {
|
||||
logger.info({callId}, 'caller hungup before connecting to feature server');
|
||||
req.canceled = true;
|
||||
const tags = ['canceled:yes', 'sipStatus:487'];
|
||||
if (req.locals.originator) tags.push(`originator:${req.locals.originator}`);
|
||||
stats.increment('sbc.terminations', tags);
|
||||
activeCallIds.delete(callId);
|
||||
stats.gauge('sbc.sip.calls.count', activeCallIds.size);
|
||||
});
|
||||
stats.increment('sbc.invites', ['direction:inbound']);
|
||||
next();
|
||||
}
|
||||
|
||||
async function challengeDeviceCalls(req, res, next) {
|
||||
req.locals = req.locals || {};
|
||||
try {
|
||||
const gateway = await lookupSipGatewayBySignalingAddress(req.source_address, req.source_port);
|
||||
if (!gateway) {
|
||||
@@ -19,12 +35,14 @@ module.exports = function(srf, logger) {
|
||||
if (gateway.application_sid) req.locals.application_sid = gateway.application_sid;
|
||||
next();
|
||||
} catch (err) {
|
||||
stats.increment('sbc.terminations', ['sipStatus:500']);
|
||||
logger.error(err, `${req.get('Call-ID')} Error looking up related info for inbound call`);
|
||||
res.send(500);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
initLocals,
|
||||
challengeDeviceCalls
|
||||
};
|
||||
};
|
||||
|
||||
Generated
+51
-4
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "sbc-inbound",
|
||||
"version": "0.2.1",
|
||||
"version": "0.3.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -325,6 +325,15 @@
|
||||
"integrity": "sha512-3/qRXczDi2Cdbz6jE+W3IflJOutRVica8frpBn14de1mBOkzDo+6tY33kNhvkw54Kn3PzRRD2VnGbGPcTAk4sw==",
|
||||
"dev": true
|
||||
},
|
||||
"bindings": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"file-uri-to-path": "1.0.0"
|
||||
}
|
||||
},
|
||||
"blue-tape": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/blue-tape/-/blue-tape-1.0.0.tgz",
|
||||
@@ -1073,6 +1082,12 @@
|
||||
"flat-cache": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"file-uri-to-path": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
|
||||
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
|
||||
"optional": true
|
||||
},
|
||||
"fill-range": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||
@@ -1382,6 +1397,14 @@
|
||||
"integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==",
|
||||
"dev": true
|
||||
},
|
||||
"hot-shots": {
|
||||
"version": "6.8.7",
|
||||
"resolved": "https://registry.npmjs.org/hot-shots/-/hot-shots-6.8.7.tgz",
|
||||
"integrity": "sha512-XH8iezBSZgVw2jegu96pUfF1Zv0VZ/iXjb7L5yE3F7mn7/bdhf4qeniXjO0wQWeefe433rhOsazNKLxM+XMI9w==",
|
||||
"requires": {
|
||||
"unix-dgram": "2.0.x"
|
||||
}
|
||||
},
|
||||
"http-signature": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
|
||||
@@ -1824,9 +1847,9 @@
|
||||
}
|
||||
},
|
||||
"jambonz-rtpengine-utils": {
|
||||
"version": "0.0.5",
|
||||
"resolved": "https://registry.npmjs.org/jambonz-rtpengine-utils/-/jambonz-rtpengine-utils-0.0.5.tgz",
|
||||
"integrity": "sha512-tkAwXkV6nYVBvF/epcIoNOUX8NDepFo25WP4a2DBu0+g8e76MzDChXGuziYRGswL3TFZxd6faTbU44rg+UcoMA==",
|
||||
"version": "0.0.9",
|
||||
"resolved": "https://registry.npmjs.org/jambonz-rtpengine-utils/-/jambonz-rtpengine-utils-0.0.9.tgz",
|
||||
"integrity": "sha512-G1d0ZHv5n5cYat0weDtgXyxrkXtZXg5GhSNCt9ekv2S1Yox3afzPdENLcL9eqltytHoBU/kJTnMQR7+8BTjFTQ==",
|
||||
"requires": {
|
||||
"debug": "^4.1.1",
|
||||
"rtpengine-client": "0.0.9"
|
||||
@@ -1842,6 +1865,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"jambonz-stats-collector": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/jambonz-stats-collector/-/jambonz-stats-collector-0.0.1.tgz",
|
||||
"integrity": "sha512-SjldpRYr5fRn/gXb1w9T9YvTiV+5cenVyNQjZfjOGBpGUlcHQomK84oxgdIiaLbGXEg7VxM5E9kupEjoF6hKfg==",
|
||||
"requires": {
|
||||
"hot-shots": "^6.8.7"
|
||||
}
|
||||
},
|
||||
"js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
@@ -2172,6 +2203,12 @@
|
||||
"lru-cache": "^4.1.3"
|
||||
}
|
||||
},
|
||||
"nan": {
|
||||
"version": "2.14.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
|
||||
"integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
|
||||
"optional": true
|
||||
},
|
||||
"natural-compare": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
||||
@@ -4838,6 +4875,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"unix-dgram": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/unix-dgram/-/unix-dgram-2.0.3.tgz",
|
||||
"integrity": "sha512-Bay5CkSLcdypcBCsxvHEvaG3mftzT5FlUnRToPWEAVxwYI8NI/8zSJ/Gknlp86MPhV6hBA8I8TBsETj2tssoHQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"bindings": "^1.3.0",
|
||||
"nan": "^2.13.2"
|
||||
}
|
||||
},
|
||||
"uri-js": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
|
||||
|
||||
+3
-1
@@ -28,9 +28,11 @@
|
||||
"debug": "^4.1.1",
|
||||
"drachtio-fn-b2b-sugar": "0.0.12",
|
||||
"drachtio-srf": "^4.4.28",
|
||||
"hot-shots": "^6.8.7",
|
||||
"jambonz-db-helpers": "^0.3.2",
|
||||
"jambonz-http-authenticator": "0.1.1",
|
||||
"jambonz-rtpengine-utils": "0.0.5",
|
||||
"jambonz-rtpengine-utils": "0.0.9",
|
||||
"jambonz-stats-collector": "0.0.1",
|
||||
"pino": "^5.14.0",
|
||||
"rtpengine-client": "^0.0.8"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user