Can't record custom spans with @sentry/astro
Is there an existing issue for this?
- [x] I have checked for existing issues https://github.com/getsentry/sentry-javascript/issues
- [x] I have reviewed the documentation https://docs.sentry.io/
- [x] I am using the latest SDK release https://github.com/getsentry/sentry-javascript/releases
How do you use Sentry?
Sentry Saas (sentry.io)
Which SDK are you using?
@sentry/astro
SDK Version
9.19.0
Framework Version
5.7.13
Link to Sentry event
No response
Reproduction Example/SDK Setup
Here's an Astro starter repo with the Sentry integration setup as per the instructions on the Sentry site.
https://github.com/dowski/sentry-tracing-bug
You might need your own secret+DSN configured, but after that npm run dev should let you try it out.
Steps to Reproduce
- Create a new Astro site with
npm create astro@latest - Follow the Sentry instructions to add Sentry w/ tracing
- Verified that error logging works
- Added custom trace code
- Reloaded the page
In the console log I added, I see my span typed as SentryNonRecordingSpan. I also see a warning: "Multiple browserTracingIntegration instances are not supported."
Expected Result
My custom bar span is visible in the Sentry dashboard.
Actual Result
I see lots of Astro trace spans, but not my custom one. I've tried this on a couple different times with fresh projects and I get the same result. Here's a link to a sample trace in case you can view it internally.
https://timelinedesign.sentry.io/traces/trace/d8cc48a9f65646d2a5d64506cf7f95f4/?mode=samples&pageEnd&pageStart&project=4509334607167488&query=&sort=-span.duration&source=traces&statsPeriod=14d&table=trace×tamp=1747426373.733
Thanks for writing in and providing a reproduction!
I just looked at it and the SDK reached the code path in this condition: https://github.com/getsentry/sentry-javascript/blob/c3a9682cdeeda275010ce3539a641641c255f4e8/packages/core/src/tracing/trace.ts#L299
It should not go into this code path as tracing/spans are enabled. However, the Sentry client config is initialized too late and when loading the page, this happends:
- Astro loads the script of the page and Sentry runs without the client options
- this is why you see a non-recording span. Sentry thinks that your tracing is not enabled as there is no enabling option for it
- The Sentry config is loaded
- Sentry runs again, but with the client options
This looks like this in the HTML:
<!-- 1. Includes the content of the `script` tag of the page -->
<script type="module" src="/_astro/index.astro_astro_type_script_index_0_lang.Bcqpd90i.js">
<!-- 2. Includes the content injected via `injectScript('page', ...)` and Sentry is loaded too late -->
<script type="module" src="/_astro/page.CanSrq-7.js"></script>
Ideally, we want this:
- Sentry is initialized
- Astro loads with all client options
Thanks for the investigation, @s1gr1d! Can you suggest a workaround for the time being?
@dowski I took another look at your repro to find a workaround. Astro takes the place where you add your <script> tags quite literally. So since you add this tag outside of your <Layout>, it is actually injected even outside the <html> tag in the rendered page (see "Cause"). Therefore it really is loaded before anything else, so there's no way for the SDK to come in earlier.
Cause
Original code
<script>
import * as Sentry from "@sentry/astro";
Sentry.startSpan({ name: "Bar span", op: "bar" }, (span) => {
...
});
</script>
<Layout>
<button id="error-button">Throw test error</button>
<script is:inline>
function handleClick() {
throw new Error("This is a test error");
}
document
.querySelector("#error-button")
.addEventListener("click", handleClick);
</script>
<Welcome />
</Layout>
leads to this rendered html
As you can see, the script tag is really outside of the main <html>.
Solution
To fix this, I recommend you move your <script> tag into the <Layout> or you structure your <Layout> component in a way that ensures that scripts are put into <head> but at the very bottom of <head>.
Here's the simplest fix I could find:
<Layout>
<script>
import * as Sentry from "@sentry/astro";
Sentry.startSpanManual({ name: "Bar span", op: "bar" }, (span) => {
...
});
</script>
<button id="error-button">Throw test error</button>
<script is:inline>
function handleClick() {
throw new Error("This is a test error");
}
document
.querySelector("#error-button")
.addEventListener("click", handleClick);
</script>
<Welcome />
</Layout>
Which leads to a correct script load order:
side note: There are two things that regularly trip me up when working with Astro. Just putting them here as a reminder, mostly for myself but maybe it's also helpful context:
- Astro layouts are really just components you have to embed in every page. You can do whatever you want with them. There's no implicit embedding like in meta frameworks like NextJS or SvelteKit.
-
<script>tags in Astro are also just html<script>tags with some added benefits around bundling. They're not specially treated like<script>tags in Svelte or Vue templates in the sense that they're put into the right place.
I'll close this issue as this gets documented: https://github.com/getsentry/sentry-docs/pull/14143