@sentry/core 10.30.0 → 10.32.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/attributes.js +98 -0
- package/build/cjs/attributes.js.map +1 -0
- package/build/cjs/client.js +11 -6
- package/build/cjs/client.js.map +1 -1
- package/build/cjs/envelope.js +41 -7
- package/build/cjs/envelope.js.map +1 -1
- package/build/cjs/index.js +30 -0
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/integrations/eventFilters.js +1 -1
- package/build/cjs/integrations/eventFilters.js.map +1 -1
- package/build/cjs/integrations/mcp-server/correlation.js +17 -3
- package/build/cjs/integrations/mcp-server/correlation.js.map +1 -1
- package/build/cjs/integrations/mcp-server/sessionExtraction.js +44 -0
- package/build/cjs/integrations/mcp-server/sessionExtraction.js.map +1 -1
- package/build/cjs/integrations/mcp-server/transport.js +17 -3
- package/build/cjs/integrations/mcp-server/transport.js.map +1 -1
- package/build/cjs/integrations/requestdata.js +72 -6
- package/build/cjs/integrations/requestdata.js.map +1 -1
- package/build/cjs/integrations/serverSpanStreaming.js +51 -0
- package/build/cjs/integrations/serverSpanStreaming.js.map +1 -0
- package/build/cjs/semanticAttributes.js +36 -0
- package/build/cjs/semanticAttributes.js.map +1 -1
- package/build/cjs/spans/captureSpan.js +107 -0
- package/build/cjs/spans/captureSpan.js.map +1 -0
- package/build/cjs/spans/spanBuffer.js +117 -0
- package/build/cjs/spans/spanBuffer.js.map +1 -0
- package/build/cjs/spans/spanFirstUtils.js +187 -0
- package/build/cjs/spans/spanFirstUtils.js.map +1 -0
- package/build/cjs/tracing/ai/messageTruncation.js +120 -11
- package/build/cjs/tracing/ai/messageTruncation.js.map +1 -1
- package/build/cjs/tracing/google-genai/index.js +31 -14
- package/build/cjs/tracing/google-genai/index.js.map +1 -1
- package/build/cjs/tracing/google-genai/utils.js +24 -5
- package/build/cjs/tracing/google-genai/utils.js.map +1 -1
- package/build/cjs/tracing/sentrySpan.js +31 -0
- package/build/cjs/tracing/sentrySpan.js.map +1 -1
- package/build/cjs/tracing/trace.js +1 -0
- package/build/cjs/tracing/trace.js.map +1 -1
- package/build/cjs/tracing/vercel-ai/index.js +4 -5
- package/build/cjs/tracing/vercel-ai/index.js.map +1 -1
- package/build/cjs/tracing/vercel-ai/vercel-ai-attributes.js +0 -10
- package/build/cjs/tracing/vercel-ai/vercel-ai-attributes.js.map +1 -1
- package/build/cjs/utils/applyScopeDataToEvent.js +5 -0
- package/build/cjs/utils/applyScopeDataToEvent.js.map +1 -1
- package/build/cjs/utils/beforeSendSpan.js +36 -0
- package/build/cjs/utils/beforeSendSpan.js.map +1 -0
- package/build/cjs/utils/featureFlags.js +1 -0
- package/build/cjs/utils/featureFlags.js.map +1 -1
- package/build/cjs/utils/request.js +75 -12
- package/build/cjs/utils/request.js.map +1 -1
- package/build/cjs/utils/should-ignore-span.js +31 -9
- package/build/cjs/utils/should-ignore-span.js.map +1 -1
- package/build/cjs/utils/spanUtils.js +101 -2
- package/build/cjs/utils/spanUtils.js.map +1 -1
- package/build/cjs/utils/traceData.js +1 -4
- package/build/cjs/utils/traceData.js.map +1 -1
- package/build/cjs/utils/version.js +1 -1
- package/build/cjs/utils/version.js.map +1 -1
- package/build/esm/attributes.js +95 -0
- package/build/esm/attributes.js.map +1 -0
- package/build/esm/client.js +6 -1
- package/build/esm/client.js.map +1 -1
- package/build/esm/envelope.js +41 -8
- package/build/esm/envelope.js.map +1 -1
- package/build/esm/index.js +10 -4
- package/build/esm/index.js.map +1 -1
- package/build/esm/integrations/eventFilters.js +1 -1
- package/build/esm/integrations/eventFilters.js.map +1 -1
- package/build/esm/integrations/mcp-server/correlation.js +17 -3
- package/build/esm/integrations/mcp-server/correlation.js.map +1 -1
- package/build/esm/integrations/mcp-server/sessionExtraction.js +43 -1
- package/build/esm/integrations/mcp-server/sessionExtraction.js.map +1 -1
- package/build/esm/integrations/mcp-server/transport.js +18 -4
- package/build/esm/integrations/mcp-server/transport.js.map +1 -1
- package/build/esm/integrations/requestdata.js +72 -6
- package/build/esm/integrations/requestdata.js.map +1 -1
- package/build/esm/integrations/serverSpanStreaming.js +49 -0
- package/build/esm/integrations/serverSpanStreaming.js.map +1 -0
- package/build/esm/package.json +1 -1
- package/build/esm/semanticAttributes.js +26 -1
- package/build/esm/semanticAttributes.js.map +1 -1
- package/build/esm/spans/captureSpan.js +105 -0
- package/build/esm/spans/captureSpan.js.map +1 -0
- package/build/esm/spans/spanBuffer.js +115 -0
- package/build/esm/spans/spanBuffer.js.map +1 -0
- package/build/esm/spans/spanFirstUtils.js +183 -0
- package/build/esm/spans/spanFirstUtils.js.map +1 -0
- package/build/esm/tracing/ai/messageTruncation.js +121 -11
- package/build/esm/tracing/ai/messageTruncation.js.map +1 -1
- package/build/esm/tracing/google-genai/index.js +34 -17
- package/build/esm/tracing/google-genai/index.js.map +1 -1
- package/build/esm/tracing/google-genai/utils.js +24 -6
- package/build/esm/tracing/google-genai/utils.js.map +1 -1
- package/build/esm/tracing/sentrySpan.js +32 -1
- package/build/esm/tracing/sentrySpan.js.map +1 -1
- package/build/esm/tracing/trace.js +1 -0
- package/build/esm/tracing/trace.js.map +1 -1
- package/build/esm/tracing/vercel-ai/index.js +5 -6
- package/build/esm/tracing/vercel-ai/index.js.map +1 -1
- package/build/esm/tracing/vercel-ai/vercel-ai-attributes.js +1 -10
- package/build/esm/tracing/vercel-ai/vercel-ai-attributes.js.map +1 -1
- package/build/esm/utils/applyScopeDataToEvent.js +5 -0
- package/build/esm/utils/applyScopeDataToEvent.js.map +1 -1
- package/build/esm/utils/beforeSendSpan.js +33 -0
- package/build/esm/utils/beforeSendSpan.js.map +1 -0
- package/build/esm/utils/featureFlags.js +1 -0
- package/build/esm/utils/featureFlags.js.map +1 -1
- package/build/esm/utils/request.js +76 -13
- package/build/esm/utils/request.js.map +1 -1
- package/build/esm/utils/should-ignore-span.js +31 -9
- package/build/esm/utils/should-ignore-span.js.map +1 -1
- package/build/esm/utils/spanUtils.js +97 -3
- package/build/esm/utils/spanUtils.js.map +1 -1
- package/build/esm/utils/traceData.js +1 -4
- package/build/esm/utils/traceData.js.map +1 -1
- package/build/esm/utils/version.js +1 -1
- package/build/esm/utils/version.js.map +1 -1
- package/build/types/attributes.d.ts +2 -2
- package/build/types/attributes.d.ts.map +1 -1
- package/build/types/client.d.ts +40 -2
- package/build/types/client.d.ts.map +1 -1
- package/build/types/envelope.d.ts +6 -1
- package/build/types/envelope.d.ts.map +1 -1
- package/build/types/index.d.ts +12 -5
- package/build/types/index.d.ts.map +1 -1
- package/build/types/integrations/mcp-server/correlation.d.ts +2 -2
- package/build/types/integrations/mcp-server/correlation.d.ts.map +1 -1
- package/build/types/integrations/mcp-server/sessionExtraction.d.ts +13 -1
- package/build/types/integrations/mcp-server/sessionExtraction.d.ts.map +1 -1
- package/build/types/integrations/mcp-server/transport.d.ts.map +1 -1
- package/build/types/integrations/requestdata.d.ts.map +1 -1
- package/build/types/integrations/serverSpanStreaming.d.ts +8 -0
- package/build/types/integrations/serverSpanStreaming.d.ts.map +1 -0
- package/build/types/semanticAttributes.d.ts +21 -0
- package/build/types/semanticAttributes.d.ts.map +1 -1
- package/build/types/spans/captureSpan.d.ts +10 -0
- package/build/types/spans/captureSpan.d.ts.map +1 -0
- package/build/types/spans/spanBuffer.d.ts +31 -0
- package/build/types/spans/spanBuffer.d.ts.map +1 -0
- package/build/types/spans/spanFirstUtils.d.ts +20 -0
- package/build/types/spans/spanFirstUtils.d.ts.map +1 -0
- package/build/types/tracing/ai/messageTruncation.d.ts +0 -20
- package/build/types/tracing/ai/messageTruncation.d.ts.map +1 -1
- package/build/types/tracing/google-genai/index.d.ts.map +1 -1
- package/build/types/tracing/google-genai/utils.d.ts +25 -0
- package/build/types/tracing/google-genai/utils.d.ts.map +1 -1
- package/build/types/tracing/sentrySpan.d.ts +10 -1
- package/build/types/tracing/sentrySpan.d.ts.map +1 -1
- package/build/types/tracing/vercel-ai/index.d.ts.map +1 -1
- package/build/types/types-hoist/attributes.d.ts +19 -0
- package/build/types/types-hoist/attributes.d.ts.map +1 -0
- package/build/types/types-hoist/envelope.d.ts +22 -2
- package/build/types/types-hoist/envelope.d.ts.map +1 -1
- package/build/types/types-hoist/link.d.ts +2 -2
- package/build/types/types-hoist/link.d.ts.map +1 -1
- package/build/types/types-hoist/options.d.ts +31 -2
- package/build/types/types-hoist/options.d.ts.map +1 -1
- package/build/types/types-hoist/span.d.ts +27 -0
- package/build/types/types-hoist/span.d.ts.map +1 -1
- package/build/types/utils/applyScopeDataToEvent.d.ts.map +1 -1
- package/build/types/utils/beforeSendSpan.d.ts +22 -0
- package/build/types/utils/beforeSendSpan.d.ts.map +1 -0
- package/build/types/utils/featureFlags.d.ts.map +1 -1
- package/build/types/utils/request.d.ts +1 -1
- package/build/types/utils/request.d.ts.map +1 -1
- package/build/types/utils/should-ignore-span.d.ts +3 -3
- package/build/types/utils/should-ignore-span.d.ts.map +1 -1
- package/build/types/utils/spanUtils.d.ts +26 -2
- package/build/types/utils/spanUtils.d.ts.map +1 -1
- package/build/types/utils/traceData.d.ts.map +1 -1
- package/build/types-ts3.8/attributes.d.ts +2 -2
- package/build/types-ts3.8/client.d.ts +40 -2
- package/build/types-ts3.8/envelope.d.ts +6 -1
- package/build/types-ts3.8/index.d.ts +12 -5
- package/build/types-ts3.8/integrations/mcp-server/correlation.d.ts +2 -2
- package/build/types-ts3.8/integrations/mcp-server/sessionExtraction.d.ts +13 -1
- package/build/types-ts3.8/integrations/serverSpanStreaming.d.ts +8 -0
- package/build/types-ts3.8/semanticAttributes.d.ts +21 -0
- package/build/types-ts3.8/spans/captureSpan.d.ts +10 -0
- package/build/types-ts3.8/spans/spanBuffer.d.ts +31 -0
- package/build/types-ts3.8/spans/spanFirstUtils.d.ts +20 -0
- package/build/types-ts3.8/tracing/ai/messageTruncation.d.ts +0 -20
- package/build/types-ts3.8/tracing/google-genai/utils.d.ts +25 -0
- package/build/types-ts3.8/tracing/sentrySpan.d.ts +10 -1
- package/build/types-ts3.8/types-hoist/attributes.d.ts +19 -0
- package/build/types-ts3.8/types-hoist/envelope.d.ts +22 -2
- package/build/types-ts3.8/types-hoist/link.d.ts +2 -2
- package/build/types-ts3.8/types-hoist/options.d.ts +31 -2
- package/build/types-ts3.8/types-hoist/span.d.ts +27 -0
- package/build/types-ts3.8/utils/beforeSendSpan.d.ts +22 -0
- package/build/types-ts3.8/utils/request.d.ts +1 -1
- package/build/types-ts3.8/utils/should-ignore-span.d.ts +3 -3
- package/build/types-ts3.8/utils/spanUtils.d.ts +26 -2
- package/package.json +1 -1
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { defineIntegration } from '../integration.js';
|
|
2
|
+
import { SEMANTIC_ATTRIBUTE_USER_IP_ADDRESS, SEMANTIC_ATTRIBUTE_URL_QUERY, SEMANTIC_ATTRIBUTE_URL_FULL, SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD } from '../semanticAttributes.js';
|
|
3
|
+
import { safeSetSpanJSONAttributes } from '../spans/spanFirstUtils.js';
|
|
2
4
|
import { parseCookie } from '../utils/cookie.js';
|
|
5
|
+
import { httpHeadersToSpanAttributes } from '../utils/request.js';
|
|
3
6
|
import { getClientIPAddress, ipHeaderNames } from '../vendor/getIpAddress.js';
|
|
4
7
|
|
|
5
8
|
// TODO(v11): Change defaults based on `sendDefaultPii`
|
|
@@ -21,14 +24,67 @@ const _requestDataIntegration = ((options = {}) => {
|
|
|
21
24
|
|
|
22
25
|
return {
|
|
23
26
|
name: INTEGRATION_NAME,
|
|
27
|
+
setup(client) {
|
|
28
|
+
client.on('processSegmentSpan', (spanJSON, { scopeData }) => {
|
|
29
|
+
const { sdkProcessingMetadata = {} } = scopeData;
|
|
30
|
+
const { normalizedRequest, ipAddress } = sdkProcessingMetadata;
|
|
31
|
+
|
|
32
|
+
if (!normalizedRequest) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const includeWithDefaultPiiApplied = getIncludeWithDefaultPiiApplied(
|
|
37
|
+
include,
|
|
38
|
+
client,
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
// no need to check for include after calling `extractNormalizedRequestData`
|
|
42
|
+
// because it already internally only return what's permitted by `include`
|
|
43
|
+
const { method, url, query_string, headers, data, env } = extractNormalizedRequestData(
|
|
44
|
+
normalizedRequest,
|
|
45
|
+
includeWithDefaultPiiApplied,
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
safeSetSpanJSONAttributes(spanJSON, {
|
|
49
|
+
...(method ? { [SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD]: method } : {}),
|
|
50
|
+
...(url ? { [SEMANTIC_ATTRIBUTE_URL_FULL]: url } : {}),
|
|
51
|
+
...(query_string ? { [SEMANTIC_ATTRIBUTE_URL_QUERY]: query_string } : {}),
|
|
52
|
+
...(headers ? httpHeadersToSpanAttributes(headers, client.getOptions().sendDefaultPii) : {}),
|
|
53
|
+
// TODO: Apparently, Relay still needs Pii rule updates, so I'm leaving this out for now
|
|
54
|
+
// ...(cookies
|
|
55
|
+
// ? Object.keys(cookies).reduce(
|
|
56
|
+
// (acc, cookieName) => ({
|
|
57
|
+
// ...acc,
|
|
58
|
+
// [`http.request.header.cookie.${cookieName}`]: cookies[cookieName] ?? '',
|
|
59
|
+
// }),
|
|
60
|
+
// {} as Record<string, string>,
|
|
61
|
+
// )
|
|
62
|
+
// : {}),
|
|
63
|
+
...(include.ip
|
|
64
|
+
? {
|
|
65
|
+
[SEMANTIC_ATTRIBUTE_USER_IP_ADDRESS]:
|
|
66
|
+
(normalizedRequest.headers && getClientIPAddress(normalizedRequest.headers)) || ipAddress,
|
|
67
|
+
}
|
|
68
|
+
: {}),
|
|
69
|
+
...(data ? { 'http.request.body.content': data } : {}),
|
|
70
|
+
...(env
|
|
71
|
+
? {
|
|
72
|
+
'http.request.env': Object.keys(env).reduce(
|
|
73
|
+
(acc, key) => ({ ...acc, [key]: env[key] ?? '' }),
|
|
74
|
+
{} ,
|
|
75
|
+
),
|
|
76
|
+
}
|
|
77
|
+
: {}),
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
},
|
|
81
|
+
// TODO (span-streaming): probably fine to leave as-is for errors.
|
|
82
|
+
// For spans, we go through global context -> attribute conversion or omit this completely (TBD)
|
|
24
83
|
processEvent(event, _hint, client) {
|
|
25
84
|
const { sdkProcessingMetadata = {} } = event;
|
|
26
85
|
const { normalizedRequest, ipAddress } = sdkProcessingMetadata;
|
|
27
86
|
|
|
28
|
-
const includeWithDefaultPiiApplied =
|
|
29
|
-
...include,
|
|
30
|
-
ip: include.ip ?? client.getOptions().sendDefaultPii,
|
|
31
|
-
};
|
|
87
|
+
const includeWithDefaultPiiApplied = getIncludeWithDefaultPiiApplied(include, client);
|
|
32
88
|
|
|
33
89
|
if (normalizedRequest) {
|
|
34
90
|
addNormalizedRequestDataToEvent(event, normalizedRequest, { ipAddress }, includeWithDefaultPiiApplied);
|
|
@@ -45,6 +101,16 @@ const _requestDataIntegration = ((options = {}) => {
|
|
|
45
101
|
*/
|
|
46
102
|
const requestDataIntegration = defineIntegration(_requestDataIntegration);
|
|
47
103
|
|
|
104
|
+
const getIncludeWithDefaultPiiApplied = (
|
|
105
|
+
include
|
|
106
|
+
|
|
107
|
+
,
|
|
108
|
+
client,
|
|
109
|
+
) => ({
|
|
110
|
+
...include,
|
|
111
|
+
ip: include.ip ?? client.getOptions().sendDefaultPii,
|
|
112
|
+
});
|
|
113
|
+
|
|
48
114
|
/**
|
|
49
115
|
* Add already normalized request data to an event.
|
|
50
116
|
* This mutates the passed in event.
|
|
@@ -84,14 +150,14 @@ function extractNormalizedRequestData(
|
|
|
84
150
|
|
|
85
151
|
// Remove the Cookie header in case cookie data should not be included in the event
|
|
86
152
|
if (!include.cookies) {
|
|
87
|
-
delete
|
|
153
|
+
delete headers.cookie;
|
|
88
154
|
}
|
|
89
155
|
|
|
90
156
|
// Remove IP headers in case IP data should not be included in the event
|
|
91
157
|
if (!include.ip) {
|
|
92
158
|
ipHeaderNames.forEach(ipHeaderName => {
|
|
93
159
|
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
94
|
-
delete
|
|
160
|
+
delete headers[ipHeaderName];
|
|
95
161
|
});
|
|
96
162
|
}
|
|
97
163
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requestdata.js","sources":["../../../src/integrations/requestdata.ts"],"sourcesContent":["import { defineIntegration } from '../integration';\nimport type { Event } from '../types-hoist/event';\nimport type { IntegrationFn } from '../types-hoist/integration';\nimport type { RequestEventData } from '../types-hoist/request';\nimport { parseCookie } from '../utils/cookie';\nimport { getClientIPAddress, ipHeaderNames } from '../vendor/getIpAddress';\n\ninterface RequestDataIncludeOptions {\n cookies?: boolean;\n data?: boolean;\n headers?: boolean;\n ip?: boolean;\n query_string?: boolean;\n url?: boolean;\n}\n\ntype RequestDataIntegrationOptions = {\n /**\n * Controls what data is pulled from the request and added to the event.\n */\n include?: RequestDataIncludeOptions;\n};\n\n// TODO(v11): Change defaults based on `sendDefaultPii`\nconst DEFAULT_INCLUDE: RequestDataIncludeOptions = {\n cookies: true,\n data: true,\n headers: true,\n query_string: true,\n url: true,\n};\n\nconst INTEGRATION_NAME = 'RequestData';\n\nconst _requestDataIntegration = ((options: RequestDataIntegrationOptions = {}) => {\n const include = {\n ...DEFAULT_INCLUDE,\n ...options.include,\n };\n\n return {\n name: INTEGRATION_NAME,\n processEvent(event, _hint, client) {\n const { sdkProcessingMetadata = {} } = event;\n const { normalizedRequest, ipAddress } = sdkProcessingMetadata;\n\n const includeWithDefaultPiiApplied: RequestDataIncludeOptions = {\n ...include,\n ip: include.ip ?? client.getOptions().sendDefaultPii,\n };\n\n if (normalizedRequest) {\n addNormalizedRequestDataToEvent(event, normalizedRequest, { ipAddress }, includeWithDefaultPiiApplied);\n }\n\n return event;\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Add data about a request to an event. Primarily for use in Node-based SDKs, but included in `@sentry/core`\n * so it can be used in cross-platform SDKs like `@sentry/nextjs`.\n */\nexport const requestDataIntegration = defineIntegration(_requestDataIntegration);\n\n/**\n * Add already normalized request data to an event.\n * This mutates the passed in event.\n */\nfunction addNormalizedRequestDataToEvent(\n event: Event,\n req: RequestEventData,\n // Data that should not go into `event.request` but is somehow related to requests\n additionalData: { ipAddress?: string },\n include: RequestDataIncludeOptions,\n): void {\n event.request = {\n ...event.request,\n ...extractNormalizedRequestData(req, include),\n };\n\n if (include.ip) {\n const ip = (req.headers && getClientIPAddress(req.headers)) || additionalData.ipAddress;\n if (ip) {\n event.user = {\n ...event.user,\n ip_address: ip,\n };\n }\n }\n}\n\nfunction extractNormalizedRequestData(\n normalizedRequest: RequestEventData,\n include: RequestDataIncludeOptions,\n): RequestEventData {\n const requestData: RequestEventData = {};\n const headers = { ...normalizedRequest.headers };\n\n if (include.headers) {\n requestData.headers = headers;\n\n // Remove the Cookie header in case cookie data should not be included in the event\n if (!include.cookies) {\n delete (headers as { cookie?: string }).cookie;\n }\n\n // Remove IP headers in case IP data should not be included in the event\n if (!include.ip) {\n ipHeaderNames.forEach(ipHeaderName => {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete (headers as Record<string, unknown>)[ipHeaderName];\n });\n }\n }\n\n requestData.method = normalizedRequest.method;\n\n if (include.url) {\n requestData.url = normalizedRequest.url;\n }\n\n if (include.cookies) {\n const cookies = normalizedRequest.cookies || (headers?.cookie ? parseCookie(headers.cookie) : undefined);\n requestData.cookies = cookies || {};\n }\n\n if (include.query_string) {\n requestData.query_string = normalizedRequest.query_string;\n }\n\n if (include.data) {\n requestData.data = normalizedRequest.data;\n }\n\n return requestData;\n}\n"],"names":[],"mappings":";;;;AAuBA;AACA,MAAM,eAAe,GAA8B;AACnD,EAAE,OAAO,EAAE,IAAI;AACf,EAAE,IAAI,EAAE,IAAI;AACZ,EAAE,OAAO,EAAE,IAAI;AACf,EAAE,YAAY,EAAE,IAAI;AACpB,EAAE,GAAG,EAAE,IAAI;AACX,CAAC;;AAED,MAAM,gBAAA,GAAmB,aAAa;;AAEtC,MAAM,uBAAA,IAA2B,CAAC,OAAO,GAAkC,EAAE,KAAK;AAClF,EAAE,MAAM,UAAU;AAClB,IAAI,GAAG,eAAe;AACtB,IAAI,GAAG,OAAO,CAAC,OAAO;AACtB,GAAG;;AAEH,EAAE,OAAO;AACT,IAAI,IAAI,EAAE,gBAAgB;AAC1B,IAAI,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE;AACvC,MAAM,MAAM,EAAE,qBAAA,GAAwB,EAAC,EAAE,GAAI,KAAK;AAClD,MAAM,MAAM,EAAE,iBAAiB,EAAE,SAAA,EAAU,GAAI,qBAAqB;;AAEpE,MAAM,MAAM,4BAA4B,GAA8B;AACtE,QAAQ,GAAG,OAAO;AAClB,QAAQ,EAAE,EAAE,OAAO,CAAC,EAAA,IAAM,MAAM,CAAC,UAAU,EAAE,CAAC,cAAc;AAC5D,OAAO;;AAEP,MAAM,IAAI,iBAAiB,EAAE;AAC7B,QAAQ,+BAA+B,CAAC,KAAK,EAAE,iBAAiB,EAAE,EAAE,SAAA,EAAW,EAAE,4BAA4B,CAAC;AAC9G,MAAM;;AAEN,MAAM,OAAO,KAAK;AAClB,IAAI,CAAC;AACL,GAAG;AACH,CAAC,CAAA;;AAED;AACA;AACA;AACA;MACa,sBAAA,GAAyB,iBAAiB,CAAC,uBAAuB;;AAE/E;AACA;AACA;AACA;AACA,SAAS,+BAA+B;AACxC,EAAE,KAAK;AACP,EAAE,GAAG;AACL;AACA,EAAE,cAAc;AAChB,EAAE,OAAO;AACT,EAAQ;AACR,EAAE,KAAK,CAAC,OAAA,GAAU;AAClB,IAAI,GAAG,KAAK,CAAC,OAAO;AACpB,IAAI,GAAG,4BAA4B,CAAC,GAAG,EAAE,OAAO,CAAC;AACjD,GAAG;;AAEH,EAAE,IAAI,OAAO,CAAC,EAAE,EAAE;AAClB,IAAI,MAAM,EAAA,GAAK,CAAC,GAAG,CAAC,WAAW,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,cAAc,CAAC,SAAS;AAC3F,IAAI,IAAI,EAAE,EAAE;AACZ,MAAM,KAAK,CAAC,IAAA,GAAO;AACnB,QAAQ,GAAG,KAAK,CAAC,IAAI;AACrB,QAAQ,UAAU,EAAE,EAAE;AACtB,OAAO;AACP,IAAI;AACJ,EAAE;AACF;;AAEA,SAAS,4BAA4B;AACrC,EAAE,iBAAiB;AACnB,EAAE,OAAO;AACT,EAAoB;AACpB,EAAE,MAAM,WAAW,GAAqB,EAAE;AAC1C,EAAE,MAAM,UAAU,EAAE,GAAG,iBAAiB,CAAC,SAAS;;AAElD,EAAE,IAAI,OAAO,CAAC,OAAO,EAAE;AACvB,IAAI,WAAW,CAAC,OAAA,GAAU,OAAO;;AAEjC;AACA,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE;AAC1B,MAAM,OAAO,CAAC,OAAA,GAAgC,MAAM;AACpD,IAAI;;AAEJ;AACA,IAAI,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE;AACrB,MAAM,aAAa,CAAC,OAAO,CAAC,gBAAgB;AAC5C;AACA,QAAQ,OAAO,CAAC,OAAA,GAAoC,YAAY,CAAC;AACjE,MAAM,CAAC,CAAC;AACR,IAAI;AACJ,EAAE;;AAEF,EAAE,WAAW,CAAC,MAAA,GAAS,iBAAiB,CAAC,MAAM;;AAE/C,EAAE,IAAI,OAAO,CAAC,GAAG,EAAE;AACnB,IAAI,WAAW,CAAC,GAAA,GAAM,iBAAiB,CAAC,GAAG;AAC3C,EAAE;;AAEF,EAAE,IAAI,OAAO,CAAC,OAAO,EAAE;AACvB,IAAI,MAAM,UAAU,iBAAiB,CAAC,OAAA,KAAY,OAAO,EAAE,SAAS,WAAW,CAAC,OAAO,CAAC,MAAM,CAAA,GAAI,SAAS,CAAC;AAC5G,IAAI,WAAW,CAAC,OAAA,GAAU,OAAA,IAAW,EAAE;AACvC,EAAE;;AAEF,EAAE,IAAI,OAAO,CAAC,YAAY,EAAE;AAC5B,IAAI,WAAW,CAAC,YAAA,GAAe,iBAAiB,CAAC,YAAY;AAC7D,EAAE;;AAEF,EAAE,IAAI,OAAO,CAAC,IAAI,EAAE;AACpB,IAAI,WAAW,CAAC,IAAA,GAAO,iBAAiB,CAAC,IAAI;AAC7C,EAAE;;AAEF,EAAE,OAAO,WAAW;AACpB;;;;"}
|
|
1
|
+
{"version":3,"file":"requestdata.js","sources":["../../../src/integrations/requestdata.ts"],"sourcesContent":["import type { Client } from '../client';\nimport { defineIntegration } from '../integration';\nimport {\n SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD,\n SEMANTIC_ATTRIBUTE_URL_FULL,\n SEMANTIC_ATTRIBUTE_URL_QUERY,\n SEMANTIC_ATTRIBUTE_USER_IP_ADDRESS,\n} from '../semanticAttributes';\nimport { safeSetSpanJSONAttributes } from '../spans/spanFirstUtils';\nimport type { Event } from '../types-hoist/event';\nimport type { IntegrationFn } from '../types-hoist/integration';\nimport type { ClientOptions } from '../types-hoist/options';\nimport type { RequestEventData } from '../types-hoist/request';\nimport type { BaseTransportOptions } from '../types-hoist/transport';\nimport { parseCookie } from '../utils/cookie';\nimport { httpHeadersToSpanAttributes } from '../utils/request';\nimport { getClientIPAddress, ipHeaderNames } from '../vendor/getIpAddress';\n\ninterface RequestDataIncludeOptions {\n cookies?: boolean;\n data?: boolean;\n headers?: boolean;\n ip?: boolean;\n query_string?: boolean;\n url?: boolean;\n}\n\ntype RequestDataIntegrationOptions = {\n /**\n * Controls what data is pulled from the request and added to the event.\n */\n include?: RequestDataIncludeOptions;\n};\n\n// TODO(v11): Change defaults based on `sendDefaultPii`\nconst DEFAULT_INCLUDE: RequestDataIncludeOptions = {\n cookies: true,\n data: true,\n headers: true,\n query_string: true,\n url: true,\n};\n\nconst INTEGRATION_NAME = 'RequestData';\n\nconst _requestDataIntegration = ((options: RequestDataIntegrationOptions = {}) => {\n const include = {\n ...DEFAULT_INCLUDE,\n ...options.include,\n };\n\n return {\n name: INTEGRATION_NAME,\n setup(client) {\n client.on('processSegmentSpan', (spanJSON, { scopeData }) => {\n const { sdkProcessingMetadata = {} } = scopeData;\n const { normalizedRequest, ipAddress } = sdkProcessingMetadata;\n\n if (!normalizedRequest) {\n return;\n }\n\n const includeWithDefaultPiiApplied: RequestDataIncludeOptions = getIncludeWithDefaultPiiApplied(\n include,\n client,\n );\n\n // no need to check for include after calling `extractNormalizedRequestData`\n // because it already internally only return what's permitted by `include`\n const { method, url, query_string, headers, data, env } = extractNormalizedRequestData(\n normalizedRequest,\n includeWithDefaultPiiApplied,\n );\n\n safeSetSpanJSONAttributes(spanJSON, {\n ...(method ? { [SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD]: method } : {}),\n ...(url ? { [SEMANTIC_ATTRIBUTE_URL_FULL]: url } : {}),\n ...(query_string ? { [SEMANTIC_ATTRIBUTE_URL_QUERY]: query_string } : {}),\n ...(headers ? httpHeadersToSpanAttributes(headers, client.getOptions().sendDefaultPii) : {}),\n // TODO: Apparently, Relay still needs Pii rule updates, so I'm leaving this out for now\n // ...(cookies\n // ? Object.keys(cookies).reduce(\n // (acc, cookieName) => ({\n // ...acc,\n // [`http.request.header.cookie.${cookieName}`]: cookies[cookieName] ?? '',\n // }),\n // {} as Record<string, string>,\n // )\n // : {}),\n ...(include.ip\n ? {\n [SEMANTIC_ATTRIBUTE_USER_IP_ADDRESS]:\n (normalizedRequest.headers && getClientIPAddress(normalizedRequest.headers)) || ipAddress,\n }\n : {}),\n ...(data ? { 'http.request.body.content': data } : {}),\n ...(env\n ? {\n 'http.request.env': Object.keys(env).reduce(\n (acc, key) => ({ ...acc, [key]: env[key] ?? '' }),\n {} as Record<string, string>,\n ),\n }\n : {}),\n });\n });\n },\n // TODO (span-streaming): probably fine to leave as-is for errors.\n // For spans, we go through global context -> attribute conversion or omit this completely (TBD)\n processEvent(event, _hint, client) {\n const { sdkProcessingMetadata = {} } = event;\n const { normalizedRequest, ipAddress } = sdkProcessingMetadata;\n\n const includeWithDefaultPiiApplied: RequestDataIncludeOptions = getIncludeWithDefaultPiiApplied(include, client);\n\n if (normalizedRequest) {\n addNormalizedRequestDataToEvent(event, normalizedRequest, { ipAddress }, includeWithDefaultPiiApplied);\n }\n\n return event;\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Add data about a request to an event. Primarily for use in Node-based SDKs, but included in `@sentry/core`\n * so it can be used in cross-platform SDKs like `@sentry/nextjs`.\n */\nexport const requestDataIntegration = defineIntegration(_requestDataIntegration);\n\nconst getIncludeWithDefaultPiiApplied = (\n include: {\n cookies?: boolean;\n data?: boolean;\n headers?: boolean;\n ip?: boolean;\n query_string?: boolean;\n url?: boolean;\n },\n client: Client<ClientOptions<BaseTransportOptions>>,\n): RequestDataIncludeOptions => ({\n ...include,\n ip: include.ip ?? client.getOptions().sendDefaultPii,\n});\n\n/**\n * Add already normalized request data to an event.\n * This mutates the passed in event.\n */\nfunction addNormalizedRequestDataToEvent(\n event: Event,\n req: RequestEventData,\n // Data that should not go into `event.request` but is somehow related to requests\n additionalData: { ipAddress?: string },\n include: RequestDataIncludeOptions,\n): void {\n event.request = {\n ...event.request,\n ...extractNormalizedRequestData(req, include),\n };\n\n if (include.ip) {\n const ip = (req.headers && getClientIPAddress(req.headers)) || additionalData.ipAddress;\n if (ip) {\n event.user = {\n ...event.user,\n ip_address: ip,\n };\n }\n }\n}\n\nfunction extractNormalizedRequestData(\n normalizedRequest: RequestEventData,\n include: RequestDataIncludeOptions,\n): RequestEventData {\n const requestData: RequestEventData = {};\n const headers = { ...normalizedRequest.headers };\n\n if (include.headers) {\n requestData.headers = headers;\n\n // Remove the Cookie header in case cookie data should not be included in the event\n if (!include.cookies) {\n delete headers.cookie;\n }\n\n // Remove IP headers in case IP data should not be included in the event\n if (!include.ip) {\n ipHeaderNames.forEach(ipHeaderName => {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete headers[ipHeaderName];\n });\n }\n }\n\n requestData.method = normalizedRequest.method;\n\n if (include.url) {\n requestData.url = normalizedRequest.url;\n }\n\n if (include.cookies) {\n const cookies = normalizedRequest.cookies || (headers?.cookie ? parseCookie(headers.cookie) : undefined);\n requestData.cookies = cookies || {};\n }\n\n if (include.query_string) {\n requestData.query_string = normalizedRequest.query_string;\n }\n\n if (include.data) {\n requestData.data = normalizedRequest.data;\n }\n\n return requestData;\n}\n"],"names":[],"mappings":";;;;;;;AAkCA;AACA,MAAM,eAAe,GAA8B;AACnD,EAAE,OAAO,EAAE,IAAI;AACf,EAAE,IAAI,EAAE,IAAI;AACZ,EAAE,OAAO,EAAE,IAAI;AACf,EAAE,YAAY,EAAE,IAAI;AACpB,EAAE,GAAG,EAAE,IAAI;AACX,CAAC;;AAED,MAAM,gBAAA,GAAmB,aAAa;;AAEtC,MAAM,uBAAA,IAA2B,CAAC,OAAO,GAAkC,EAAE,KAAK;AAClF,EAAE,MAAM,UAAU;AAClB,IAAI,GAAG,eAAe;AACtB,IAAI,GAAG,OAAO,CAAC,OAAO;AACtB,GAAG;;AAEH,EAAE,OAAO;AACT,IAAI,IAAI,EAAE,gBAAgB;AAC1B,IAAI,KAAK,CAAC,MAAM,EAAE;AAClB,MAAM,MAAM,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,QAAQ,EAAE,EAAE,SAAA,EAAW,KAAK;AACnE,QAAQ,MAAM,EAAE,qBAAA,GAAwB,EAAC,EAAE,GAAI,SAAS;AACxD,QAAQ,MAAM,EAAE,iBAAiB,EAAE,SAAA,EAAU,GAAI,qBAAqB;;AAEtE,QAAQ,IAAI,CAAC,iBAAiB,EAAE;AAChC,UAAU;AACV,QAAQ;;AAER,QAAQ,MAAM,4BAA4B,GAA8B,+BAA+B;AACvG,UAAU,OAAO;AACjB,UAAU,MAAM;AAChB,SAAS;;AAET;AACA;AACA,QAAQ,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,GAAA,EAAI,GAAI,4BAA4B;AAC9F,UAAU,iBAAiB;AAC3B,UAAU,4BAA4B;AACtC,SAAS;;AAET,QAAQ,yBAAyB,CAAC,QAAQ,EAAE;AAC5C,UAAU,IAAI,MAAA,GAAS,EAAE,CAAC,sCAAsC,GAAG,MAAA,EAAO,GAAI,EAAE,CAAC;AACjF,UAAU,IAAI,GAAA,GAAM,EAAE,CAAC,2BAA2B,GAAG,GAAA,EAAI,GAAI,EAAE,CAAC;AAChE,UAAU,IAAI,YAAA,GAAe,EAAE,CAAC,4BAA4B,GAAG,YAAA,EAAa,GAAI,EAAE,CAAC;AACnF,UAAU,IAAI,OAAA,GAAU,2BAA2B,CAAC,OAAO,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC,cAAc,IAAI,EAAE,CAAC;AACtG;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU,IAAI,OAAO,CAAC;AACtB,cAAc;AACd,gBAAgB,CAAC,kCAAkC;AACnD,kBAAkB,CAAC,iBAAiB,CAAC,OAAA,IAAW,kBAAkB,CAAC,iBAAiB,CAAC,OAAO,CAAC,KAAK,SAAS;AAC3G;AACA,cAAc,EAAE,CAAC;AACjB,UAAU,IAAI,IAAA,GAAO,EAAE,2BAA2B,EAAE,IAAA,EAAK,GAAI,EAAE,CAAC;AAChE,UAAU,IAAI;AACd,cAAc;AACd,gBAAgB,kBAAkB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM;AAC3D,kBAAkB,CAAC,GAAG,EAAE,GAAG,MAAM,EAAE,GAAG,GAAG,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,CAAA,IAAK,EAAA,EAAI,CAAC;AACnE,kBAAkB,EAAC;AACnB,iBAAiB;AACjB;AACA,cAAc,EAAE,CAAC;AACjB,SAAS,CAAC;AACV,MAAM,CAAC,CAAC;AACR,IAAI,CAAC;AACL;AACA;AACA,IAAI,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE;AACvC,MAAM,MAAM,EAAE,qBAAA,GAAwB,EAAC,EAAE,GAAI,KAAK;AAClD,MAAM,MAAM,EAAE,iBAAiB,EAAE,SAAA,EAAU,GAAI,qBAAqB;;AAEpE,MAAM,MAAM,4BAA4B,GAA8B,+BAA+B,CAAC,OAAO,EAAE,MAAM,CAAC;;AAEtH,MAAM,IAAI,iBAAiB,EAAE;AAC7B,QAAQ,+BAA+B,CAAC,KAAK,EAAE,iBAAiB,EAAE,EAAE,SAAA,EAAW,EAAE,4BAA4B,CAAC;AAC9G,MAAM;;AAEN,MAAM,OAAO,KAAK;AAClB,IAAI,CAAC;AACL,GAAG;AACH,CAAC,CAAA;;AAED;AACA;AACA;AACA;MACa,sBAAA,GAAyB,iBAAiB,CAAC,uBAAuB;;AAE/E,MAAM,kCAAkC;AACxC,EAAE;;AAOA;AACF,EAAE,MAAM;AACR,MAAiC;AACjC,EAAE,GAAG,OAAO;AACZ,EAAE,EAAE,EAAE,OAAO,CAAC,EAAA,IAAM,MAAM,CAAC,UAAU,EAAE,CAAC,cAAc;AACtD,CAAC,CAAC;;AAEF;AACA;AACA;AACA;AACA,SAAS,+BAA+B;AACxC,EAAE,KAAK;AACP,EAAE,GAAG;AACL;AACA,EAAE,cAAc;AAChB,EAAE,OAAO;AACT,EAAQ;AACR,EAAE,KAAK,CAAC,OAAA,GAAU;AAClB,IAAI,GAAG,KAAK,CAAC,OAAO;AACpB,IAAI,GAAG,4BAA4B,CAAC,GAAG,EAAE,OAAO,CAAC;AACjD,GAAG;;AAEH,EAAE,IAAI,OAAO,CAAC,EAAE,EAAE;AAClB,IAAI,MAAM,EAAA,GAAK,CAAC,GAAG,CAAC,WAAW,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,cAAc,CAAC,SAAS;AAC3F,IAAI,IAAI,EAAE,EAAE;AACZ,MAAM,KAAK,CAAC,IAAA,GAAO;AACnB,QAAQ,GAAG,KAAK,CAAC,IAAI;AACrB,QAAQ,UAAU,EAAE,EAAE;AACtB,OAAO;AACP,IAAI;AACJ,EAAE;AACF;;AAEA,SAAS,4BAA4B;AACrC,EAAE,iBAAiB;AACnB,EAAE,OAAO;AACT,EAAoB;AACpB,EAAE,MAAM,WAAW,GAAqB,EAAE;AAC1C,EAAE,MAAM,UAAU,EAAE,GAAG,iBAAiB,CAAC,SAAS;;AAElD,EAAE,IAAI,OAAO,CAAC,OAAO,EAAE;AACvB,IAAI,WAAW,CAAC,OAAA,GAAU,OAAO;;AAEjC;AACA,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE;AAC1B,MAAM,OAAO,OAAO,CAAC,MAAM;AAC3B,IAAI;;AAEJ;AACA,IAAI,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE;AACrB,MAAM,aAAa,CAAC,OAAO,CAAC,gBAAgB;AAC5C;AACA,QAAQ,OAAO,OAAO,CAAC,YAAY,CAAC;AACpC,MAAM,CAAC,CAAC;AACR,IAAI;AACJ,EAAE;;AAEF,EAAE,WAAW,CAAC,MAAA,GAAS,iBAAiB,CAAC,MAAM;;AAE/C,EAAE,IAAI,OAAO,CAAC,GAAG,EAAE;AACnB,IAAI,WAAW,CAAC,GAAA,GAAM,iBAAiB,CAAC,GAAG;AAC3C,EAAE;;AAEF,EAAE,IAAI,OAAO,CAAC,OAAO,EAAE;AACvB,IAAI,MAAM,UAAU,iBAAiB,CAAC,OAAA,KAAY,OAAO,EAAE,SAAS,WAAW,CAAC,OAAO,CAAC,MAAM,CAAA,GAAI,SAAS,CAAC;AAC5G,IAAI,WAAW,CAAC,OAAA,GAAU,OAAA,IAAW,EAAE;AACvC,EAAE;;AAEF,EAAE,IAAI,OAAO,CAAC,YAAY,EAAE;AAC5B,IAAI,WAAW,CAAC,YAAA,GAAe,iBAAiB,CAAC,YAAY;AAC7D,EAAE;;AAEF,EAAE,IAAI,OAAO,CAAC,IAAI,EAAE;AACpB,IAAI,WAAW,CAAC,IAAA,GAAO,iBAAiB,CAAC,IAAI;AAC7C,EAAE;;AAEF,EAAE,OAAO,WAAW;AACpB;;;;"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { DEBUG_BUILD } from '../debug-build.js';
|
|
2
|
+
import { defineIntegration } from '../integration.js';
|
|
3
|
+
import { captureSpan } from '../spans/captureSpan.js';
|
|
4
|
+
import { SpanBuffer } from '../spans/spanBuffer.js';
|
|
5
|
+
import { isV2BeforeSendSpanCallback } from '../utils/beforeSendSpan.js';
|
|
6
|
+
import { debug } from '../utils/debug-logger.js';
|
|
7
|
+
|
|
8
|
+
const INTEGRATION_NAME = 'ServerSpanStreaming';
|
|
9
|
+
|
|
10
|
+
const _serverSpanStreamingIntegration = ((options) => {
|
|
11
|
+
return {
|
|
12
|
+
name: INTEGRATION_NAME,
|
|
13
|
+
setup(client) {
|
|
14
|
+
const clientOptions = client.getOptions();
|
|
15
|
+
const beforeSendSpan = clientOptions.beforeSendSpan;
|
|
16
|
+
|
|
17
|
+
const initialMessage = 'serverSpanStreamingIntegration requires';
|
|
18
|
+
const fallbackMsg = 'Falling back to static trace lifecycle.';
|
|
19
|
+
|
|
20
|
+
if (clientOptions.traceLifecycle !== 'stream') {
|
|
21
|
+
client.getOptions().traceLifecycle = 'static';
|
|
22
|
+
DEBUG_BUILD && debug.warn(`${initialMessage} \`traceLifecycle\` to be set to "stream"! ${fallbackMsg}`);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (beforeSendSpan && !isV2BeforeSendSpanCallback(beforeSendSpan)) {
|
|
27
|
+
client.getOptions().traceLifecycle = 'static';
|
|
28
|
+
DEBUG_BUILD &&
|
|
29
|
+
debug.warn(`${initialMessage} a beforeSendSpan callback using \`withStreamSpan\`! ${fallbackMsg}`);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const buffer = new SpanBuffer(client, options);
|
|
34
|
+
|
|
35
|
+
client.on('enqueueSpan', spanJSON => {
|
|
36
|
+
buffer.addSpan(spanJSON);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
client.on('afterSpanEnd', span => {
|
|
40
|
+
captureSpan(span, client);
|
|
41
|
+
});
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}) ;
|
|
45
|
+
|
|
46
|
+
const serverSpanStreamingIntegration = defineIntegration(_serverSpanStreamingIntegration);
|
|
47
|
+
|
|
48
|
+
export { serverSpanStreamingIntegration };
|
|
49
|
+
//# sourceMappingURL=serverSpanStreaming.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serverSpanStreaming.js","sources":["../../../src/integrations/serverSpanStreaming.ts"],"sourcesContent":["import { DEBUG_BUILD } from '../debug-build';\nimport { defineIntegration } from '../integration';\nimport { captureSpan } from '../spans/captureSpan';\nimport { SpanBuffer } from '../spans/spanBuffer';\nimport type { IntegrationFn } from '../types-hoist/integration';\nimport { isV2BeforeSendSpanCallback } from '../utils/beforeSendSpan';\nimport { debug } from '../utils/debug-logger';\n\nexport interface ServerSpanStreamingOptions {\n /** Max spans per envelope batch (default: 1000) */\n maxSpanLimit?: number;\n /** Flush interval in ms (default: 5000) */\n flushInterval?: number;\n}\n\nconst INTEGRATION_NAME = 'ServerSpanStreaming';\n\nconst _serverSpanStreamingIntegration = ((options?: ServerSpanStreamingOptions) => {\n return {\n name: INTEGRATION_NAME,\n setup(client) {\n const clientOptions = client.getOptions();\n const beforeSendSpan = clientOptions.beforeSendSpan;\n\n const initialMessage = 'serverSpanStreamingIntegration requires';\n const fallbackMsg = 'Falling back to static trace lifecycle.';\n\n if (clientOptions.traceLifecycle !== 'stream') {\n client.getOptions().traceLifecycle = 'static';\n DEBUG_BUILD && debug.warn(`${initialMessage} \\`traceLifecycle\\` to be set to \"stream\"! ${fallbackMsg}`);\n return;\n }\n\n if (beforeSendSpan && !isV2BeforeSendSpanCallback(beforeSendSpan)) {\n client.getOptions().traceLifecycle = 'static';\n DEBUG_BUILD &&\n debug.warn(`${initialMessage} a beforeSendSpan callback using \\`withStreamSpan\\`! ${fallbackMsg}`);\n return;\n }\n\n const buffer = new SpanBuffer(client, options);\n\n client.on('enqueueSpan', spanJSON => {\n buffer.addSpan(spanJSON);\n });\n\n client.on('afterSpanEnd', span => {\n captureSpan(span, client);\n });\n },\n };\n}) satisfies IntegrationFn;\n\nexport const serverSpanStreamingIntegration = defineIntegration(_serverSpanStreamingIntegration);\n"],"names":[],"mappings":";;;;;;;AAeA,MAAM,gBAAA,GAAmB,qBAAqB;;AAE9C,MAAM,mCAAmC,CAAC,OAAO,KAAkC;AACnF,EAAE,OAAO;AACT,IAAI,IAAI,EAAE,gBAAgB;AAC1B,IAAI,KAAK,CAAC,MAAM,EAAE;AAClB,MAAM,MAAM,aAAA,GAAgB,MAAM,CAAC,UAAU,EAAE;AAC/C,MAAM,MAAM,cAAA,GAAiB,aAAa,CAAC,cAAc;;AAEzD,MAAM,MAAM,cAAA,GAAiB,yCAAyC;AACtE,MAAM,MAAM,WAAA,GAAc,yCAAyC;;AAEnE,MAAM,IAAI,aAAa,CAAC,cAAA,KAAmB,QAAQ,EAAE;AACrD,QAAQ,MAAM,CAAC,UAAU,EAAE,CAAC,cAAA,GAAiB,QAAQ;AACrD,QAAQ,eAAe,KAAK,CAAC,IAAI,CAAC,CAAC,EAAA,cAAA,CAAA,2CAAA,EAAA,WAAA,CAAA,CAAA,CAAA;AACA,QAAA;AACA,MAAA;;AAEA,MAAA,IAAA,cAAA,IAAA,CAAA,0BAAA,CAAA,cAAA,CAAA,EAAA;AACA,QAAA,MAAA,CAAA,UAAA,EAAA,CAAA,cAAA,GAAA,QAAA;AACA,QAAA,WAAA;AACA,UAAA,KAAA,CAAA,IAAA,CAAA,CAAA,EAAA,cAAA,CAAA,qDAAA,EAAA,WAAA,CAAA,CAAA,CAAA;AACA,QAAA;AACA,MAAA;;AAEA,MAAA,MAAA,MAAA,GAAA,IAAA,UAAA,CAAA,MAAA,EAAA,OAAA,CAAA;;AAEA,MAAA,MAAA,CAAA,EAAA,CAAA,aAAA,EAAA,QAAA,IAAA;AACA,QAAA,MAAA,CAAA,OAAA,CAAA,QAAA,CAAA;AACA,MAAA,CAAA,CAAA;;AAEA,MAAA,MAAA,CAAA,EAAA,CAAA,cAAA,EAAA,IAAA,IAAA;AACA,QAAA,WAAA,CAAA,IAAA,EAAA,MAAA,CAAA;AACA,MAAA,CAAA,CAAA;AACA,IAAA,CAAA;AACA,GAAA;AACA,CAAA,CAAA;;AAEA,MAAA,8BAAA,GAAA,iBAAA,CAAA,+BAAA;;;;"}
|
package/build/esm/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"type":"module","version":"10.
|
|
1
|
+
{"type":"module","version":"10.32.0-alpha.0","sideEffects":false}
|
|
@@ -65,6 +65,7 @@ const SEMANTIC_ATTRIBUTE_CACHE_ITEM_SIZE = 'cache.item_size';
|
|
|
65
65
|
/** TODO: Remove these once we update to latest semantic conventions */
|
|
66
66
|
const SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD = 'http.request.method';
|
|
67
67
|
const SEMANTIC_ATTRIBUTE_URL_FULL = 'url.full';
|
|
68
|
+
const SEMANTIC_ATTRIBUTE_URL_QUERY = 'url.query';
|
|
68
69
|
|
|
69
70
|
/**
|
|
70
71
|
* A span link attribute to mark the link as a special span link.
|
|
@@ -78,5 +79,29 @@ const SEMANTIC_ATTRIBUTE_URL_FULL = 'url.full';
|
|
|
78
79
|
*/
|
|
79
80
|
const SEMANTIC_LINK_ATTRIBUTE_LINK_TYPE = 'sentry.link.type';
|
|
80
81
|
|
|
81
|
-
|
|
82
|
+
// some attributes for now exclusively used for span streaming
|
|
83
|
+
// @see https://develop.sentry.dev/sdk/telemetry/spans/span-protocol/#common-attribute-keys
|
|
84
|
+
|
|
85
|
+
/** The release version of the application */
|
|
86
|
+
const SEMANTIC_ATTRIBUTE_SENTRY_RELEASE = 'sentry.release';
|
|
87
|
+
/** The environment name (e.g., "production", "staging", "development") */
|
|
88
|
+
const SEMANTIC_ATTRIBUTE_SENTRY_ENVIRONMENT = 'sentry.environment';
|
|
89
|
+
/** The segment name (e.g., "GET /users") */
|
|
90
|
+
const SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_NAME = 'sentry.segment.name';
|
|
91
|
+
/** The id of the segment that this span belongs to. */
|
|
92
|
+
const SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_ID = 'sentry.segment.id';
|
|
93
|
+
/** The user ID (gated by sendDefaultPii) */
|
|
94
|
+
const SEMANTIC_ATTRIBUTE_USER_ID = 'user.id';
|
|
95
|
+
/** The user email (gated by sendDefaultPii) */
|
|
96
|
+
const SEMANTIC_ATTRIBUTE_USER_EMAIL = 'user.email';
|
|
97
|
+
/** The user IP address (gated by sendDefaultPii) */
|
|
98
|
+
const SEMANTIC_ATTRIBUTE_USER_IP_ADDRESS = 'user.ip_address';
|
|
99
|
+
/** The user username (gated by sendDefaultPii) */
|
|
100
|
+
const SEMANTIC_ATTRIBUTE_USER_USERNAME = 'user.name';
|
|
101
|
+
/** The name of the Sentry SDK (e.g., "sentry.php", "sentry.javascript") */
|
|
102
|
+
const SEMANTIC_ATTRIBUTE_SENTRY_SDK_NAME = 'sentry.sdk.name';
|
|
103
|
+
/** The version of the Sentry SDK */
|
|
104
|
+
const SEMANTIC_ATTRIBUTE_SENTRY_SDK_VERSION = 'sentry.sdk.version';
|
|
105
|
+
|
|
106
|
+
export { SEMANTIC_ATTRIBUTE_CACHE_HIT, SEMANTIC_ATTRIBUTE_CACHE_ITEM_SIZE, SEMANTIC_ATTRIBUTE_CACHE_KEY, SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME, SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD, SEMANTIC_ATTRIBUTE_PROFILE_ID, SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME, SEMANTIC_ATTRIBUTE_SENTRY_ENVIRONMENT, SEMANTIC_ATTRIBUTE_SENTRY_IDLE_SPAN_FINISH_REASON, SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT, SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_PREVIOUS_TRACE_SAMPLE_RATE, SEMANTIC_ATTRIBUTE_SENTRY_RELEASE, SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, SEMANTIC_ATTRIBUTE_SENTRY_SDK_NAME, SEMANTIC_ATTRIBUTE_SENTRY_SDK_VERSION, SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_ID, SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_NAME, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, SEMANTIC_ATTRIBUTE_URL_FULL, SEMANTIC_ATTRIBUTE_URL_QUERY, SEMANTIC_ATTRIBUTE_USER_EMAIL, SEMANTIC_ATTRIBUTE_USER_ID, SEMANTIC_ATTRIBUTE_USER_IP_ADDRESS, SEMANTIC_ATTRIBUTE_USER_USERNAME, SEMANTIC_LINK_ATTRIBUTE_LINK_TYPE };
|
|
82
107
|
//# sourceMappingURL=semanticAttributes.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"semanticAttributes.js","sources":["../../src/semanticAttributes.ts"],"sourcesContent":["/**\n * Use this attribute to represent the source of a span.\n * Should be one of: custom, url, route, view, component, task, unknown\n *\n */\nexport const SEMANTIC_ATTRIBUTE_SENTRY_SOURCE = 'sentry.source';\n\n/**\n * Attributes that holds the sample rate that was locally applied to a span.\n * If this attribute is not defined, it means that the span inherited a sampling decision.\n *\n * NOTE: Is only defined on root spans.\n */\nexport const SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE = 'sentry.sample_rate';\n\n/**\n * Attribute holding the sample rate of the previous trace.\n * This is used to sample consistently across subsequent traces in the browser SDK.\n *\n * Note: Only defined on root spans, if opted into consistent sampling\n */\nexport const SEMANTIC_ATTRIBUTE_SENTRY_PREVIOUS_TRACE_SAMPLE_RATE = 'sentry.previous_trace_sample_rate';\n\n/**\n * Use this attribute to represent the operation of a span.\n */\nexport const SEMANTIC_ATTRIBUTE_SENTRY_OP = 'sentry.op';\n\n/**\n * Use this attribute to represent the origin of a span.\n */\nexport const SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN = 'sentry.origin';\n\n/** The reason why an idle span finished. */\nexport const SEMANTIC_ATTRIBUTE_SENTRY_IDLE_SPAN_FINISH_REASON = 'sentry.idle_span_finish_reason';\n\n/** The unit of a measurement, which may be stored as a TimedEvent. */\nexport const SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT = 'sentry.measurement_unit';\n\n/** The value of a measurement, which may be stored as a TimedEvent. */\nexport const SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE = 'sentry.measurement_value';\n\n/**\n * A custom span name set by users guaranteed to be taken over any automatically\n * inferred name. This attribute is removed before the span is sent.\n *\n * @internal only meant for internal SDK usage\n * @hidden\n */\nexport const SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME = 'sentry.custom_span_name';\n\n/**\n * The id of the profile that this span occurred in.\n */\nexport const SEMANTIC_ATTRIBUTE_PROFILE_ID = 'sentry.profile_id';\n\nexport const SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME = 'sentry.exclusive_time';\n\nexport const SEMANTIC_ATTRIBUTE_CACHE_HIT = 'cache.hit';\n\nexport const SEMANTIC_ATTRIBUTE_CACHE_KEY = 'cache.key';\n\nexport const SEMANTIC_ATTRIBUTE_CACHE_ITEM_SIZE = 'cache.item_size';\n\n/** TODO: Remove these once we update to latest semantic conventions */\nexport const SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD = 'http.request.method';\nexport const SEMANTIC_ATTRIBUTE_URL_FULL = 'url.full';\n\n/**\n * A span link attribute to mark the link as a special span link.\n *\n * Known values:\n * - `previous_trace`: The span links to the frontend root span of the previous trace.\n * - `next_trace`: The span links to the frontend root span of the next trace. (Not set by the SDK)\n *\n * Other values may be set as appropriate.\n * @see https://develop.sentry.dev/sdk/telemetry/traces/span-links/#link-types\n */\nexport const SEMANTIC_LINK_ATTRIBUTE_LINK_TYPE = 'sentry.link.type';\n"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACO,MAAM,gCAAA,GAAmC;;AAEhD;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,qCAAA,GAAwC;;AAErD;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,oDAAA,GAAuD;;AAEpE;AACA;AACA;AACO,MAAM,4BAAA,GAA+B;;AAE5C;AACA;AACA;AACO,MAAM,gCAAA,GAAmC;;AAEhD;AACO,MAAM,iDAAA,GAAoD;;AAEjE;AACO,MAAM,0CAAA,GAA6C;;AAE1D;AACO,MAAM,2CAAA,GAA8C;;AAE3D;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,0CAAA,GAA6C;;AAE1D;AACA;AACA;AACO,MAAM,6BAAA,GAAgC;;AAEtC,MAAM,iCAAA,GAAoC;;AAE1C,MAAM,4BAAA,GAA+B;;AAErC,MAAM,4BAAA,GAA+B;;AAErC,MAAM,kCAAA,GAAqC;;AAElD;AACO,MAAM,sCAAA,GAAyC;AAC/C,MAAM,2BAAA,GAA8B;;
|
|
1
|
+
{"version":3,"file":"semanticAttributes.js","sources":["../../src/semanticAttributes.ts"],"sourcesContent":["/**\n * Use this attribute to represent the source of a span.\n * Should be one of: custom, url, route, view, component, task, unknown\n *\n */\nexport const SEMANTIC_ATTRIBUTE_SENTRY_SOURCE = 'sentry.source';\n\n/**\n * Attributes that holds the sample rate that was locally applied to a span.\n * If this attribute is not defined, it means that the span inherited a sampling decision.\n *\n * NOTE: Is only defined on root spans.\n */\nexport const SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE = 'sentry.sample_rate';\n\n/**\n * Attribute holding the sample rate of the previous trace.\n * This is used to sample consistently across subsequent traces in the browser SDK.\n *\n * Note: Only defined on root spans, if opted into consistent sampling\n */\nexport const SEMANTIC_ATTRIBUTE_SENTRY_PREVIOUS_TRACE_SAMPLE_RATE = 'sentry.previous_trace_sample_rate';\n\n/**\n * Use this attribute to represent the operation of a span.\n */\nexport const SEMANTIC_ATTRIBUTE_SENTRY_OP = 'sentry.op';\n\n/**\n * Use this attribute to represent the origin of a span.\n */\nexport const SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN = 'sentry.origin';\n\n/** The reason why an idle span finished. */\nexport const SEMANTIC_ATTRIBUTE_SENTRY_IDLE_SPAN_FINISH_REASON = 'sentry.idle_span_finish_reason';\n\n/** The unit of a measurement, which may be stored as a TimedEvent. */\nexport const SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT = 'sentry.measurement_unit';\n\n/** The value of a measurement, which may be stored as a TimedEvent. */\nexport const SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE = 'sentry.measurement_value';\n\n/**\n * A custom span name set by users guaranteed to be taken over any automatically\n * inferred name. This attribute is removed before the span is sent.\n *\n * @internal only meant for internal SDK usage\n * @hidden\n */\nexport const SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME = 'sentry.custom_span_name';\n\n/**\n * The id of the profile that this span occurred in.\n */\nexport const SEMANTIC_ATTRIBUTE_PROFILE_ID = 'sentry.profile_id';\n\nexport const SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME = 'sentry.exclusive_time';\n\nexport const SEMANTIC_ATTRIBUTE_CACHE_HIT = 'cache.hit';\n\nexport const SEMANTIC_ATTRIBUTE_CACHE_KEY = 'cache.key';\n\nexport const SEMANTIC_ATTRIBUTE_CACHE_ITEM_SIZE = 'cache.item_size';\n\n/** TODO: Remove these once we update to latest semantic conventions */\nexport const SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD = 'http.request.method';\nexport const SEMANTIC_ATTRIBUTE_URL_FULL = 'url.full';\nexport const SEMANTIC_ATTRIBUTE_URL_QUERY = 'url.query';\n\n/**\n * A span link attribute to mark the link as a special span link.\n *\n * Known values:\n * - `previous_trace`: The span links to the frontend root span of the previous trace.\n * - `next_trace`: The span links to the frontend root span of the next trace. (Not set by the SDK)\n *\n * Other values may be set as appropriate.\n * @see https://develop.sentry.dev/sdk/telemetry/traces/span-links/#link-types\n */\nexport const SEMANTIC_LINK_ATTRIBUTE_LINK_TYPE = 'sentry.link.type';\n\n// some attributes for now exclusively used for span streaming\n// @see https://develop.sentry.dev/sdk/telemetry/spans/span-protocol/#common-attribute-keys\n\n/** The release version of the application */\nexport const SEMANTIC_ATTRIBUTE_SENTRY_RELEASE = 'sentry.release';\n/** The environment name (e.g., \"production\", \"staging\", \"development\") */\nexport const SEMANTIC_ATTRIBUTE_SENTRY_ENVIRONMENT = 'sentry.environment';\n/** The segment name (e.g., \"GET /users\") */\nexport const SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_NAME = 'sentry.segment.name';\n/** The id of the segment that this span belongs to. */\nexport const SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_ID = 'sentry.segment.id';\n/** The user ID (gated by sendDefaultPii) */\nexport const SEMANTIC_ATTRIBUTE_USER_ID = 'user.id';\n/** The user email (gated by sendDefaultPii) */\nexport const SEMANTIC_ATTRIBUTE_USER_EMAIL = 'user.email';\n/** The user IP address (gated by sendDefaultPii) */\nexport const SEMANTIC_ATTRIBUTE_USER_IP_ADDRESS = 'user.ip_address';\n/** The user username (gated by sendDefaultPii) */\nexport const SEMANTIC_ATTRIBUTE_USER_USERNAME = 'user.name';\n/** The name of the Sentry SDK (e.g., \"sentry.php\", \"sentry.javascript\") */\nexport const SEMANTIC_ATTRIBUTE_SENTRY_SDK_NAME = 'sentry.sdk.name';\n/** The version of the Sentry SDK */\nexport const SEMANTIC_ATTRIBUTE_SENTRY_SDK_VERSION = 'sentry.sdk.version';\n"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACO,MAAM,gCAAA,GAAmC;;AAEhD;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,qCAAA,GAAwC;;AAErD;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,oDAAA,GAAuD;;AAEpE;AACA;AACA;AACO,MAAM,4BAAA,GAA+B;;AAE5C;AACA;AACA;AACO,MAAM,gCAAA,GAAmC;;AAEhD;AACO,MAAM,iDAAA,GAAoD;;AAEjE;AACO,MAAM,0CAAA,GAA6C;;AAE1D;AACO,MAAM,2CAAA,GAA8C;;AAE3D;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,0CAAA,GAA6C;;AAE1D;AACA;AACA;AACO,MAAM,6BAAA,GAAgC;;AAEtC,MAAM,iCAAA,GAAoC;;AAE1C,MAAM,4BAAA,GAA+B;;AAErC,MAAM,4BAAA,GAA+B;;AAErC,MAAM,kCAAA,GAAqC;;AAElD;AACO,MAAM,sCAAA,GAAyC;AAC/C,MAAM,2BAAA,GAA8B;AACpC,MAAM,4BAAA,GAA+B;;AAE5C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,iCAAA,GAAoC;;AAEjD;AACA;;AAEA;AACO,MAAM,iCAAA,GAAoC;AACjD;AACO,MAAM,qCAAA,GAAwC;AACrD;AACO,MAAM,sCAAA,GAAyC;AACtD;AACO,MAAM,oCAAA,GAAuC;AACpD;AACO,MAAM,0BAAA,GAA6B;AAC1C;AACO,MAAM,6BAAA,GAAgC;AAC7C;AACO,MAAM,kCAAA,GAAqC;AAClD;AACO,MAAM,gCAAA,GAAmC;AAChD;AACO,MAAM,kCAAA,GAAqC;AAClD;AACO,MAAM,qCAAA,GAAwC;;;;"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { getClient, getGlobalScope } from '../currentScopes.js';
|
|
2
|
+
import { DEBUG_BUILD } from '../debug-build.js';
|
|
3
|
+
import { SEMANTIC_ATTRIBUTE_USER_USERNAME, SEMANTIC_ATTRIBUTE_USER_IP_ADDRESS, SEMANTIC_ATTRIBUTE_USER_EMAIL, SEMANTIC_ATTRIBUTE_USER_ID, SEMANTIC_ATTRIBUTE_SENTRY_SDK_VERSION, SEMANTIC_ATTRIBUTE_SENTRY_SDK_NAME, SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_ID, SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_NAME, SEMANTIC_ATTRIBUTE_SENTRY_ENVIRONMENT, SEMANTIC_ATTRIBUTE_SENTRY_RELEASE } from '../semanticAttributes.js';
|
|
4
|
+
import { getCapturedScopesOnSpan } from '../tracing/utils.js';
|
|
5
|
+
import { mergeScopeData } from '../utils/applyScopeDataToEvent.js';
|
|
6
|
+
import { isV2BeforeSendSpanCallback } from '../utils/beforeSendSpan.js';
|
|
7
|
+
import { debug } from '../utils/debug-logger.js';
|
|
8
|
+
import { spanToV2JSON, INTERNAL_getSegmentSpan } from '../utils/spanUtils.js';
|
|
9
|
+
import { applyBeforeSendSpanCallback, safeSetSpanJSONAttributes, contextsToAttributes } from './spanFirstUtils.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Captures a span and returns a JSON representation to be enqueued for sending.
|
|
13
|
+
*
|
|
14
|
+
* IMPORTANT: This function converts the span to JSON immediately to avoid writing
|
|
15
|
+
* to an already-ended OTel span instance (which is blocked by the OTel Span class).
|
|
16
|
+
*/
|
|
17
|
+
function captureSpan(span, client = getClient()) {
|
|
18
|
+
if (!client) {
|
|
19
|
+
DEBUG_BUILD && debug.warn('No client available to capture span.');
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Convert to JSON FIRST - we cannot write to an already-ended span
|
|
24
|
+
const spanJSON = spanToV2JSON(span);
|
|
25
|
+
|
|
26
|
+
const segmentSpan = INTERNAL_getSegmentSpan(span);
|
|
27
|
+
const serializedSegmentSpan = spanToV2JSON(segmentSpan);
|
|
28
|
+
|
|
29
|
+
const { isolationScope: spanIsolationScope, scope: spanScope } = getCapturedScopesOnSpan(span);
|
|
30
|
+
|
|
31
|
+
const finalScopeData = getFinalScopeData(spanIsolationScope, spanScope);
|
|
32
|
+
|
|
33
|
+
applyCommonSpanAttributes(spanJSON, serializedSegmentSpan, client, finalScopeData);
|
|
34
|
+
|
|
35
|
+
if (span === segmentSpan) {
|
|
36
|
+
applyScopeToSegmentSpan(spanJSON, finalScopeData);
|
|
37
|
+
client.emit('processSegmentSpan', spanJSON, { scopeData: finalScopeData });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Allow integrations to add additional data to the span JSON
|
|
41
|
+
client.emit('processSpan', spanJSON, { readOnlySpan: span });
|
|
42
|
+
|
|
43
|
+
const beforeSendSpan = client.getOptions().beforeSendSpan;
|
|
44
|
+
const processedSpan = isV2BeforeSendSpanCallback(beforeSendSpan)
|
|
45
|
+
? applyBeforeSendSpanCallback(spanJSON, beforeSendSpan)
|
|
46
|
+
: spanJSON;
|
|
47
|
+
|
|
48
|
+
const spanWithRef = {
|
|
49
|
+
...processedSpan,
|
|
50
|
+
_segmentSpan: segmentSpan,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
client.emit('enqueueSpan', spanWithRef);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function applyScopeToSegmentSpan(segmentSpanJSON, scopeData) {
|
|
57
|
+
// TODO: Apply all scope and request data from auto instrumentation (contexts, request) to segment span
|
|
58
|
+
const { contexts } = scopeData;
|
|
59
|
+
|
|
60
|
+
safeSetSpanJSONAttributes(segmentSpanJSON, contextsToAttributes(contexts));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function applyCommonSpanAttributes(
|
|
64
|
+
spanJSON,
|
|
65
|
+
serializedSegmentSpan,
|
|
66
|
+
client,
|
|
67
|
+
scopeData,
|
|
68
|
+
) {
|
|
69
|
+
const sdk = client.getSdkMetadata();
|
|
70
|
+
const { release, environment, sendDefaultPii } = client.getOptions();
|
|
71
|
+
|
|
72
|
+
// avoid overwriting any previously set attributes (from users or potentially our SDK instrumentation)
|
|
73
|
+
safeSetSpanJSONAttributes(spanJSON, {
|
|
74
|
+
[SEMANTIC_ATTRIBUTE_SENTRY_RELEASE]: release,
|
|
75
|
+
[SEMANTIC_ATTRIBUTE_SENTRY_ENVIRONMENT]: environment,
|
|
76
|
+
[SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_NAME]: serializedSegmentSpan.name,
|
|
77
|
+
[SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_ID]: serializedSegmentSpan.span_id,
|
|
78
|
+
[SEMANTIC_ATTRIBUTE_SENTRY_SDK_NAME]: sdk?.sdk?.name,
|
|
79
|
+
[SEMANTIC_ATTRIBUTE_SENTRY_SDK_VERSION]: sdk?.sdk?.version,
|
|
80
|
+
...(sendDefaultPii
|
|
81
|
+
? {
|
|
82
|
+
[SEMANTIC_ATTRIBUTE_USER_ID]: scopeData.user?.id,
|
|
83
|
+
[SEMANTIC_ATTRIBUTE_USER_EMAIL]: scopeData.user?.email,
|
|
84
|
+
[SEMANTIC_ATTRIBUTE_USER_IP_ADDRESS]: scopeData.user?.ip_address,
|
|
85
|
+
[SEMANTIC_ATTRIBUTE_USER_USERNAME]: scopeData.user?.username,
|
|
86
|
+
}
|
|
87
|
+
: {}),
|
|
88
|
+
...scopeData.attributes,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// TODO: Extract this to a helper in core. It's used in multiple places.
|
|
93
|
+
function getFinalScopeData(isolationScope, scope) {
|
|
94
|
+
const finalScopeData = getGlobalScope().getScopeData();
|
|
95
|
+
if (isolationScope) {
|
|
96
|
+
mergeScopeData(finalScopeData, isolationScope.getScopeData());
|
|
97
|
+
}
|
|
98
|
+
if (scope) {
|
|
99
|
+
mergeScopeData(finalScopeData, scope.getScopeData());
|
|
100
|
+
}
|
|
101
|
+
return finalScopeData;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export { captureSpan };
|
|
105
|
+
//# sourceMappingURL=captureSpan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"captureSpan.js","sources":["../../../src/spans/captureSpan.ts"],"sourcesContent":["import type { Client } from '../client';\nimport { getClient, getGlobalScope } from '../currentScopes';\nimport { DEBUG_BUILD } from '../debug-build';\nimport type { Scope, ScopeData } from '../scope';\nimport {\n SEMANTIC_ATTRIBUTE_SENTRY_ENVIRONMENT,\n SEMANTIC_ATTRIBUTE_SENTRY_RELEASE,\n SEMANTIC_ATTRIBUTE_SENTRY_SDK_NAME,\n SEMANTIC_ATTRIBUTE_SENTRY_SDK_VERSION,\n SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_ID,\n SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_NAME,\n SEMANTIC_ATTRIBUTE_USER_EMAIL,\n SEMANTIC_ATTRIBUTE_USER_ID,\n SEMANTIC_ATTRIBUTE_USER_IP_ADDRESS,\n SEMANTIC_ATTRIBUTE_USER_USERNAME,\n} from '../semanticAttributes';\nimport { getCapturedScopesOnSpan } from '../tracing/utils';\nimport type { Span, SpanV2JSON } from '../types-hoist/span';\nimport { mergeScopeData } from '../utils/applyScopeDataToEvent';\nimport { isV2BeforeSendSpanCallback } from '../utils/beforeSendSpan';\nimport { debug } from '../utils/debug-logger';\nimport { INTERNAL_getSegmentSpan, spanToV2JSON } from '../utils/spanUtils';\nimport { applyBeforeSendSpanCallback, contextsToAttributes, safeSetSpanJSONAttributes } from './spanFirstUtils';\n/**\n * Captures a span and returns a JSON representation to be enqueued for sending.\n *\n * IMPORTANT: This function converts the span to JSON immediately to avoid writing\n * to an already-ended OTel span instance (which is blocked by the OTel Span class).\n */\nexport function captureSpan(span: Span, client = getClient()): void {\n if (!client) {\n DEBUG_BUILD && debug.warn('No client available to capture span.');\n return;\n }\n\n // Convert to JSON FIRST - we cannot write to an already-ended span\n const spanJSON = spanToV2JSON(span);\n\n const segmentSpan = INTERNAL_getSegmentSpan(span);\n const serializedSegmentSpan = spanToV2JSON(segmentSpan);\n\n const { isolationScope: spanIsolationScope, scope: spanScope } = getCapturedScopesOnSpan(span);\n\n const finalScopeData = getFinalScopeData(spanIsolationScope, spanScope);\n\n applyCommonSpanAttributes(spanJSON, serializedSegmentSpan, client, finalScopeData);\n\n if (span === segmentSpan) {\n applyScopeToSegmentSpan(spanJSON, finalScopeData);\n client.emit('processSegmentSpan', spanJSON, { scopeData: finalScopeData });\n }\n\n // Allow integrations to add additional data to the span JSON\n client.emit('processSpan', spanJSON, { readOnlySpan: span });\n\n const beforeSendSpan = client.getOptions().beforeSendSpan;\n const processedSpan = isV2BeforeSendSpanCallback(beforeSendSpan)\n ? applyBeforeSendSpanCallback(spanJSON, beforeSendSpan)\n : spanJSON;\n\n const spanWithRef = {\n ...processedSpan,\n _segmentSpan: segmentSpan,\n };\n\n client.emit('enqueueSpan', spanWithRef);\n}\n\nfunction applyScopeToSegmentSpan(segmentSpanJSON: SpanV2JSON, scopeData: ScopeData): void {\n // TODO: Apply all scope and request data from auto instrumentation (contexts, request) to segment span\n const { contexts } = scopeData;\n\n safeSetSpanJSONAttributes(segmentSpanJSON, contextsToAttributes(contexts));\n}\n\nfunction applyCommonSpanAttributes(\n spanJSON: SpanV2JSON,\n serializedSegmentSpan: SpanV2JSON,\n client: Client,\n scopeData: ScopeData,\n): void {\n const sdk = client.getSdkMetadata();\n const { release, environment, sendDefaultPii } = client.getOptions();\n\n // avoid overwriting any previously set attributes (from users or potentially our SDK instrumentation)\n safeSetSpanJSONAttributes(spanJSON, {\n [SEMANTIC_ATTRIBUTE_SENTRY_RELEASE]: release,\n [SEMANTIC_ATTRIBUTE_SENTRY_ENVIRONMENT]: environment,\n [SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_NAME]: serializedSegmentSpan.name,\n [SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_ID]: serializedSegmentSpan.span_id,\n [SEMANTIC_ATTRIBUTE_SENTRY_SDK_NAME]: sdk?.sdk?.name,\n [SEMANTIC_ATTRIBUTE_SENTRY_SDK_VERSION]: sdk?.sdk?.version,\n ...(sendDefaultPii\n ? {\n [SEMANTIC_ATTRIBUTE_USER_ID]: scopeData.user?.id,\n [SEMANTIC_ATTRIBUTE_USER_EMAIL]: scopeData.user?.email,\n [SEMANTIC_ATTRIBUTE_USER_IP_ADDRESS]: scopeData.user?.ip_address,\n [SEMANTIC_ATTRIBUTE_USER_USERNAME]: scopeData.user?.username,\n }\n : {}),\n ...scopeData.attributes,\n });\n}\n\n// TODO: Extract this to a helper in core. It's used in multiple places.\nfunction getFinalScopeData(isolationScope: Scope | undefined, scope: Scope | undefined): ScopeData {\n const finalScopeData = getGlobalScope().getScopeData();\n if (isolationScope) {\n mergeScopeData(finalScopeData, isolationScope.getScopeData());\n }\n if (scope) {\n mergeScopeData(finalScopeData, scope.getScopeData());\n }\n return finalScopeData;\n}\n"],"names":[],"mappings":";;;;;;;;;;AAuBA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,WAAW,CAAC,IAAI,EAAQ,MAAA,GAAS,SAAS,EAAE,EAAQ;AACpE,EAAE,IAAI,CAAC,MAAM,EAAE;AACf,IAAI,eAAe,KAAK,CAAC,IAAI,CAAC,sCAAsC,CAAC;AACrE,IAAI;AACJ,EAAE;;AAEF;AACA,EAAE,MAAM,QAAA,GAAW,YAAY,CAAC,IAAI,CAAC;;AAErC,EAAE,MAAM,WAAA,GAAc,uBAAuB,CAAC,IAAI,CAAC;AACnD,EAAE,MAAM,qBAAA,GAAwB,YAAY,CAAC,WAAW,CAAC;;AAEzD,EAAE,MAAM,EAAE,cAAc,EAAE,kBAAkB,EAAE,KAAK,EAAE,SAAA,EAAU,GAAI,uBAAuB,CAAC,IAAI,CAAC;;AAEhG,EAAE,MAAM,iBAAiB,iBAAiB,CAAC,kBAAkB,EAAE,SAAS,CAAC;;AAEzE,EAAE,yBAAyB,CAAC,QAAQ,EAAE,qBAAqB,EAAE,MAAM,EAAE,cAAc,CAAC;;AAEpF,EAAE,IAAI,IAAA,KAAS,WAAW,EAAE;AAC5B,IAAI,uBAAuB,CAAC,QAAQ,EAAE,cAAc,CAAC;AACrD,IAAI,MAAM,CAAC,IAAI,CAAC,oBAAoB,EAAE,QAAQ,EAAE,EAAE,SAAS,EAAE,cAAA,EAAgB,CAAC;AAC9E,EAAE;;AAEF;AACA,EAAE,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,EAAE,EAAE,YAAY,EAAE,IAAA,EAAM,CAAC;;AAE9D,EAAE,MAAM,iBAAiB,MAAM,CAAC,UAAU,EAAE,CAAC,cAAc;AAC3D,EAAE,MAAM,aAAA,GAAgB,0BAA0B,CAAC,cAAc;AACjE,MAAM,2BAA2B,CAAC,QAAQ,EAAE,cAAc;AAC1D,MAAM,QAAQ;;AAEd,EAAE,MAAM,cAAc;AACtB,IAAI,GAAG,aAAa;AACpB,IAAI,YAAY,EAAE,WAAW;AAC7B,GAAG;;AAEH,EAAE,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC;AACzC;;AAEA,SAAS,uBAAuB,CAAC,eAAe,EAAc,SAAS,EAAmB;AAC1F;AACA,EAAE,MAAM,EAAE,QAAA,EAAS,GAAI,SAAS;;AAEhC,EAAE,yBAAyB,CAAC,eAAe,EAAE,oBAAoB,CAAC,QAAQ,CAAC,CAAC;AAC5E;;AAEA,SAAS,yBAAyB;AAClC,EAAE,QAAQ;AACV,EAAE,qBAAqB;AACvB,EAAE,MAAM;AACR,EAAE,SAAS;AACX,EAAQ;AACR,EAAE,MAAM,GAAA,GAAM,MAAM,CAAC,cAAc,EAAE;AACrC,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,cAAA,EAAe,GAAI,MAAM,CAAC,UAAU,EAAE;;AAEtE;AACA,EAAE,yBAAyB,CAAC,QAAQ,EAAE;AACtC,IAAI,CAAC,iCAAiC,GAAG,OAAO;AAChD,IAAI,CAAC,qCAAqC,GAAG,WAAW;AACxD,IAAI,CAAC,sCAAsC,GAAG,qBAAqB,CAAC,IAAI;AACxE,IAAI,CAAC,oCAAoC,GAAG,qBAAqB,CAAC,OAAO;AACzE,IAAI,CAAC,kCAAkC,GAAG,GAAG,EAAE,GAAG,EAAE,IAAI;AACxD,IAAI,CAAC,qCAAqC,GAAG,GAAG,EAAE,GAAG,EAAE,OAAO;AAC9D,IAAI,IAAI;AACR,QAAQ;AACR,UAAU,CAAC,0BAA0B,GAAG,SAAS,CAAC,IAAI,EAAE,EAAE;AAC1D,UAAU,CAAC,6BAA6B,GAAG,SAAS,CAAC,IAAI,EAAE,KAAK;AAChE,UAAU,CAAC,kCAAkC,GAAG,SAAS,CAAC,IAAI,EAAE,UAAU;AAC1E,UAAU,CAAC,gCAAgC,GAAG,SAAS,CAAC,IAAI,EAAE,QAAQ;AACtE;AACA,QAAQ,EAAE,CAAC;AACX,IAAI,GAAG,SAAS,CAAC,UAAU;AAC3B,GAAG,CAAC;AACJ;;AAEA;AACA,SAAS,iBAAiB,CAAC,cAAc,EAAqB,KAAK,EAAgC;AACnG,EAAE,MAAM,iBAAiB,cAAc,EAAE,CAAC,YAAY,EAAE;AACxD,EAAE,IAAI,cAAc,EAAE;AACtB,IAAI,cAAc,CAAC,cAAc,EAAE,cAAc,CAAC,YAAY,EAAE,CAAC;AACjE,EAAE;AACF,EAAE,IAAI,KAAK,EAAE;AACb,IAAI,cAAc,CAAC,cAAc,EAAE,KAAK,CAAC,YAAY,EAAE,CAAC;AACxD,EAAE;AACF,EAAE,OAAO,cAAc;AACvB;;;;"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { DEBUG_BUILD } from '../debug-build.js';
|
|
2
|
+
import { createSpanV2Envelope } from '../envelope.js';
|
|
3
|
+
import { getDynamicSamplingContextFromSpan } from '../tracing/dynamicSamplingContext.js';
|
|
4
|
+
import { debug } from '../utils/debug-logger.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A buffer for span JSON objects that flushes them to Sentry in Span v2 envelopes.
|
|
8
|
+
* Handles interval-based flushing, size thresholds, and graceful shutdown.
|
|
9
|
+
*/
|
|
10
|
+
class SpanBuffer {
|
|
11
|
+
|
|
12
|
+
constructor(client, options) {
|
|
13
|
+
this._spanTreeMap = new Map();
|
|
14
|
+
this._client = client;
|
|
15
|
+
|
|
16
|
+
const { maxSpanLimit, flushInterval } = options ?? {};
|
|
17
|
+
|
|
18
|
+
this._maxSpanLimit = maxSpanLimit && maxSpanLimit > 0 && maxSpanLimit <= 1000 ? maxSpanLimit : 1000;
|
|
19
|
+
this._flushInterval = flushInterval && flushInterval > 0 ? flushInterval : 5000;
|
|
20
|
+
|
|
21
|
+
this._flushIntervalId = setInterval(() => {
|
|
22
|
+
this.flush();
|
|
23
|
+
}, this._flushInterval);
|
|
24
|
+
|
|
25
|
+
this._client.on('flush', () => {
|
|
26
|
+
this.flush();
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Add a span to the buffer.
|
|
32
|
+
*/
|
|
33
|
+
addSpan(spanJSON) {
|
|
34
|
+
const traceId = spanJSON.trace_id;
|
|
35
|
+
let traceBucket = this._spanTreeMap.get(traceId);
|
|
36
|
+
if (traceBucket) {
|
|
37
|
+
traceBucket.add(spanJSON);
|
|
38
|
+
} else {
|
|
39
|
+
traceBucket = new Set([spanJSON]);
|
|
40
|
+
this._spanTreeMap.set(traceId, traceBucket);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (traceBucket.size >= this._maxSpanLimit) {
|
|
44
|
+
this._flushTrace(traceId);
|
|
45
|
+
this._debounceFlushInterval();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Flush all buffered traces.
|
|
51
|
+
*/
|
|
52
|
+
flush() {
|
|
53
|
+
if (!this._spanTreeMap.size) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
DEBUG_BUILD && debug.log(`Flushing span tree map with ${this._spanTreeMap.size} traces`);
|
|
58
|
+
|
|
59
|
+
this._spanTreeMap.forEach((_, traceId) => {
|
|
60
|
+
this._flushTrace(traceId);
|
|
61
|
+
});
|
|
62
|
+
this._debounceFlushInterval();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
_flushTrace(traceId) {
|
|
66
|
+
const traceBucket = this._spanTreeMap.get(traceId);
|
|
67
|
+
if (!traceBucket) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (!traceBucket.size) {
|
|
72
|
+
this._spanTreeMap.delete(traceId);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const firstSpanJSON = traceBucket.values().next().value;
|
|
77
|
+
|
|
78
|
+
const segmentSpan = firstSpanJSON?._segmentSpan;
|
|
79
|
+
if (!segmentSpan) {
|
|
80
|
+
DEBUG_BUILD && debug.warn('No segment span reference found on span JSON, cannot compute DSC');
|
|
81
|
+
this._spanTreeMap.delete(traceId);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const dsc = getDynamicSamplingContextFromSpan(segmentSpan);
|
|
86
|
+
|
|
87
|
+
const cleanedSpans = Array.from(traceBucket).map(spanJSON => {
|
|
88
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
89
|
+
const { _segmentSpan, ...cleanSpanJSON } = spanJSON;
|
|
90
|
+
return cleanSpanJSON;
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const envelope = createSpanV2Envelope(cleanedSpans, dsc, this._client);
|
|
94
|
+
|
|
95
|
+
DEBUG_BUILD && debug.log(`Sending span envelope for trace ${traceId} with ${cleanedSpans.length} spans`);
|
|
96
|
+
|
|
97
|
+
this._client.sendEnvelope(envelope).then(null, reason => {
|
|
98
|
+
DEBUG_BUILD && debug.error('Error while sending span stream envelope:', reason);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
this._spanTreeMap.delete(traceId);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
_debounceFlushInterval() {
|
|
105
|
+
if (this._flushIntervalId) {
|
|
106
|
+
clearInterval(this._flushIntervalId);
|
|
107
|
+
}
|
|
108
|
+
this._flushIntervalId = setInterval(() => {
|
|
109
|
+
this.flush();
|
|
110
|
+
}, this._flushInterval);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export { SpanBuffer };
|
|
115
|
+
//# sourceMappingURL=spanBuffer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spanBuffer.js","sources":["../../../src/spans/spanBuffer.ts"],"sourcesContent":["import type { Client } from '../client';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { createSpanV2Envelope } from '../envelope';\nimport { getDynamicSamplingContextFromSpan } from '../tracing/dynamicSamplingContext';\nimport type { SpanV2JSON, SpanV2JSONWithSegmentRef } from '../types-hoist/span';\nimport { debug } from '../utils/debug-logger';\n\nexport interface SpanBufferOptions {\n /** Max spans per trace before auto-flush (default: 1000) */\n maxSpanLimit?: number;\n /** Flush interval in ms (default: 5000) */\n flushInterval?: number;\n}\n\n/**\n * A buffer for span JSON objects that flushes them to Sentry in Span v2 envelopes.\n * Handles interval-based flushing, size thresholds, and graceful shutdown.\n */\nexport class SpanBuffer {\n private _spanTreeMap: Map<string, Set<SpanV2JSONWithSegmentRef>>;\n private _flushIntervalId: ReturnType<typeof setInterval> | null;\n private _client: Client;\n private _maxSpanLimit: number;\n private _flushInterval: number;\n\n public constructor(client: Client, options?: SpanBufferOptions) {\n this._spanTreeMap = new Map();\n this._client = client;\n\n const { maxSpanLimit, flushInterval } = options ?? {};\n\n this._maxSpanLimit = maxSpanLimit && maxSpanLimit > 0 && maxSpanLimit <= 1000 ? maxSpanLimit : 1000;\n this._flushInterval = flushInterval && flushInterval > 0 ? flushInterval : 5_000;\n\n this._flushIntervalId = setInterval(() => {\n this.flush();\n }, this._flushInterval);\n\n this._client.on('flush', () => {\n this.flush();\n });\n }\n\n /**\n * Add a span to the buffer.\n */\n public addSpan(spanJSON: SpanV2JSONWithSegmentRef): void {\n const traceId = spanJSON.trace_id;\n let traceBucket = this._spanTreeMap.get(traceId);\n if (traceBucket) {\n traceBucket.add(spanJSON);\n } else {\n traceBucket = new Set([spanJSON]);\n this._spanTreeMap.set(traceId, traceBucket);\n }\n\n if (traceBucket.size >= this._maxSpanLimit) {\n this._flushTrace(traceId);\n this._debounceFlushInterval();\n }\n }\n\n /**\n * Flush all buffered traces.\n */\n public flush(): void {\n if (!this._spanTreeMap.size) {\n return;\n }\n\n DEBUG_BUILD && debug.log(`Flushing span tree map with ${this._spanTreeMap.size} traces`);\n\n this._spanTreeMap.forEach((_, traceId) => {\n this._flushTrace(traceId);\n });\n this._debounceFlushInterval();\n }\n\n private _flushTrace(traceId: string): void {\n const traceBucket = this._spanTreeMap.get(traceId);\n if (!traceBucket) {\n return;\n }\n\n if (!traceBucket.size) {\n this._spanTreeMap.delete(traceId);\n return;\n }\n\n const firstSpanJSON = traceBucket.values().next().value;\n\n const segmentSpan = firstSpanJSON?._segmentSpan;\n if (!segmentSpan) {\n DEBUG_BUILD && debug.warn('No segment span reference found on span JSON, cannot compute DSC');\n this._spanTreeMap.delete(traceId);\n return;\n }\n\n const dsc = getDynamicSamplingContextFromSpan(segmentSpan);\n\n const cleanedSpans: SpanV2JSON[] = Array.from(traceBucket).map(spanJSON => {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { _segmentSpan, ...cleanSpanJSON } = spanJSON;\n return cleanSpanJSON;\n });\n\n const envelope = createSpanV2Envelope(cleanedSpans, dsc, this._client);\n\n DEBUG_BUILD && debug.log(`Sending span envelope for trace ${traceId} with ${cleanedSpans.length} spans`);\n\n this._client.sendEnvelope(envelope).then(null, reason => {\n DEBUG_BUILD && debug.error('Error while sending span stream envelope:', reason);\n });\n\n this._spanTreeMap.delete(traceId);\n }\n\n private _debounceFlushInterval(): void {\n if (this._flushIntervalId) {\n clearInterval(this._flushIntervalId);\n }\n this._flushIntervalId = setInterval(() => {\n this.flush();\n }, this._flushInterval);\n }\n}\n"],"names":[],"mappings":"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"}
|