Skip to content

Commit 05684d4

Browse files
Lms24andreiborza
andauthored
feat(core): Add getTraceMetaTags function (#13201)
Export function `getTraceMetaTags` that gives users an easy way to get stringified Html meta tags for server->client trace propagation. --------- Co-authored-by: Andrei <168741329+andreiborza@users.noreply.github.com>
1 parent 64d80dd commit 05684d4

File tree

16 files changed

+138
-12
lines changed

16 files changed

+138
-12
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
const { loggingTransport } = require('@sentry-internal/node-integration-tests');
2+
const Sentry = require('@sentry/node');
3+
4+
Sentry.init({
5+
dsn: 'https://public@dsn.ingest.sentry.io/1337',
6+
tracesSampleRate: 1.0,
7+
transport: loggingTransport,
8+
});
9+
10+
// express must be required after Sentry is initialized
11+
const express = require('express');
12+
const { startExpressServerAndSendPortToRunner } = require('@sentry-internal/node-integration-tests');
13+
14+
const app = express();
15+
16+
app.get('/test', (_req, res) => {
17+
res.send({
18+
response: `
19+
<html>
20+
<head>
21+
${Sentry.getTraceMetaTags()}
22+
</head>
23+
<body>
24+
Hi :)
25+
</body>
26+
</html>
27+
`,
28+
});
29+
});
30+
31+
Sentry.setupExpressErrorHandler(app);
32+
33+
startExpressServerAndSendPortToRunner(app);
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { cleanupChildProcesses, createRunner } from '../../../utils/runner';
2+
3+
describe('getTraceMetaTags', () => {
4+
afterAll(() => {
5+
cleanupChildProcesses();
6+
});
7+
8+
test('injects sentry tracing <meta> tags', async () => {
9+
const traceId = 'cd7ee7a6fe3ebe7ab9c3271559bc203c';
10+
const parentSpanId = '100ff0980e7a4ead';
11+
12+
const runner = createRunner(__dirname, 'server.js').start();
13+
14+
const response = await runner.makeRequest('get', '/test', {
15+
'sentry-trace': `${traceId}-${parentSpanId}-1`,
16+
baggage: 'sentry-environment=production',
17+
});
18+
19+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
20+
// @ts-ignore
21+
const html = response?.response as unknown as string;
22+
23+
expect(html).toMatch(/<meta name="sentry-trace" content="cd7ee7a6fe3ebe7ab9c3271559bc203c-[a-z0-9]{16}-1"\/>/);
24+
expect(html).toContain('<meta name="baggage" content="sentry-environment=production"/>');
25+
});
26+
});

packages/astro/src/index.server.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export {
5656
getSpanDescendants,
5757
getSpanStatusFromHttpCode,
5858
getTraceData,
59+
getTraceMetaTags,
5960
graphqlIntegration,
6061
hapiIntegration,
6162
httpIntegration,

packages/astro/src/server/middleware.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
getActiveSpan,
77
getClient,
88
getCurrentScope,
9+
getTraceMetaTags,
910
setHttpStatus,
1011
startSpan,
1112
withIsolationScope,
@@ -14,8 +15,6 @@ import type { Client, Scope, Span, SpanAttributes } from '@sentry/types';
1415
import { addNonEnumerableProperty, objectify, stripUrlQueryAndFragment } from '@sentry/utils';
1516
import type { APIContext, MiddlewareResponseHandler } from 'astro';
1617

17-
import { getTraceData } from '@sentry/node';
18-
1918
type MiddlewareOptions = {
2019
/**
2120
* If true, the client IP will be attached to the event by calling `setUser`.
@@ -189,16 +188,13 @@ function addMetaTagToHead(htmlChunk: string, scope: Scope, client: Client, span?
189188
if (typeof htmlChunk !== 'string') {
190189
return htmlChunk;
191190
}
192-
const { 'sentry-trace': sentryTrace, baggage } = getTraceData(span, scope, client);
191+
const metaTags = getTraceMetaTags(span, scope, client);
193192

194-
if (!sentryTrace) {
193+
if (!metaTags) {
195194
return htmlChunk;
196195
}
197196

198-
const sentryTraceMeta = `<meta name="sentry-trace" content="${sentryTrace}"/>`;
199-
const baggageMeta = baggage && `<meta name="baggage" content="${baggage}"/>`;
200-
201-
const content = `<head>\n${sentryTraceMeta}`.concat(baggageMeta ? `\n${baggageMeta}` : '', '\n');
197+
const content = `<head>${metaTags}`;
202198

203199
return htmlChunk.replace('<head>', content);
204200
}

packages/astro/test/server/middleware.test.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,12 @@ describe('sentryMiddleware', () => {
3434
});
3535
vi.spyOn(SentryNode, 'getActiveSpan').mockImplementation(getSpanMock);
3636
vi.spyOn(SentryNode, 'getClient').mockImplementation(() => ({}) as Client);
37-
vi.spyOn(SentryNode, 'getTraceData').mockImplementation(() => ({
38-
'sentry-trace': '123',
39-
baggage: 'abc',
40-
}));
37+
vi.spyOn(SentryNode, 'getTraceMetaTags').mockImplementation(
38+
() => `
39+
<meta name="sentry-trace" content="123">
40+
<meta name="baggage" content="abc">
41+
`,
42+
);
4143
vi.spyOn(SentryCore, 'getDynamicSamplingContextFromSpan').mockImplementation(() => ({
4244
transaction: 'test',
4345
}));

packages/aws-serverless/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export {
2121
getGlobalScope,
2222
getIsolationScope,
2323
getTraceData,
24+
getTraceMetaTags,
2425
setCurrentClient,
2526
Scope,
2627
SDK_VERSION,

packages/bun/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export {
4141
getGlobalScope,
4242
getIsolationScope,
4343
getTraceData,
44+
getTraceMetaTags,
4445
setCurrentClient,
4546
Scope,
4647
SDK_VERSION,

packages/cloudflare/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export {
5656
getActiveSpan,
5757
getRootSpan,
5858
getTraceData,
59+
getTraceMetaTags,
5960
startSpan,
6061
startInactiveSpan,
6162
startSpanManual,

packages/core/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ export {
8383
export { parseSampleRate } from './utils/parseSampleRate';
8484
export { applySdkMetadata } from './utils/sdkMetadata';
8585
export { getTraceData } from './utils/traceData';
86+
export { getTraceMetaTags } from './utils/meta';
8687
export { DEFAULT_ENVIRONMENT } from './constants';
8788
export { addBreadcrumb } from './breadcrumbs';
8889
export { functionToStringIntegration } from './integrations/functiontostring';

packages/core/src/utils/meta.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import type { Client, Scope, Span } from '@sentry/types';
2+
import { getTraceData } from './traceData';
3+
4+
/**
5+
* Returns a string of meta tags that represent the current trace data.
6+
*
7+
* You can use this to propagate a trace from your server-side rendered Html to the browser.
8+
* This function returns up to two meta tags, `sentry-trace` and `baggage`, depending on the
9+
* current trace data state.
10+
*
11+
* @example
12+
* Usage example:
13+
*
14+
* ```js
15+
* function renderHtml() {
16+
* return `
17+
* <head>
18+
* ${getTraceMetaTags()}
19+
* </head>
20+
* `;
21+
* }
22+
* ```
23+
*
24+
*/
25+
export function getTraceMetaTags(span?: Span, scope?: Scope, client?: Client): string {
26+
return Object.entries(getTraceData(span, scope, client))
27+
.map(([key, value]) => `<meta name="${key}" content="${value}"/>`)
28+
.join('\n');
29+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { getTraceMetaTags } from '../../../src/utils/meta';
2+
import * as TraceDataModule from '../../../src/utils/traceData';
3+
4+
describe('getTraceMetaTags', () => {
5+
it('renders baggage and sentry-trace values to stringified Html meta tags', () => {
6+
jest.spyOn(TraceDataModule, 'getTraceData').mockReturnValueOnce({
7+
'sentry-trace': '12345678901234567890123456789012-1234567890123456-1',
8+
baggage: 'sentry-environment=production',
9+
});
10+
11+
expect(getTraceMetaTags()).toBe(`<meta name="sentry-trace" content="12345678901234567890123456789012-1234567890123456-1"/>
12+
<meta name="baggage" content="sentry-environment=production"/>`);
13+
});
14+
15+
it('renders just sentry-trace values to stringified Html meta tags', () => {
16+
jest.spyOn(TraceDataModule, 'getTraceData').mockReturnValueOnce({
17+
'sentry-trace': '12345678901234567890123456789012-1234567890123456-1',
18+
});
19+
20+
expect(getTraceMetaTags()).toBe(
21+
'<meta name="sentry-trace" content="12345678901234567890123456789012-1234567890123456-1"/>',
22+
);
23+
});
24+
25+
it('returns an empty string if neither sentry-trace nor baggage values are available', () => {
26+
jest.spyOn(TraceDataModule, 'getTraceData').mockReturnValueOnce({});
27+
28+
expect(getTraceMetaTags()).toBe('');
29+
});
30+
});

packages/deno/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export {
5656
getActiveSpan,
5757
getRootSpan,
5858
getTraceData,
59+
getTraceMetaTags,
5960
startSpan,
6061
startInactiveSpan,
6162
startSpanManual,

packages/google-cloud-serverless/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export {
2121
getGlobalScope,
2222
getIsolationScope,
2323
getTraceData,
24+
getTraceMetaTags,
2425
setCurrentClient,
2526
Scope,
2627
SDK_VERSION,

packages/node/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ export {
9696
getCurrentScope,
9797
getIsolationScope,
9898
getTraceData,
99+
getTraceMetaTags,
99100
withScope,
100101
withIsolationScope,
101102
captureException,

packages/sveltekit/src/server/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export {
5252
getSpanDescendants,
5353
getSpanStatusFromHttpCode,
5454
getTraceData,
55+
getTraceMetaTags,
5556
graphqlIntegration,
5657
hapiIntegration,
5758
httpIntegration,

packages/vercel-edge/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export {
5656
getActiveSpan,
5757
getRootSpan,
5858
getTraceData,
59+
getTraceMetaTags,
5960
startSpan,
6061
startInactiveSpan,
6162
startSpanManual,

0 commit comments

Comments
 (0)