8000 feat(sveltekit): Add meta tag for backend -> frontend (#7574) · bertho-zero/sentry-javascript@11704a3 · GitHub
[go: up one dir, main page]

Skip to content

Commit 11704a3

Browse files
authored
feat(sveltekit): Add meta tag for backend -> frontend (getsentry#7574)
1 parent dce26c9 commit 11704a3

File tree

2 files changed

+75
-17
lines changed

2 files changed

+75
-17
lines changed

packages/sveltekit/src/server/handle.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
/* eslint-disable @sentry-internal/sdk/no-optional-chaining */
22
import type { Span } from '@sentry/core';
3-
import { trace } from '@sentry/core';
3+
import { getActiveTransaction, trace } from '@sentry/core';
44
import { captureException } from '@sentry/node';
55
import {
66
addExceptionMechanism,
77
baggageHeaderToDynamicSamplingContext,
8+
dynamicSamplingContextToSentryBaggageHeader,
89
extractTraceparentData,
910
objectify,
1011
} from '@sentry/utils';
11-
import type { Handle } from '@sveltejs/kit';
12+
import type { Handle, ResolveOptions } from '@sveltejs/kit';
1213
import * as domain from 'domain';
1314

1415
function sendErrorToSentry(e: unknown): unknown {
@@ -34,6 +35,20 @@ function sendErrorToSentry(e: unknown): unknown {
3435
return objectifiedErr;
3536
}
3637

38+
export const transformPageChunk: NonNullable<ResolveOptions['transformPageChunk']> = ({ html }) => {
39+
const transaction = getActiveTransaction();
40+
if (transaction) {
41+
const traceparentData = transaction.toTraceparent();
42+
const dynamicSamplingContext = dynamicSamplingContextToSentryBaggageHeader(transaction.getDynamicSamplingContext());
43+
const content = `<meta name="sentry-trace" content="${traceparentData}"/>
44+
<meta name="baggage" content="${dynamicSamplingContext}"/>
45+
%sveltekit.head%`;
46+
return html.replace('%sveltekit.head%', content);
47+
}
48+
49+
return html;
50+
};
51+
3752
/**
3853
* A SvelteKit handle function that wraps the request for Sentry error and
3954
* performance monitoring.
@@ -68,7 +83,7 @@ export const sentryHandle: Handle = ({ event, resolve }) => {
6883
},
6984
},
7085
async (span?: Span) => {
71-
const res = await resolve(event);
86+
const res = await resolve(event, { transformPageChunk });
7287
if (span) {
7388
span.setHttpStatus(res.status);
7489
}

packages/sveltekit/test/server/handle.test.ts

Lines changed: 57 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { Transaction } from '@sentry/types';
44
import type { Handle } from '@sveltejs/kit';
55
import { vi } from 'vitest';
66

7-
import { sentryHandle } from '../../src/server/handle';
7+
import { sentryHandle, transformPageChunk } from '../../src/server/handle';
88
import { getDefaultNodeClientOptions } from '../utils';
99

1010
const mockCaptureException = vi.fn();
@@ -94,22 +94,22 @@ function resolve(type: Type, isError: boolean): Parameters<Handle>[0]['resolve']
9494
let hub: Hub;
9595
let client: NodeClient;
9696

97-
describe('handleSentry', () => {
98-
before 8000 All(() => {
99-
addTracingExtensions();
100-
});
97+
beforeAll(() => {
98+
addTracingExtensions();
99+
});
101100

102-
beforeEach(() => {
103-
mockScope = new Scope();
104-
const options = getDefaultNodeClientOptions({ tracesSampleRate: 1.0 });
105-
client = new NodeClient(options);
106-
hub = new Hub(client);
107-
makeMain(hub);
101+
beforeEach(() => {
102+
mockScope = new Scope();
103+
const options = getDefaultNodeClientOptions({ tracesSampleRate: 1.0 });
104+
client = new NodeClient(options);
105+
hub = new Hub(client);
106+
makeMain(hub);
108107

109-
mockCaptureException.mockClear();
110-
mockAddExceptionMechanism.mockClear();
111-
});
108+
mockCaptureException.mockClear();
109+
mockAddExceptionMechanism.mockClear();
110+
});
112111

112+
describe('handleSentry', () => {
113113
describe.each([
114114
// isSync, isError, expectedResponse
115115
[Type.Sync, true, undefined],
@@ -247,5 +247,48 @@ describe('handleSentry', () => {
247247
);
248248
}
249249
});
250+
251+
it('calls `transformPageChunk`', async () => {
252+
const mockResolve = vi.fn().mockImplementation(resolve(type, isError));
253+
const event = mockEvent();
254+
try {
255+
await sentryHandle({ event, resolve: mockResolve });
256+
} catch (e) {
257+
expect(e).toBeInstanceOf(Error);
258+
expect(e.message).toEqual(type);
259+
}
260+
261+
expect(mockResolve).toHaveBeenCalledTimes(1);
262+
expect(mockResolve).toHaveBeenCalledWith(event, { transformPageChunk: expect.any(Function) });
263+
});
264+
});
265+
});
266+
267+
describe('transformPageChunk', () => {
268+
const html = `<!DOCTYPE html>
269+
<html lang="en">
270+
<head>
271+
<meta charset="utf-8" />
272+
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
273+
<meta name="viewport" content="width=device-width" />
274+
%sveltekit.head%
275+
</head>
276+
<body data-sveltekit-preload-data="hover">
277+
<div style="display: contents">%sveltekit.body%</div>
278+
</body>
279+
</html>`;
280+
281+
it('does not add meta tags if no active transaction', () => {
282+
const transformed = transformPageChunk({ html, done: true });
283+
expect(transformed).toEqual(html);
284+
});
285+
286+
it('adds meta tags if there is an active transaction', () => {
287+
const transaction = hub.startTransaction({ name: 'test' });
288+
hub.getScope().setSpan(transaction);
289+
const transformed = transformPageChunk({ html, done: true }) as string;
290+
291+
expect(transformed.includes('<meta name="sentry-trace"')).toEqual(true);
292+
expect(transformed.includes('<meta name="baggage"')).toEqual(true);
250293
});
251294
});

0 commit comments

Comments
 (0)
0