Skip to content

Commit 8599411

Browse files
feat: implement Sentry error tracking with privacy-first anonymization (#6881)
* feat: add sentry to core * feat: implement comprehensive Sentry error tracking with privacy-first anonymization - Add Sentry ErrorBoundary components following React best practices - Implement shared anonymization logic between core and GUI environments - Create organized sentry directory structure with clean exports - Add Continue team member access control (@continue.dev email check) - Preserve node_modules package names for debugging while anonymizing user paths - Include comprehensive test coverage for all anonymization scenarios - Set up source maps for readable production error stack traces - Add browser-compatible hashing without crypto module dependency 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * feat: complete Sentry integration with GUI components and tests - Add GUI TelemetryProviders with Sentry ErrorBoundary - Create shared isContinueTeamMember utilities for both core and GUI - Update all imports and dependencies for new sentry structure - Add comprehensive test coverage and fix all TypeScript issues 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * prettier * fix: resolve GUI build errors by removing sentry index.ts and using specific imports - Remove problematic index.ts that was pulling Node.js-specific Sentry code into browser bundle - Update GUI to import specifically from anonymization.ts and constants.ts files - Update core imports to use specific SentryLogger.ts import path - GUI build now succeeds with proper source map upload to Sentry 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * fix: move TelemetryProviders inside AuthProvider to fix test failures - Move TelemetryProviders from main.tsx to Layout.tsx inside AuthProvider - Fixes "useAuth must be used within an AuthProvider" error in tests - TelemetryProviders now has access to auth context for Continue team member check - GUI build and functionality remain working correctly 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * prettier * merge main * Update package.json * fix tests * fix errors * Update extension.ts * disable sentry in tests/local dev * add additional error handling * Update SentryLogger.ts * remove global try/catch * remove test code * linting * Update SentryLogger.ts * more logs * Update core.ts * lower sampling rate * fix tests * feat: use `Logger` * Update logger.ts * Update logger.ts Co-Authored-By: Claude <[email protected]> * lint fixes Co-Authored-By: Claude <[email protected]> * fix: rename logger.ts to Logger.ts for case sensitivity This fixes TypeScript compilation errors in CI where the file was tracked as lowercase logger.ts but referenced as Logger.ts in imports. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * address ting-wai's feedback * Update core.ts --------- Co-authored-by: Claude <[email protected]>
1 parent 6f9e167 commit 8599411

34 files changed

+4325
-521
lines changed

core/.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@ target
44
npm-debug.log*
55
.env
66
test/.continue-test
7-
coverage
7+
coverage
8+
# Sentry Config File
9+
.sentryclirc

core/config/ConfigHandler.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
} from "../control-plane/AuthTypes.js";
1919
import { getControlPlaneEnv } from "../control-plane/env.js";
2020
import { PolicySingleton } from "../control-plane/PolicySingleton.js";
21-
import { logger } from "../util/logger.js";
21+
import { Logger } from "../util/Logger.js";
2222
import { Telemetry } from "../util/posthog.js";
2323
import {
2424
ASSISTANTS,
@@ -596,7 +596,7 @@ export class ConfigHandler {
596596
);
597597

598598
if (config.errors?.length) {
599-
logger.warn("Errors loading config: ", config.errors);
599+
Logger.error("Errors loading config: ", config.errors);
600600
}
601601
return config;
602602
}

core/config/ProfileLifecycleManager.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
IDE,
1313
} from "../index.js";
1414

15+
import { Logger } from "../util/Logger.js";
1516
import { finalToBrowserConfig } from "./load.js";
1617
import { IProfileLoader } from "./profile/IProfileLoader.js";
1718

@@ -98,6 +99,11 @@ export class ProfileLifecycleManager {
9899
try {
99100
result = await this.profileLoader.doLoadConfig();
100101
} catch (e) {
102+
// Capture config loading system failures to Sentry
103+
Logger.error(e, {
104+
context: "profile_config_loading",
105+
});
106+
101107
const message =
102108
e instanceof Error
103109
? `${e.message}\n${e.stack ? e.stack : ""}`

core/config/profile/doLoadConfig.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import { GlobalContext } from "../../util/GlobalContext";
3636
import { getConfigJsonPath, getConfigYamlPath } from "../../util/paths";
3737
import { localPathOrUriToPath } from "../../util/pathToUri";
3838
import { Telemetry } from "../../util/posthog";
39+
import { SentryLogger } from "../../util/sentry/SentryLogger";
3940
import { TTS } from "../../util/tts";
4041
import { getWorkspaceContinueRuleDotFiles } from "../getWorkspaceContinueRuleDotFiles";
4142
import { loadContinueConfigFromJson } from "../load";
@@ -346,6 +347,24 @@ export default async function doLoadConfig(options: {
346347
ideInfo,
347348
);
348349

350+
// Setup Sentry logger with same telemetry settings
351+
// TODO: Remove Continue team member check once Sentry is ready for all users
352+
let userEmail: string | undefined;
353+
try {
354+
// Access the session info to get user email for Continue team member check
355+
const sessionInfo = await (controlPlaneClient as any).sessionInfoPromise;
356+
userEmail = sessionInfo?.account?.id;
357+
} catch (error) {
358+
// Ignore errors getting session info, will default to no Sentry
359+
}
360+
361+
await SentryLogger.setup(
362+
newConfig.allowAnonymousTelemetry ?? false,
363+
await ide.getUniqueId(),
364+
ideInfo,
365+
userEmail,
366+
);
367+
349368
// TODO: pass config to pre-load non-system TTS models
350369
await TTS.setup();
351370

core/control-plane/client.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import fetch, { RequestInit, Response } from "node-fetch";
1212

1313
import { OrganizationDescription } from "../config/ProfileLifecycleManager.js";
1414
import { IdeInfo, IdeSettings, ModelDescription } from "../index.js";
15+
import { Logger } from "../util/Logger.js";
1516

1617
import { ControlPlaneSessionInfo, isOnPremSession } from "./AuthTypes.js";
1718
import { getControlPlaneEnv } from "./env.js";
@@ -146,6 +147,11 @@ export class ControlPlaneClient {
146147
});
147148
return (await resp.json()) as any;
148149
} catch (e) {
150+
// Capture control plane API failures to Sentry
151+
Logger.error(e, {
152+
context: "control_plane_list_assistants",
153+
organizationId,
154+
});
149155
return [];
150156
}
151157
}
@@ -217,6 +223,11 @@ export class ControlPlaneClient {
217223
const { fullSlugs } = (await resp.json()) as any;
218224
return fullSlugs;
219225
} catch (e) {
226+
// Capture control plane API failures to Sentry
227+
Logger.error(e, {
228+
context: "control_plane_list_assistant_slugs",
229+
organizationId,
230+
});
220231
return null;
221232
}
222233
}
@@ -247,6 +258,10 @@ export class ControlPlaneClient {
247258
});
248259
return (await resp.json()) as FreeTrialStatus;
249260
} catch (e) {
261+
// Capture control plane API failures to Sentry
262+
Logger.error(e, {
263+
context: "control_plane_free_trial_status",
264+
});
250265
return null;
251266
}
252267
}
@@ -281,6 +296,11 @@ export class ControlPlaneClient {
281296
);
282297
return (await resp.json()) as { url: string };
283298
} catch (e) {
299+
// Capture control plane API failures to Sentry
300+
Logger.error(e, {
301+
context: "control_plane_models_checkout_url",
302+
vsCodeUriScheme,
303+
});
284304
return null;
285305
}
286306
}

0 commit comments

Comments
 (0)