Skip to content

Commit

Permalink
feat: Update to v8.51.0 of the JavaScript SDKs (#1066)
Browse files Browse the repository at this point in the history
  • Loading branch information
timfish authored Jan 27, 2025
1 parent 3c8599b commit c187b53
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 173 deletions.
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,16 @@
"e2e": "xvfb-maybe vitest run --root=./test/e2e --silent=false --disable-console-intercept"
},
"dependencies": {
"@sentry/browser": "8.50.0",
"@sentry/core": "8.50.0",
"@sentry/node": "8.50.0",
"@sentry/browser": "8.51.0",
"@sentry/core": "8.51.0",
"@sentry/node": "8.51.0",
"deepmerge": "4.3.1"
},
"devDependencies": {
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-typescript": "^11.1.6",
"@sentry-internal/eslint-config-sdk": "8.50.0",
"@sentry-internal/typescript": "8.50.0",
"@sentry-internal/eslint-config-sdk": "8.51.0",
"@sentry-internal/typescript": "8.51.0",
"@types/busboy": "^1.5.4",
"@types/form-data": "^2.5.0",
"@types/koa": "^2.0.52",
Expand Down
95 changes: 44 additions & 51 deletions src/main/integrations/sentry-minidump/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
Scope,
ScopeData,
SentryError,
Session,
} from '@sentry/core';
import { NodeClient } from '@sentry/node';
import { app, crashReporter } from 'electron';
Expand All @@ -16,7 +17,7 @@ import { getEventDefaults } from '../../context';
import { EXIT_REASONS, getSentryCachePath, usesCrashpad } from '../../electron-normalize';
import { getRendererProperties, trackRendererProperties } from '../../renderers';
import { ElectronMainOptions } from '../../sdk';
import { checkPreviousSession, sessionCrashed } from '../../sessions';
import { previousSessionWasAbnormal, restorePreviousSession, setPreviousSessionAsCurrent } from '../../sessions';
import { BufferedWriteStore } from '../../store';
import { getMinidumpLoader, MinidumpLoader } from './minidump-loader';

