UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

128 lines • 4.18 kB
/** * @license * Copyright 2026 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import process from 'node:process'; import readline from 'node:readline'; import { parseArgs } from 'node:util'; import { logger, flushLogs, saveLogsToFile } from '../../utils/logger.js'; import { WatchdogMessageType } from '../types.js'; import { ClearcutSender } from './ClearcutSender.js'; function parseWatchdogArgs() { const { values } = parseArgs({ options: { 'parent-pid': { type: 'string' }, 'app-version': { type: 'string' }, 'os-type': { type: 'string' }, 'log-file': { type: 'string' }, 'clearcut-endpoint': { type: 'string' }, 'clearcut-force-flush-interval-ms': { type: 'string' }, 'clearcut-include-pid-header': { type: 'boolean' }, }, strict: true, }); // Verify required arguments const parentPid = parseInt(values['parent-pid'] ?? '', 10); const appVersion = values['app-version']; const osType = parseInt(values['os-type'] ?? '', 10); if (isNaN(parentPid) || !appVersion || isNaN(osType)) { console.error('Invalid arguments provided for watchdog process: ', JSON.stringify({ parentPid, appVersion, osType })); process.exit(1); } // Parse Optional Arguments const logFile = values['log-file']; const clearcutEndpoint = values['clearcut-endpoint']; const clearcutIncludePidHeader = values['clearcut-include-pid-header']; let clearcutForceFlushIntervalMs; if (values['clearcut-force-flush-interval-ms']) { const parsed = parseInt(values['clearcut-force-flush-interval-ms'], 10); if (!isNaN(parsed)) { clearcutForceFlushIntervalMs = parsed; } } return { parentPid, appVersion, osType, logFile, clearcutEndpoint, clearcutForceFlushIntervalMs, clearcutIncludePidHeader, }; } function main() { const { parentPid, appVersion, osType, logFile, clearcutEndpoint, clearcutForceFlushIntervalMs, clearcutIncludePidHeader, } = parseWatchdogArgs(); let logStream; if (logFile) { logStream = saveLogsToFile(logFile); } const exit = (code) => { if (!logStream) { process.exit(code); } void flushLogs(logStream).finally(() => { process.exit(code); }); }; logger?.('Watchdog started', JSON.stringify({ pid: process.pid, parentPid, version: appVersion, osType, }, null, 2)); const sender = new ClearcutSender({ appVersion, osType: osType, clearcutEndpoint, forceFlushIntervalMs: clearcutForceFlushIntervalMs, includePidHeader: clearcutIncludePidHeader, }); let isShuttingDown = false; function onParentDeath(reason) { if (isShuttingDown) { return; } isShuttingDown = true; logger?.(`Parent death detected (${reason}). Sending shutdown event...`); sender .sendShutdownEvent() .then(() => { logger?.('Shutdown event sent. Exiting.'); exit(0); }) .catch(err => { logger?.('Failed to send shutdown event', err); exit(1); }); } process.stdin.on('end', () => onParentDeath('stdin end')); process.stdin.on('close', () => onParentDeath('stdin close')); process.on('disconnect', () => onParentDeath('ipc disconnect')); const rl = readline.createInterface({ input: process.stdin, terminal: false, }); rl.on('line', line => { try { if (!line.trim()) { return; } const msg = JSON.parse(line); if (msg.type === WatchdogMessageType.LOG_EVENT && msg.payload) { sender.enqueueEvent(msg.payload); } } catch (err) { logger?.('Failed to parse IPC message', err); } }); } try { main(); } catch (err) { console.error('Watchdog fatal error:', err); process.exit(1); } //# sourceMappingURL=main.js.map