Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ test('sends a pageload transaction', async ({ page }) => {
},
transaction: '/',
transaction_info: {
source: 'url',
source: 'route',
},
});
});

test('sends a navigation transaction', async ({ page }) => {
test('sends a navigation transaction with parametrized route', async ({ page }) => {
const transactionPromise = waitForTransaction('solidstart-dynamic-import', async transactionEvent => {
return transactionEvent?.transaction === '/users/5' && transactionEvent.contexts?.trace?.op === 'navigation';
return transactionEvent?.transaction === '/users/:id' && transactionEvent.contexts?.trace?.op === 'navigation';
});

await page.goto(`/`);
Expand All @@ -39,9 +39,9 @@ test('sends a navigation transaction', async ({ page }) => {
origin: 'auto.navigation.solidstart.solidrouter',
},
},
transaction: '/users/5',
transaction: '/users/:id',
transaction_info: {
source: 'url',
source: 'route',
},
});
});
Expand All @@ -51,7 +51,7 @@ test('updates the transaction when using the back button', async ({ page }) => {
// The sentry solidRouterBrowserTracingIntegration tries to update such
// transactions with the proper name once the `useLocation` hook triggers.
const navigationTxnPromise = waitForTransaction('solidstart-dynamic-import', async transactionEvent => {
return transactionEvent?.transaction === '/users/6' && transactionEvent.contexts?.trace?.op === 'navigation';
return transactionEvent?.transaction === '/users/:id' && transactionEvent.contexts?.trace?.op === 'navigation';
});

await page.goto(`/back-navigation`);
Expand All @@ -65,9 +65,9 @@ test('updates the transaction when using the back button', async ({ page }) => {
origin: 'auto.navigation.solidstart.solidrouter',
},
},
transaction: '/users/6',
transaction: '/users/:id',
transaction_info: {
source: 'url',
source: 'route',
},
});

Expand All @@ -89,7 +89,7 @@ test('updates the transaction when using the back button', async ({ page }) => {
},
transaction: '/back-navigation',
transaction_info: {
source: 'url',
source: 'route',
},
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ test('sends a pageload transaction', async ({ page }) => {
},
transaction: '/',
transaction_info: {
source: 'url',
source: 'route',
},
});
});

test('sends a navigation transaction', async ({ page }) => {
test('sends a navigation transaction with parametrized route', async ({ page }) => {
const transactionPromise = waitForTransaction('solidstart-spa', async transactionEvent => {
return transactionEvent?.transaction === '/users/5' && transactionEvent.contexts?.trace?.op === 'navigation';
return transactionEvent?.transaction === '/users/:id' && transactionEvent.contexts?.trace?.op === 'navigation';
});

await page.goto(`/`);
Expand All @@ -39,9 +39,9 @@ test('sends a navigation transaction', async ({ page }) => {
origin: 'auto.navigation.solidstart.solidrouter',
},
},
transaction: '/users/5',
transaction: '/users/:id',
transaction_info: {
source: 'url',
source: 'route',
},
});
});
Expand All @@ -51,7 +51,7 @@ test('updates the transaction when using the back button', async ({ page }) => {
// The sentry solidRouterBrowserTracingIntegration tries to update such
// transactions with the proper name once the `useLocation` hook triggers.
const navigationTxnPromise = waitForTransaction('solidstart-spa', async transactionEvent => {
return transactionEvent?.transaction === '/users/6' && transactionEvent.contexts?.trace?.op === 'navigation';
return transactionEvent?.transaction === '/users/:id' && transactionEvent.contexts?.trace?.op === 'navigation';
});

await page.goto(`/back-navigation`);
Expand All @@ -65,9 +65,9 @@ test('updates the transaction when using the back button', async ({ page }) => {
origin: 'auto.navigation.solidstart.solidrouter',
},
},
transaction: '/users/6',
transaction: '/users/:id',
transaction_info: {
source: 'url',
source: 'route',
},
});

Expand All @@ -89,7 +89,7 @@ test('updates the transaction when using the back button', async ({ page }) => {
},
transaction: '/back-navigation',
transaction_info: {
source: 'url',
source: 'route',
},
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ test('sends a pageload transaction', async ({ page }) => {
},
transaction: '/',
transaction_info: {
source: 'url',
source: 'route',
},
});
});

test('sends a navigation transaction', async ({ page }) => {
test('sends a navigation transaction with parametrized route', async ({ page }) => {
const transactionPromise = waitForTransaction('solidstart-top-level-import', async transactionEvent => {
return transactionEvent?.transaction === '/users/5' && transactionEvent.contexts?.trace?.op === 'navigation';
return transactionEvent?.transaction === '/users/:id' && transactionEvent.contexts?.trace?.op === 'navigation';
});

await page.goto(`/`);
Expand All @@ -39,9 +39,9 @@ test('sends a navigation transaction', async ({ page }) => {
origin: 'auto.navigation.solidstart.solidrouter',
},
},
transaction: '/users/5',
transaction: '/users/:id',
transaction_info: {
source: 'url',
source: 'route',
},
});
});
Expand All @@ -51,7 +51,7 @@ test('updates the transaction when using the back button', async ({ page }) => {
// The sentry solidRouterBrowserTracingIntegration tries to update such
// transactions with the proper name once the `useLocation` hook triggers.
const navigationTxnPromise = waitForTransaction('solidstart-top-level-import', async transactionEvent => {
return transactionEvent?.transaction === '/users/6' && transactionEvent.contexts?.trace?.op === 'navigation';
return transactionEvent?.transaction === '/users/:id' && transactionEvent.contexts?.trace?.op === 'navigation';
});

await page.goto(`/back-navigation`);
Expand All @@ -65,9 +65,9 @@ test('updates the transaction when using the back button', async ({ page }) => {
origin: 'auto.navigation.solidstart.solidrouter',
},
},
transaction: '/users/6',
transaction: '/users/:id',
transaction_info: {
source: 'url',
source: 'route',
},
});

