diff --git a/dev-packages/e2e-tests/test-applications/create-remix-app-express-vite-dev/instrument.mjs b/dev-packages/e2e-tests/test-applications/create-remix-app-express-vite-dev/instrument.mjs index 5fb6bd039fdb..b52053445456 100644 --- a/dev-packages/e2e-tests/test-applications/create-remix-app-express-vite-dev/instrument.mjs +++ b/dev-packages/e2e-tests/test-applications/create-remix-app-express-vite-dev/instrument.mjs @@ -6,6 +6,5 @@ Sentry.init({ environment: 'qa', // dynamic sampling bias to keep transactions dsn: process.env.E2E_TEST_DSN, tunnel: 'http://localhost:3031/', // proxy server - autoInstrumentRemix: true, // auto instrument Remix integrations: [Sentry.nativeNodeFetchIntegration()], }); diff --git a/dev-packages/e2e-tests/test-applications/create-remix-app-express/instrument.mjs b/dev-packages/e2e-tests/test-applications/create-remix-app-express/instrument.mjs index f2e7d35fab80..0cbfe8ec4e5b 100644 --- a/dev-packages/e2e-tests/test-applications/create-remix-app-express/instrument.mjs +++ b/dev-packages/e2e-tests/test-applications/create-remix-app-express/instrument.mjs @@ -7,7 +7,6 @@ Sentry.init({ dsn: process.env.E2E_TEST_DSN, tunnel: 'http://localhost:3031/', // proxy server sendDefaultPii: true, // Testing the FormData - autoInstrumentRemix: true, // auto instrument Remix captureActionFormDataKeys: { file: true, text: true, diff --git a/dev-packages/e2e-tests/test-applications/create-remix-app-v2/instrument.server.cjs b/dev-packages/e2e-tests/test-applications/create-remix-app-v2/instrument.server.cjs index 5b80ca7b8695..6d211cac4592 100644 --- a/dev-packages/e2e-tests/test-applications/create-remix-app-v2/instrument.server.cjs +++ b/dev-packages/e2e-tests/test-applications/create-remix-app-v2/instrument.server.cjs @@ -5,5 +5,4 @@ Sentry.init({ environment: 'qa', // dynamic sampling bias to keep transactions dsn: process.env.E2E_TEST_DSN, tunnel: 'http://localhost:3031/', // proxy server - autoInstrumentRemix: true, // auto instrument Remix }); diff --git a/dev-packages/e2e-tests/test-applications/create-remix-app/instrument.server.cjs b/dev-packages/e2e-tests/test-applications/create-remix-app/instrument.server.cjs index 5b80ca7b8695..6d211cac4592 100644 --- a/dev-packages/e2e-tests/test-applications/create-remix-app/instrument.server.cjs +++ b/dev-packages/e2e-tests/test-applications/create-remix-app/instrument.server.cjs @@ -5,5 +5,4 @@ Sentry.init({ environment: 'qa', // dynamic sampling bias to keep transactions dsn: process.env.E2E_TEST_DSN, tunnel: 'http://localhost:3031/', // proxy server - autoInstrumentRemix: true, // auto instrument Remix }); diff --git a/docs/migration/v8-to-v9.md b/docs/migration/v8-to-v9.md index bb0cfe487da0..fbb5f3aec298 100644 --- a/docs/migration/v8-to-v9.md +++ b/docs/migration/v8-to-v9.md @@ -82,6 +82,10 @@ If you need to support older browsers, we recommend transpiling your code using - When `skipOpenTelemetrySetup: true` is configured, `httpIntegration({ spans: false })` will be configured by default. This means that you no longer have to specify this yourself in this scenario. With this change, no spans are emitted once `skipOpenTelemetrySetup: true` is configured, without any further configuration being needed. +### `@sentry/remix` + +- The Remix SDK now uses OpenTelemetry instrumentation by default. This is identical to have used the v7 SDK with `autoInstrumentRemix: true`. + ### Uncategorized (TODO) - Next.js withSentryConfig returning Promise @@ -114,6 +118,7 @@ It will be removed in a future major version. - [General](#general) - [Server-side SDKs (Node, Deno, Bun, ...)](#server-side-sdks-node-deno-bun-) - [Next.js SDK](#nextjs-sdk) +- [Remix SDK](#remix-sdk) - [Vue/Nuxt SDK](#vuenuxt-sdk) ### General @@ -136,6 +141,12 @@ It will be removed in a future major version. - `experimental_captureRequestError` +### Remix SDK + +- `options.autoInstrumentRemix` + +The `autoInstrumentRemix` has been removed from the Remix SDK. The default behaviour of the Remix SDK is now as if `autoInstrumentRemix` was set to `true`. + ### Vue/Nuxt SDK - vueComponent tracking options diff --git a/packages/remix/README.md b/packages/remix/README.md index 7914555728f1..e4d5c60d8bd7 100644 --- a/packages/remix/README.md +++ b/packages/remix/README.md @@ -10,137 +10,44 @@ [](https://www.npmjs.com/package/@sentry/remix) [](https://www.npmjs.com/package/@sentry/remix) -## General - This package is a wrapper around `@sentry/node` for the server and `@sentry/react` for the client, with added functionality related to Remix. -To use this SDK, initialize Sentry in your Remix entry points for both the client and server. - -```ts -// entry.client.tsx - -import { useLocation, useMatches } from '@remix-run/react'; -import * as Sentry from '@sentry/remix'; -import { useEffect } from 'react'; - -Sentry.init({ - dsn: '__DSN__', - tracesSampleRate: 1, - integrations: [ - Sentry.browserTracingIntegration({ - useEffect, - useLocation, - useMatches, - }), - ], - // ... -}); -``` +## Compatibility -```ts -// entry.server.tsx +Currently, the minimum supported version of Remix is `1.0.0`. -import { prisma } from '~/db.server'; +## Installation -import * as Sentry from '@sentry/remix'; +To get started installing the SDK, use the Sentry Remix Wizard by running the following command in your terminal or +read the [Getting Started Docs](https://docs.sentry.io/platforms/javascript/guides/remix/): -Sentry.init({ - dsn: '__DSN__', - tracesSampleRate: 1, - integrations: [new Sentry.Integrations.Prisma({ client: prisma })], - // ... -}); +```sh +npx @sentry/wizard@latest -i remix ``` -Also, wrap your Remix root with `withSentry` to catch React component errors and to get parameterized router -transactions. - -```ts -// root.tsx - -import { - Links, - LiveReload, - Meta, - Outlet, - Scripts, - ScrollRestoration, -} from "@remix-run/react"; +The wizard will prompt you to log in to Sentry. After the wizard setup is completed, the SDK will automatically capture +unhandled errors, and monitor performance. -import { withSentry } from "@sentry/remix"; +## Custom Usage -function App() { - return ( - -
- -An error has occurred
- } -}); -``` - -To set context information or send manual events, use the exported functions of `@sentry/remix`. - -```ts -import * as Sentry from '@sentry/remix'; +import * as Sentry from '@sentry/nextjs'; // Set user information, as well as tags and further extras -Sentry.setExtra('battery', 0.7); Sentry.setTag('user_mode', 'admin'); Sentry.setUser({ id: '4711' }); +Sentry.setContext('application_area', { location: 'checkout' }); // Add a breadcrumb for future events Sentry.addBreadcrumb({ - message: 'My Breadcrumb', + message: '"Add to cart" clicked', // ... }); -// Capture exceptions, messages or manual events +// Capture exceptions or messages +Sentry.captureException(new Error('Oh no.')); Sentry.captureMessage('Hello, world!'); -Sentry.captureException(new Error('Good bye')); -Sentry.captureEvent({ - message: 'Manual', - stacktrace: [ - // ... - ], -}); ``` - -## Sourcemaps and Releases - -The Remix SDK provides a script that automatically creates a release and uploads sourcemaps. To generate sourcemaps with -Remix, you need to call `remix build` with the `--sourcemap` option. - -On release, call `sentry-upload-sourcemaps` to upload source maps and create a release. To see more details on how to -use the command, call `sentry-upload-sourcemaps --help`. - -For more advanced configuration, -[directly use `sentry-cli` to upload source maps.](https://github.com/getsentry/sentry-cli). diff --git a/packages/remix/package.json b/packages/remix/package.json index 9967c77676bc..b3a87413d8a5 100644 --- a/packages/remix/package.json +++ b/packages/remix/package.json @@ -12,10 +12,7 @@ "engines": { "node": ">=14.18" }, - "files": [ - "/build", - "/scripts" - ], + "files": ["/build", "/scripts"], "main": "build/cjs/index.server.js", "module": "build/esm/index.server.js", "browser": "build/esm/index.client.js", @@ -43,9 +40,7 @@ }, "typesVersions": { "<4.9": { - "build/types/index.d.ts": [ - "build/types-ts3.8/index.d.ts" - ] + "build/types/index.d.ts": ["build/types-ts3.8/index.d.ts"] } }, "publishConfig": { @@ -92,15 +87,10 @@ "fix": "eslint . --format stylish --fix", "lint": "eslint . --format stylish", "test": "yarn test:unit", - "test:integration": "run-s test:integration:otel test:integration:legacy", - "test:integration:otel": "export USE_OTEL=1 && run-s test:integration:v1 test:integration:v2", - "test:integration:legacy": "export USE_OTEL=0 && run-s test:integration:v1 test:integration:v2", + "test:integration": "run-s test:integration:v1 test:integration:v2", "test:integration:v1": "run-s test:integration:clean test:integration:prepare test:integration:client test:integration:server", "test:integration:v2": "export REMIX_VERSION=2 && yarn test:integration:v1", - "test:integration:ci": "run-s test:integration:ci:otel test:integration:ci:legacy", - "test:integration:ci:otel": "USE_OTEL=1 yarn test:integration:ci:common", - "test:integration:ci:legacy": "USE_OTEL=0 yarn test:integration:ci:common", - "test:integration:ci:common": "run-s test:integration:clean test:integration:prepare test:integration:client:ci test:integration:server", + "test:integration:ci": "run-s test:integration:clean test:integration:prepare test:integration:client:ci test:integration:server", "test:integration:prepare": "(cd test/integration && yarn install)", "test:integration:clean": "(cd test/integration && rimraf .cache node_modules build)", "test:integration:client": "yarn playwright install-deps && yarn playwright test test/integration/test/client/ --project='chromium'", @@ -113,8 +103,5 @@ "volta": { "extends": "../../package.json" }, - "sideEffects": [ - "./esm/index.server.js", - "./src/index.server.ts" - ] + "sideEffects": ["./esm/index.server.js", "./src/index.server.ts"] } diff --git a/packages/remix/playwright.config.ts b/packages/remix/playwright.config.ts index 142272a44740..6177eeb8f4c7 100644 --- a/packages/remix/playwright.config.ts +++ b/packages/remix/playwright.config.ts @@ -13,9 +13,6 @@ const config: PlaywrightTestConfig = { // Note that 3 is a random number selected to work well with our CI setup workers: process.env.CI ? 3 : undefined, webServer: { - env: { - NODE_OPTIONS: process.env.USE_OTEL === '1' ? '--require ./instrument.server.cjs' : '', - }, command: '(cd test/integration/ && yarn build && yarn start)', port: 3000, }, diff --git a/packages/remix/src/index.server.ts b/packages/remix/src/index.server.ts index f6a5f5060dd9..a2c7a4d35ab8 100644 --- a/packages/remix/src/index.server.ts +++ b/packages/remix/src/index.server.ts @@ -169,8 +169,7 @@ export function getRemixDefaultIntegrations(options: RemixOptions): Integration[ return [ ...getDefaultNodeIntegrations(options as NodeOptions).filter(integration => integration.name !== 'Http'), httpIntegration(), - // eslint-disable-next-line deprecation/deprecation - options.autoInstrumentRemix ? remixIntegration() : undefined, + remixIntegration(), ].filter(int => int) as Integration[]; } @@ -202,7 +201,7 @@ export function init(options: RemixOptions): NodeClient | undefined { const client = nodeInit(options as NodeOptions); - instrumentServer(options); + instrumentServer(); return client; } diff --git a/packages/remix/src/utils/instrumentServer.ts b/packages/remix/src/utils/instrumentServer.ts index 797c295b0abf..7e09c1c406bb 100644 --- a/packages/remix/src/utils/instrumentServer.ts +++ b/packages/remix/src/utils/instrumentServer.ts @@ -1,21 +1,12 @@ -/* eslint-disable max-lines */ -import type { RequestEventData, Span, TransactionSource, WrappedFunction } from '@sentry/core'; +import type { RequestEventData, WrappedFunction } from '@sentry/core'; import { - SEMANTIC_ATTRIBUTE_SENTRY_OP, - SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, - SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, fill, - getActiveSpan, getClient, - getRootSpan, getTraceData, hasTracingEnabled, isNodeEnv, loadModule, logger, - setHttpStatus, - spanToJSON, - startSpan, winterCGRequestToRequestData, withIsolationScope, } from '@sentry/core'; @@ -23,8 +14,6 @@ import { continueTrace } from '@sentry/opentelemetry'; import { DEBUG_BUILD } from './debug-build'; import { captureRemixServerException, errorHandleDataFunction, errorHandleDocumentRequestFunction } from './errors'; import { getFutureFlagsServer, getRemixVersionFromBuild } from './futureFlags'; -import type { RemixOptions } from './remixOptions'; -import { createRoutes, getTransactionName } from './utils'; import { extractData, isDeferredData, isResponse, isRouteErrorResponse, json } from './vendor/response'; import type { AppData, @@ -38,7 +27,6 @@ import type { RemixRequest, RequestHandler, ServerBuild, - ServerRoute, ServerRouteManifest, } from './vendor/types'; @@ -99,7 +87,7 @@ export function wrapHandleErrorWithSentry( }; } -function makeWrappedDocumentRequestFunction(autoInstrumentRemix?: boolean, remixVersion?: number) { +function makeWrappedDocumentRequestFunction(remixVersion?: number) { return function (origDocumentRequestFunction: HandleDocumentRequestFunction): HandleDocumentRequestFunction { return async function ( this: unknown, @@ -119,86 +107,38 @@ function makeWrappedDocumentRequestFunction(autoInstrumentRemix?: boolean, remix const isRemixV2 = FUTURE_FLAGS?.v2_errorBoundary || remixVersion === 2; - if (!autoInstrumentRemix) { - const activeSpan = getActiveSpan(); - const rootSpan = activeSpan && getRootSpan(activeSpan); - - const name = rootSpan ? spanToJSON(rootSpan).description : undefined; - - return startSpan( - { - // If we don't have a root span, `onlyIfParent` will lead to the span not being created anyhow - // So we don't need to care too much about the fallback name, it's just for typing purposes.... - name: name || '