UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

71 lines (70 loc) • 2.72 kB
import { r as resolveStateDir } from "./state-dir-CYkBUd_G.mjs"; import { t as createSubsystemLogger } from "./subsystem-4NzR43uz.mjs"; import { i as captureDiagnosticProfile, n as ProfileFailure } from "./diagnostic-profile-DiD3FYyW.mjs"; import { writeHeapSnapshot } from "node:v8"; import path from "node:path"; import fs from "node:fs/promises"; //#region src/logging/diagnostic-heap-snapshot.ts const MAX_HEAP_BYTES = 6 * 1024 ** 3; const COOLDOWN_MS = 6e4; const log = createSubsystemLogger("gateway").child("diagnostics/heap-snapshot"); let nextCaptureAt = 0; /** Owns opt-in main-isolate snapshots; native capture cannot be interrupted. */ async function captureDiagnosticHeapSnapshot(options) { let ownedPath; let elapsedMs = 0; let heapUsedAfter = 0; const outcome = await captureDiagnosticProfile({ ...options, durationMs: 0, setup: async (session) => { if (performance.now() < nextCaptureAt) throw new ProfileFailure("cooldown"); if (process.memoryUsage().heapUsed > MAX_HEAP_BYTES) throw new ProfileFailure("heap-too-large"); const directory = path.join(resolveStateDir(), "diagnostics"); await fs.mkdir(directory, { recursive: true, mode: 448 }); if (options.signal.aborted || !options.hasAuthority()) throw new ProfileFailure("cancelled"); const filename = path.join(directory, `heap-${(/* @__PURE__ */ new Date()).toISOString().replaceAll(":", "-")}.heapsnapshot`); const file = await fs.open(filename, "wx", 384); ownedPath = filename; await file.close(); await session.post("HeapProfiler.enable"); }, start: async () => { const heapUsedBefore = process.memoryUsage().heapUsed; if (heapUsedBefore > MAX_HEAP_BYTES) throw new ProfileFailure("heap-too-large"); log.warn("Writing heap snapshot: the main thread will block until capture finishes", { heapUsedBefore, reason: options.reason }); const startedAt = performance.now(); try { writeHeapSnapshot(ownedPath); } finally { nextCaptureAt = performance.now() + COOLDOWN_MS; } elapsedMs = performance.now() - startedAt; heapUsedAfter = process.memoryUsage().heapUsed; }, stop: async () => ({ profile: { path: ownedPath, sizeBytes: (await fs.stat(ownedPath)).size } }), disable: (session) => session.post("HeapProfiler.disable"), sanitize: (profile, _packageRoot, measurement) => ({ ...profile, heapUsedBefore: measurement.before.heapUsed, heapUsedAfter, elapsedMs }) }); if (outcome.status === "unavailable" && ownedPath) { const removalFailed = await fs.unlink(ownedPath).then(() => false, () => true); outcome.cleanupFailed ||= removalFailed; } return outcome; } //#endregion export { captureDiagnosticHeapSnapshot };