Expand All @@ -89,7 +89,7 @@ test('updates the transaction when using the back button', async ({ page }) => {
},
transaction: '/back-navigation',
transaction_info: {
source: 'url',
source: 'route',
},
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ test('sends a pageload transaction', async ({ page }) => {
},
transaction: '/',
transaction_info: {
source: 'url',
source: 'route',
},
});
});

test('sends a navigation transaction', async ({ page }) => {
test('sends a navigation transaction with parametrized route', async ({ page }) => {
const transactionPromise = waitForTransaction('solidstart', async transactionEvent => {
return transactionEvent?.transaction === '/users/5' && transactionEvent.contexts?.trace?.op === 'navigation';
return transactionEvent?.transaction === '/users/:id' && transactionEvent.contexts?.trace?.op === 'navigation';
});

await page.goto(`/`);
Expand All @@ -39,9 +39,9 @@ test('sends a navigation transaction', async ({ page }) => {
origin: 'auto.navigation.solidstart.solidrouter',
},
},
transaction: '/users/5',
transaction: '/users/:id',
transaction_info: {
source: 'url',
source: 'route',
},
});
});
Expand All @@ -51,7 +51,7 @@ test('updates the transaction when using the back button', async ({ page }) => {
// The sentry solidRouterBrowserTracingIntegration tries to update such
// transactions with the proper name once the `useLocation` hook triggers.
const navigationTxnPromise = waitForTransaction('solidstart', async transactionEvent => {
return transactionEvent?.transaction === '/users/6' && transactionEvent.contexts?.trace?.op === 'navigation';
return transactionEvent?.transaction === '/users/:id' && transactionEvent.contexts?.trace?.op === 'navigation';
});

await page.goto(`/back-navigation`);
Expand All @@ -65,9 +65,9 @@ test('updates the transaction when using the back button', async ({ page }) => {
origin: 'auto.navigation.solidstart.solidrouter',
},
},
transaction: '/users/6',
transaction: '/users/:id',
transaction_info: {
source: 'url',
source: 'route',
},
});

Expand All @@ -89,7 +89,7 @@ test('updates the transaction when using the back button', async ({ page }) => {
},
transaction: '/back-navigation',
transaction_info: {
source: 'url',
source: 'route',
},
});
});
55 changes: 42 additions & 13 deletions packages/solid/src/solidrouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import type {
RouteSectionProps,
StaticRouter,
} from '@solidjs/router';
import { useBeforeLeave, useLocation } from '@solidjs/router';
import { useBeforeLeave, useCurrentMatches, useLocation } from '@solidjs/router';
import type { Component, JSX, ParentProps } from 'solid-js';
import { createEffect, mergeProps, splitProps } from 'solid-js';
import { createComponent } from 'solid-js/web';
Expand Down Expand Up @@ -66,31 +66,60 @@ function SentryDefaultRoot(props: ParentProps): JSX.Element {
*/
function withSentryRouterRoot(Root: Component<RouteSectionProps>): Component<RouteSectionProps> {
const SentryRouterRoot = (props: RouteSectionProps): JSX.Element => {
// TODO: This is a rudimentary first version of handling navigation spans
// It does not
// - use query params
// - parameterize the route
// Tracks the target of a pending navigation, so the effect can skip
// stale updates during <Navigate> redirects where the location signal
// hasn't caught up to the navigation span yet.
let pendingNavigationTarget: string | undefined;

useBeforeLeave(({ to }: BeforeLeaveEventArgs) => {
// `to` could be `-1` if the browser back-button was used
handleNavigation(to.toString());
const target = to.toString();
pendingNavigationTarget = target;
handleNavigation(target);
});

const location = useLocation();
const matches = useCurrentMatches();

createEffect(() => {
const name = location.pathname;
const rootSpan = getActiveRootSpan();
if (!rootSpan) {
return;
}

if (rootSpan) {
// During <Navigate> redirects, the effect can fire before the router
// transition completes. In that case, location.pathname still points
// to the old route while the active span is already the navigation span.
// Skip the update to avoid overwriting the span with stale route data.
// `-1` is solid router's representation of a browser back-button
// navigation, where we don't know the target URL upfront.
if (pendingNavigationTarget && pendingNavigationTarget !== '-1' && name !== pendingNavigationTarget) {
return;
}
pendingNavigationTarget = undefined;

const currentMatches = matches();
const lastMatch = currentMatches[currentMatches.length - 1];

if (lastMatch) {
const parametrizedRoute = lastMatch.route.pattern || name;
rootSpan.updateName(parametrizedRoute);
rootSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');

const params = lastMatch.params;
for (const [key, value] of Object.entries(params)) {
if (value !== undefined) {
rootSpan.setAttribute(`url.path.parameter.${key}`, value);
rootSpan.setAttribute(`params.${key}`, value);
}
}
} else {
// No matched route - update back-button navigations and set source to url
const { op, description } = spanToJSON(rootSpan);

// We only need to update navigation spans that have been created by
// a browser back-button navigation (stored as `-1` by solid router)
// everything else was already instrumented correctly in `useBeforeLeave`
if (op === 'navigation' && description === '-1') {
rootSpan.updateName(name);
rootSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'url');
}
rootSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'url');
}
});

Expand Down
Loading
Loading