diff --git a/packages/nextjs/src/common/_error.ts b/packages/nextjs/src/common/_error.ts index 385df8244a17..a1585d3c6d4c 100644 --- a/packages/nextjs/src/common/_error.ts +++ b/packages/nextjs/src/common/_error.ts @@ -1,7 +1,6 @@ import { captureException, withScope } from '@sentry/core'; -import { vercelWaitUntil } from '@sentry/utils'; +import { flushSafelyWithTimeout, vercelWaitUntil } from '@sentry/utils'; import type { NextPageContext } from 'next'; -import { flushSafelyWithTimeout } from './utils/responseEnd'; type ContextOrProps = { req?: NextPageContext['req']; diff --git a/packages/nextjs/src/common/utils/edgeWrapperUtils.ts b/packages/nextjs/src/common/utils/edgeWrapperUtils.ts index 5eed59aca0a3..322996c6ad76 100644 --- a/packages/nextjs/src/common/utils/edgeWrapperUtils.ts +++ b/packages/nextjs/src/common/utils/edgeWrapperUtils.ts @@ -9,10 +9,9 @@ import { startSpan, withIsolationScope, } from '@sentry/core'; -import { vercelWaitUntil, winterCGRequestToRequestData } from '@sentry/utils'; +import { flushSafelyWithTimeout, vercelWaitUntil, winterCGRequestToRequestData } from '@sentry/utils'; import type { EdgeRouteHandler } from '../../edge/types'; -import { flushSafelyWithTimeout } from './responseEnd'; import { commonObjectToIsolationScope, escapeNextjsTracing } from './tracingUtils'; /** diff --git a/packages/nextjs/src/common/utils/responseEnd.ts b/packages/nextjs/src/common/utils/responseEnd.ts index b59dbf0ce170..5b1e7a1807ef 100644 --- a/packages/nextjs/src/common/utils/responseEnd.ts +++ b/packages/nextjs/src/common/utils/responseEnd.ts @@ -1,9 +1,7 @@ import type { ServerResponse } from 'http'; -import { flush, setHttpStatus } from '@sentry/core'; +import { setHttpStatus } from '@sentry/core'; import type { Span } from '@sentry/types'; -import { fill, logger } from '@sentry/utils'; - -import { DEBUG_BUILD } from '../debug-build'; +import { fill } from '@sentry/utils'; import type { ResponseEndMethod, WrappedResponseEndMethod } from '../types'; /** @@ -43,16 +41,3 @@ export function finishSpan(span: Span, res: ServerResponse): void { setHttpStatus(span, res.statusCode); span.end(); } - -/** - * Flushes pending Sentry events with a 2 second timeout and in a way that cannot create unhandled promise rejections. - */ -export async function flushSafelyWithTimeout(): Promise { - try { - DEBUG_BUILD && logger.log('Flushing events...'); - await flush(2000); - DEBUG_BUILD && logger.log('Done flushing events'); - } catch (e) { - DEBUG_BUILD && logger.log('Error while flushing events:\n', e); - } -} diff --git a/packages/nextjs/src/common/utils/wrapperUtils.ts b/packages/nextjs/src/common/utils/wrapperUtils.ts index ff04aebbd3ed..55798a46fddb 100644 --- a/packages/nextjs/src/common/utils/wrapperUtils.ts +++ b/packages/nextjs/src/common/utils/wrapperUtils.ts @@ -14,9 +14,9 @@ import { withIsolationScope, } from '@sentry/core'; import type { Span } from '@sentry/types'; -import { isString, vercelWaitUntil } from '@sentry/utils'; +import { flushSafelyWithTimeout, isString, vercelWaitUntil } from '@sentry/utils'; -import { autoEndSpanOnResponseEnd, flushSafelyWithTimeout } from './responseEnd'; +import { autoEndSpanOnResponseEnd } from './responseEnd'; import { commonObjectToIsolationScope, escapeNextjsTracing } from './tracingUtils'; declare module 'http' { diff --git a/packages/nextjs/src/common/withServerActionInstrumentation.ts b/packages/nextjs/src/common/withServerActionInstrumentation.ts index 0b8d3b6d7c60..de7519765fe8 100644 --- a/packages/nextjs/src/common/withServerActionInstrumentation.ts +++ b/packages/nextjs/src/common/withServerActionInstrumentation.ts @@ -5,11 +5,11 @@ import { withIsolationScope, } from '@sentry/core'; import { captureException, continueTrace, getClient, handleCallbackErrors, startSpan } from '@sentry/core'; -import { logger, vercelWaitUntil } from '@sentry/utils'; +import { flushSafelyWithTimeout, logger, vercelWaitUntil } from '@sentry/utils'; import { DEBUG_BUILD } from './debug-build'; import { isNotFoundNavigationError, isRedirectNavigationError } from './nextNavigationErrorUtils'; -import { flushSafelyWithTimeout } from './utils/responseEnd'; + import { escapeNextjsTracing } from './utils/tracingUtils'; interface Options { diff --git a/packages/nextjs/src/common/wrapApiHandlerWithSentry.ts b/packages/nextjs/src/common/wrapApiHandlerWithSentry.ts index a6463b0a7791..15e4a9ac99ea 100644 --- a/packages/nextjs/src/common/wrapApiHandlerWithSentry.ts +++ b/packages/nextjs/src/common/wrapApiHandlerWithSentry.ts @@ -7,10 +7,9 @@ import { withIsolationScope, } from '@sentry/core'; import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core'; -import { isString, logger, objectify, vercelWaitUntil } from '@sentry/utils'; +import { flushSafelyWithTimeout, isString, logger, objectify, vercelWaitUntil } from '@sentry/utils'; import type { NextApiRequest } from 'next'; import type { AugmentedNextApiResponse, NextApiHandler } from './types'; -import { flushSafelyWithTimeout } from './utils/responseEnd'; import { escapeNextjsTracing } from './utils/tracingUtils'; export type AugmentedNextApiRequest = NextApiRequest & { diff --git a/packages/nextjs/src/common/wrapRouteHandlerWithSentry.ts b/packages/nextjs/src/common/wrapRouteHandlerWithSentry.ts index 71061e913dac..d238d731c9fd 100644 --- a/packages/nextjs/src/common/wrapRouteHandlerWithSentry.ts +++ b/packages/nextjs/src/common/wrapRouteHandlerWithSentry.ts @@ -10,10 +10,14 @@ import { withIsolationScope, withScope, } from '@sentry/core'; -import { propagationContextFromHeaders, vercelWaitUntil, winterCGHeadersToDict } from '@sentry/utils'; +import { + flushSafelyWithTimeout, + propagationContextFromHeaders, + vercelWaitUntil, + winterCGHeadersToDict, +} from '@sentry/utils'; import { isNotFoundNavigationError, isRedirectNavigationError } from './nextNavigationErrorUtils'; import type { RouteHandlerContext } from './types'; -import { flushSafelyWithTimeout } from './utils/responseEnd'; import { commonObjectToIsolationScope, commonObjectToPropagationContext, diff --git a/packages/nextjs/src/common/wrapServerComponentWithSentry.ts b/packages/nextjs/src/common/wrapServerComponentWithSentry.ts index 079722dad76d..4d6ce22cbecd 100644 --- a/packages/nextjs/src/common/wrapServerComponentWithSentry.ts +++ b/packages/nextjs/src/common/wrapServerComponentWithSentry.ts @@ -13,12 +13,17 @@ import { withIsolationScope, withScope, } from '@sentry/core'; -import { propagationContextFromHeaders, uuid4, vercelWaitUntil, winterCGHeadersToDict } from '@sentry/utils'; +import { + flushSafelyWithTimeout, + propagationContextFromHeaders, + uuid4, + vercelWaitUntil, + winterCGHeadersToDict, +} from '@sentry/utils'; import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core'; import { isNotFoundNavigationError, isRedirectNavigationError } from '../common/nextNavigationErrorUtils'; import type { ServerComponentContext } from '../common/types'; -import { flushSafelyWithTimeout } from './utils/responseEnd'; import { commonObjectToIsolationScope, commonObjectToPropagationContext } from './utils/tracingUtils'; /** diff --git a/packages/nuxt/src/server/sdk.ts b/packages/nuxt/src/server/sdk.ts index 59832bbb2a39..89f24b091c62 100644 --- a/packages/nuxt/src/server/sdk.ts +++ b/packages/nuxt/src/server/sdk.ts @@ -1,4 +1,4 @@ -import { applySdkMetadata, flush, getGlobalScope } from '@sentry/core'; +import { applySdkMetadata, getGlobalScope } from '@sentry/core'; import { type NodeOptions, getDefaultIntegrations as getDefaultNodeIntegrations, @@ -6,7 +6,7 @@ import { init as initNode, } from '@sentry/node'; import type { Client, EventProcessor, Integration } from '@sentry/types'; -import { logger, vercelWaitUntil } from '@sentry/utils'; +import { flushSafelyWithTimeout, logger, vercelWaitUntil } from '@sentry/utils'; import { DEBUG_BUILD } from '../common/debug-build'; import type { SentryNuxtServerOptions } from '../common/types'; @@ -85,16 +85,3 @@ export function mergeRegisterEsmLoaderHooks( } return options.registerEsmLoaderHooks ?? { exclude: [/vue/] }; } - -/** - * Flushes pending Sentry events with a 2-second timeout and in a way that cannot create unhandled promise rejections. - */ -export async function flushSafelyWithTimeout(): Promise { - try { - DEBUG_BUILD && logger.log('Flushing events...'); - await flush(2000); - DEBUG_BUILD && logger.log('Done flushing events'); - } catch (e) { - DEBUG_BUILD && logger.log('Error while flushing events:\n', e); - } -} diff --git a/packages/solidstart/src/server/utils.ts b/packages/solidstart/src/server/utils.ts index f570ae355424..4931f8a5d70b 100644 --- a/packages/solidstart/src/server/utils.ts +++ b/packages/solidstart/src/server/utils.ts @@ -1,20 +1,13 @@ -import { flush, getGlobalScope } from '@sentry/node'; +import { getGlobalScope } from '@sentry/node'; import type { EventProcessor, Options } from '@sentry/types'; -import { logger } from '@sentry/utils'; -import { DEBUG_BUILD } from '../common/debug-build'; +import { flushSafelyWithTimeout, logger } from '@sentry/utils'; /** Flush the event queue to ensure that events get sent to Sentry before the response is finished and the lambda ends */ export async function flushIfServerless(): Promise { const isServerless = !!process.env.LAMBDA_TASK_ROOT || !!process.env.VERCEL; if (isServerless) { - try { - DEBUG_BUILD && logger.log('Flushing events...'); - await flush(2000); - DEBUG_BUILD && logger.log('Done flushing events'); - } catch (e) { - DEBUG_BUILD && logger.log('Error while flushing events:\n', e); - } + await flushSafelyWithTimeout(); } } diff --git a/packages/sveltekit/src/server/utils.ts b/packages/sveltekit/src/server/utils.ts index 8d7f2c649331..82dc4fc14933 100644 --- a/packages/sveltekit/src/server/utils.ts +++ b/packages/sveltekit/src/server/utils.ts @@ -1,8 +1,7 @@ -import { captureException, flush } from '@sentry/node'; -import { logger, objectify } from '@sentry/utils'; +import { captureException } from '@sentry/node'; +import { flushSafelyWithTimeout, objectify } from '@sentry/utils'; import type { RequestEvent } from '@sveltejs/kit'; -import { DEBUG_BUILD } from '../common/debug-build'; import { isHttpError, isRedirect } from '../common/utils'; /** @@ -23,13 +22,7 @@ export async function flushIfServerless(): Promise { const platformSupportsStreaming = !process.env.LAMBDA_TASK_ROOT && !process.env.VERCEL; if (!platformSupportsStreaming) { - try { - DEBUG_BUILD && logger.log('Flushing events...'); - await flush(2000); - DEBUG_BUILD && logger.log('Done flushing events'); - } catch (e) { - DEBUG_BUILD && logger.log('Error while flushing events:\n', e); - } + await flushSafelyWithTimeout(); } } diff --git a/packages/utils/src/flush-safely.ts b/packages/utils/src/flush-safely.ts new file mode 100644 index 000000000000..fb0623f95685 --- /dev/null +++ b/packages/utils/src/flush-safely.ts @@ -0,0 +1,16 @@ +import { flush } from '@sentry/core'; +import { DEBUG_BUILD } from './debug-build'; +import { logger } from './logger'; + +/** + * Flushes pending Sentry events with a default 2-second timeout and in a way that cannot create unhandled promise rejections. + */ +export async function flushSafelyWithTimeout(timeout = 2000): Promise { + try { + DEBUG_BUILD && logger.log('Flushing events...'); + await flush(timeout); + DEBUG_BUILD && logger.log('Done flushing events'); + } catch (e) { + DEBUG_BUILD && logger.log('Error while flushing events:\n', e); + } +} diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 4a2d68ca0d8b..93d90edb2d20 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -4,6 +4,7 @@ export * from './breadcrumb-log-level'; export * from './browser'; export * from './dsn'; export * from './error'; +export * from './flush-safely'; export * from './worldwide'; export * from './instrument'; export * from './is';