Skip to content

Commit 71af30f

Browse files
authored
feat(solidstart): Add server action instrumentation helper (#13035)
Can be used like this: ```js const getUserData = async () => { 'use server'; return await withServerActionInstrumentation('getData', () => { return { prefecture: 'Kanagawa' }; }); }; ``` Can also be used for api routes like this: ```js export async function GET() { return await withServerActionInstrumentation('getUser', () => { return json({ prefecture: 'Akita' }) }) } ```
1 parent 7dc6a25 commit 71af30f

File tree

16 files changed

+392
-7
lines changed

16 files changed

+392
-7
lines changed

dev-packages/e2e-tests/test-applications/solidstart/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"This is currently not an issue outside of our repo. See: https://github.com/nksaraf/vinxi/issues/177"
1212
],
1313
"preview": "HOST=localhost PORT=3030 NODE_OPTIONS='--import ./src/instrument.server.mjs' vinxi dev",
14+
"start": "HOST=localhost PORT=3030 NODE_OPTIONS='--import ./src/instrument.server.mjs' vinxi start",
1415
"test:prod": "TEST_ENV=production playwright test",
1516
"test:build": "pnpm install && npx playwright install && pnpm build",
1617
"test:assert": "pnpm test:prod"
@@ -31,7 +32,7 @@
3132
"jsdom": "^24.0.0",
3233
"solid-js": "1.8.17",
3334
"typescript": "^5.4.5",
34-
"vinxi": "^0.3.12",
35+
"vinxi": "^0.4.0",
3536
"vite": "^5.2.8",
3637
"vite-plugin-solid": "^2.10.2",
3738
"vitest": "^1.5.0"

dev-packages/e2e-tests/test-applications/solidstart/src/entry-client.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Sentry.init({
1212
tunnel: 'http://localhost:3031/', // proxy server
1313
// Performance Monitoring
1414
tracesSampleRate: 1.0, // Capture 100% of the transactions
15+
debug: !!import.meta.env.DEBUG,
1516
});
1617

1718
mount(() => <StartClient />, document.getElementById('app')!);

dev-packages/e2e-tests/test-applications/solidstart/src/instrument.server.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ Sentry.init({
55
environment: 'qa', // dynamic sampling bias to keep transactions
66
tracesSampleRate: 1.0, // Capture 100% of the transactions
77
tunnel: 'http://localhost:3031/', // proxy server
8+
debug: !!process.env.DEBUG,
89
});

