Skip to content

[Remix] Can't get source mapping to work consistently #10548

Closed as not planned
Closed as not planned

Description

Is there an existing issue for this?

How do you use Sentry?

Sentry Saas (sentry.io)

Which SDK are you using?

@sentry/remix

SDK Version

7.93

Framework Version

7.79

Link to Sentry event

https://hello-travel.sentry.io/issues/4949583427/events/236fed44801a4b4f8b4ad78bd27886b2/

SDK Setup

Client side configuration

// file: app/entry.client.tsx
import * as Sentry from "@sentry/remix";

Sentry.init({
  dsn: "xxxxxxx",
  release: getPublicEnv("SENTRY_RELEASE"),
  integrations: [
    new Sentry.BrowserTracing({
      routingInstrumentation: Sentry.remixRouterInstrumentation(
        useEffect,
        useLocation,
        useMatches,
      ),
    }),
    // Replay is only available in the client
    new Sentry.Replay(),
  ],

  environment: process.env.NODE_ENV,
  debug: false,
  enabled: "development" !== process.env.NODE_ENV,

  // Set tracesSampleRate to 1.0 to capture 100%
  // of transactions for performance monitoring.
  // We recommend adjusting this value in production
  tracesSampleRate: 1,

  // Set `tracePropagationTargets` to control for which URLs distribud tracing should be enabled
  tracePropagationTargets: [
    "localhost",
    /^http:\/\/dev\.socialtrip\.com:3333/,
    getPublicEnv("SITE_URL"),
  ],

  // Capture Replay for 10% of all sessions,
  // plus for 100% of sessions with an error
  replaysSessionSampleRate: 0,
  replaysOnErrorSampleRate: 1,
});
// file: app/root.tsx
import { withSentry } from "@sentry/remix";

function App() {
   // ....
}

export default withSentry(App, {
  errorBoundaryOptions: {
    fallback: ErrorBoundary,
  },
});
// file: app/entry.server.tsx
import * as Sentry from "@sentry/remix";

// Init sentry
Sentry.init({
  dsn: "xxxxx",
  release: getPublicEnv("SENTRY_RELEASE"),
  environment: process.env.NODE_ENV,
  debug: false,
  enabled: "development" !== process.env.NODE_ENV,
  denyUrls: [
    /\/build\//,
    /\/favicons\//,
    /\/img\//,
    /\/fonts\//,
    /\/favicon.ico/,
    /\/site\.webmanifest/,
  ],
  integrations: [new Sentry.Integrations.Http({ tracing: true })],
  tracesSampleRate: 1,
});

// Remix stuff....

// function we export for Remix so it can handle errors
export function handleError(
  error: unknown,
  { request }: DataFunctionArgs,
): void {
  if (error instanceof Error) {
    Sentry.captureRemixServerException(error, "remix.server", request);
  } else {
    Sentry.captureException(error);
  }
}

Server side (lambda) configuration:

// in our lambda handler file
import * as Sentry from "@sentry/node";

Sentry.init({
  dsn: process.env.SENTRY_DSN,
  release: process.env.SENTRY_RELEASE,
  environment: process.env.NODE_ENV,
  enabled: true,
  debug: false,
  tracesSampleRate: 1,
});

// function we use to capture errors in try/catch
function captureError(
  error: unknown,
  event: APIGatewayProxyEventV2,
  context: Context,
) {
  console.error(error);
  Sentry.configureScope((scope) => {
    scope.setExtra("awsRequestId", event.requestContext.requestId);
    scope.setExtra("awsRequestURL", createURLFromEvent(event));
  });
  Sentry.captureException(error);
}

// our try/catch block is like:
try {
  // lambda/remix stuff...
} catch (error) {
  captureError(error, event, context);
  writeErrorToStream(streamResponse, 500, "Internal Server Error");
} finally {
  await Sentry.flush(2000);
  streamResponse.end();
}

Deploy flow

Scripts used in package.json:

"scripts": {
  "build": "NODE_ENV=production remix build --sourcemap && tsx bin/build-lambda-server.ts",
  "deploy": "tsx bin/deploy.ts",
}
  1. Build remix bundles: npm run build

The script bin/build-lambda-server.ts creates a new build with esbuild (and sourcemap enabled) for our lambda function, something like:

// file: bin/build-lambda-server.ts
const result = await esbuild.build({
  entryPoints: [`${paths.serverDir}/server.lambda.prod.ts`],
  bundle: true,
  minify: true,
  sourcemap: true,
  metafile: true,
  platform: "node",
  format: "esm",
  target: "esnext",
  outfile: `${paths.serverBundle}/index.mjs`,
  outExtension: { ".js": ".mjs" },
  banner: {
    js: 'import { createRequire } from "module";const require = createRequire(import.meta.url);',
  },
  define: {
    __SENTRY_DEBUG__: "false",
    __RRWEB_EXCLUDE_IFRAME__: "true",
    __RRWEB_EXCLUDE_SHADOW_DOM__: "true",
    __SENTRY_EXCLUDE_REPLAY_WORKER__: "true",
    "process.env.NODE_ENV": '"production"',
  },
  logLevel: "info",
});
// file: server/server.lambda.prod.ts
export const handler = createStreamRequestHandler({
  build: build as any, // this is the remix server build
  mode: process.env.NODE_ENV,
  getLoadContext: async (request: Request) => {
    // specific stuff
  },
});
  1. Deploy both client bundle & lambda function bundle: npm run deploy
// file bin/deploy.ts
const remixPublicPath = "/_static/"; // same as in remix.config.js publicPath property

const release = execSync("git rev-parse HEAD")
  .toString()
  .trim()
  .substring(0, 12);

// 1. .... build an archive for the lambda

// 2. Send both client & server bundle sourcemaps to Sentry
// client bundle sourcemap is handled by sentry
execSync(
  `npx sentry-upload-sourcemaps --org hello-travel --project remix --release ${release} --urlPrefix "~${remixPublicPath}"`,
  { cwd: paths.appDir },
);
// server bundle sourcemap is sent manually
execSync(
  `npx sentry-cli sourcemaps upload --org=hello-travel --project=remix --release=${release} --url-prefix="~/var/task" ./server/build/index.mjs.map`,
  {
    cwd: paths.appDir,
  },
);

// 3. other stuff not relevant to sentry (like updating lambda function code, cleanup, etc...)

Steps to Reproduce

Well, see the detailed code samples

Expected Result

Having traces with sourcemapping for both client and server errors.

Please note that I'm pretty sure I saw it working once for client errors. Didn't do any modification since then though....

Actual Result

Client error event example:

Capture d’écran 2024-02-07 à 11 02 12

Server (lambda function) error event example:

Capture d’écran 2024-01-24 à 15 32 47

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Type

    Projects

    • Status

      Waiting for: Community

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions