-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
meta.ts
86 lines (78 loc) · 2.9 KB
/
meta.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import {
getDynamicSamplingContextFromClient,
getDynamicSamplingContextFromSpan,
getRootSpan,
spanToTraceHeader,
} from '@sentry/core';
import type { Client, Scope, Span } from '@sentry/types';
import {
TRACEPARENT_REGEXP,
dynamicSamplingContextToSentryBaggageHeader,
generateSentryTraceHeader,
logger,
} from '@sentry/utils';
/**
* Extracts the tracing data from the current span or from the client's scope
* (via transaction or propagation context) and renders the data to <meta> tags.
*
* This function creates two serialized <meta> tags:
* - `<meta name="sentry-trace" content="..."/>`
* - `<meta name="baggage" content="..."/>`
*
* TODO: Extract this later on and export it from the Core or Node SDK
*
* @param span the currently active span
* @param client the SDK's client
*
* @returns an object with the two serialized <meta> tags
*/
export function getTracingMetaTags(
span: Span | undefined,
scope: Scope,
client: Client | undefined,
): { sentryTrace: string; baggage?: string } {
const { dsc, sampled, traceId } = scope.getPropagationContext();
const rootSpan = span && getRootSpan(span);
const sentryTrace = span ? spanToTraceHeader(span) : generateSentryTraceHeader(traceId, undefined, sampled);
const dynamicSamplingContext = rootSpan
? getDynamicSamplingContextFromSpan(rootSpan)
: dsc
? dsc
: client
? getDynamicSamplingContextFromClient(traceId, client)
: undefined;
const baggage = dynamicSamplingContextToSentryBaggageHeader(dynamicSamplingContext);
const isValidSentryTraceHeader = TRACEPARENT_REGEXP.test(sentryTrace);
if (!isValidSentryTraceHeader) {
logger.warn('Invalid sentry-trace data. Returning empty <meta name="sentry-trace"/> tag');
}
const validBaggage = isValidBaggageString(baggage);
if (!validBaggage) {
logger.warn('Invalid baggage data. Returning empty <meta name="baggage"/> tag');
}
return {
sentryTrace: `<meta name="sentry-trace" content="${isValidSentryTraceHeader ? sentryTrace : ''}"/>`,
baggage: baggage && `<meta name="baggage" content="${validBaggage ? baggage : ''}"/>`,
};
}
/**
* Tests string against baggage spec as defined in:
*
* - W3C Baggage grammar: https://www.w3.org/TR/baggage/#definition
* - RFC7230 token definition: https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6
*
* exported for testing
*/
export function isValidBaggageString(baggage?: string): boolean {
if (!baggage || !baggage.length) {
return false;
}
const keyRegex = "[-!#$%&'*+.^_`|~A-Za-z0-9]+";
const valueRegex = '[!#-+-./0-9:<=>?@A-Z\\[\\]a-z{-}]+';
const spaces = '\\s*';
// eslint-disable-next-line @sentry-internal/sdk/no-regexp-constructor -- RegExp for readability, no user input
const baggageRegex = new RegExp(
`^${keyRegex}${spaces}=${spaces}${valueRegex}(${spaces},${spaces}${keyRegex}${spaces}=${spaces}${valueRegex})*$`,
);
return baggageRegex.test(baggage);
}