Files
2026-07-13 13:08:41 +08:00

170 lines
4.3 KiB
TypeScript

import { app } from "electron";
import * as Sentry from "@sentry/electron/main";
let isSentryInitialized = false;
type MainSentryRuntimeContext = {
profileHash?: string;
cacheRecoveryStatus?: string;
cacheRecoveryMode?: string;
};
function parseBoolean(value: string | undefined, defaultValue: boolean): boolean {
if (value === undefined) {
return defaultValue;
}
return !["0", "false", "no", "off"].includes(value.trim().toLowerCase());
}
function parseSampleRate(value: string | undefined, defaultValue: number): number {
if (!value) {
return defaultValue;
}
const parsed = Number.parseFloat(value);
if (Number.isNaN(parsed)) {
return defaultValue;
}
return Math.max(0, Math.min(1, parsed));
}
function getEnvironment(): string {
if (process.env.SENTRY_ENVIRONMENT) {
return process.env.SENTRY_ENVIRONMENT;
}
if (process.env.NODE_ENV) {
return process.env.NODE_ENV;
}
return app.isPackaged ? "production" : "development";
}
function getRelease(): string {
if (process.env.SENTRY_RELEASE) {
return process.env.SENTRY_RELEASE;
}
return `presenton-electron@${app.getVersion()}`;
}
export function initMainSentry(): void {
if (isSentryInitialized) {
return;
}
const dsn = "https://48b091ed88ae147c0957a46a823c1449@o4509882707410944.ingest.us.sentry.io/4511171070394368";
const isEnabled = parseBoolean(process.env.SENTRY_ENABLED, true);
if (!isEnabled) {
return;
}
const tracesSampleRate = parseSampleRate(
process.env.SENTRY_TRACES_SAMPLE_RATE,
app.isPackaged ? 0.2 : 1.0,
);
try {
Sentry.init({
dsn,
enabled: true,
release: getRelease(),
environment: getEnvironment(),
debug: parseBoolean(process.env.SENTRY_DEBUG, false),
sendDefaultPii: parseBoolean(process.env.SENTRY_SEND_DEFAULT_PII, false),
enableLogs: parseBoolean(process.env.SENTRY_ENABLE_LOGS, true),
tracesSampleRate,
integrations: [Sentry.startupTracingIntegration()],
});
isSentryInitialized = true;
Sentry.setTag("process.type", "main");
Sentry.setTag("electron.version", process.versions.electron ?? "unknown");
Sentry.setTag("chromium.version", process.versions.chrome ?? "unknown");
Sentry.setTag("node.version", process.versions.node ?? "unknown");
Sentry.setTag("os.platform", process.platform);
Sentry.setTag("os.arch", process.arch);
Sentry.setContext("runtime", {
appVersion: app.getVersion(),
electronVersion: process.versions.electron ?? "unknown",
chromiumVersion: process.versions.chrome ?? "unknown",
nodeVersion: process.versions.node ?? "unknown",
platform: process.platform,
arch: process.arch,
packaged: app.isPackaged,
});
console.log("[Sentry] Initialized in Electron main process.");
} catch (error) {
console.error("[Sentry] Failed to initialize in Electron main process:", error);
}
}
export function setMainSentryRuntimeContext(context: MainSentryRuntimeContext): void {
if (!isSentryInitialized) {
return;
}
try {
if (context.profileHash) {
Sentry.setTag("profile.hash", context.profileHash);
}
if (context.cacheRecoveryStatus) {
Sentry.setTag("cache_recovery.status", context.cacheRecoveryStatus);
}
if (context.cacheRecoveryMode) {
Sentry.setTag("cache_recovery.mode", context.cacheRecoveryMode);
}
Sentry.setContext("presenton", {
profileHash: context.profileHash,
cacheRecoveryStatus: context.cacheRecoveryStatus,
cacheRecoveryMode: context.cacheRecoveryMode,
});
} catch {
/* ignore context failures */
}
}
export function captureMainException(
error: unknown,
context?: Record<string, unknown>,
): void {
if (!isSentryInitialized) {
return;
}
try {
Sentry.withScope((scope) => {
if (context) {
scope.setContext("presenton", context);
}
Sentry.captureException(error);
});
} catch {
/* ignore capture failures */
}
}
export function addMainBreadcrumb(
category: string,
message: string,
data?: Record<string, unknown>,
): void {
if (!isSentryInitialized) {
return;
}
try {
Sentry.addBreadcrumb({
category,
message,
level: "info",
data,
});
} catch {
/* ignore breadcrumb failures */
}
}