diff --git a/dev-packages/browser-integration-tests/suites/sessions/update-session/test.ts b/dev-packages/browser-integration-tests/suites/sessions/update-session/test.ts index 816cdf1dc056..863933086e65 100644 --- a/dev-packages/browser-integration-tests/suites/sessions/update-session/test.ts +++ b/dev-packages/browser-integration-tests/suites/sessions/update-session/test.ts @@ -18,7 +18,7 @@ sentryTest('should update session when an error is thrown.', async ({ getLocalTe expect(updatedSession).toBeDefined(); expect(updatedSession.init).toBe(false); expect(updatedSession.errors).toBe(1); - expect(updatedSession.status).toBe('crashed'); + expect(updatedSession.status).toBe('unhandled'); expect(pageloadSession.sid).toBe(updatedSession.sid); }); diff --git a/packages/core/src/client.ts b/packages/core/src/client.ts index 365b4f42d078..be5805211d6f 100644 --- a/packages/core/src/client.ts +++ b/packages/core/src/client.ts @@ -963,7 +963,7 @@ export abstract class Client { if (shouldUpdateAndSend) { updateSession(session, { - ...(crashed && { status: 'crashed' }), + ...(crashed && { status: 'unhandled' }), errors: session.errors || Number(errored || crashed), }); this.captureSession(session); diff --git a/packages/core/src/scope.ts b/packages/core/src/scope.ts index 8b1e21acfb4a..d2330ca5faf2 100644 --- a/packages/core/src/scope.ts +++ b/packages/core/src/scope.ts @@ -53,7 +53,7 @@ export interface ScopeContext { export interface SdkProcessingMetadata { [key: string]: unknown; requestSession?: { - status: 'ok' | 'errored' | 'crashed'; + status: 'ok' | 'errored' | 'crashed' | 'unhandled'; }; normalizedRequest?: RequestEventData; dynamicSamplingContext?: Partial; diff --git a/packages/core/src/server-runtime-client.ts b/packages/core/src/server-runtime-client.ts index 44e608925535..ad71272fc4c3 100644 --- a/packages/core/src/server-runtime-client.ts +++ b/packages/core/src/server-runtime-client.ts @@ -225,10 +225,16 @@ function setCurrentRequestSessionErroredOrCrashed(eventHint?: EventHint): void { const isHandledException = eventHint?.mechanism?.handled ?? true; // A request session can go from "errored" -> "crashed" but not "crashed" -> "errored". // Crashed (unhandled exception) is worse than errored (handled exception). - if (isHandledException && requestSession.status !== 'crashed') { - requestSession.status = 'errored'; - } else if (!isHandledException) { - requestSession.status = 'crashed'; + if (isHandledException) { + // If it's a handled exception, we can only downgrade from 'ok' to 'errored'. + // We should not downgrade from 'unhandled' or 'crashed'. + if (requestSession.status === 'ok') { + requestSession.status = 'errored'; + } + } else { + // If it's an unhandled exception, we always set the status to 'unhandled'. + // 'unhandled' is the most severe status. + requestSession.status = 'unhandled'; } } } diff --git a/packages/core/src/types-hoist/session.ts b/packages/core/src/types-hoist/session.ts index 1cdfef158af8..e5e1753dd8ef 100644 --- a/packages/core/src/types-hoist/session.ts +++ b/packages/core/src/types-hoist/session.ts @@ -30,7 +30,7 @@ export interface Session { export type SessionContext = Partial; -export type SessionStatus = 'ok' | 'exited' | 'crashed' | 'abnormal'; +export type SessionStatus = 'ok' | 'exited' | 'crashed' | 'abnormal' | 'unhandled'; /** JSDoc */ export interface SessionAggregates { diff --git a/packages/node-core/src/integrations/http/httpServerIntegration.ts b/packages/node-core/src/integrations/http/httpServerIntegration.ts index f37ddc07a125..b87dc8000bb6 100644 --- a/packages/node-core/src/integrations/http/httpServerIntegration.ts +++ b/packages/node-core/src/integrations/http/httpServerIntegration.ts @@ -37,7 +37,7 @@ const INTEGRATION_NAME = 'Http.Server'; const clientToRequestSessionAggregatesMap = new Map< Client, - { [timestampRoundedToSeconds: string]: { exited: number; crashed: number; errored: number } } + { [timestampRoundedToSeconds: string]: { exited: number; crashed: number; errored: number; unhandled: number } } >(); // We keep track of emit functions we wrapped, to avoid double wrapping @@ -277,8 +277,12 @@ export function recordRequestSession( const dateBucketKey = roundedDate.toISOString(); const existingClientAggregate = clientToRequestSessionAggregatesMap.get(client); - const bucket = existingClientAggregate?.[dateBucketKey] || { exited: 0, crashed: 0, errored: 0 }; - bucket[({ ok: 'exited', crashed: 'crashed', errored: 'errored' } as const)[requestSession.status]]++; + const bucket = existingClientAggregate?.[dateBucketKey] || { exited: 0, crashed: 0, errored: 0, unhandled: 0 }; + bucket[ + ({ ok: 'exited', crashed: 'crashed', errored: 'errored', unhandled: 'unhandled' } as const)[ + requestSession.status + ] + ]++; if (existingClientAggregate) { existingClientAggregate[dateBucketKey] = bucket; @@ -297,7 +301,7 @@ export function recordRequestSession( started: timestamp, exited: value.exited, errored: value.errored, - crashed: value.crashed, + crashed: (value.crashed || 0) + (value.unhandled || 0), }), ); client.sendSession({ aggregates: aggregatePayload });