Skip to content

Commit 1d44621

Browse files
committed
feat(sveltekit): Register a route provider backed by reported route ids
SvelteKit has no public route matcher and `page.route.id` is not available synchronously, so the provider answers from route ids the instrumentation has already seen rather than by matching. Uses core's cached provider, so the statefulness stays private and the API stays URL in, string out.
1 parent 0291fba commit 1d44621

4 files changed

Lines changed: 31 additions & 0 deletions

File tree

packages/sveltekit/src/client/browserTracingIntegration.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import type { Integration } from '@sentry/core';
2+
import { setRouteProvider } from '@sentry/core';
23
import { browserTracingIntegration as originalBrowserTracingIntegration } from '@sentry/svelte';
4+
import { routeProvider } from './routeCache';
35
// The `sentrySvelteKit()` Vite plugin redirects this to the Svelte 4 or Svelte 5 variant per Kit
46
// version; without the plugin it resolves via `exports` to the Svelte 4 variant, so builds don't break.
57
import { instrumentSvelteKitTracing } from '@sentry/sveltekit/browser-tracing-variant';
@@ -20,6 +22,10 @@ export function browserTracingIntegration(
2022

2123
return {
2224
...integration,
25+
setup: client => {
26+
setRouteProvider(routeProvider, client);
27+
integration.setup?.(client);
28+
},
2329
afterAllSetup: client => {
2430
integration.afterAllSetup(client);
2531
instrumentSvelteKitTracing(client, options);
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { createCachedRouteProvider } from '@sentry/core';
2+
3+
// SvelteKit has no public route matcher, and `page.route.id` is not available synchronously, so the
4+
// provider answers from route ids the instrumentation has already seen rather than by matching.
5+
export const routeProvider = createCachedRouteProvider();
6+
7+
/**
8+
* Records the parameterized route id SvelteKit reported for a path.
9+
*
10+
* Called from both the Kit 2 and Kit 3 instrumentation, since `page.route.id` is the only place the
11+
* route id is available.
12+
*/
13+
export function recordRouteId(pathname: string | undefined, routeId: string | null | undefined): void {
14+
routeProvider.record(pathname, routeId);
15+
}

packages/sveltekit/src/client/svelte4BrowserTracing.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import type { Navigation, Page } from '@sveltejs/kit';
1717
// eslint-disable-next-line typescript/no-deprecated
1818
import { navigating, page } from '$app/stores';
1919
import type { Readable } from 'svelte/store';
20+
import { recordRouteId } from './routeCache';
2021

2122
/**
2223
* SvelteKit 2 / Svelte 4 browser tracing (`$app/stores`). Selected at build time, so it's only
@@ -62,6 +63,8 @@ function _instrumentPageload(client: Client, pageStore: Readable<Page>): void {
6263

6364
const routeId = pageState.route?.id;
6465

66+
recordRouteId(pageState.url?.pathname, routeId);
67+
6568
if (routeId) {
6669
pageloadSpan.updateName(routeId);
6770
pageloadSpan.setAttributes({ [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route', [URL_TEMPLATE]: routeId });
@@ -105,6 +108,8 @@ function _instrumentNavigations(client: Client, navigatingStore: Readable<Naviga
105108
const parameterizedRouteOrigin = from?.route.id;
106109
const parameterizedRouteDestination = to?.route.id;
107110

111+
recordRouteId(to?.url.pathname, parameterizedRouteDestination);
112+
108113
if (routingSpan) {
109114
// If a routing span is still open from a previous navigation, we finish it.
110115
routingSpan.end();

packages/sveltekit/src/client/svelte5BrowserTracing.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
import { SENTRY_OP, URL_TEMPLATE } from '@sentry/conventions/attributes';
1616
import type { Navigation } from '@sveltejs/kit';
1717
import { getCurrentNavigation, onNavigationChange, onPageRouteChange } from './navigationState.svelte';
18+
import { recordRouteId } from './routeCache';
1819

1920
/**
2021
* SvelteKit 3 / Svelte 5 browser tracing (`$app/state` runes). Selected at build time, so it's only
@@ -55,6 +56,8 @@ function _instrumentPageLoad(client: Client): void {
5556
// `page.route.id` isn't available synchronously when we set up (during `Sentry.init`), so we react
5657
// to it and upgrade the pageload span from `url` to the parameterized `route` once it resolves.
5758
onPageRouteChange(routeId => {
59+
recordRouteId(WINDOW.location?.pathname, routeId);
60+
5861
if (routeId) {
5962
pageLoadSpan.updateName(routeId);
6063
pageLoadSpan.setAttributes({ [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route', [URL_TEMPLATE]: routeId });
@@ -88,6 +91,8 @@ function _instrumentNavigations(client: Client): void {
8891
const parameterizedRouteOrigin = from?.route.id;
8992
const parameterizedRouteDestination = to?.route.id;
9093

94+
recordRouteId(to?.url.pathname, parameterizedRouteDestination);
95+
9196
routingSpan?.end();
9297

9398
const navigationInfo = {

0 commit comments

Comments
 (0)