diff --git a/app.js b/app.js index e3969dc6..12152e9f 100644 --- a/app.js +++ b/app.js @@ -29,6 +29,12 @@ const {LifeCycleEvents, FS_UUID_SET_NAME, SystemState, FEATURE_SERVER} = require const installSrfLocals = require('./lib/utils/install-srf-locals'); const createHttpListener = require('./lib/utils/http-listener'); const healthCheck = require('@jambonz/http-health-check'); +const ProcessMonitor = require('./lib/utils/process-monitor'); +const monitor = new ProcessMonitor(logger); + +// Log startup +monitor.logStartup(); +monitor.setupSignalHandlers(); logger.on('level-change', (lvl, _val, prevLvl, _prevVal, instance) => { if (logger !== instance) { diff --git a/lib/tasks/llm/llms/ultravox_s2s.js b/lib/tasks/llm/llms/ultravox_s2s.js index 6d0d621d..1946ba4f 100644 --- a/lib/tasks/llm/llms/ultravox_s2s.js +++ b/lib/tasks/llm/llms/ultravox_s2s.js @@ -218,7 +218,7 @@ class TaskLlmUltravox_S2S extends Task { async _onServerEvent(_ep, evt) { let endConversation = false; const type = evt.type; - this.logger.debug({evt}, 'TaskLlmUltravox_S2S:_onServerEvent'); + //this.logger.debug({evt}, 'TaskLlmUltravox_S2S:_onServerEvent'); /* server errors of some sort */ if (type === 'error') { diff --git a/lib/utils/process-monitor.js b/lib/utils/process-monitor.js new file mode 100644 index 00000000..4c3dc3b4 --- /dev/null +++ b/lib/utils/process-monitor.js @@ -0,0 +1,91 @@ +// lib/utils/process-monitor.js +const fs = require('fs'); +const path = require('path'); + +class ProcessMonitor { + constructor(logger) { + this.logger = logger; + this.packageInfo = this.getPackageInfo(); + this.processName = this.packageInfo.name || 'unknown-app'; + } + + getPackageInfo() { + try { + const packagePath = path.join(process.cwd(), 'package.json'); + return JSON.parse(fs.readFileSync(packagePath, 'utf8')); + } catch (e) { + return { name: 'unknown', version: 'unknown' }; + } + } + + logStartup(additionalInfo = {}) { + const startupInfo = { + msg: `${this.processName} started`, + app_name: this.processName, + app_version: this.packageInfo.version, + pid: process.pid, + ppid: process.ppid, + pm2_instance_id: process.env.NODE_APP_INSTANCE || 'not_pm2', + pm2_id: process.env.pm_id, + is_pm2: !!process.env.PM2, + node_version: process.version, + uptime: process.uptime(), + timestamp: new Date().toISOString(), + ...additionalInfo + }; + + this.logger.info(startupInfo); + return startupInfo; + } + + setupSignalHandlers() { + // Log when we receive signals that would cause restart + process.on('SIGINT', () => { + this.logger.info({ + msg: 'SIGINT received', + app_name: this.processName, + pid: process.pid, + ppid: process.ppid, + uptime: process.uptime(), + timestamp: new Date().toISOString() + }); + process.exit(0); + }); + + process.on('SIGTERM', () => { + this.logger.info({ + msg: 'SIGTERM received', + app_name: this.processName, + pid: process.pid, + ppid: process.ppid, + uptime: process.uptime(), + timestamp: new Date().toISOString() + }); + process.exit(0); + }); + + process.on('uncaughtException', (error) => { + this.logger.error({ + msg: 'Uncaught exception - process will restart', + app_name: this.processName, + error: error.message, + stack: error.stack, + pid: process.pid, + timestamp: new Date().toISOString() + }); + process.exit(1); + }); + + process.on('unhandledRejection', (reason, promise) => { + this.logger.error({ + msg: 'Unhandled rejection', + app_name: this.processName, + reason, + pid: process.pid, + timestamp: new Date().toISOString() + }); + }); + } +} + +module.exports = ProcessMonitor; diff --git a/lib/utils/ws-requestor.js b/lib/utils/ws-requestor.js index 9d68dad2..284b3272 100644 --- a/lib/utils/ws-requestor.js +++ b/lib/utils/ws-requestor.js @@ -293,7 +293,7 @@ class WsRequestor extends BaseRequestor { /* send the message */ this.ws.send(JSON.stringify(obj), async() => { - this.logger.debug({obj}, `WsRequestor:request websocket: sent (${url})`); + if (obj.type !== 'llm:event') this.logger.debug({obj}, `WsRequestor:request websocket: sent (${url})`); // If session:reconnect is waiting for ack, hold here until ack to send queuedMsgs if (this._reconnectPromise) { try {