






















@@ -227,6 +227,7 @@ export type ReadConfigFileSnapshotForWriteResult = {
227227};
228228229229export type ConfigWriteNotification = RuntimeConfigWriteNotification;
230+export type ConfigSnapshotReadMeasure = <T>(name: string, run: () => T | Promise<T>) => Promise<T>;
230231231232export class ConfigRuntimeRefreshError extends Error {
232233constructor(message: string, options?: { cause?: unknown }) {
@@ -903,6 +904,7 @@ export type ConfigIoDeps = {
903904homedir?: () => string;
904905configPath?: string;
905906logger?: Pick<typeof console, "error" | "warn">;
907+measure?: ConfigSnapshotReadMeasure;
906908};
907909908910function warnOnConfigMiskeys(raw: unknown, logger: Pick<typeof console, "warn">): void {
@@ -960,6 +962,7 @@ function normalizeDeps(overrides: ConfigIoDeps = {}): Required<ConfigIoDeps> {
960962overrides.homedir ?? (() => resolveRequiredHomeDir(overrides.env ?? process.env, os.homedir)),
961963configPath: overrides.configPath ?? "",
962964logger: overrides.logger ?? console,
965+measure: overrides.measure ?? (async (_name, run) => await run()),
963966};
964967}
965968@@ -1637,11 +1640,15 @@ export function createConfigIO(
16371640let fallbackHash = hashConfigRaw(null);
1638164116391642try {
1640-const raw = deps.fs.readFileSync(configPath, "utf-8");
1641-const rawHash = hashConfigRaw(raw);
1643+const raw = await deps.measure("config.snapshot.read.file", () =>
1644+deps.fs.readFileSync(configPath, "utf-8"),
1645+);
1646+const rawHash = await deps.measure("config.snapshot.read.hash", () => hashConfigRaw(raw));
16421647fallbackRaw = raw;
16431648fallbackHash = rawHash;
1644-const parsedRes = parseConfigJson5(raw, deps.json5);
1649+const parsedRes = await deps.measure("config.snapshot.read.parse", () =>
1650+parseConfigJson5(raw, deps.json5),
1651+);
16451652if (!parsedRes.ok) {
16461653return await finalizeReadConfigSnapshotInternalResult(deps, {
16471654snapshot: createConfigFileSnapshot({
@@ -1663,12 +1670,14 @@ export function createConfigIO(
16631670fallbackSourceConfig = coerceConfig(parsedRes.parsed);
1664167116651672// Resolve $include directives
1666-const recovered = await maybeRecoverSuspiciousConfigRead({
1667- deps,
1668- configPath,
1669- raw,
1670-parsed: parsedRes.parsed,
1671-});
1673+const recovered = await deps.measure("config.snapshot.read.recovery-check", () =>
1674+maybeRecoverSuspiciousConfigRead({
1675+ deps,
1676+ configPath,
1677+ raw,
1678+parsed: parsedRes.parsed,
1679+}),
1680+);
16721681const effectiveRaw = recovered.raw;
16731682const effectiveParsed = recovered.parsed;
16741683const hash = hashConfigRaw(effectiveRaw);
@@ -1679,7 +1688,9 @@ export function createConfigIO(
1679168816801689let resolved: unknown;
16811690try {
1682-resolved = resolveConfigIncludesForRead(effectiveParsed, configPath, deps);
1691+resolved = await deps.measure("config.snapshot.read.includes", () =>
1692+resolveConfigIncludesForRead(effectiveParsed, configPath, deps),
1693+);
16831694} catch (err) {
16841695const message =
16851696err instanceof ConfigIncludeError
@@ -1703,7 +1714,9 @@ export function createConfigIO(
17031714});
17041715}
170517161706-const readResolution = resolveConfigForRead(resolved, deps.env);
1717+const readResolution = await deps.measure("config.snapshot.read.env", () =>
1718+resolveConfigForRead(resolved, deps.env),
1719+);
1707172017081721// Convert missing env var references to config warnings instead of fatal errors.
17091722// This allows the gateway to start in degraded mode when non-critical config
@@ -1714,13 +1727,16 @@ export function createConfigIO(
17141727}));
1715172817161729const resolvedConfigRaw = readResolution.resolvedConfigRaw;
1717-const legacyResolution = resolveLegacyConfigForRead(resolvedConfigRaw, effectiveParsed);
1718-const installMigration = migrateAndStripShippedPluginInstallConfigRecords(
1719-legacyResolution.effectiveConfigRaw,
1720-{
1721-persist: options.persistShippedPluginInstallMigration !== false,
1722-rootConfigRaw: effectiveParsed,
1723-},
1730+const legacyResolution = await deps.measure("config.snapshot.read.legacy", () =>
1731+resolveLegacyConfigForRead(resolvedConfigRaw, effectiveParsed),
1732+);
1733+const installMigration = await deps.measure(
1734+"config.snapshot.read.plugin-install-migration",
1735+() =>
1736+migrateAndStripShippedPluginInstallConfigRecords(legacyResolution.effectiveConfigRaw, {
1737+persist: options.persistShippedPluginInstallMigration !== false,
1738+rootConfigRaw: effectiveParsed,
1739+}),
17241740);
17251741const effectiveConfigRaw = installMigration.config;
17261742const snapshotRaw = installMigration.persistedRootRaw ?? effectiveRaw;
@@ -1729,10 +1745,12 @@ export function createConfigIO(
17291745 ? hashConfigRaw(installMigration.persistedRootRaw)
17301746 : hash;
17311747fallbackSourceConfig = coerceConfig(effectiveConfigRaw);
1732-const validated = validateConfigObjectWithPlugins(effectiveConfigRaw, {
1733-env: deps.env,
1734-pluginValidation: overrides.pluginValidation,
1735-});
1748+const validated = await deps.measure("config.snapshot.read.validate", () =>
1749+validateConfigObjectWithPlugins(effectiveConfigRaw, {
1750+env: deps.env,
1751+pluginValidation: overrides.pluginValidation,
1752+}),
1753+);
17361754if (!validated.ok) {
17371755return await finalizeReadConfigSnapshotInternalResult(deps, {
17381756snapshot: createConfigFileSnapshot({
@@ -1752,25 +1770,29 @@ export function createConfigIO(
17521770}
1753177117541772warnIfConfigFromFuture(validated.config, deps.logger);
1755-const snapshotConfig = materializeRuntimeConfig(validated.config, "snapshot");
1756-return await finalizeReadConfigSnapshotInternalResult(deps, {
1757-snapshot: createConfigFileSnapshot({
1758-path: configPath,
1759-exists: true,
1760-raw: snapshotRaw,
1761-parsed: snapshotParsed,
1762-// Use resolvedConfigRaw (after $include and ${ENV} substitution but BEFORE runtime defaults)
1763-// for config set/unset operations (issue #6070)
1764-sourceConfig: coerceConfig(effectiveConfigRaw),
1765-valid: true,
1766-runtimeConfig: snapshotConfig,
1767-hash: snapshotHash,
1768-issues: [],
1769-warnings: [...validated.warnings, ...envVarWarnings],
1770-legacyIssues: legacyResolution.sourceLegacyIssues,
1773+const snapshotConfig = await deps.measure("config.snapshot.read.materialize", () =>
1774+materializeRuntimeConfig(validated.config, "snapshot"),
1775+);
1776+return await deps.measure("config.snapshot.read.observe", () =>
1777+finalizeReadConfigSnapshotInternalResult(deps, {
1778+snapshot: createConfigFileSnapshot({
1779+path: configPath,
1780+exists: true,
1781+raw: snapshotRaw,
1782+parsed: snapshotParsed,
1783+// Use resolvedConfigRaw (after $include and ${ENV} substitution but BEFORE runtime defaults)
1784+// for config set/unset operations (issue #6070)
1785+sourceConfig: coerceConfig(effectiveConfigRaw),
1786+valid: true,
1787+runtimeConfig: snapshotConfig,
1788+hash: snapshotHash,
1789+issues: [],
1790+warnings: [...validated.warnings, ...envVarWarnings],
1791+legacyIssues: legacyResolution.sourceLegacyIssues,
1792+}),
1793+envSnapshotForRestore: readResolution.envSnapshotForRestore,
17711794}),
1772-envSnapshotForRestore: readResolution.envSnapshotForRestore,
1773-});
1795+);
17741796} catch (err) {
17751797const nodeErr = err as NodeJS.ErrnoException;
17761798let message: string;
@@ -2304,8 +2326,12 @@ export async function readSourceConfigBestEffort(): Promise<OpenClawConfig> {
23042326return await createConfigIO().readSourceConfigBestEffort();
23052327}
230623282307-export async function readConfigFileSnapshot(): Promise<ConfigFileSnapshot> {
2308-return await createConfigIO().readConfigFileSnapshot();
2329+export async function readConfigFileSnapshot(options?: {
2330+measure?: ConfigSnapshotReadMeasure;
2331+}): Promise<ConfigFileSnapshot> {
2332+return await createConfigIO(
2333+options?.measure ? { measure: options.measure } : {},
2334+).readConfigFileSnapshot();
23092335}
2310233623112337export async function promoteConfigSnapshotToLastKnownGood(
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。