feat(telemetry): collect PostHog $exception error reports in CLI and daemon (#262)

* feat(telemetry): add node exception reporter

* feat(telemetry): report node cli exceptions

* feat(telemetry): add daemon exception reporter

* feat(telemetry): report daemon exceptions

* docs(telemetry): document error reports

* fix(telemetry): pass redaction snapshots from node call sites

* test(telemetry): verify prepared node exception payload

* fix(telemetry): close daemon exception lifecycle gaps

* test(telemetry): verify prepared daemon exception payload

* test(telemetry): close error collection acceptance gaps

* test(telemetry): close posthog exception acceptance gaps
This commit is contained in:
Andrey Avtomonov 2026-06-05 19:36:21 +02:00 committed by GitHub
parent c3d8cedb0b
commit fb7b94b60e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
36 changed files with 2870 additions and 140 deletions

View file

@ -16,6 +16,16 @@ type PostHogClient = {
properties: Record<string, unknown>;
groups?: Record<string, string>;
}): void;
captureException(
error: unknown,
distinctId?: string,
additionalProperties?: Record<string, unknown>,
): void;
captureExceptionImmediate(
error: unknown,
distinctId?: string,
additionalProperties?: Record<string, unknown>,
): Promise<void>;
shutdown(): Promise<void> | void;
};
@ -105,6 +115,57 @@ export async function trackTelemetryEvent(input: {
}
}
function writeDebugExceptionPayload(input: {
error: Error;
distinctId: string;
properties: Record<string, unknown>;
stderr: TelemetrySink;
}): void {
input.stderr.write(
`[telemetry-exception] ${JSON.stringify({
distinctId: input.distinctId,
message: input.error.message,
name: input.error.name,
properties: input.properties,
})}\n`,
);
}
export async function trackTelemetryException(input: {
error: Error;
distinctId: string;
properties: Record<string, unknown>;
env?: TelemetryEmitterEnv;
stderr: TelemetrySink;
projectApiKey?: string;
host?: string;
immediate?: boolean;
}): Promise<void> {
const env = input.env ?? process.env;
if (debugEnabled(env)) {
writeDebugExceptionPayload(input);
return;
}
const projectApiKey = telemetryProjectApiKey(input.projectApiKey);
const host = telemetryHost(env, input.host);
const client = await getPostHogClient(projectApiKey, host);
if (!client) {
return;
}
try {
if (input.immediate) {
await client.captureExceptionImmediate(input.error, input.distinctId, input.properties);
return;
}
client.captureException(input.error, input.distinctId, input.properties);
} catch {
return;
}
}
export async function shutdownTelemetryEmitter(): Promise<void> {
const client = await clientPromise;
if (!client) {