Compare commits

..

4 Commits

Author SHA1 Message Date
Sam Machin
68a9b4226d fix min 25 (#396) 2025-03-11 07:48:04 -04:00
rammohan-y
b154b56064 updated realtimedb-helper to 0.8.13 (#395) 2025-03-10 09:54:24 -04:00
Hoan Luu Huu
556d5c3526 support fetching logs from cloudwatch for call_sid (#393)
* support fetching logs from cloudwatch for call_sid

* wip

* wip

* wip

* ưip

* wip

* fix review comments
2025-03-10 08:31:24 -04:00
Hoan Luu Huu
2ac0da0d14 Should not allow create phone_number on different voip_carrier and account (#394)
* shouldnt create phonenumber on different carrier and account

* wip
2025-03-06 07:40:54 -05:00
5 changed files with 1922 additions and 7 deletions

View File

@@ -16,7 +16,7 @@ router.get('/', async(req, res) => {
const service_provider_sid = account_sid ? null : parseServiceProviderSid(req.originalUrl);
const {page, count, alert_type, days, start, end} = req.query || {};
if (!page || page < 1) throw new DbErrorBadRequest('missing or invalid "page" query arg');
if (!count || count < 25 || count > 500) throw new DbErrorBadRequest('missing or invalid "count" query arg');
if (!count || count > 500) throw new DbErrorBadRequest('missing or invalid "count" query arg');
if (account_sid) {
const data = await queryAlerts({

View File

@@ -40,6 +40,10 @@ async function validateAdd(req) {
if (!result || result.length === 0) {
throw new DbErrorBadRequest(`voip_carrier not found for sid ${req.body.voip_carrier_sid}`);
}
const carrier = result[0];
if (carrier.account_sid && req.body.account_sid && req.body.account_sid !== carrier.account_sid) {
throw new DbErrorBadRequest('voip_carrier_sid does not belong to the account');
}
}
}

View File

@@ -4,6 +4,7 @@ const {DbErrorBadRequest} = require('../../utils/errors');
const {getHomerApiKey, getHomerSipTrace, getHomerPcap} = require('../../utils/homer-utils');
const {getJaegerTrace} = require('../../utils/jaeger-utils');
const Account = require('../../models/account');
const { CloudWatchLogsClient, FilterLogEventsCommand } = require('@aws-sdk/client-cloudwatch-logs');
const {
getS3Object,
getGoogleStorageObject,
@@ -31,7 +32,7 @@ router.get('/', async(req, res) => {
const service_provider_sid = account_sid ? null : parseServiceProviderSid(req.originalUrl);
const {page, count, trunk, direction, days, answered, start, end, filter} = req.query || {};
if (!page || page < 1) throw new DbErrorBadRequest('missing or invalid "page" query arg');
if (!count || count < 25 || count > 500) throw new DbErrorBadRequest('missing or invalid "count" query arg');
if (!count || count > 500) throw new DbErrorBadRequest('missing or invalid "count" query arg');
if (account_sid) {
const data = await queryCdrs({
@@ -106,6 +107,71 @@ router.get('/:call_id/:method/pcap', async(req, res) => {
}
});
router.get('/:call_sid/logs', async(req, res) => {
const {logger, queryCdrs} = req.app.locals;
const aws_region = process.env.AWS_REGION;
const {call_sid} = req.params;
const {logGroupName = 'jambonz-feature_server'} = req.query;
const account_sid = parseAccountSid(req.originalUrl);
if (!aws_region) {
return res.status(400).send({msg: 'Logs are only available in AWS environments'});
}
if (!account_sid) {
return res.status(400).send({msg: 'account_sid is required,' +
'please use /Accounts/{account_sid}/RecentCalls/{call_sid}/logs'});
}
try {
//find back the call in CDR to get timestame of the call
// this allow us limit search in cloudwatch logs
const data = await queryCdrs({
account_sid,
filter: call_sid,
page: 0,
page_size: 50
});
if (!data || data.data.length === 0) {
return res.status(404).send({msg: 'Call not found'});
}
const {
attempted_at, //2025-02-24T13:11:51.969Z
terminated_at, //2025-02-24T13:11:56.153Z
sip_callid
} = data.data[0];
const TIMEBUFFER = 60; //60 seconds
const startTime = new Date(attempted_at).getTime() - TIMEBUFFER * 1000;
const endTime = new Date(terminated_at).getTime() + TIMEBUFFER * 1000;
const client = new CloudWatchLogsClient({ region: aws_region });
let params = {
logGroupName,
startTime,
endTime,
filterPattern: `{ ($.callSid = "${call_sid}") || ($.callId = "${sip_callid}") }`
};
const command = new FilterLogEventsCommand(params);
const response = await client.send(command);
// if response have nextToken, we need to fetch all logs
while (response.nextToken) {
params = {
...params,
nextToken: response.nextToken
};
const command = new FilterLogEventsCommand(params);
const response2 = await client.send(command);
response.events = response.events.concat(response2.events);
response.nextToken = response2.nextToken;
}
let logs = [];
if (response.events && response.events.length > 0) {
logs = response.events.map((e) => e.message);
}
res.status(200).json(logs);
} catch (err) {
logger.error({err}, 'Cannot fetch logs from cloudwatch');
res.status(500).send({msg: err.message});
}
});
router.get('/trace/:trace_id', async(req, res) => {
const {logger} = req.app.locals;
const {trace_id} = req.params;

1852
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -20,6 +20,7 @@
"url": "https://github.com/jambonz/jambonz-api-server.git"
},
"dependencies": {
"@aws-sdk/client-cloudwatch-logs": "^3.750.0",
"@aws-sdk/client-s3": "^3.550.0",
"@aws-sdk/client-transcribe": "^3.549.0",
"@azure/storage-blob": "^12.17.0",
@@ -29,7 +30,7 @@
"@jambonz/db-helpers": "^0.9.3",
"@jambonz/lamejs": "^1.2.2",
"@jambonz/mw-registrar": "^0.2.7",
"@jambonz/realtimedb-helpers": "^0.8.10",
"@jambonz/realtimedb-helpers": "^0.8.13",
"@jambonz/speech-utils": "^0.2.3",
"@jambonz/time-series": "^0.2.8",
"@jambonz/verb-specifications": "^0.0.72",