

























@@ -1,3 +1,4 @@
1+import { monitorEventLoopDelay } from "node:perf_hooks";
12import { getActiveEmbeddedRunCount } from "../agents/pi-embedded-runner/run-state.js";
23import { getTotalPendingReplies } from "../auto-reply/reply/dispatcher-registry.js";
34import type { CanvasHostServer } from "../canvas-host/server.js";
@@ -142,18 +143,52 @@ const canvasRuntime = runtimeForLogger(logCanvas);
142143143144function createGatewayStartupTrace() {
144145const enabled = isTruthyEnvValue(process.env.OPENCLAW_GATEWAY_STARTUP_TRACE);
146+const eventLoopDelay = enabled ? monitorEventLoopDelay({ resolution: 10 }) : undefined;
147+eventLoopDelay?.enable();
145148const started = performance.now();
146149let last = started;
147-const emit = (name: string, durationMs: number, totalMs: number) => {
150+const formatMetric = (key: string, value: number | string) =>
151+`${key}=${typeof value === "number" ? value.toFixed(1) : value}`;
152+const readEventLoopMaxMs = () => {
153+if (!eventLoopDelay) {
154+return 0;
155+}
156+const maxMs = eventLoopDelay.max / 1_000_000;
157+eventLoopDelay.reset();
158+return maxMs;
159+};
160+const emit = (
161+name: string,
162+durationMs: number,
163+totalMs: number,
164+extras: ReadonlyArray<readonly [string, number | string]> = [],
165+) => {
148166if (enabled) {
149-log.info(`startup trace: ${name} ${durationMs.toFixed(1)}ms total=${totalMs.toFixed(1)}ms`);
167+const metrics = [
168+`eventLoopMax=${readEventLoopMaxMs().toFixed(1)}ms`,
169+ ...extras.map(([key, value]) => formatMetric(key, value)),
170+].join(" ");
171+log.info(
172+`startup trace: ${name} ${durationMs.toFixed(1)}ms total=${totalMs.toFixed(1)}ms ${metrics}`,
173+);
150174}
151175};
152176return {
153177mark(name: string) {
154178const now = performance.now();
155179emit(name, now - last, now - started);
156180last = now;
181+if (name === "ready") {
182+eventLoopDelay?.disable();
183+}
184+},
185+detail(name: string, metrics: ReadonlyArray<readonly [string, number | string]>) {
186+if (!enabled) {
187+return;
188+}
189+log.info(
190+`startup trace: ${name} ${metrics.map(([key, value]) => formatMetric(key, value)).join(" ")}`,
191+);
157192},
158193async measure<T>(name: string, run: () => Promise<T> | T): Promise<T> {
159194const before = performance.now();
@@ -381,6 +416,20 @@ export async function startGatewayServer(
381416 pluginLookUpTable,
382417 baseMethods,
383418} = pluginBootstrap;
419+if (pluginLookUpTable) {
420+const metrics = pluginLookUpTable.metrics;
421+startupTrace.detail("plugins.lookup-table", [
422+["registrySnapshotMs", metrics.registrySnapshotMs],
423+["manifestRegistryMs", metrics.manifestRegistryMs],
424+["startupPlanMs", metrics.startupPlanMs],
425+["ownerMapsMs", metrics.ownerMapsMs],
426+["totalMs", metrics.totalMs],
427+["indexPlugins", String(metrics.indexPluginCount)],
428+["manifestPlugins", String(metrics.manifestPluginCount)],
429+["startupPlugins", String(metrics.startupPluginCount)],
430+["deferredChannelPlugins", String(metrics.deferredChannelPluginCount)],
431+]);
432+}
384433let { pluginRegistry, baseGatewayMethods } = pluginBootstrap;
385434const channelLogs = Object.fromEntries(
386435listChannelPlugins().map((plugin) => [plugin.id, logChannels.child(plugin.id)]),
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。