-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
Copy pathtraceData.ts
93 lines (82 loc) · 3.24 KB
/
traceData.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
87
88
89
90
91
92
93
import type { SerializedTraceData } from '@sentry/types';
import {
TRACEPARENT_REGEXP,
dynamicSamplingContextToSentryBaggageHeader,
generateSentryTraceHeader,
logger,
} from '@sentry/utils';
import { getAsyncContextStrategy } from '../asyncContext';
import { getMainCarrier } from '../carrier';
import { getClient, getCurrentScope } from '../currentScopes';
import { isEnabled } from '../exports';
import { getDynamicSamplingContextFromClient, getDynamicSamplingContextFromSpan } from '../tracing';
import { getActiveSpan, getRootSpan, spanToTraceHeader } from './spanUtils';
/**
* Extracts trace propagation data from the current span or from the client's scope (via transaction or propagation
* context) and serializes it to `sentry-trace` and `baggage` values to strings. These values can be used to propagate
* a trace via our tracing Http headers or Html `<meta>` tags.
*
* This function also applies some validation to the generated sentry-trace and baggage values to ensure that
* only valid strings are returned.
*
* @returns an object with the tracing data values. The object keys are the name of the tracing key to be used as header
* or meta tag name.
*/
export function getTraceData(): SerializedTraceData {
if (!isEnabled()) {
return {};
}
const carrier = getMainCarrier();
const acs = getAsyncContextStrategy(carrier);
if (acs.getTraceData) {
return acs.getTraceData();
}
const client = getClient();
const scope = getCurrentScope();
const span = getActiveSpan();
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. Cannot generate trace data');
return {};
}
const validBaggage = isValidBaggageString(baggage);
if (!validBaggage) {
logger.warn('Invalid baggage data. Not returning "baggage" value');
}
return {
'sentry-trace': sentryTrace,
...(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);
}