diff --git a/packages/cli/src/commands/render.ts b/packages/cli/src/commands/render.ts index bb3307d431..71ad9f4ba3 100644 --- a/packages/cli/src/commands/render.ts +++ b/packages/cli/src/commands/render.ts @@ -1558,6 +1558,10 @@ function trackRenderMetrics( extractPhase3Ms: extract?.extractMs, extractCacheHits: extract?.cacheHits, extractCacheMisses: extract?.cacheMisses, + extractCachePublishFailures: extract?.cachePublishFailures, + extractCacheGcEvictions: extract?.cacheGcEvictions, + extractCacheGcBytesFreed: extract?.cacheGcBytesFreed, + extractCacheAgedPartialsCleared: extract?.cacheAgedPartialsCleared, ...renderJobObservabilityTelemetryPayload(job), ...getMemorySnapshot(), }); diff --git a/packages/cli/src/server/studioRenderTelemetry.test.ts b/packages/cli/src/server/studioRenderTelemetry.test.ts index db89492f70..0d95543978 100644 --- a/packages/cli/src/server/studioRenderTelemetry.test.ts +++ b/packages/cli/src/server/studioRenderTelemetry.test.ts @@ -109,10 +109,12 @@ const fullPerf: RenderPerfSummary = { extractMs: 60, cacheHits: 3, cacheMisses: 4, - cachePublishFailures: 0, - cacheGcEvictions: 0, - cacheGcBytesFreed: 0, - cacheAgedPartialsCleared: 0, + // Distinct non-zero values: all-zeros cannot tell a correct mapping from + // one that crossed two fields. + cachePublishFailures: 5, + cacheGcEvictions: 6, + cacheGcBytesFreed: 7, + cacheAgedPartialsCleared: 8, }, tmpPeakBytes: 1024, captureAvgMs: 13, @@ -184,6 +186,10 @@ describe("studioRenderTelemetry", () => { expect(p.extractPhase3Ms).toBe(60); expect(p.extractCacheHits).toBe(3); expect(p.extractCacheMisses).toBe(4); + expect(p.extractCachePublishFailures).toBe(5); + expect(p.extractCacheGcEvictions).toBe(6); + expect(p.extractCacheGcBytesFreed).toBe(7); + expect(p.extractCacheAgedPartialsCleared).toBe(8); // observability aggregate expect(p.observabilityRenderJobId).toBe("render-123"); expect(p.observabilityCompositionHash).toBe("abc123"); diff --git a/packages/cli/src/server/studioRenderTelemetry.ts b/packages/cli/src/server/studioRenderTelemetry.ts index 1feb70e6f4..64cb4570cf 100644 --- a/packages/cli/src/server/studioRenderTelemetry.ts +++ b/packages/cli/src/server/studioRenderTelemetry.ts @@ -74,6 +74,10 @@ function extractPayload( extractPhase3Ms: extract.extractMs, extractCacheHits: extract.cacheHits, extractCacheMisses: extract.cacheMisses, + extractCachePublishFailures: extract.cachePublishFailures, + extractCacheGcEvictions: extract.cacheGcEvictions, + extractCacheGcBytesFreed: extract.cacheGcBytesFreed, + extractCacheAgedPartialsCleared: extract.cacheAgedPartialsCleared, }; } diff --git a/packages/cli/src/telemetry/events.ts b/packages/cli/src/telemetry/events.ts index 02b01701f7..198de52f6d 100644 --- a/packages/cli/src/telemetry/events.ts +++ b/packages/cli/src/telemetry/events.ts @@ -275,6 +275,17 @@ export function trackRenderComplete( extractPhase3Ms?: number; extractCacheHits?: number; extractCacheMisses?: number; + /** + * Frame-cache health. `cachePublishFailures` is the one to alert on: the + * render still succeeded from the partial dir, so nothing surfaces, but + * every later render re-extracts — warm renders going cold with no signal. + * The GC counters give it a denominator (was the entry evicted, or did the + * publish fail?). + */ + extractCachePublishFailures?: number; + extractCacheGcEvictions?: number; + extractCacheGcBytesFreed?: number; + extractCacheAgedPartialsCleared?: number; // Attribute this event to a specific user (e.g. the browser user who // triggered a studio render); defaults to the install anonymousId. distinctId?: string; @@ -368,6 +379,10 @@ export function trackRenderComplete( extract_phase3_ms: props.extractPhase3Ms, extract_cache_hits: props.extractCacheHits, extract_cache_misses: props.extractCacheMisses, + extract_cache_publish_failures: props.extractCachePublishFailures, + extract_cache_gc_evictions: props.extractCacheGcEvictions, + extract_cache_gc_bytes_freed: props.extractCacheGcBytesFreed, + extract_cache_aged_partials_cleared: props.extractCacheAgedPartialsCleared, }, props.distinctId, );