Expand Down Expand Up @@ -82,7 +83,7 @@ export const sentryMinidumpIntegration = defineIntegration((options: Options = {

async function sendNativeCrashes(
client: NodeClient,
getEvent: (minidumpProcess: string | undefined) => Event,
getEvent: (minidumpProcess: string | undefined) => Event | Promise<Event>,
): Promise<boolean> {
// Whenever we are called, assume that the crashes we are going to load down
// below have occurred recently. This means, we can use the same event data
Expand All @@ -108,29 +109,11 @@ export const sentryMinidumpIntegration = defineIntegration((options: Options = {
await minidumpLoader?.(deleteAll, async (minidumpProcess, attachment) => {
minidumpFound = true;

const event = getEvent(minidumpProcess);

// If this is a native main process crash, we need to apply the scope and context from the previous run
if (event.tags?.['event.process'] === 'browser') {
const previousRun = await scopeLastRun;
if (previousRun) {
if (previousRun.scope) {
applyScopeDataToEvent(event, previousRun.scope);
}

event.release = previousRun.event?.release || event.release;
event.environment = previousRun.event?.environment || event.environment;
event.contexts = previousRun.event?.contexts || event.contexts;
}
}

if (!event) {
return;
}
const event = await getEvent(minidumpProcess);

if (minidumpsRemaining > 0) {
minidumpsRemaining -= 1;
captureEvent(event as Event, { attachments: [attachment] });
captureEvent(event, { attachments: [attachment] });
}
});

Expand All @@ -145,7 +128,7 @@ export const sentryMinidumpIntegration = defineIntegration((options: Options = {
): Promise<void> {
const { getRendererName } = options;

const found = await sendNativeCrashes(client, (minidumpProcess) => {
await sendNativeCrashes(client, (minidumpProcess) => {
// We only call 'getRendererName' if this was in fact a renderer crash
const crashedProcess =
(minidumpProcess === 'renderer' && getRendererName ? getRendererName(contents) : minidumpProcess) ||
Expand All @@ -170,20 +153,12 @@ export const sentryMinidumpIntegration = defineIntegration((options: Options = {
},
};
});

if (found) {
sessionCrashed();
}
}

async function sendChildProcessCrash(
client: NodeClient,
options: ElectronMainOptions,
details: Omit<Electron.Details, 'exitCode'>,
): Promise<void> {
async function sendChildProcessCrash(client: NodeClient, details: Omit<Electron.Details, 'exitCode'>): Promise<void> {
logger.log(`${details.type} process has ${details.reason}`);

const found = await sendNativeCrashes(client, (minidumpProcess) => ({
await sendNativeCrashes(client, (minidumpProcess) => ({
contexts: {
electron: { details },
},
Expand All @@ -197,10 +172,6 @@ export const sentryMinidumpIntegration = defineIntegration((options: Options = {
event_type: 'native',
},
}));

if (found) {
sessionCrashed();
}
}

return {
Expand Down Expand Up @@ -238,25 +209,47 @@ export const sentryMinidumpIntegration = defineIntegration((options: Options = {
});
app.on('child-process-gone', async (_, details) => {
if (EXIT_REASONS.includes(details.reason)) {
await sendChildProcessCrash(client, options, details);
await sendChildProcessCrash(client, details);
}
});

let sessionToRestore: Session | undefined;

// Start to submit recent minidump crashes. This will load breadcrumbs and
// context information that was cached on disk in the previous app run, prior to the crash.
sendNativeCrashes(client, (minidumpProcess) => ({
level: 'fatal',
platform: 'native',
tags: {
'event.environment': 'native',
'event.process': minidumpProcess || (usesCrashpad() ? 'unknown' : 'browser'),
},
}))
.then((minidumpsFound) =>
// Check for previous uncompleted session. If a previous session exists
// and no minidumps were found, its likely an abnormal exit
checkPreviousSession(minidumpsFound),
)
sendNativeCrashes(client, async (minidumpProcess) => {
const event: Event = {
level: 'fatal',
platform: 'native',
tags: {
'event.environment': 'native',
'event.process': minidumpProcess || (usesCrashpad() ? 'unknown' : 'browser'),
},
};

// This crash was found at startup, we need to apply the scope and context from the previous run
const previousRun = await scopeLastRun;
if (previousRun) {
if (previousRun.scope) {
applyScopeDataToEvent(event, previousRun.scope);
}

event.release = previousRun.event?.release;
event.environment = previousRun.event?.environment;
event.contexts = previousRun.event?.contexts;
}

sessionToRestore = await setPreviousSessionAsCurrent();

return event;
})
.then(async (minidumpsFound) => {
if (!minidumpsFound) {
await previousSessionWasAbnormal();
} else if (sessionToRestore) {
restorePreviousSession(sessionToRestore);
}
})
.catch((error) => logger.error(error));
},
};
Expand Down
67 changes: 64 additions & 3 deletions src/main/sessions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,20 @@ let previousSession: Promise<Partial<Session> | undefined> | undefined;
function getSessionStore(): Store<SessionContext | undefined> {
if (!sessionStore) {
sessionStore = new Store<SessionContext | undefined>(getSentryCachePath(), 'session', undefined);
previousSession = sessionStore.get();
previousSession = sessionStore.get().then((sesh) => (sesh ? makeSession(sesh) : sesh));
}

return sessionStore;
}

/** Copies a session and removes the toJSON function so it can be serialised without conversion */
function makeSessionSafeToSerialize(session: Session): Session {
const copy = { ...session };
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
delete (copy as any).toJSON;
return copy;
}

let persistTimer: ReturnType<typeof setInterval> | undefined;

/** Starts a session */
Expand All @@ -45,7 +53,7 @@ export function startSession(sendOnCreate: boolean): void {
}

getSessionStore()
.set(session)
.set(makeSessionSafeToSerialize(session))
.catch(() => {
// Does not throw
});
Expand All @@ -55,7 +63,7 @@ export function startSession(sendOnCreate: boolean): void {
const currentSession = getCurrentScope().getSession();
// Only bother saving if it hasn't already ended
if (currentSession && currentSession.status === 'ok') {
await getSessionStore().set(currentSession);
await getSessionStore().set(makeSessionSafeToSerialize(currentSession));
}
}, PERSIST_INTERVAL_MS);
}
Expand Down Expand Up @@ -110,6 +118,59 @@ export async function unreportedDuringLastSession(crashDate: Date | undefined):
return crashTime > lastPersist && crashTime < prevSessionEnd;
}

/** Sets the previous session as the current session and returns any existing session */
export async function setPreviousSessionAsCurrent(): Promise<Session | undefined> {
const previous = await previousSession;

const scope = getCurrentScope();
const currentSession = scope.getSession();

if (previous) {
previousSession = undefined;

if (previous.status === 'ok') {
scope.setSession(makeSession(previous));
}
}

return currentSession;
}

/** Restores a session */
export function restorePreviousSession(session: Session): void {
getCurrentScope().setSession(session);
}

/** Report the previous session as abnormal */
export async function previousSessionWasAbnormal(): Promise<void> {
const client = getClient<NodeClient>();

const previous = await previousSession;

if (previous && client) {
// Ignore if the previous session is already ended
if (previous.status !== 'ok') {
previousSession = undefined;
return;
}

logger.log(`Found previous abnormal session`);

const sesh = makeSession(previous);

updateSession(sesh, {
status: 'abnormal',
errors: (sesh.errors || 0) + 1,
release: (previous as unknown as SerializedSession).attrs?.release,
environment: (previous as unknown as SerializedSession).attrs?.environment,
});

await client.sendSession(sesh);

previousSession = undefined;
}
}

/** Checks if the previous session needs sending as crashed or abnormal */
export async function checkPreviousSession(crashed: boolean): Promise<void> {
const client = getClient<NodeClient>();
Expand Down
1 change: 1 addition & 0 deletions src/renderer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ export {
featureFlagsIntegration,
launchDarklyIntegration,
openFeatureIntegration,
unleashIntegration,
} from '@sentry/browser';

export type { BrowserOptions, ReportDialogOptions } from '@sentry/browser';
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ interface ElectronRendererOptions extends Omit<BrowserOptions, 'dsn' | 'environm
export function init<O extends ElectronRendererOptions>(
options: ElectronRendererOptions & O = {} as ElectronRendererOptions & O,
// This parameter name ensures that TypeScript error messages contain a hint for fixing SDK version mismatches
originalInit: (if_you_get_a_typescript_error_ensure_sdks_use_version_v8_50_0: O) => void = browserInit,
originalInit: (if_you_get_a_typescript_error_ensure_sdks_use_version_v8_51_0: O) => void = browserInit,
): void {
// Ensure the browser SDK is only init'ed once.
if (window?.__SENTRY__RENDERER_INIT__) {
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/test-apps/native-sentry/unknown/event.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
"event.environment": "native",
"event.origin": "electron",
"event.process": "unknown",
"app-run": "second"
"app-run": "first"
}
},
"attachments": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"init": false,
"started": 0,
"timestamp": 0,
"status": "ok",
"status": "exited",
"errors": 0,
"duration": 0,
"attrs": {
Expand Down
17 changes: 0 additions & 17 deletions test/e2e/test-apps/sessions/native-crash-main/session-4.json

This file was deleted.

This file was deleted.

This file was deleted.

Loading

0 comments on commit c187b53

Please sign in to comment.