dev-packages/e2e-tests/test-applications/solidstart/src/routes/index.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ export default function Home() {
1111
<li>
1212
<A href="/client-error">Client error</A>
1313
</li>
14+
<li>
15+
<A href="/server-error">Server error</A>
16+
</li>
1417
<li>
1518
<A id="navLink" href="/users/5">
1619
User 5
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { withServerActionInstrumentation } from '@sentry/solidstart';
2+
import { createAsync } from '@solidjs/router';
3+
4+
const getPrefecture = async () => {
5+
'use server';
6+
return await withServerActionInstrumentation('getPrefecture', () => {
7+
throw new Error('Error thrown from Solid Start E2E test app server route');
8+
9+
return { prefecture: 'Kanagawa' };
10+
});
11+
};
12+
13+
export default function ServerErrorPage() {
14+
const data = createAsync(() => getPrefecture());
15+
16+
return <div>Prefecture: {data()?.prefecture}</div>;
17+
}
Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
1-
import { useParams } from '@solidjs/router';
1+
import { withServerActionInstrumentation } from '@sentry/solidstart';
2+
import { createAsync, useParams } from '@solidjs/router';
23

4+
const getPrefecture = async () => {
5+
'use server';
6+
return await withServerActionInstrumentation('getPrefecture', () => {
7+
return { prefecture: 'Ehime' };
8+
});
9+
};
310
export default function User() {
411
const params = useParams();
5-
return <div>User ID: {params.id}</div>;
12+
const userData = createAsync(() => getPrefecture());
13+
14+
return (
15+
<div>
16+
User ID: {params.id}
17+
<br />
18+
Prefecture: {userData()?.prefecture}
19+
</div>
20+
);
621
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { expect, test } from '@playwright/test';
2+
import { waitForError } from '@sentry-internal/test-utils';
3+
4+
test.describe('server-side errors', () => {
5+
test('captures server action error', async ({ page }) => {
6+
const errorEventPromise = waitForError('solidstart', errorEvent => {
7+
return errorEvent?.exception?.values?.[0]?.value === 'Error thrown from Solid Start E2E test app server route';
8+
});
9+
10+
await page.goto(`/server-error`);
11+
12+
const error = await errorEventPromise;
13+
14+
expect(error.tags).toMatchObject({ runtime: 'node' });
15+
expect(error).toMatchObject({
16+
exception: {
17+
values: [
18+
{
19+
type: 'Error',
20+
value: 'Error thrown from Solid Start E2E test app server route',
21+
mechanism: {
22+
type: 'solidstart',
23+
handled: false,
24+
},
25+
},
26+
],
27+
},
28+
transaction: 'GET /server-error',
29+
});
30+
});
31+
});
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { expect, test } from '@playwright/test';
2+
import { waitForTransaction } from '@sentry-internal/test-utils';
3+
import {
4+
SEMANTIC_ATTRIBUTE_SENTRY_OP,
5+
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
6+
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
7+
} from '@sentry/core';
8+
9+
test('sends a server action transaction on pageload', async ({ page }) => {
10+
const transactionPromise = waitForTransaction('solidstart', transactionEvent => {
11+
return transactionEvent?.transaction === 'GET /users/6';
12+
});
13+
14+
await page.goto('/users/6');
15+
16+
const transaction = await transactionPromise;
17+
18+
expect(transaction.spans).toEqual(
19+
expect.arrayContaining([
20+
expect.objectContaining({
21+
description: 'getPrefecture',
22+
data: {
23+
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.server_action',
24+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.solidstart',
25+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'component',
26+
},
27+
}),
28+
]),
29+
);
30+
});
31+
32+
test('sends a server action transaction on client navigation', async ({ page }) => {
33+
const transactionPromise = waitForTransaction('solidstart', transactionEvent => {
34+
return transactionEvent?.transaction === 'POST getPrefecture';
35+
});
36+
37+
await page.goto('/');
38+
await page.locator('#navLink').click();
39+
await page.waitForURL('/users/5');
40+
41+
const transaction = await transactionPromise;
42+
43+
expect(transaction.spans).toEqual(
44+
expect.arrayContaining([
45+
expect.objectContaining({
46+
description: 'getPrefecture',
47+
data: {
48+
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.server_action',
49+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.solidstart',
50+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'component',
51+
},
52+
}),
53+
]),
54+
);
55+
});

packages/solidstart/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@
7272
"@sentry/solid": "8.20.0",
7373
"@sentry/types": "8.20.0",
7474
"@sentry/utils": "8.20.0",
75-
"@sentry/vite-plugin": "2.19.0"
75+
"@sentry/vite-plugin": "2.19.0",
76+
"@opentelemetry/instrumentation": "^0.52.1"
7677
},
7778
"devDependencies": {
7879
"@solidjs/router": "^0.13.4",

packages/solidstart/rollup.npm.config.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export default makeNPMConfigVariants(
1616
// prevent this internal code from ending up in our built package (this doesn't happen automatially because
1717
// the name doesn't match an SDK dependency)
1818
packageSpecificConfig: {
19-
external: ['solid-js', '@sentry/solid', '@sentry/solid/solidrouter'],
19+
external: ['solid-js/web', 'solid-js', '@sentry/solid', '@sentry/solid/solidrouter'],
2020
output: {
2121
dynamicImportInCjs: true,
2222
},

0 commit comments

Comments
 (0)