Skip to content

Commit 1854214

Browse files
authored
fix(astro): Ensure span name from beforeStartSpan isn't overwritten (#17500)
Fix a bug in our Astro SDK's `browserTracingIntegration`. Previously, if users followed our docs how to set a custom span name for the pageload span [via `beforeStartSpan`](https://docs.sentry.io/platforms/javascript/guides/astro/tracing/instrumentation/automatic-instrumentation/#beforeStartSpan), the name would get overwritten by our route parameterization logic. This was because the route parametrization logic ran after the span was already created and it would simply update the span name. In this case though, we can already start the span with the parameterized name instead of updating after it was started.
1 parent 4c6c012 commit 1854214

File tree

5 files changed

+92
-27
lines changed

5 files changed

+92
-27
lines changed

dev-packages/e2e-tests/test-applications/astro-5/sentry.client.config.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,17 @@ Sentry.init({
55
environment: 'qa',
66
tracesSampleRate: 1.0,
77
tunnel: 'http://localhost:3031/', // proxy server
8-
integrations: [Sentry.browserTracingIntegration()],
8+
integrations: [
9+
Sentry.browserTracingIntegration({
10+
beforeStartSpan: opts => {
11+
if (opts.name.startsWith('/blog/')) {
12+
return {
13+
...opts,
14+
name: window.location.pathname,
15+
};
16+
}
17+
return opts;
18+
},
19+
}),
20+
],
921
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
import Layout from '../../layouts/Layout.astro';
3+
4+
export const prerender = false;
5+
6+
const { slug } = Astro.params;
7+
---
8+
9+
<Layout title="Dynamic SSR page">
10+
<h1>Blog post: {slug}</h1>
11+
</Layout>

dev-packages/e2e-tests/test-applications/astro-5/src/pages/index.astro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import Layout from '../layouts/Layout.astro';
1717
<a href="/test-static" title="static page">Static Page</a>
1818
<a href="/server-island">Server Island</a>
1919
<a href="/user-page/myUsername123">Test Parametrized Routes</a>
20+
<a href="/blog/my-post">Route Parametrization override</a>
2021
</ul>
2122
</main>
2223
</Layout>

dev-packages/e2e-tests/test-applications/astro-5/tests/tracing.dynamic.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,4 +369,18 @@ test.describe('parametrized vs static paths', () => {
369369
request: { url: expect.stringContaining('/user-page/settings') },
370370
});
371371
});
372+
373+
test('allows for span name override via beforeStartSpan', async ({ page }) => {
374+
const clientPageloadTxnPromise = waitForTransaction('astro-5', txnEvent => {
375+
return txnEvent?.transaction?.startsWith('/blog/') ?? false;
376+
});
377+
378+
await page.goto('/blog/my-post');
379+
380+
const clientPageloadTxn = await clientPageloadTxnPromise;
381+
expect(clientPageloadTxn).toMatchObject({
382+
transaction: '/blog/my-post',
383+
transaction_info: { source: 'custom' },
384+
});
385+
});
372386
});
Lines changed: 53 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
1-
import { browserTracingIntegration as originalBrowserTracingIntegration, WINDOW } from '@sentry/browser';
1+
import {
2+
browserTracingIntegration as originalBrowserTracingIntegration,
3+
startBrowserTracingPageLoadSpan,
4+
WINDOW,
5+
} from '@sentry/browser';
26
import type { Integration, TransactionSource } from '@sentry/core';
3-
import { debug, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE } from '@sentry/core';
7+
import {
8+
browserPerformanceTimeOrigin,
9+
debug,
10+
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
11+
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
12+
} from '@sentry/core';
413
import { DEBUG_BUILD } from '../debug-build';
514

615
/**
@@ -18,35 +27,53 @@ function getMetaContent(metaName: string): string | undefined {
1827
export function browserTracingIntegration(
1928
options: Parameters<typeof originalBrowserTracingIntegration>[0] = {},
2029
): Integration {
21-
const integration = originalBrowserTracingIntegration(options);
30+
const integration = originalBrowserTracingIntegration({ ...options, instrumentPageLoad: false });
2231

2332
return {
2433
...integration,
25-
setup(client) {
26-
// Original integration setup call
27-
integration.setup?.(client);
28-
29-
client.on('afterStartPageLoadSpan', pageLoadSpan => {
30-
const routeNameFromMetaTags = getMetaContent('sentry-route-name');
31-
32-
if (routeNameFromMetaTags) {
33-
let decodedRouteName;
34-
try {
35-
decodedRouteName = decodeURIComponent(routeNameFromMetaTags);
36-
} catch {
37-
// We ignore errors here, e.g. if the value cannot be URL decoded.
38-
return;
39-
}
40-
41-
DEBUG_BUILD && debug.log(`[Tracing] Using route name from Sentry HTML meta-tag: ${decodedRouteName}`);
42-
43-
pageLoadSpan.updateName(decodedRouteName);
44-
pageLoadSpan.setAttributes({
45-
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route' as TransactionSource,
46-
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.pageload.astro',
34+
afterAllSetup(client) {
35+
// Original integration afterAllSetup call
36+
integration.afterAllSetup?.(client);
37+
38+
if (WINDOW.location) {
39+
if (options.instrumentPageLoad != false) {
40+
const origin = browserPerformanceTimeOrigin();
41+
42+
const { name, source } = getPageloadSpanName();
43+
44+
startBrowserTracingPageLoadSpan(client, {
45+
name,
46+
// pageload should always start at timeOrigin (and needs to be in s, not ms)
47+
startTime: origin ? origin / 1000 : undefined,
48+
attributes: {
49+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,
50+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.pageload.astro',
51+
},
4752
});
4853
}
49-
});
54+
}
5055
},
5156
};
5257
}
58+
59+
function getPageloadSpanName(): { name: string; source: TransactionSource } {
60+
try {
61+
const routeNameFromMetaTags = getMetaContent('sentry-route-name');
62+
if (routeNameFromMetaTags) {
63+
const decodedRouteName = decodeURIComponent(routeNameFromMetaTags);
64+
65+
DEBUG_BUILD && debug.log(`[Tracing] Using route name from Sentry HTML meta-tag: ${decodedRouteName}`);
66+
67+
return {
68+
name: decodedRouteName,
69+
source: 'route',
70+
};
71+
}
72+
} catch {
73+
// fail silently if decoding or reading the meta tag fails
74+
}
75+
return {
76+
name: WINDOW.location.pathname,
77+
source: 'url',
78+
};
79+
}

0 commit comments

Comments
 (0)