fix: gate diagnostics timeline by flag

This commit is contained in:
Shakker
2026-04-29 19:37:57 +01:00
parent 097eed8cd8
commit d001c3436b
4 changed files with 36 additions and 4 deletions

View File

@@ -112,7 +112,7 @@ Inline `--password` can be exposed in local process listings. Prefer `--password
### Startup profiling
- Set `OPENCLAW_GATEWAY_STARTUP_TRACE=1` to log phase timings during Gateway startup, including per-phase `eventLoopMax` delay and plugin lookup-table timings for installed-index, manifest registry, startup planning, and owner-map work.
- Set `OPENCLAW_DIAGNOSTICS=1` with `OPENCLAW_DIAGNOSTICS_TIMELINE_PATH=<path>` to write a best-effort JSONL startup diagnostics timeline for external QA harnesses. Add `OPENCLAW_DIAGNOSTICS_EVENT_LOOP=1` to include event-loop samples.
- Set `OPENCLAW_DIAGNOSTICS=timeline` with `OPENCLAW_DIAGNOSTICS_TIMELINE_PATH=<path>` to write a best-effort JSONL startup diagnostics timeline for external QA harnesses. Add `OPENCLAW_DIAGNOSTICS_EVENT_LOOP=1` to include event-loop samples.
- Run `pnpm test:startup:gateway -- --runs 5 --warmup 1` to benchmark Gateway startup. The benchmark records first process output, `/healthz`, `/readyz`, startup trace timings, event-loop delay, and plugin lookup-table timing details.
## Query a running Gateway

View File

@@ -50,6 +50,28 @@ Disable all flags:
OPENCLAW_DIAGNOSTICS=0
```
## Timeline artifacts
The `timeline` flag writes structured startup and runtime timing events for
external QA harnesses:
```bash
OPENCLAW_DIAGNOSTICS=timeline \
OPENCLAW_DIAGNOSTICS_TIMELINE_PATH=/tmp/openclaw-timeline.jsonl \
openclaw gateway run
```
`OPENCLAW_DIAGNOSTICS=1`, `OPENCLAW_DIAGNOSTICS=all`, and
`OPENCLAW_DIAGNOSTICS=*` also enable the timeline because they enable every
diagnostics flag. Prefer `timeline` when you only want the JSONL timing
artifact.
Timeline records use the `openclaw.diagnostics.v1` envelope. Events can include
process ids, phase names, span names, durations, plugin ids, dependency counts,
event-loop delay samples, provider operation names, child-process exit state,
and startup error names/messages. Treat timeline files as local diagnostics
artifacts; review them before sharing outside your machine.
## Where logs go
Flags emit logs into the standard diagnostics log file. By default:

View File

@@ -17,7 +17,7 @@ async function createTimelineEnv() {
tempDirs.push(dir);
return {
env: {
OPENCLAW_DIAGNOSTICS: "1",
OPENCLAW_DIAGNOSTICS: "timeline",
OPENCLAW_DIAGNOSTICS_RUN_ID: "run-1",
OPENCLAW_DIAGNOSTICS_ENV: "env-1",
OPENCLAW_DIAGNOSTICS_TIMELINE_PATH: join(dir, "nested", "timeline.jsonl"),
@@ -43,6 +43,15 @@ describe("diagnostics timeline", () => {
const { env } = await createTimelineEnv();
expect(isDiagnosticsTimelineEnabled(env)).toBe(true);
expect(isDiagnosticsTimelineEnabled({ ...env, OPENCLAW_DIAGNOSTICS: "1" })).toBe(true);
expect(isDiagnosticsTimelineEnabled({ ...env, OPENCLAW_DIAGNOSTICS: "all" })).toBe(true);
expect(isDiagnosticsTimelineEnabled({ ...env, OPENCLAW_DIAGNOSTICS: "*" })).toBe(true);
expect(
isDiagnosticsTimelineEnabled({ ...env, OPENCLAW_DIAGNOSTICS: "diagnostics.timeline" }),
).toBe(true);
expect(isDiagnosticsTimelineEnabled({ ...env, OPENCLAW_DIAGNOSTICS: "telegram.http" })).toBe(
false,
);
expect(isDiagnosticsTimelineEnabled({ ...env, OPENCLAW_DIAGNOSTICS: "0" })).toBe(false);
expect(isDiagnosticsTimelineEnabled({ ...env, OPENCLAW_DIAGNOSTICS_TIMELINE_PATH: "" })).toBe(
false,

View File

@@ -2,7 +2,7 @@ import { randomUUID } from "node:crypto";
import { appendFileSync, mkdirSync } from "node:fs";
import { dirname } from "node:path";
import { performance } from "node:perf_hooks";
import { isTruthyEnvValue } from "./env.js";
import { isDiagnosticFlagEnabled } from "./diagnostic-flags.js";
export const OPENCLAW_DIAGNOSTICS_TIMELINE_SCHEMA_VERSION = "openclaw.diagnostics.v1";
@@ -56,7 +56,8 @@ const createdTimelineDirs = new Set<string>();
export function isDiagnosticsTimelineEnabled(env: NodeJS.ProcessEnv = process.env): boolean {
return (
isTruthyEnvValue(env.OPENCLAW_DIAGNOSTICS) &&
(isDiagnosticFlagEnabled("timeline", undefined, env) ||
isDiagnosticFlagEnabled("diagnostics.timeline", undefined, env)) &&
typeof env.OPENCLAW_DIAGNOSTICS_TIMELINE_PATH === "string" &&
env.OPENCLAW_DIAGNOSTICS_TIMELINE_PATH.trim().length > 0
);