mirror of
https://github.com/jambonz/jambonz-feature-server.git
synced 2026-02-15 10:49:07 +00:00
feat: add alert for jambonz parsing falure (#148)
* feat: add alert for jambonz parsing falure * fix: review comment * fix: update time-series version
This commit is contained in:
@@ -19,6 +19,10 @@ module.exports = function(srf, logger) {
|
|||||||
lookupAppByRealm,
|
lookupAppByRealm,
|
||||||
lookupAppByTeamsTenant
|
lookupAppByTeamsTenant
|
||||||
} = srf.locals.dbHelpers;
|
} = srf.locals.dbHelpers;
|
||||||
|
const {
|
||||||
|
writeAlerts,
|
||||||
|
AlertType
|
||||||
|
} = srf.locals;
|
||||||
const {lookupAccountDetails} = dbUtils(logger, srf);
|
const {lookupAccountDetails} = dbUtils(logger, srf);
|
||||||
|
|
||||||
function initLocals(req, res, next) {
|
function initLocals(req, res, next) {
|
||||||
@@ -311,6 +315,12 @@ module.exports = function(srf, logger) {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
span?.setAttributes({webhookStatus: err.statusCode});
|
span?.setAttributes({webhookStatus: err.statusCode});
|
||||||
span?.end();
|
span?.end();
|
||||||
|
writeAlerts({
|
||||||
|
account_sid: req.locals.account_sid,
|
||||||
|
target_sid: req.locals.callSid,
|
||||||
|
alert_type: AlertType.INVALID_APP_PAYLOAD,
|
||||||
|
message: `${err?.message}`.trim()
|
||||||
|
}).catch((err) => this.logger.info({err}, 'Error generating alert for parsing application'));
|
||||||
logger.info({err}, `Error retrieving or parsing application: ${err?.message}`);
|
logger.info({err}, `Error retrieving or parsing application: ${err?.message}`);
|
||||||
res.send(480, {headers: {'X-Reason': err?.message || 'unknown'}});
|
res.send(480, {headers: {'X-Reason': err?.message || 'unknown'}});
|
||||||
app.requestor.close();
|
app.requestor.close();
|
||||||
|
|||||||
14
package-lock.json
generated
14
package-lock.json
generated
@@ -13,7 +13,7 @@
|
|||||||
"@jambonz/http-health-check": "^0.0.1",
|
"@jambonz/http-health-check": "^0.0.1",
|
||||||
"@jambonz/realtimedb-helpers": "^0.4.29",
|
"@jambonz/realtimedb-helpers": "^0.4.29",
|
||||||
"@jambonz/stats-collector": "^0.1.6",
|
"@jambonz/stats-collector": "^0.1.6",
|
||||||
"@jambonz/time-series": "^0.1.9",
|
"@jambonz/time-series": "^0.1.10",
|
||||||
"@opentelemetry/api": "^1.1.0",
|
"@opentelemetry/api": "^1.1.0",
|
||||||
"@opentelemetry/exporter-jaeger": "^1.3.1",
|
"@opentelemetry/exporter-jaeger": "^1.3.1",
|
||||||
"@opentelemetry/exporter-trace-otlp-http": "^0.27.0",
|
"@opentelemetry/exporter-trace-otlp-http": "^0.27.0",
|
||||||
@@ -566,9 +566,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jambonz/time-series": {
|
"node_modules/@jambonz/time-series": {
|
||||||
"version": "0.1.9",
|
"version": "0.1.10",
|
||||||
"resolved": "https://registry.npmjs.org/@jambonz/time-series/-/time-series-0.1.9.tgz",
|
"resolved": "https://registry.npmjs.org/@jambonz/time-series/-/time-series-0.1.10.tgz",
|
||||||
"integrity": "sha512-FLD7mLGEMToG7s6LGWr/GtNp61753RBxyYuKSxCVI6G14bm6ydgcBdG85h8EGTVQlIp9dnwbn5ebSVsGb8a46w==",
|
"integrity": "sha512-4wJcTPFjUJV6WWQEgqcrJrVU7kPUjmIbr43euGmpNDURCtt44MLBtrX7fF3SB5TWEAyno8z5hyN5bJPyEEHuGA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"debug": "^4.3.1",
|
"debug": "^4.3.1",
|
||||||
"influx": "^5.8.0"
|
"influx": "^5.8.0"
|
||||||
@@ -6714,9 +6714,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@jambonz/time-series": {
|
"@jambonz/time-series": {
|
||||||
"version": "0.1.9",
|
"version": "0.1.10",
|
||||||
"resolved": "https://registry.npmjs.org/@jambonz/time-series/-/time-series-0.1.9.tgz",
|
"resolved": "https://registry.npmjs.org/@jambonz/time-series/-/time-series-0.1.10.tgz",
|
||||||
"integrity": "sha512-FLD7mLGEMToG7s6LGWr/GtNp61753RBxyYuKSxCVI6G14bm6ydgcBdG85h8EGTVQlIp9dnwbn5ebSVsGb8a46w==",
|
"integrity": "sha512-4wJcTPFjUJV6WWQEgqcrJrVU7kPUjmIbr43euGmpNDURCtt44MLBtrX7fF3SB5TWEAyno8z5hyN5bJPyEEHuGA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"debug": "^4.3.1",
|
"debug": "^4.3.1",
|
||||||
"influx": "^5.8.0"
|
"influx": "^5.8.0"
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
"@jambonz/http-health-check": "^0.0.1",
|
"@jambonz/http-health-check": "^0.0.1",
|
||||||
"@jambonz/realtimedb-helpers": "^0.4.29",
|
"@jambonz/realtimedb-helpers": "^0.4.29",
|
||||||
"@jambonz/stats-collector": "^0.1.6",
|
"@jambonz/stats-collector": "^0.1.6",
|
||||||
"@jambonz/time-series": "^0.1.9",
|
"@jambonz/time-series": "^0.1.10",
|
||||||
"@opentelemetry/api": "^1.1.0",
|
"@opentelemetry/api": "^1.1.0",
|
||||||
"@opentelemetry/exporter-jaeger": "^1.3.1",
|
"@opentelemetry/exporter-jaeger": "^1.3.1",
|
||||||
"@opentelemetry/exporter-trace-otlp-http": "^0.27.0",
|
"@opentelemetry/exporter-trace-otlp-http": "^0.27.0",
|
||||||
|
|||||||
71
test/scenarios/uac-invite-expect-480.xml
Normal file
71
test/scenarios/uac-invite-expect-480.xml
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||||
|
<!DOCTYPE scenario SYSTEM "sipp.dtd">
|
||||||
|
|
||||||
|
|
||||||
|
<scenario name="Basic Sipstone UAC">
|
||||||
|
<!-- In client mode (sipp placing calls), the Call-ID MUST be -->
|
||||||
|
<!-- generated by sipp. To do so, use [call_id] keyword. -->
|
||||||
|
<send retrans="500">
|
||||||
|
<![CDATA[
|
||||||
|
|
||||||
|
INVITE sip:[to]@[remote_ip]:[remote_port] SIP/2.0
|
||||||
|
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||||
|
From: [from] <sip:[from]@[local_ip]:[local_port]>;tag=[pid]SIPpTag00[call_number]
|
||||||
|
To: <sip:[to]@[remote_ip]:[remote_port]>
|
||||||
|
Call-ID: [call_id]
|
||||||
|
CSeq: 1 INVITE
|
||||||
|
Contact: sip:[from]@[local_ip]:[local_port]
|
||||||
|
Max-Forwards: 70
|
||||||
|
X-Account-Sid: bb845d4b-83a9-4cde-a6e9-50f3743bab3f
|
||||||
|
Subject: uac-say
|
||||||
|
Content-Type: application/sdp
|
||||||
|
Content-Length: [len]
|
||||||
|
|
||||||
|
v=0
|
||||||
|
o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
|
||||||
|
s=-
|
||||||
|
c=IN IP[media_ip_type] [media_ip]
|
||||||
|
t=0 0
|
||||||
|
m=audio [media_port] RTP/AVP 0
|
||||||
|
a=rtpmap:0 PCMU/8000
|
||||||
|
|
||||||
|
]]>
|
||||||
|
</send>
|
||||||
|
|
||||||
|
<recv response="100"
|
||||||
|
optional="true">
|
||||||
|
</recv>
|
||||||
|
|
||||||
|
<recv response="180" optional="true">
|
||||||
|
</recv>
|
||||||
|
|
||||||
|
<recv response="183" optional="true">
|
||||||
|
</recv>
|
||||||
|
|
||||||
|
<!-- By adding rrs="true" (Record Route Sets), the route sets -->
|
||||||
|
<!-- are saved and used for following messages sent. Useful to test -->
|
||||||
|
<!-- against stateful SIP proxies/B2BUAs. -->
|
||||||
|
<recv response="480" rtd="true">
|
||||||
|
</recv>
|
||||||
|
|
||||||
|
<!-- Packet lost can be simulated in any send/recv message by -->
|
||||||
|
<!-- by adding the 'lost = "10"'. Value can be [1-100] percent. -->
|
||||||
|
<send>
|
||||||
|
<![CDATA[
|
||||||
|
|
||||||
|
ACK sip:[to]@[remote_ip]:[remote_port] SIP/2.0
|
||||||
|
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||||
|
From: [from] <sip:[from]@[local_ip]:[local_port]>;tag=[pid]SIPpTag00[call_number]
|
||||||
|
To: [to] <sip:[to]@[remote_ip]:[remote_port]>[peer_tag_param]
|
||||||
|
Call-ID: [call_id]
|
||||||
|
CSeq: 1 ACK
|
||||||
|
Contact: sip:[from]@[local_ip]:[local_port]
|
||||||
|
Max-Forwards: 70
|
||||||
|
Subject: uac-say
|
||||||
|
Content-Length: 0
|
||||||
|
|
||||||
|
]]>
|
||||||
|
</send>
|
||||||
|
|
||||||
|
</scenario>
|
||||||
|
|
||||||
@@ -1,6 +1,15 @@
|
|||||||
const test = require('tape');
|
const test = require('tape');
|
||||||
const { sippUac } = require('./sipp')('test_fs');
|
const { sippUac } = require('./sipp')('test_fs');
|
||||||
const clearModule = require('clear-module');
|
const clearModule = require('clear-module');
|
||||||
|
const provisionCallHook = require('./utils');
|
||||||
|
const opts = {
|
||||||
|
timestamp: () => {return `, "time": "${new Date().toISOString()}"`;},
|
||||||
|
level: process.env.JAMBONES_LOGLEVEL || 'info'
|
||||||
|
};
|
||||||
|
const logger = require('pino')(opts);
|
||||||
|
const { queryAlerts } = require('@jambonz/time-series')(
|
||||||
|
logger, process.env.JAMBONES_TIME_SERIES_HOST
|
||||||
|
);
|
||||||
|
|
||||||
process.on('unhandledRejection', (reason, p) => {
|
process.on('unhandledRejection', (reason, p) => {
|
||||||
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
|
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
|
||||||
@@ -28,7 +37,7 @@ test('basic webhook tests', async(t) => {
|
|||||||
reason: 'Gone Fishin',
|
reason: 'Gone Fishin',
|
||||||
headers: {
|
headers: {
|
||||||
'Retry-After': 300
|
'Retry-After': 300
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -45,3 +54,43 @@ test('basic webhook tests', async(t) => {
|
|||||||
t.error(err);
|
t.error(err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('invalid jambonz json create alert tests', async(t) => {
|
||||||
|
clearModule.all();
|
||||||
|
const {srf, disconnect} = require('../app');
|
||||||
|
|
||||||
|
try {
|
||||||
|
await connect(srf);
|
||||||
|
|
||||||
|
// GIVEN
|
||||||
|
// Invalid json array
|
||||||
|
const verbs = {
|
||||||
|
verb: 'say',
|
||||||
|
text: 'hello'
|
||||||
|
};
|
||||||
|
|
||||||
|
const from = 'invalid_json_create_alert';
|
||||||
|
provisionCallHook(from, verbs)
|
||||||
|
|
||||||
|
// THEN
|
||||||
|
await sippUac('uac-invite-expect-480.xml', '172.38.0.10', from);
|
||||||
|
// sleep testcase for more than 7 second to wait alert pushed to database.
|
||||||
|
await sleep(8000);
|
||||||
|
const data = await queryAlerts(
|
||||||
|
{account_sid: 'bb845d4b-83a9-4cde-a6e9-50f3743bab3f', page: 1, page_size: 25, days: 7});
|
||||||
|
let checked = false;
|
||||||
|
for (let i = 0; i < data.total; i++) {
|
||||||
|
checked = data.data[i].message === 'malformed jambonz payload: must be array'
|
||||||
|
}
|
||||||
|
t.ok(checked, 'alert is raised as expected');
|
||||||
|
disconnect();
|
||||||
|
} catch (err) {
|
||||||
|
console.log(`error received: ${err}`);
|
||||||
|
disconnect();
|
||||||
|
t.error(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function sleep(ms) {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user