From 196ea61ec4d2a82dbd58caad8959c9901e2dba2a Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Fri, 29 May 2026 23:35:09 +0200 Subject: [PATCH] refactor: share diagnostics timeline span helpers --- src/infra/diagnostics-timeline.ts | 215 ++++++++++++++---------------- 1 file changed, 103 insertions(+), 112 deletions(-) diff --git a/src/infra/diagnostics-timeline.ts b/src/infra/diagnostics-timeline.ts index f08090ca5e3..cff2fff9ac5 100644 --- a/src/infra/diagnostics-timeline.ts +++ b/src/infra/diagnostics-timeline.ts @@ -70,6 +70,13 @@ export type ActiveDiagnosticsTimelineSpan = { attributes?: DiagnosticsTimelineAttributes; }; +type StartedDiagnosticsTimelineSpan = ActiveDiagnosticsTimelineSpan & { + config?: OpenClawConfig; + env: NodeJS.ProcessEnv; + startedAt: number; + omitErrorMessage?: boolean; +}; + let warnedAboutTimelineWrite = false; const createdTimelineDirs = new Set(); const activeDiagnosticsTimelineSpan = new AsyncLocalStorage(); @@ -192,72 +199,107 @@ export function getActiveDiagnosticsTimelineSpan(): ActiveDiagnosticsTimelineSpa return activeDiagnosticsTimelineSpan.getStore(); } +function startDiagnosticsTimelineSpan( + name: string, + options: DiagnosticsTimelineSpanOptions, +): StartedDiagnosticsTimelineSpan | undefined { + const env = options.env ?? process.env; + if (!isDiagnosticsTimelineEnabled({ config: options.config, env })) { + return undefined; + } + const activeSpan = getActiveDiagnosticsTimelineSpan(); + const phase = options.phase ?? activeSpan?.phase; + const parentSpanId = options.parentSpanId ?? activeSpan?.spanId; + const span: StartedDiagnosticsTimelineSpan = { + name, + env, + ...(options.config ? { config: options.config } : {}), + spanId: randomUUID(), + startedAt: performance.now(), + ...(phase ? { phase } : {}), + ...(parentSpanId ? { parentSpanId } : {}), + ...(options.attributes ? { attributes: options.attributes } : {}), + ...(options.omitErrorMessage ? { omitErrorMessage: true } : {}), + }; + emitDiagnosticsTimelineEvent( + { + type: "span.start", + name: span.name, + phase: span.phase, + spanId: span.spanId, + parentSpanId: span.parentSpanId, + attributes: span.attributes, + }, + { config: span.config, env: span.env }, + ); + return span; +} + +function runInDiagnosticsTimelineSpan(span: StartedDiagnosticsTimelineSpan, run: () => T): T { + return activeDiagnosticsTimelineSpan.run( + { + name: span.name, + ...(span.phase ? { phase: span.phase } : {}), + spanId: span.spanId, + ...(span.parentSpanId ? { parentSpanId: span.parentSpanId } : {}), + ...(span.attributes ? { attributes: span.attributes } : {}), + }, + run, + ); +} + +function emitFinishedDiagnosticsTimelineSpan(span: StartedDiagnosticsTimelineSpan): void { + emitDiagnosticsTimelineEvent( + { + type: "span.end", + name: span.name, + phase: span.phase, + spanId: span.spanId, + parentSpanId: span.parentSpanId, + durationMs: performance.now() - span.startedAt, + attributes: span.attributes, + }, + { config: span.config, env: span.env }, + ); +} + +function emitFailedDiagnosticsTimelineSpan( + span: StartedDiagnosticsTimelineSpan, + error: unknown, +): void { + emitDiagnosticsTimelineEvent( + { + type: "span.error", + name: span.name, + phase: span.phase, + spanId: span.spanId, + parentSpanId: span.parentSpanId, + durationMs: performance.now() - span.startedAt, + attributes: span.attributes, + errorName: error instanceof Error ? error.name : typeof error, + ...(span.omitErrorMessage + ? {} + : { errorMessage: error instanceof Error ? error.message : String(error) }), + }, + { config: span.config, env: span.env }, + ); +} + export async function measureDiagnosticsTimelineSpan( name: string, run: () => Promise | T, options: DiagnosticsTimelineSpanOptions = {}, ): Promise { - const env = options.env ?? process.env; - if (!isDiagnosticsTimelineEnabled({ config: options.config, env })) { + const span = startDiagnosticsTimelineSpan(name, options); + if (!span) { return await run(); } - const activeSpan = getActiveDiagnosticsTimelineSpan(); - const spanId = randomUUID(); - const phase = options.phase ?? activeSpan?.phase; - const parentSpanId = options.parentSpanId ?? activeSpan?.spanId; - const startedAt = performance.now(); - emitDiagnosticsTimelineEvent( - { - type: "span.start", - name, - phase, - spanId, - parentSpanId, - attributes: options.attributes, - }, - { config: options.config, env }, - ); try { - const result = await activeDiagnosticsTimelineSpan.run( - { - name, - ...(phase ? { phase } : {}), - spanId, - ...(parentSpanId ? { parentSpanId } : {}), - ...(options.attributes ? { attributes: options.attributes } : {}), - }, - () => run(), - ); - emitDiagnosticsTimelineEvent( - { - type: "span.end", - name, - phase, - spanId, - parentSpanId, - durationMs: performance.now() - startedAt, - attributes: options.attributes, - }, - { config: options.config, env }, - ); + const result = await runInDiagnosticsTimelineSpan(span, () => run()); + emitFinishedDiagnosticsTimelineSpan(span); return result; } catch (error) { - emitDiagnosticsTimelineEvent( - { - type: "span.error", - name, - phase, - spanId, - parentSpanId, - durationMs: performance.now() - startedAt, - attributes: options.attributes, - errorName: error instanceof Error ? error.name : typeof error, - ...(options.omitErrorMessage - ? {} - : { errorMessage: error instanceof Error ? error.message : String(error) }), - }, - { config: options.config, env }, - ); + emitFailedDiagnosticsTimelineSpan(span, error); throw error; } } @@ -267,67 +309,16 @@ export function measureDiagnosticsTimelineSpanSync( run: () => T, options: DiagnosticsTimelineSpanOptions = {}, ): T { - const env = options.env ?? process.env; - if (!isDiagnosticsTimelineEnabled({ config: options.config, env })) { + const span = startDiagnosticsTimelineSpan(name, options); + if (!span) { return run(); } - const activeSpan = getActiveDiagnosticsTimelineSpan(); - const spanId = randomUUID(); - const phase = options.phase ?? activeSpan?.phase; - const parentSpanId = options.parentSpanId ?? activeSpan?.spanId; - const startedAt = performance.now(); - emitDiagnosticsTimelineEvent( - { - type: "span.start", - name, - phase, - spanId, - parentSpanId, - attributes: options.attributes, - }, - { config: options.config, env }, - ); try { - const result = activeDiagnosticsTimelineSpan.run( - { - name, - ...(phase ? { phase } : {}), - spanId, - ...(parentSpanId ? { parentSpanId } : {}), - ...(options.attributes ? { attributes: options.attributes } : {}), - }, - run, - ); - emitDiagnosticsTimelineEvent( - { - type: "span.end", - name, - phase, - spanId, - parentSpanId, - durationMs: performance.now() - startedAt, - attributes: options.attributes, - }, - { config: options.config, env }, - ); + const result = runInDiagnosticsTimelineSpan(span, run); + emitFinishedDiagnosticsTimelineSpan(span); return result; } catch (error) { - emitDiagnosticsTimelineEvent( - { - type: "span.error", - name, - phase, - spanId, - parentSpanId, - durationMs: performance.now() - startedAt, - attributes: options.attributes, - errorName: error instanceof Error ? error.name : typeof error, - ...(options.omitErrorMessage - ? {} - : { errorMessage: error instanceof Error ? error.message : String(error) }), - }, - { config: options.config, env }, - ); + emitFailedDiagnosticsTimelineSpan(span, error); throw error; } }