Skip to content

Commit 377e8a8

Browse files
Lms24cursoragent
andcommitted
feat(solid): Set url attributes on solid router and tanstack router spans
Adds url.template, url.path, and url.full to pageload and navigation spans for Solid Router and TanStack Solid Router, including redirect and back-button navigation cases. Updates solidstart and solid-tanstack-router e2e tests. part of #21921 Co-Authored-By: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent d262ae6 commit 377e8a8

8 files changed

Lines changed: 214 additions & 38 deletions

File tree

dev-packages/e2e-tests/test-applications/solid-tanstack-router/tests/routing-instrumentation.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ test('sends a pageload transaction with a parameterized URL', async ({ page }) =
1818
'sentry.origin': 'auto.pageload.solid.tanstack_router',
1919
'sentry.op': 'pageload',
2020
'url.path.parameter.postId': '456',
21+
'url.template': '/posts/$postId',
22+
'url.path': '/posts/456',
23+
'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/posts\/456$/),
2124
},
2225
op: 'pageload',
2326
origin: 'auto.pageload.solid.tanstack_router',
@@ -59,6 +62,9 @@ test('sends a navigation transaction with a parameterized URL', async ({ page })
5962
'sentry.origin': 'auto.navigation.solid.tanstack_router',
6063
'sentry.op': 'navigation',
6164
'url.path.parameter.postId': '2',
65+
'url.template': '/posts/$postId',
66+
'url.path': '/posts/2',
67+
'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/posts\/2$/),
6268
},
6369
op: 'navigation',
6470
origin: 'auto.navigation.solid.tanstack_router',
@@ -90,6 +96,9 @@ test('sends a pageload transaction named after the resolved route when a redirec
9096
'sentry.origin': 'auto.pageload.solid.tanstack_router',
9197
'sentry.op': 'pageload',
9298
'url.path.parameter.postId': '1',
99+
'url.template': '/posts/$postId',
100+
'url.path': '/posts/1',
101+
'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/posts\/1$/),
93102
},
94103
op: 'pageload',
95104
origin: 'auto.pageload.solid.tanstack_router',
@@ -130,6 +139,9 @@ test('sends a navigation transaction when a redirect is thrown in beforeLoad', a
130139
'sentry.origin': 'auto.navigation.solid.tanstack_router',
131140
'sentry.op': 'navigation',
132141
'url.path.parameter.postId': '1',
142+
'url.template': '/posts/$postId',
143+
'url.path': '/posts/1',
144+
'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/posts\/1$/),
133145
},
134146
op: 'navigation',
135147
origin: 'auto.navigation.solid.tanstack_router',
@@ -175,6 +187,9 @@ test('sends a navigation transaction for a normal navigation that happens after
175187
'sentry.origin': 'auto.navigation.solid.tanstack_router',
176188
'sentry.op': 'navigation',
177189
'url.path.parameter.postId': '2',
190+
'url.template': '/posts/$postId',
191+
'url.path': '/posts/2',
192+
'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/posts\/2$/),
178193
},
179194
op: 'navigation',
180195
origin: 'auto.navigation.solid.tanstack_router',
@@ -201,6 +216,12 @@ test('sends pageload transaction with web vitals measurements', async ({ page })
201216
trace: {
202217
op: 'pageload',
203218
origin: 'auto.pageload.solid.tanstack_router',
219+
data: {
220+
'sentry.source': 'route',
221+
'url.template': '/',
222+
'url.path': '/',
223+
'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/$/),
224+
},
204225
},
205226
},
206227
transaction: '/',

dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/tests/performance.client.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ test('sends a pageload transaction', async ({ page }) => {
1414
trace: {
1515
op: 'pageload',
1616
origin: 'auto.pageload.browser',
17+
data: {
18+
'sentry.source': 'route',
19+
'url.template': '/',
20+
'url.path': '/',
21+
'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/$/),
22+
},
1723
},
1824
},
1925
transaction: '/',
@@ -37,6 +43,12 @@ test('sends a navigation transaction with parametrized route', async ({ page })
3743
trace: {
3844
op: 'navigation',
3945
origin: 'auto.navigation.solidstart.solidrouter',
46+
data: {
47+
'sentry.source': 'route',
48+
'url.template': '/users/:id',
49+
'url.path': '/users/5',
50+
'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/users\/5$/),
51+
},
4052
},
4153
},
4254
transaction: '/users/:id',
@@ -63,6 +75,12 @@ test('updates the transaction when using the back button', async ({ page }) => {
6375
trace: {
6476
op: 'navigation',
6577
origin: 'auto.navigation.solidstart.solidrouter',
78+
data: {
79+
'sentry.source': 'route',
80+
'url.template': '/users/:id',
81+
'url.path': '/users/6',
82+
'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/users\/6$/),
83+
},
6684
},
6785
},
6886
transaction: '/users/:id',
@@ -85,6 +103,12 @@ test('updates the transaction when using the back button', async ({ page }) => {
85103
trace: {
86104
op: 'navigation',
87105
origin: 'auto.navigation.solidstart.solidrouter',
106+
data: {
107+
'sentry.source': 'route',
108+
'url.template': '/back-navigation',
109+
'url.path': '/back-navigation',
110+
'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/back-navigation$/),
111+
},
88112
},
89113
},
90114
transaction: '/back-navigation',

dev-packages/e2e-tests/test-applications/solidstart-spa/tests/performance.client.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ test('sends a pageload transaction', async ({ page }) => {
1414
trace: {
1515
op: 'pageload',
1616
origin: 'auto.pageload.browser',
17+
data: {
18+
'sentry.source': 'route',
19+
'url.template': '/',
20+
'url.path': '/',
21+
'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/$/),
22+
},
1723
},
1824
},
1925
transaction: '/',
@@ -37,6 +43,12 @@ test('sends a navigation transaction with parametrized route', async ({ page })
3743
trace: {
3844
op: 'navigation',
3945
origin: 'auto.navigation.solidstart.solidrouter',
46+
data: {
47+
'sentry.source': 'route',
48+
'url.template': '/users/:id',
49+
'url.path': '/users/5',
50+
'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/users\/5$/),
51+
},
4052
},
4153
},
4254
transaction: '/users/:id',
@@ -63,6 +75,12 @@ test('updates the transaction when using the back button', async ({ page }) => {
6375
trace: {
6476
op: 'navigation',
6577
origin: 'auto.navigation.solidstart.solidrouter',
78+
data: {
79+
'sentry.source': 'route',
80+
'url.template': '/users/:id',
81+
'url.path': '/users/6',
82+
'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/users\/6$/),
83+
},
6684
},
6785
},
6886
transaction: '/users/:id',
@@ -85,6 +103,12 @@ test('updates the transaction when using the back button', async ({ page }) => {
85103
trace: {
86104
op: 'navigation',
87105
origin: 'auto.navigation.solidstart.solidrouter',
106+
data: {
107+
'sentry.source': 'route',
108+
'url.template': '/back-navigation',
109+
'url.path': '/back-navigation',
110+
'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/back-navigation$/),
111+
},
88112
},
89113
},
90114
transaction: '/back-navigation',

dev-packages/e2e-tests/test-applications/solidstart-top-level-import/tests/performance.client.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ test('sends a pageload transaction', async ({ page }) => {
1414
trace: {
1515
op: 'pageload',
1616
origin: 'auto.pageload.browser',
17+
data: {
18+
'sentry.source': 'route',
19+
'url.template': '/',
20+
'url.path': '/',
21+
'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/$/),
22+
},
1723
},
1824
},
1925
transaction: '/',
@@ -37,6 +43,12 @@ test('sends a navigation transaction with parametrized route', async ({ page })
3743
trace: {
3844
op: 'navigation',
3945
origin: 'auto.navigation.solidstart.solidrouter',
46+
data: {
47+
'sentry.source': 'route',
48+
'url.template': '/users/:id',
49+
'url.path': '/users/5',
50+
'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/users\/5$/),
51+
},
4052
},
4153
},
4254
transaction: '/users/:id',
@@ -63,6 +75,12 @@ test('updates the transaction when using the back button', async ({ page }) => {
6375
trace: {
6476
op: 'navigation',
6577
origin: 'auto.navigation.solidstart.solidrouter',
78+
data: {
79+
'sentry.source': 'route',
80+
'url.template': '/users/:id',
81+
'url.path': '/users/6',
82+
'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/users\/6$/),
83+
},
6684
},
6785
},
6886
transaction: '/users/:id',
@@ -85,6 +103,12 @@ test('updates the transaction when using the back button', async ({ page }) => {
85103
trace: {
86104
op: 'navigation',
87105
origin: 'auto.navigation.solidstart.solidrouter',
106+
data: {
107+
'sentry.source': 'route',
108+
'url.template': '/back-navigation',
109+
'url.path': '/back-navigation',
110+
'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/back-navigation$/),
111+
},
88112
},
89113
},
90114
transaction: '/back-navigation',

dev-packages/e2e-tests/test-applications/solidstart/tests/performance.client.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ test('sends a pageload transaction', async ({ page }) => {
1414
trace: {
1515
op: 'pageload',
1616
origin: 'auto.pageload.browser',
17+
data: {
18+
'sentry.source': 'route',
19+
'url.template': '/',
20+
'url.path': '/',
21+
'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/$/),
22+
},
1723
},
1824
},
1925
transaction: '/',
@@ -37,6 +43,12 @@ test('sends a navigation transaction with parametrized route', async ({ page })
3743
trace: {
3844
op: 'navigation',
3945
origin: 'auto.navigation.solidstart.solidrouter',
46+
data: {
47+
'sentry.source': 'route',
48+
'url.template': '/users/:id',
49+
'url.path': '/users/5',
50+
'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/users\/5$/),
51+
},
4052
},
4153
},
4254
transaction: '/users/:id',
@@ -63,6 +75,12 @@ test('updates the transaction when using the back button', async ({ page }) => {
6375
trace: {
6476
op: 'navigation',
6577
origin: 'auto.navigation.solidstart.solidrouter',
78+
data: {
79+
'sentry.source': 'route',
80+
'url.template': '/users/:id',
81+
'url.path': '/users/6',
82+
'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/users\/6$/),
83+
},
6684
},
6785
},
6886
transaction: '/users/:id',
@@ -85,6 +103,12 @@ test('updates the transaction when using the back button', async ({ page }) => {
85103
trace: {
86104
op: 'navigation',
87105
origin: 'auto.navigation.solidstart.solidrouter',
106+
data: {
107+
'sentry.source': 'route',
108+
'url.template': '/back-navigation',
109+
'url.path': '/back-navigation',
110+
'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/back-navigation$/),
111+
},
88112
},
89113
},
90114
transaction: '/back-navigation',

packages/solid/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@
5555
},
5656
"dependencies": {
5757
"@sentry/browser": "10.64.0",
58-
"@sentry/core": "10.64.0"
58+
"@sentry/core": "10.64.0",
59+
"@sentry/conventions": "^0.15.1"
5960
},
6061
"peerDependencies": {
6162
"@solidjs/router": "^0.13.4 || ^0.14.0 || ^0.15.0",

packages/solid/src/solidrouter.ts

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import {
22
browserTracingIntegration,
3+
getAbsoluteUrl,
34
getActiveSpan,
45
getRootSpan,
56
spanToJSON,
67
startBrowserTracingNavigationSpan,
78
} from '@sentry/browser';
9+
import { PARAMS_KEY, URL_FULL, URL_PATH, URL_PATH_PARAMETER_KEY, URL_TEMPLATE } from '@sentry/conventions/attributes';
810
import type { Client, Integration, Span } from '@sentry/core';
911
import {
1012
getClient,
@@ -27,6 +29,15 @@ import { createComponent } from 'solid-js/web';
2729

2830
const CLIENTS_WITH_INSTRUMENT_NAVIGATION = new WeakSet<Client>();
2931

32+
function locationToSpanUrlAttributes(pathname: string, search: string = '', hash: string = ''): Record<string, string> {
33+
const pathWithSearch = `${pathname}${search}${hash}`;
34+
35+
return {
36+
[URL_PATH]: pathname,
37+
[URL_FULL]: getAbsoluteUrl(pathWithSearch),
38+
};
39+
}
40+
3041
function handleNavigation(location: string): void {
3142
const client = getClient();
3243
if (!client || !CLIENTS_WITH_INSTRUMENT_NAVIGATION.has(client)) {
@@ -40,14 +51,20 @@ function handleNavigation(location: string): void {
4051
const { name } = metaData?.sdk || {};
4152
const framework = name?.includes('solidstart') ? 'solidstart' : 'solid';
4253

43-
startBrowserTracingNavigationSpan(client, {
44-
name: location,
45-
attributes: {
46-
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',
47-
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: `auto.navigation.${framework}.solidrouter`,
48-
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',
54+
const isBackNavigation = location === '-1';
55+
56+
startBrowserTracingNavigationSpan(
57+
client,
58+
{
59+
name: location,
60+
attributes: {
61+
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',
62+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: `auto.navigation.${framework}.solidrouter`,
63+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',
64+
},
4965
},
50-
});
66+
isBackNavigation ? undefined : { url: getAbsoluteUrl(location) },
67+
);
5168
}
5269

5370
function getActiveRootSpan(): Span | undefined {
@@ -101,16 +118,22 @@ function withSentryRouterRoot(Root: Component<RouteSectionProps>): Component<Rou
101118
const currentMatches = matches();
102119
const lastMatch = currentMatches[currentMatches.length - 1];
103120

121+
const urlAttributes = locationToSpanUrlAttributes(name, location.search, location.hash);
122+
104123
if (lastMatch) {
105124
const parametrizedRoute = lastMatch.route.pattern || name;
106125
rootSpan.updateName(parametrizedRoute);
107-
rootSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');
126+
rootSpan.setAttributes({
127+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',
128+
[URL_TEMPLATE]: parametrizedRoute,
129+
...urlAttributes,
130+
});
108131

109132
const params = lastMatch.params;
110133
for (const [key, value] of Object.entries(params)) {
111134
if (value !== undefined) {
112-
rootSpan.setAttribute(`url.path.parameter.${key}`, value);
113-
rootSpan.setAttribute(`params.${key}`, value);
135+
rootSpan.setAttribute(URL_PATH_PARAMETER_KEY.replace('<key>', key), value);
136+
rootSpan.setAttribute(PARAMS_KEY.replace('<key>', key), value);
114137
}
115138
}
116139
} else {
@@ -119,7 +142,7 @@ function withSentryRouterRoot(Root: Component<RouteSectionProps>): Component<Rou
119142
if (op === 'navigation' && description === '-1') {
120143
rootSpan.updateName(name);
121144
}
122-
rootSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'url');
145+
rootSpan.setAttributes({ [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url', ...urlAttributes });
123146
}
124147
});
125148

0 commit comments

Comments
 (0)