Skip to content

Commit a178c92

Browse files
feat(Sky): Wire polyfill telemetry through PostHog bridge
Add a new Telemetry polyfill that loads before other polyfills and installs `globalThis.__LAND_POLYFILL_TELEMETRY__` as a no-op. PostHogBridge then swaps in a real handler that captures polyfill errors via PH.captureException with categorized properties: - polyfill_category: error category (e.g. 'ipc.fire-and-forget', 'polyfill.install') - polyfill_*: detail payload under non-reserved keys This enables monitoring polyfill failures in production to identify issues with Electron IPC, file system shims, and process polyfills that might otherwise fail silently.
1 parent 63951b3 commit a178c92

2 files changed

Lines changed: 53 additions & 6 deletions

File tree

Source/Workbench/Electron/Polyfills.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,16 @@
1414

1515
try {
1616
// Single source of truth for polyfills is now `Element/Output/
17-
// Source/Polyfill/*`. Wind's `Wind/Source/Polyfills/*` are thin re-
18-
// exports of the same modules kept around so Cocoon and any lingering
19-
// VS Code imports continue to resolve; importing through Output
20-
// directly here means a polyfill fix (e.g. the colon-prefix
21-
// `MountainIPCInvoke` routing) lands in one place and every tier
22-
// picks it up on rebuild.
17+
// Source/Polyfill/*`. Importing through Output directly here means a
18+
// polyfill fix (e.g. the colon-prefix `MountainIPCInvoke` routing)
19+
// lands in one place and every tier picks it up on rebuild.
20+
//
21+
// Telemetry MUST load first - it installs
22+
// `globalThis.__LAND_POLYFILL_TELEMETRY__` which the other polyfills
23+
// reference from their silent catches. Sky's `PostHogBridge.ts`
24+
// later wires a real handler via `Set(...)`; before that, calls are
25+
// no-op'd.
26+
await import("@codeeditorland/output/Configuration/Polyfill/Telemetry.js");
2327
await import("@codeeditorland/output/Configuration/Polyfill/ProcessPolyfill.js");
2428
await import("@codeeditorland/output/Configuration/Polyfill/FileProtocolShim.js");
2529
await import("@codeeditorland/output/Configuration/Polyfill/FileSystemPolyfill.js");

Source/Workbench/Electron/PostHogBridge.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,49 @@ const Initialize = async (): Promise<void> => {
332332
);
333333
(DrainTimer as unknown as { unref?: () => void }).unref?.();
334334

335+
// Wire up Output's polyfill telemetry hook. The polyfills load
336+
// long before this bridge runs, so they install
337+
// `globalThis.__LAND_POLYFILL_TELEMETRY__` early as a no-op and we
338+
// swap in a real handler here. Categories are kept low-cardinality
339+
// (e.g. `ipc.fire-and-forget`, `polyfill.install`) so the
340+
// `$exception` slot can be grouped sensibly in PostHog. The detail
341+
// payload is passed through under `polyfill_*` properties so it
342+
// doesn't collide with PH's reserved `$exception_*` keys.
343+
const PolyfillTelemetry = (
344+
globalThis as {
345+
__LAND_POLYFILL_TELEMETRY__?: {
346+
Set: (
347+
H: (
348+
Category: string,
349+
Error: unknown,
350+
Detail?: Record<string, unknown>,
351+
) => void,
352+
) => void;
353+
};
354+
}
355+
).__LAND_POLYFILL_TELEMETRY__;
356+
PolyfillTelemetry?.Set((Category, RawError, Detail) => {
357+
const ErrorObj =
358+
RawError instanceof Error
359+
? RawError
360+
: new Error(
361+
typeof RawError === "string"
362+
? RawError
363+
: `polyfill[${Category}] failure`,
364+
);
365+
const Properties: Record<string, unknown> = {
366+
polyfill_category: Category,
367+
$exception_type: `land:polyfill:${Category}`,
368+
$exception_origin: "polyfill",
369+
};
370+
if (Detail) {
371+
for (const [Key, Value] of Object.entries(Detail)) {
372+
Properties[`polyfill_${Key.toLowerCase()}`] = Value;
373+
}
374+
}
375+
PH.captureException(ErrorObj, Properties);
376+
});
377+
335378
// Per-component buffers - flushed independently
336379
const Buffers = new Map<string, BufferedMark[]>();
337380
const Timers = new Map<string, ReturnType<typeof setTimeout>>();

0 commit comments

Comments
 (0)