Skip to content

Commit 08fe765

Browse files
committed
fix(remix): Paramaterize server side transactions
1 parent cb925e3 commit 08fe765

File tree

1 file changed

+80
-12
lines changed

1 file changed

+80
-12
lines changed

packages/remix/src/utils/instrumentServer.ts

Lines changed: 80 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,7 @@
11
/* eslint-disable max-lines */
22
import { captureException, getCurrentHub } from '@sentry/node';
33
import { getActiveTransaction } from '@sentry/tracing';
4-
import {
5-
addExceptionMechanism,
6-
fill,
7-
loadModule,
8-
logger,
9-
serializeBaggage,
10-
stripUrlQueryAndFragment,
11-
} from '@sentry/utils';
4+
import { addExceptionMechanism, fill, loadModule, logger, serializeBaggage } from '@sentry/utils';
125

136
// Types vendored from @remix-run/server-runtime@1.6.0:
147
// https://github.com/remix-run/remix/blob/f3691d51027b93caa3fd2cdfe146d7b62a6eb8f2/packages/remix-server-runtime/server.ts
@@ -92,6 +85,14 @@ interface DataFunction {
9285
(args: DataFunctionArgs): Promise<Response> | Response | Promise<AppData> | AppData;
9386
}
9487

88+
// Taken from Remix Implementation
89+
// https://github.com/remix-run/remix/blob/97999d02493e8114c39d48b76944069d58526e8d/packages/remix-server-runtime/routeMatching.ts#L6-L10
90+
export interface RouteMatch<Route> {
91+
params: Params;
92+
pathname: string;
93+
route: Route;
94+
}
95+
9596
// Taken from Remix Implementation
9697
// https://github.com/remix-run/remix/blob/7688da5c75190a2e29496c78721456d6e12e3abe/packages/remix-server-runtime/responses.ts#L54-L62
9798
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -262,18 +263,58 @@ function makeWrappedMeta(origMeta: MetaFunction | HtmlMetaDescriptor = {}): Meta
262263
};
263264
}
264265

265-
function wrapRequestHandler(origRequestHandler: RequestHandler): RequestHandler {
266+
function createRoutes(manifest: ServerRouteManifest, parentId?: string): ServerRoute[] {
267+
return Object.entries(manifest)
268+
.filter(([, route]) => route.parentId === parentId)
269+
.map(([id, route]) => ({
270+
...route,
271+
children: createRoutes(manifest, id),
272+
}));
273+
}
274+
275+
function wrapRequestHandler(origRequestHandler: RequestHandler, build: ServerBuild): RequestHandler {
276+
const routes = createRoutes(build.routes);
277+
const pkg = loadModule<{ matchRoutes: (routes: ServerRoute[], pathname: string) => any[] }>('react-router-dom');
278+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
279+
// https://github.com/remix-run/remix/blob/38e127b1d97485900b9c220d93503de0deb1fc81/packages/remix-server-runtime/routeMatching.ts#L12-L24
280+
function matchServerRoutes(routes: ServerRoute[], pathname: string): RouteMatch<ServerRoute>[] | null {
281+
if (!pkg) {
282+
return null;
283+
}
284+
285+
const matches = pkg.matchRoutes(routes, pathname);
286+
if (!matches) {
287+
return null;
288+
}
289+
290+
return matches.map(match => ({
291+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
292+
params: match.params,
293+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
294+
pathname: match.pathname,
295+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
296+
route: match.route as unknown as ServerRoute,
297+
}));
298+
}
299+
266300
return async function (this: unknown, request: Request, loadContext?: unknown): Promise<Response> {
267301
const hub = getCurrentHub();
268302
const currentScope = hub.getScope();
303+
304+
const url = new URL(request.url);
305+
const matches = matchServerRoutes(routes, url.pathname);
306+
307+
const match = matches && getRequestMatch(url, matches);
308+
const name = match === null ? url.pathname : match.route.id;
309+
const source = match === null ? 'url' : 'route';
269310
const transaction = hub.startTransaction({
270-
name: stripUrlQueryAndFragment(request.url),
311+
name,
271312
op: 'http.server',
272313
tags: {
273314
method: request.method,
274315
},
275316
metadata: {
276-
source: 'url',
317+
source,
277318
},
278319
});
279320

@@ -290,6 +331,33 @@ function wrapRequestHandler(origRequestHandler: RequestHandler): RequestHandler
290331
};
291332
}
292333

334+
// https://github.com/remix-run/remix/blob/97999d02493e8114c39d48b76944069d58526e8d/packages/remix-server-runtime/server.ts#L573-L586
335+
function isIndexRequestUrl(url: URL): boolean {
336+
for (const param of url.searchParams.getAll('index')) {
337+
// only use bare `?index` params without a value
338+
// ✅ /foo?index
339+
// ✅ /foo?index&index=123
340+
// ✅ /foo?index=123&index
341+
// ❌ /foo?index=123
342+
if (param === '') {
343+
return true;
344+
}
345+
}
346+
347+
return false;
348+
}
349+
350+
// https://github.com/remix-run/remix/blob/97999d02493e8114c39d48b76944069d58526e8d/packages/remix-server-runtime/server.ts#L588-L596
351+
function getRequestMatch(url: URL, matches: RouteMatch<ServerRoute>[]): RouteMatch<ServerRoute> {
352+
const match = matches.slice(-1)[0];
353+
354+
if (!isIndexRequestUrl(url) && match.route.id.endsWith('/index')) {
355+
return matches.slice(-2)[0];
356+
}
357+
358+
return match;
359+
}
360+
293361
function makeWrappedCreateRequestHandler(
294362
origCreateRequestHandler: CreateRequestHandlerFunction,
295363
): CreateRequestHandlerFunction {
@@ -318,7 +386,7 @@ function makeWrappedCreateRequestHandler(
318386

319387
const requestHandler = origCreateRequestHandler.call(this, { ...build, routes, entry: wrappedEntry }, mode);
320388

321-
return wrapRequestHandler(requestHandler);
389+
return wrapRequestHandler(requestHandler, build);
322390
};
323391
}
324392

0 commit comments

Comments
 (0)