@sentry/core 10.47.0 → 10.48.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 +43 -0
- package/build/cjs/attributes.js.map +1 -1
- package/build/cjs/client.js +13 -6
- package/build/cjs/client.js.map +1 -1
- package/build/cjs/envelope.js +4 -3
- package/build/cjs/envelope.js.map +1 -1
- package/build/cjs/index.js +44 -13
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/integration.js +6 -0
- package/build/cjs/integration.js.map +1 -1
- package/build/cjs/integrations/express/index.js +206 -0
- package/build/cjs/integrations/express/index.js.map +1 -0
- package/build/cjs/integrations/express/patch-layer.js +251 -0
- package/build/cjs/integrations/express/patch-layer.js.map +1 -0
- package/build/cjs/integrations/express/request-layer-store.js +25 -0
- package/build/cjs/integrations/express/request-layer-store.js.map +1 -0
- package/build/cjs/integrations/express/set-sdk-processing-metadata.js +17 -0
- package/build/cjs/integrations/express/set-sdk-processing-metadata.js.map +1 -0
- package/build/cjs/integrations/express/types.js +17 -0
- package/build/cjs/integrations/express/types.js.map +1 -0
- package/build/cjs/integrations/express/utils.js +238 -0
- package/build/cjs/integrations/express/utils.js.map +1 -0
- package/build/cjs/integrations/mcp-server/correlation.js +5 -1
- package/build/cjs/integrations/mcp-server/correlation.js.map +1 -1
- package/build/cjs/integrations/mcp-server/handlers.js +18 -10
- package/build/cjs/integrations/mcp-server/handlers.js.map +1 -1
- package/build/cjs/integrations/mcp-server/index.js +2 -1
- package/build/cjs/integrations/mcp-server/index.js.map +1 -1
- package/build/cjs/integrations/mcp-server/transport.js +1 -1
- package/build/cjs/integrations/mcp-server/transport.js.map +1 -1
- package/build/cjs/integrations/mcp-server/validation.js +7 -5
- package/build/cjs/integrations/mcp-server/validation.js.map +1 -1
- package/build/cjs/integrations/spanStreaming.js +48 -0
- package/build/cjs/integrations/spanStreaming.js.map +1 -0
- package/build/cjs/semanticAttributes.js +35 -3
- package/build/cjs/semanticAttributes.js.map +1 -1
- package/build/cjs/tracing/ai/gen-ai-attributes.js +9 -65
- package/build/cjs/tracing/ai/gen-ai-attributes.js.map +1 -1
- package/build/cjs/tracing/ai/utils.js +50 -0
- package/build/cjs/tracing/ai/utils.js.map +1 -1
- package/build/cjs/tracing/anthropic-ai/index.js +1 -12
- package/build/cjs/tracing/anthropic-ai/index.js.map +1 -1
- package/build/cjs/tracing/anthropic-ai/streaming.js +2 -100
- package/build/cjs/tracing/anthropic-ai/streaming.js.map +1 -1
- package/build/cjs/tracing/dynamicSamplingContext.js +2 -1
- package/build/cjs/tracing/dynamicSamplingContext.js.map +1 -1
- package/build/cjs/tracing/google-genai/constants.js +1 -6
- package/build/cjs/tracing/google-genai/constants.js.map +1 -1
- package/build/cjs/tracing/google-genai/index.js +24 -30
- package/build/cjs/tracing/google-genai/index.js.map +1 -1
- package/build/cjs/tracing/google-genai/streaming.js +2 -23
- package/build/cjs/tracing/google-genai/streaming.js.map +1 -1
- package/build/cjs/tracing/langchain/embeddings.js +132 -0
- package/build/cjs/tracing/langchain/embeddings.js.map +1 -0
- package/build/cjs/tracing/langchain/index.js.map +1 -1
- package/build/cjs/tracing/openai/index.js +2 -29
- package/build/cjs/tracing/openai/index.js.map +1 -1
- package/build/cjs/tracing/openai/streaming.js +3 -34
- package/build/cjs/tracing/openai/streaming.js.map +1 -1
- package/build/cjs/tracing/openai/utils.js +78 -204
- package/build/cjs/tracing/openai/utils.js.map +1 -1
- package/build/cjs/tracing/sentryNonRecordingSpan.js +7 -0
- package/build/cjs/tracing/sentryNonRecordingSpan.js.map +1 -1
- package/build/cjs/tracing/sentrySpan.js +39 -0
- package/build/cjs/tracing/sentrySpan.js.map +1 -1
- package/build/cjs/tracing/spans/beforeSendSpan.js +43 -0
- package/build/cjs/tracing/spans/beforeSendSpan.js.map +1 -0
- package/build/cjs/tracing/spans/captureSpan.js +126 -0
- package/build/cjs/tracing/spans/captureSpan.js.map +1 -0
- package/build/cjs/tracing/spans/envelope.js +38 -0
- package/build/cjs/tracing/spans/envelope.js.map +1 -0
- package/build/cjs/tracing/spans/estimateSize.js +41 -0
- package/build/cjs/tracing/spans/estimateSize.js.map +1 -0
- package/build/cjs/tracing/spans/hasSpanStreamingEnabled.js +11 -0
- package/build/cjs/tracing/spans/hasSpanStreamingEnabled.js.map +1 -0
- package/build/cjs/tracing/spans/spanBuffer.js +158 -0
- package/build/cjs/tracing/spans/spanBuffer.js.map +1 -0
- package/build/cjs/tracing/trace.js +83 -13
- package/build/cjs/tracing/trace.js.map +1 -1
- package/build/cjs/tracing/vercel-ai/utils.js +1 -4
- package/build/cjs/tracing/vercel-ai/utils.js.map +1 -1
- package/build/cjs/utils/featureFlags.js +6 -0
- package/build/cjs/utils/featureFlags.js.map +1 -1
- package/build/cjs/utils/object.js +33 -0
- package/build/cjs/utils/object.js.map +1 -1
- package/build/cjs/utils/spanUtils.js +116 -13
- package/build/cjs/utils/spanUtils.js.map +1 -1
- package/build/cjs/utils/stacktrace.js +3 -1
- package/build/cjs/utils/stacktrace.js.map +1 -1
- package/build/cjs/utils/string.js +3 -0
- package/build/cjs/utils/string.js.map +1 -1
- package/build/cjs/utils/version.js +1 -1
- package/build/esm/attributes.js +43 -1
- package/build/esm/attributes.js.map +1 -1
- package/build/esm/client.js +8 -1
- package/build/esm/client.js.map +1 -1
- package/build/esm/envelope.js +2 -1
- package/build/esm/envelope.js.map +1 -1
- package/build/esm/index.js +10 -2
- package/build/esm/index.js.map +1 -1
- package/build/esm/integration.js +6 -0
- package/build/esm/integration.js.map +1 -1
- package/build/esm/integrations/express/index.js +202 -0
- package/build/esm/integrations/express/index.js.map +1 -0
- package/build/esm/integrations/express/patch-layer.js +249 -0
- package/build/esm/integrations/express/patch-layer.js.map +1 -0
- package/build/esm/integrations/express/request-layer-store.js +22 -0
- package/build/esm/integrations/express/request-layer-store.js.map +1 -0
- package/build/esm/integrations/express/set-sdk-processing-metadata.js +15 -0
- package/build/esm/integrations/express/set-sdk-processing-metadata.js.map +1 -0
- package/build/esm/integrations/express/types.js +10 -0
- package/build/esm/integrations/express/types.js.map +1 -0
- package/build/esm/integrations/express/utils.js +225 -0
- package/build/esm/integrations/express/utils.js.map +1 -0
- package/build/esm/integrations/mcp-server/correlation.js +5 -1
- package/build/esm/integrations/mcp-server/correlation.js.map +1 -1
- package/build/esm/integrations/mcp-server/handlers.js +18 -10
- package/build/esm/integrations/mcp-server/handlers.js.map +1 -1
- package/build/esm/integrations/mcp-server/index.js +2 -1
- package/build/esm/integrations/mcp-server/index.js.map +1 -1
- package/build/esm/integrations/mcp-server/transport.js +1 -1
- package/build/esm/integrations/mcp-server/transport.js.map +1 -1
- package/build/esm/integrations/mcp-server/validation.js +7 -5
- package/build/esm/integrations/mcp-server/validation.js.map +1 -1
- package/build/esm/integrations/spanStreaming.js +46 -0
- package/build/esm/integrations/spanStreaming.js.map +1 -0
- package/build/esm/package.json +1 -1
- package/build/esm/semanticAttributes.js +26 -4
- package/build/esm/semanticAttributes.js.map +1 -1
- package/build/esm/tracing/ai/gen-ai-attributes.js +8 -56
- package/build/esm/tracing/ai/gen-ai-attributes.js.map +1 -1
- package/build/esm/tracing/ai/utils.js +51 -2
- package/build/esm/tracing/ai/utils.js.map +1 -1
- package/build/esm/tracing/anthropic-ai/index.js +2 -13
- package/build/esm/tracing/anthropic-ai/index.js.map +1 -1
- package/build/esm/tracing/anthropic-ai/streaming.js +3 -101
- package/build/esm/tracing/anthropic-ai/streaming.js.map +1 -1
- package/build/esm/tracing/dynamicSamplingContext.js +2 -1
- package/build/esm/tracing/dynamicSamplingContext.js.map +1 -1
- package/build/esm/tracing/google-genai/constants.js +2 -5
- package/build/esm/tracing/google-genai/constants.js.map +1 -1
- package/build/esm/tracing/google-genai/index.js +25 -31
- package/build/esm/tracing/google-genai/index.js.map +1 -1
- package/build/esm/tracing/google-genai/streaming.js +2 -23
- package/build/esm/tracing/google-genai/streaming.js.map +1 -1
- package/build/esm/tracing/langchain/embeddings.js +129 -0
- package/build/esm/tracing/langchain/embeddings.js.map +1 -0
- package/build/esm/tracing/langchain/index.js.map +1 -1
- package/build/esm/tracing/openai/index.js +3 -30
- package/build/esm/tracing/openai/index.js.map +1 -1
- package/build/esm/tracing/openai/streaming.js +4 -35
- package/build/esm/tracing/openai/streaming.js.map +1 -1
- package/build/esm/tracing/openai/utils.js +79 -196
- package/build/esm/tracing/openai/utils.js.map +1 -1
- package/build/esm/tracing/sentryNonRecordingSpan.js +7 -0
- package/build/esm/tracing/sentryNonRecordingSpan.js.map +1 -1
- package/build/esm/tracing/sentrySpan.js +40 -1
- package/build/esm/tracing/sentrySpan.js.map +1 -1
- package/build/esm/tracing/spans/beforeSendSpan.js +40 -0
- package/build/esm/tracing/spans/beforeSendSpan.js.map +1 -0
- package/build/esm/tracing/spans/captureSpan.js +122 -0
- package/build/esm/tracing/spans/captureSpan.js.map +1 -0
- package/build/esm/tracing/spans/envelope.js +36 -0
- package/build/esm/tracing/spans/envelope.js.map +1 -0
- package/build/esm/tracing/spans/estimateSize.js +39 -0
- package/build/esm/tracing/spans/estimateSize.js.map +1 -0
- package/build/esm/tracing/spans/hasSpanStreamingEnabled.js +9 -0
- package/build/esm/tracing/spans/hasSpanStreamingEnabled.js.map +1 -0
- package/build/esm/tracing/spans/spanBuffer.js +156 -0
- package/build/esm/tracing/spans/spanBuffer.js.map +1 -0
- package/build/esm/tracing/trace.js +84 -14
- package/build/esm/tracing/trace.js.map +1 -1
- package/build/esm/tracing/vercel-ai/utils.js +2 -5
- package/build/esm/tracing/vercel-ai/utils.js.map +1 -1
- package/build/esm/utils/featureFlags.js +6 -0
- package/build/esm/utils/featureFlags.js.map +1 -1
- package/build/esm/utils/object.js +33 -1
- package/build/esm/utils/object.js.map +1 -1
- package/build/esm/utils/spanUtils.js +112 -14
- package/build/esm/utils/spanUtils.js.map +1 -1
- package/build/esm/utils/stacktrace.js +3 -1
- package/build/esm/utils/stacktrace.js.map +1 -1
- package/build/esm/utils/string.js +3 -0
- package/build/esm/utils/string.js.map +1 -1
- package/build/esm/utils/version.js +1 -1
- package/build/types/attributes.d.ts +5 -0
- package/build/types/attributes.d.ts.map +1 -1
- package/build/types/client.d.ts +35 -1
- package/build/types/client.d.ts.map +1 -1
- package/build/types/envelope.d.ts.map +1 -1
- package/build/types/index.d.ts +12 -4
- package/build/types/index.d.ts.map +1 -1
- package/build/types/integration.d.ts.map +1 -1
- package/build/types/integrations/express/index.d.ts +75 -0
- package/build/types/integrations/express/index.d.ts.map +1 -0
- package/build/types/integrations/express/patch-layer.d.ts +32 -0
- package/build/types/integrations/express/patch-layer.d.ts.map +1 -0
- package/build/types/integrations/express/request-layer-store.d.ts +32 -0
- package/build/types/integrations/express/request-layer-store.d.ts.map +1 -0
- package/build/types/integrations/express/set-sdk-processing-metadata.d.ts +35 -0
- package/build/types/integrations/express/set-sdk-processing-metadata.d.ts.map +1 -0
- package/build/types/integrations/express/types.d.ts +154 -0
- package/build/types/integrations/express/types.d.ts.map +1 -0
- package/build/types/integrations/express/utils.d.ts +93 -0
- package/build/types/integrations/express/utils.d.ts.map +1 -0
- package/build/types/integrations/mcp-server/correlation.d.ts +2 -1
- package/build/types/integrations/mcp-server/correlation.d.ts.map +1 -1
- package/build/types/integrations/mcp-server/handlers.d.ts +9 -4
- package/build/types/integrations/mcp-server/handlers.d.ts.map +1 -1
- package/build/types/integrations/mcp-server/index.d.ts +2 -1
- package/build/types/integrations/mcp-server/index.d.ts.map +1 -1
- package/build/types/integrations/mcp-server/types.d.ts +40 -7
- package/build/types/integrations/mcp-server/types.d.ts.map +1 -1
- package/build/types/integrations/mcp-server/validation.d.ts +4 -1
- package/build/types/integrations/mcp-server/validation.d.ts.map +1 -1
- package/build/types/integrations/spanStreaming.d.ts +2 -0
- package/build/types/integrations/spanStreaming.d.ts.map +1 -0
- package/build/types/semanticAttributes.d.ts +23 -3
- package/build/types/semanticAttributes.d.ts.map +1 -1
- package/build/types/tracing/ai/gen-ai-attributes.d.ts +6 -38
- package/build/types/tracing/ai/gen-ai-attributes.d.ts.map +1 -1
- package/build/types/tracing/ai/utils.d.ts +21 -2
- package/build/types/tracing/ai/utils.d.ts.map +1 -1
- package/build/types/tracing/anthropic-ai/index.d.ts.map +1 -1
- package/build/types/tracing/anthropic-ai/streaming.d.ts.map +1 -1
- package/build/types/tracing/dynamicSamplingContext.d.ts.map +1 -1
- package/build/types/tracing/google-genai/constants.d.ts +1 -3
- package/build/types/tracing/google-genai/constants.d.ts.map +1 -1
- package/build/types/tracing/google-genai/index.d.ts.map +1 -1
- package/build/types/tracing/google-genai/streaming.d.ts.map +1 -1
- package/build/types/tracing/index.d.ts +1 -0
- package/build/types/tracing/index.d.ts.map +1 -1
- package/build/types/tracing/langchain/embeddings.d.ts +27 -0
- package/build/types/tracing/langchain/embeddings.d.ts.map +1 -0
- package/build/types/tracing/langchain/index.d.ts +1 -0
- package/build/types/tracing/langchain/index.d.ts.map +1 -1
- package/build/types/tracing/openai/index.d.ts.map +1 -1
- package/build/types/tracing/openai/streaming.d.ts.map +1 -1
- package/build/types/tracing/openai/utils.d.ts +4 -49
- package/build/types/tracing/openai/utils.d.ts.map +1 -1
- package/build/types/tracing/sentryNonRecordingSpan.d.ts +12 -1
- package/build/types/tracing/sentryNonRecordingSpan.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/spans/beforeSendSpan.d.ts +35 -0
- package/build/types/tracing/spans/beforeSendSpan.d.ts.map +1 -0
- package/build/types/tracing/spans/captureSpan.d.ts +26 -0
- package/build/types/tracing/spans/captureSpan.d.ts.map +1 -0
- package/build/types/tracing/spans/envelope.d.ts +8 -0
- package/build/types/tracing/spans/envelope.d.ts.map +1 -0
- package/build/types/tracing/spans/estimateSize.d.ts +12 -0
- package/build/types/tracing/spans/estimateSize.d.ts.map +1 -0
- package/build/types/tracing/spans/hasSpanStreamingEnabled.d.ts +6 -0
- package/build/types/tracing/spans/hasSpanStreamingEnabled.d.ts.map +1 -0
- package/build/types/tracing/spans/spanBuffer.d.ts +60 -0
- package/build/types/tracing/spans/spanBuffer.d.ts.map +1 -0
- package/build/types/tracing/trace.d.ts.map +1 -1
- package/build/types/tracing/vercel-ai/utils.d.ts.map +1 -1
- 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/integration.d.ts +8 -0
- package/build/types/types-hoist/integration.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 +26 -2
- package/build/types/types-hoist/options.d.ts.map +1 -1
- package/build/types/types-hoist/span.d.ts +35 -0
- package/build/types/types-hoist/span.d.ts.map +1 -1
- package/build/types/utils/featureFlags.d.ts.map +1 -1
- package/build/types/utils/object.d.ts +10 -0
- package/build/types/utils/object.d.ts.map +1 -1
- package/build/types/utils/spanUtils.d.ts +27 -2
- package/build/types/utils/spanUtils.d.ts.map +1 -1
- package/build/types/utils/stacktrace.d.ts.map +1 -1
- package/build/types/utils/string.d.ts +2 -2
- package/build/types/utils/string.d.ts.map +1 -1
- package/build/types-ts3.8/attributes.d.ts +5 -0
- package/build/types-ts3.8/client.d.ts +35 -1
- package/build/types-ts3.8/index.d.ts +12 -4
- package/build/types-ts3.8/integrations/express/index.d.ts +75 -0
- package/build/types-ts3.8/integrations/express/patch-layer.d.ts +32 -0
- package/build/types-ts3.8/integrations/express/request-layer-store.d.ts +32 -0
- package/build/types-ts3.8/integrations/express/set-sdk-processing-metadata.d.ts +35 -0
- package/build/types-ts3.8/integrations/express/types.d.ts +154 -0
- package/build/types-ts3.8/integrations/express/utils.d.ts +96 -0
- package/build/types-ts3.8/integrations/mcp-server/correlation.d.ts +2 -1
- package/build/types-ts3.8/integrations/mcp-server/handlers.d.ts +9 -4
- package/build/types-ts3.8/integrations/mcp-server/index.d.ts +2 -1
- package/build/types-ts3.8/integrations/mcp-server/types.d.ts +40 -7
- package/build/types-ts3.8/integrations/mcp-server/validation.d.ts +4 -1
- package/build/types-ts3.8/integrations/spanStreaming.d.ts +2 -0
- package/build/types-ts3.8/semanticAttributes.d.ts +23 -3
- package/build/types-ts3.8/tracing/ai/gen-ai-attributes.d.ts +6 -38
- package/build/types-ts3.8/tracing/ai/utils.d.ts +21 -2
- package/build/types-ts3.8/tracing/google-genai/constants.d.ts +1 -3
- package/build/types-ts3.8/tracing/index.d.ts +1 -0
- package/build/types-ts3.8/tracing/langchain/embeddings.d.ts +27 -0
- package/build/types-ts3.8/tracing/langchain/index.d.ts +1 -0
- package/build/types-ts3.8/tracing/openai/utils.d.ts +4 -49
- package/build/types-ts3.8/tracing/sentryNonRecordingSpan.d.ts +12 -1
- package/build/types-ts3.8/tracing/sentrySpan.d.ts +10 -1
- package/build/types-ts3.8/tracing/spans/beforeSendSpan.d.ts +35 -0
- package/build/types-ts3.8/tracing/spans/captureSpan.d.ts +26 -0
- package/build/types-ts3.8/tracing/spans/envelope.d.ts +8 -0
- package/build/types-ts3.8/tracing/spans/estimateSize.d.ts +12 -0
- package/build/types-ts3.8/tracing/spans/hasSpanStreamingEnabled.d.ts +6 -0
- package/build/types-ts3.8/tracing/spans/spanBuffer.d.ts +60 -0
- package/build/types-ts3.8/types-hoist/envelope.d.ts +22 -2
- package/build/types-ts3.8/types-hoist/integration.d.ts +8 -0
- package/build/types-ts3.8/types-hoist/link.d.ts +2 -2
- package/build/types-ts3.8/types-hoist/options.d.ts +26 -2
- package/build/types-ts3.8/types-hoist/span.d.ts +35 -0
- package/build/types-ts3.8/utils/object.d.ts +10 -0
- package/build/types-ts3.8/utils/spanUtils.d.ts +27 -2
- package/build/types-ts3.8/utils/string.d.ts +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const object = require('../../utils/object.js');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A wrapper to use the new span format in your `beforeSendSpan` callback.
|
|
7
|
+
*
|
|
8
|
+
* When using `traceLifecycle: 'stream'`, wrap your callback with this function
|
|
9
|
+
* to receive and return {@link StreamedSpanJSON} instead of the standard {@link SpanJSON}.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
*
|
|
13
|
+
* Sentry.init({
|
|
14
|
+
* traceLifecycle: 'stream',
|
|
15
|
+
* beforeSendSpan: withStreamedSpan((span) => {
|
|
16
|
+
* // span is of type StreamedSpanJSON
|
|
17
|
+
* return span;
|
|
18
|
+
* }),
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* @param callback - The callback function that receives and returns a {@link StreamedSpanJSON}.
|
|
22
|
+
* @returns A callback that is compatible with the `beforeSendSpan` option when using `traceLifecycle: 'stream'`.
|
|
23
|
+
*/
|
|
24
|
+
function withStreamedSpan(
|
|
25
|
+
callback,
|
|
26
|
+
) {
|
|
27
|
+
object.addNonEnumerableProperty(callback, '_streamed', true);
|
|
28
|
+
return callback ;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Typesafe check to identify if a `beforeSendSpan` callback expects the streamed span JSON format.
|
|
33
|
+
*
|
|
34
|
+
* @param callback - The `beforeSendSpan` callback to check.
|
|
35
|
+
* @returns `true` if the callback was wrapped with {@link withStreamedSpan}.
|
|
36
|
+
*/
|
|
37
|
+
function isStreamedBeforeSendSpanCallback(callback) {
|
|
38
|
+
return !!callback && typeof callback === 'function' && '_streamed' in callback && !!callback._streamed;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
exports.isStreamedBeforeSendSpanCallback = isStreamedBeforeSendSpanCallback;
|
|
42
|
+
exports.withStreamedSpan = withStreamedSpan;
|
|
43
|
+
//# sourceMappingURL=beforeSendSpan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"beforeSendSpan.js","sources":["../../../../src/tracing/spans/beforeSendSpan.ts"],"sourcesContent":["import type { CoreOptions } from '../../types-hoist/options';\nimport type { BeforeSendStreamedSpanCallback } from '../../types-hoist/options';\nimport type { StreamedSpanJSON } from '../../types-hoist/span';\nimport { addNonEnumerableProperty } from '../../utils/object';\n\ntype StaticBeforeSendSpanCallback = CoreOptions['beforeSendSpan'];\n\n/**\n * A wrapper to use the new span format in your `beforeSendSpan` callback.\n *\n * When using `traceLifecycle: 'stream'`, wrap your callback with this function\n * to receive and return {@link StreamedSpanJSON} instead of the standard {@link SpanJSON}.\n *\n * @example\n *\n * Sentry.init({\n * traceLifecycle: 'stream',\n * beforeSendSpan: withStreamedSpan((span) => {\n * // span is of type StreamedSpanJSON\n * return span;\n * }),\n * });\n *\n * @param callback - The callback function that receives and returns a {@link StreamedSpanJSON}.\n * @returns A callback that is compatible with the `beforeSendSpan` option when using `traceLifecycle: 'stream'`.\n */\nexport function withStreamedSpan(\n callback: (span: StreamedSpanJSON) => StreamedSpanJSON,\n): StaticBeforeSendSpanCallback & { _streamed: true } {\n addNonEnumerableProperty(callback, '_streamed', true);\n return callback as unknown as StaticBeforeSendSpanCallback & { _streamed: true };\n}\n\n/**\n * Typesafe check to identify if a `beforeSendSpan` callback expects the streamed span JSON format.\n *\n * @param callback - The `beforeSendSpan` callback to check.\n * @returns `true` if the callback was wrapped with {@link withStreamedSpan}.\n */\nexport function isStreamedBeforeSendSpanCallback(callback: unknown): callback is BeforeSendStreamedSpanCallback {\n return !!callback && typeof callback === 'function' && '_streamed' in callback && !!callback._streamed;\n}\n"],"names":["addNonEnumerableProperty"],"mappings":";;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,gBAAgB;AAChC,EAAE,QAAQ;AACV,EAAsD;AACtD,EAAEA,+BAAwB,CAAC,QAAQ,EAAE,WAAW,EAAE,IAAI,CAAC;AACvD,EAAE,OAAO,QAAA;AACT;;AAEA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,gCAAgC,CAAC,QAAQ,EAAuD;AAChH,EAAE,OAAO,CAAC,CAAC,YAAY,OAAO,aAAa,UAAA,IAAc,WAAA,IAAe,QAAA,IAAY,CAAC,CAAC,QAAQ,CAAC,SAAS;AACxG;;;;;"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const semanticAttributes = require('../../semanticAttributes.js');
|
|
4
|
+
const scopeData = require('../../utils/scopeData.js');
|
|
5
|
+
const spanUtils = require('../../utils/spanUtils.js');
|
|
6
|
+
const utils = require('../utils.js');
|
|
7
|
+
const beforeSendSpan = require('./beforeSendSpan.js');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Captures a span and returns a JSON representation to be enqueued for sending.
|
|
11
|
+
*
|
|
12
|
+
* IMPORTANT: This function converts the span to JSON immediately to avoid writing
|
|
13
|
+
* to an already-ended OTel span instance (which is blocked by the OTel Span class).
|
|
14
|
+
*
|
|
15
|
+
* @returns the final serialized span with a reference to its segment span. This reference
|
|
16
|
+
* is needed later on to compute the DSC for the span envelope.
|
|
17
|
+
*/
|
|
18
|
+
function captureSpan(span, client) {
|
|
19
|
+
// Convert to JSON FIRST - we cannot write to an already-ended span
|
|
20
|
+
const spanJSON = spanUtils.spanToStreamedSpanJSON(span);
|
|
21
|
+
|
|
22
|
+
const segmentSpan = spanUtils.INTERNAL_getSegmentSpan(span);
|
|
23
|
+
const serializedSegmentSpan = spanUtils.spanToStreamedSpanJSON(segmentSpan);
|
|
24
|
+
|
|
25
|
+
const { isolationScope: spanIsolationScope, scope: spanScope } = utils.getCapturedScopesOnSpan(span);
|
|
26
|
+
|
|
27
|
+
const finalScopeData = scopeData.getCombinedScopeData(spanIsolationScope, spanScope);
|
|
28
|
+
|
|
29
|
+
applyCommonSpanAttributes(spanJSON, serializedSegmentSpan, client, finalScopeData);
|
|
30
|
+
|
|
31
|
+
if (spanJSON.is_segment) {
|
|
32
|
+
// Allow hook subscribers to mutate the segment span JSON
|
|
33
|
+
client.emit('processSegmentSpan', spanJSON);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Allow hook subscribers to mutate the span JSON
|
|
37
|
+
client.emit('processSpan', spanJSON);
|
|
38
|
+
|
|
39
|
+
const { beforeSendSpan: beforeSendSpan$1 } = client.getOptions();
|
|
40
|
+
const processedSpan =
|
|
41
|
+
beforeSendSpan$1 && beforeSendSpan.isStreamedBeforeSendSpanCallback(beforeSendSpan$1)
|
|
42
|
+
? applyBeforeSendSpanCallback(spanJSON, beforeSendSpan$1)
|
|
43
|
+
: spanJSON;
|
|
44
|
+
|
|
45
|
+
// Backfill sentry.span.source from sentry.source. Only `sentry.span.source` is respected by Sentry.
|
|
46
|
+
// TODO(v11): Remove this backfill once we renamed SEMANTIC_ATTRIBUTE_SENTRY_SOURCE to sentry.span.source
|
|
47
|
+
const spanNameSource = processedSpan.attributes?.[semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE];
|
|
48
|
+
if (spanNameSource) {
|
|
49
|
+
safeSetSpanJSONAttributes(processedSpan, {
|
|
50
|
+
// Purposefully not using a constant defined here like in other attributes:
|
|
51
|
+
// This will be the name for SEMANTIC_ATTRIBUTE_SENTRY_SOURCE in v11
|
|
52
|
+
'sentry.span.source': spanNameSource,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
...spanUtils.streamedSpanJsonToSerializedSpan(processedSpan),
|
|
58
|
+
_segmentSpan: segmentSpan,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function applyCommonSpanAttributes(
|
|
63
|
+
spanJSON,
|
|
64
|
+
serializedSegmentSpan,
|
|
65
|
+
client,
|
|
66
|
+
scopeData,
|
|
67
|
+
) {
|
|
68
|
+
const sdk = client.getSdkMetadata();
|
|
69
|
+
const { release, environment, sendDefaultPii } = client.getOptions();
|
|
70
|
+
|
|
71
|
+
// avoid overwriting any previously set attributes (from users or potentially our SDK instrumentation)
|
|
72
|
+
safeSetSpanJSONAttributes(spanJSON, {
|
|
73
|
+
[semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_RELEASE]: release,
|
|
74
|
+
[semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_ENVIRONMENT]: environment,
|
|
75
|
+
[semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_NAME]: serializedSegmentSpan.name,
|
|
76
|
+
[semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_ID]: serializedSegmentSpan.span_id,
|
|
77
|
+
[semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_SDK_NAME]: sdk?.sdk?.name,
|
|
78
|
+
[semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_SDK_VERSION]: sdk?.sdk?.version,
|
|
79
|
+
...(sendDefaultPii
|
|
80
|
+
? {
|
|
81
|
+
[semanticAttributes.SEMANTIC_ATTRIBUTE_USER_ID]: scopeData.user?.id,
|
|
82
|
+
[semanticAttributes.SEMANTIC_ATTRIBUTE_USER_EMAIL]: scopeData.user?.email,
|
|
83
|
+
[semanticAttributes.SEMANTIC_ATTRIBUTE_USER_IP_ADDRESS]: scopeData.user?.ip_address,
|
|
84
|
+
[semanticAttributes.SEMANTIC_ATTRIBUTE_USER_USERNAME]: scopeData.user?.username,
|
|
85
|
+
}
|
|
86
|
+
: {}),
|
|
87
|
+
...scopeData.attributes,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Apply a user-provided beforeSendSpan callback to a span JSON.
|
|
93
|
+
*/
|
|
94
|
+
function applyBeforeSendSpanCallback(
|
|
95
|
+
span,
|
|
96
|
+
beforeSendSpan,
|
|
97
|
+
) {
|
|
98
|
+
const modifedSpan = beforeSendSpan(span);
|
|
99
|
+
if (!modifedSpan) {
|
|
100
|
+
spanUtils.showSpanDropWarning();
|
|
101
|
+
return span;
|
|
102
|
+
}
|
|
103
|
+
return modifedSpan;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Safely set attributes on a span JSON.
|
|
108
|
+
* If an attribute already exists, it will not be overwritten.
|
|
109
|
+
*/
|
|
110
|
+
function safeSetSpanJSONAttributes(
|
|
111
|
+
spanJSON,
|
|
112
|
+
newAttributes,
|
|
113
|
+
) {
|
|
114
|
+
const originalAttributes = spanJSON.attributes ?? (spanJSON.attributes = {});
|
|
115
|
+
|
|
116
|
+
Object.entries(newAttributes).forEach(([key, value]) => {
|
|
117
|
+
if (value != null && !(key in originalAttributes)) {
|
|
118
|
+
originalAttributes[key] = value;
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
exports.applyBeforeSendSpanCallback = applyBeforeSendSpanCallback;
|
|
124
|
+
exports.captureSpan = captureSpan;
|
|
125
|
+
exports.safeSetSpanJSONAttributes = safeSetSpanJSONAttributes;
|
|
126
|
+
//# sourceMappingURL=captureSpan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"captureSpan.js","sources":["../../../../src/tracing/spans/captureSpan.ts"],"sourcesContent":["import type { RawAttributes } from '../../attributes';\nimport type { Client } from '../../client';\nimport type { 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_SENTRY_SOURCE,\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 type { SerializedStreamedSpan, Span, StreamedSpanJSON } from '../../types-hoist/span';\nimport { getCombinedScopeData } from '../../utils/scopeData';\nimport {\n INTERNAL_getSegmentSpan,\n showSpanDropWarning,\n spanToStreamedSpanJSON,\n streamedSpanJsonToSerializedSpan,\n} from '../../utils/spanUtils';\nimport { getCapturedScopesOnSpan } from '../utils';\nimport { isStreamedBeforeSendSpanCallback } from './beforeSendSpan';\n\nexport type SerializedStreamedSpanWithSegmentSpan = SerializedStreamedSpan & {\n _segmentSpan: Span;\n};\n\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 *\n * @returns the final serialized span with a reference to its segment span. This reference\n * is needed later on to compute the DSC for the span envelope.\n */\nexport function captureSpan(span: Span, client: Client): SerializedStreamedSpanWithSegmentSpan {\n // Convert to JSON FIRST - we cannot write to an already-ended span\n const spanJSON = spanToStreamedSpanJSON(span);\n\n const segmentSpan = INTERNAL_getSegmentSpan(span);\n const serializedSegmentSpan = spanToStreamedSpanJSON(segmentSpan);\n\n const { isolationScope: spanIsolationScope, scope: spanScope } = getCapturedScopesOnSpan(span);\n\n const finalScopeData = getCombinedScopeData(spanIsolationScope, spanScope);\n\n applyCommonSpanAttributes(spanJSON, serializedSegmentSpan, client, finalScopeData);\n\n if (spanJSON.is_segment) {\n applyScopeToSegmentSpan(spanJSON, finalScopeData);\n // Allow hook subscribers to mutate the segment span JSON\n client.emit('processSegmentSpan', spanJSON);\n }\n\n // Allow hook subscribers to mutate the span JSON\n client.emit('processSpan', spanJSON);\n\n const { beforeSendSpan } = client.getOptions();\n const processedSpan =\n beforeSendSpan && isStreamedBeforeSendSpanCallback(beforeSendSpan)\n ? applyBeforeSendSpanCallback(spanJSON, beforeSendSpan)\n : spanJSON;\n\n // Backfill sentry.span.source from sentry.source. Only `sentry.span.source` is respected by Sentry.\n // TODO(v11): Remove this backfill once we renamed SEMANTIC_ATTRIBUTE_SENTRY_SOURCE to sentry.span.source\n const spanNameSource = processedSpan.attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE];\n if (spanNameSource) {\n safeSetSpanJSONAttributes(processedSpan, {\n // Purposefully not using a constant defined here like in other attributes:\n // This will be the name for SEMANTIC_ATTRIBUTE_SENTRY_SOURCE in v11\n 'sentry.span.source': spanNameSource,\n });\n }\n\n return {\n ...streamedSpanJsonToSerializedSpan(processedSpan),\n _segmentSpan: segmentSpan,\n };\n}\n\nfunction applyScopeToSegmentSpan(_segmentSpanJSON: StreamedSpanJSON, _scopeData: ScopeData): void {\n // TODO: Apply all scope and request data from auto instrumentation (contexts, request) to segment span\n // This will follow in a separate PR\n}\n\nfunction applyCommonSpanAttributes(\n spanJSON: StreamedSpanJSON,\n serializedSegmentSpan: StreamedSpanJSON,\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/**\n * Apply a user-provided beforeSendSpan callback to a span JSON.\n */\nexport function applyBeforeSendSpanCallback(\n span: StreamedSpanJSON,\n beforeSendSpan: (span: StreamedSpanJSON) => StreamedSpanJSON,\n): StreamedSpanJSON {\n const modifedSpan = beforeSendSpan(span);\n if (!modifedSpan) {\n showSpanDropWarning();\n return span;\n }\n return modifedSpan;\n}\n\n/**\n * Safely set attributes on a span JSON.\n * If an attribute already exists, it will not be overwritten.\n */\nexport function safeSetSpanJSONAttributes(\n spanJSON: StreamedSpanJSON,\n newAttributes: RawAttributes<Record<string, unknown>>,\n): void {\n const originalAttributes = spanJSON.attributes ?? (spanJSON.attributes = {});\n\n Object.entries(newAttributes).forEach(([key, value]) => {\n if (value != null && !(key in originalAttributes)) {\n originalAttributes[key] = value;\n }\n });\n}\n"],"names":["spanToStreamedSpanJSON","INTERNAL_getSegmentSpan","getCapturedScopesOnSpan","getCombinedScopeData","beforeSendSpan","isStreamedBeforeSendSpanCallback","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","streamedSpanJsonToSerializedSpan","SEMANTIC_ATTRIBUTE_SENTRY_RELEASE","SEMANTIC_ATTRIBUTE_SENTRY_ENVIRONMENT","SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_NAME","SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_ID","SEMANTIC_ATTRIBUTE_SENTRY_SDK_NAME","SEMANTIC_ATTRIBUTE_SENTRY_SDK_VERSION","SEMANTIC_ATTRIBUTE_USER_ID","SEMANTIC_ATTRIBUTE_USER_EMAIL","SEMANTIC_ATTRIBUTE_USER_IP_ADDRESS","SEMANTIC_ATTRIBUTE_USER_USERNAME","showSpanDropWarning"],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const dsn = require('../../utils/dsn.js');
|
|
4
|
+
const envelope = require('../../utils/envelope.js');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Creates a span v2 span streaming envelope
|
|
8
|
+
*/
|
|
9
|
+
function createStreamedSpanEnvelope(
|
|
10
|
+
serializedSpans,
|
|
11
|
+
dsc,
|
|
12
|
+
client,
|
|
13
|
+
) {
|
|
14
|
+
const dsn$1 = client.getDsn();
|
|
15
|
+
const tunnel = client.getOptions().tunnel;
|
|
16
|
+
const sdk = envelope.getSdkMetadataForEnvelopeHeader(client.getOptions()._metadata);
|
|
17
|
+
|
|
18
|
+
const headers = {
|
|
19
|
+
sent_at: new Date().toISOString(),
|
|
20
|
+
...(dscHasRequiredProps(dsc) && { trace: dsc }),
|
|
21
|
+
...(sdk && { sdk }),
|
|
22
|
+
...(!!tunnel && dsn$1 && { dsn: dsn.dsnToString(dsn$1) }),
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const spanContainer = [
|
|
26
|
+
{ type: 'span', item_count: serializedSpans.length, content_type: 'application/vnd.sentry.items.span.v2+json' },
|
|
27
|
+
{ items: serializedSpans },
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
return envelope.createEnvelope(headers, [spanContainer]);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function dscHasRequiredProps(dsc) {
|
|
34
|
+
return !!dsc.trace_id && !!dsc.public_key;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
exports.createStreamedSpanEnvelope = createStreamedSpanEnvelope;
|
|
38
|
+
//# sourceMappingURL=envelope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.js","sources":["../../../../src/tracing/spans/envelope.ts"],"sourcesContent":["import type { Client } from '../../client';\nimport type { DynamicSamplingContext, SpanContainerItem, StreamedSpanEnvelope } from '../../types-hoist/envelope';\nimport type { SerializedStreamedSpan } from '../../types-hoist/span';\nimport { dsnToString } from '../../utils/dsn';\nimport { createEnvelope, getSdkMetadataForEnvelopeHeader } from '../../utils/envelope';\n\n/**\n * Creates a span v2 span streaming envelope\n */\nexport function createStreamedSpanEnvelope(\n serializedSpans: Array<SerializedStreamedSpan>,\n dsc: Partial<DynamicSamplingContext>,\n client: Client,\n): StreamedSpanEnvelope {\n const dsn = client.getDsn();\n const tunnel = client.getOptions().tunnel;\n const sdk = getSdkMetadataForEnvelopeHeader(client.getOptions()._metadata);\n\n const headers: StreamedSpanEnvelope[0] = {\n sent_at: new Date().toISOString(),\n ...(dscHasRequiredProps(dsc) && { trace: dsc }),\n ...(sdk && { sdk }),\n ...(!!tunnel && dsn && { dsn: dsnToString(dsn) }),\n };\n\n const spanContainer: SpanContainerItem = [\n { type: 'span', item_count: serializedSpans.length, content_type: 'application/vnd.sentry.items.span.v2+json' },\n { items: serializedSpans },\n ];\n\n return createEnvelope<StreamedSpanEnvelope>(headers, [spanContainer]);\n}\n\nfunction dscHasRequiredProps(dsc: Partial<DynamicSamplingContext>): dsc is DynamicSamplingContext {\n return !!dsc.trace_id && !!dsc.public_key;\n}\n"],"names":["dsn","getSdkMetadataForEnvelopeHeader","dsnToString","createEnvelope"],"mappings":";;;;;AAMA;AACA;AACA;AACO,SAAS,0BAA0B;AAC1C,EAAE,eAAe;AACjB,EAAE,GAAG;AACL,EAAE,MAAM;AACR,EAAwB;AACxB,EAAE,MAAMA,KAAA,GAAM,MAAM,CAAC,MAAM,EAAE;AAC7B,EAAE,MAAM,SAAS,MAAM,CAAC,UAAU,EAAE,CAAC,MAAM;AAC3C,EAAE,MAAM,GAAA,GAAMC,wCAA+B,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,SAAS,CAAC;;AAE5E,EAAE,MAAM,OAAO,GAA4B;AAC3C,IAAI,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;AACrC,IAAI,IAAI,mBAAmB,CAAC,GAAG,CAAA,IAAK,EAAE,KAAK,EAAE,GAAA,EAAK,CAAC;AACnD,IAAI,IAAI,GAAA,IAAO,EAAE,GAAA,EAAK,CAAC;AACvB,IAAI,IAAI,CAAC,CAAC,MAAA,IAAUD,KAAA,IAAO,EAAE,GAAG,EAAEE,eAAW,CAACF,KAAG,CAAA,EAAG,CAAC;AACrD,GAAG;;AAEH,EAAE,MAAM,aAAa,GAAsB;AAC3C,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,eAAe,CAAC,MAAM,EAAE,YAAY,EAAE,6CAA6C;AACnH,IAAI,EAAE,KAAK,EAAE,eAAA,EAAiB;AAC9B,GAAG;;AAEH,EAAE,OAAOG,uBAAc,CAAuB,OAAO,EAAE,CAAC,aAAa,CAAC,CAAC;AACvE;;AAEA,SAAS,mBAAmB,CAAC,GAAG,EAAkE;AAClG,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,QAAA,IAAY,CAAC,CAAC,GAAG,CAAC,UAAU;AAC3C;;;;"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const attributes = require('../../attributes.js');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Estimates the serialized byte size of a {@link SerializedStreamedSpan}.
|
|
7
|
+
*
|
|
8
|
+
* Uses 2 bytes per character as a UTF-16 approximation, and 8 bytes per number.
|
|
9
|
+
* The estimate is intentionally conservative and may be slightly lower than the
|
|
10
|
+
* actual byte size on the wire.
|
|
11
|
+
* We compensate for this by setting the span buffers internal limit well below the limit
|
|
12
|
+
* of how large an actual span v2 envelope may be.
|
|
13
|
+
*/
|
|
14
|
+
function estimateSerializedSpanSizeInBytes(span) {
|
|
15
|
+
/*
|
|
16
|
+
* Fixed-size fields are pre-computed as a constant for performance:
|
|
17
|
+
* - two timestamps (8 bytes each = 16)
|
|
18
|
+
* - is_segment boolean (5 bytes, assumed false for most spans)
|
|
19
|
+
* - trace_id – always 32 hex chars (64 bytes)
|
|
20
|
+
* - span_id – always 16 hex chars (32 bytes)
|
|
21
|
+
* - parent_span_id – 16 hex chars, assumed present for most spans (32 bytes)
|
|
22
|
+
* - status "ok" – most common value (8 bytes)
|
|
23
|
+
* = 156 bytes total base
|
|
24
|
+
*/
|
|
25
|
+
let weight = 156;
|
|
26
|
+
weight += span.name.length * 2;
|
|
27
|
+
weight += attributes.estimateTypedAttributesSizeInBytes(span.attributes);
|
|
28
|
+
if (span.links && span.links.length > 0) {
|
|
29
|
+
// Assumption: Links are roughly equal in number of attributes
|
|
30
|
+
// probably not always true but allows us to cut down on runtime
|
|
31
|
+
const firstLink = span.links[0];
|
|
32
|
+
const attributes$1 = firstLink?.attributes;
|
|
33
|
+
// Fixed size 100 due to span_id, trace_id and sampled flag (see above)
|
|
34
|
+
const linkWeight = 100 + (attributes$1 ? attributes.estimateTypedAttributesSizeInBytes(attributes$1) : 0);
|
|
35
|
+
weight += linkWeight * span.links.length;
|
|
36
|
+
}
|
|
37
|
+
return weight;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
exports.estimateSerializedSpanSizeInBytes = estimateSerializedSpanSizeInBytes;
|
|
41
|
+
//# sourceMappingURL=estimateSize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"estimateSize.js","sources":["../../../../src/tracing/spans/estimateSize.ts"],"sourcesContent":["import { estimateTypedAttributesSizeInBytes } from '../../attributes';\nimport type { SerializedStreamedSpan } from '../../types-hoist/span';\n\n/**\n * Estimates the serialized byte size of a {@link SerializedStreamedSpan}.\n *\n * Uses 2 bytes per character as a UTF-16 approximation, and 8 bytes per number.\n * The estimate is intentionally conservative and may be slightly lower than the\n * actual byte size on the wire.\n * We compensate for this by setting the span buffers internal limit well below the limit\n * of how large an actual span v2 envelope may be.\n */\nexport function estimateSerializedSpanSizeInBytes(span: SerializedStreamedSpan): number {\n /*\n * Fixed-size fields are pre-computed as a constant for performance:\n * - two timestamps (8 bytes each = 16)\n * - is_segment boolean (5 bytes, assumed false for most spans)\n * - trace_id – always 32 hex chars (64 bytes)\n * - span_id – always 16 hex chars (32 bytes)\n * - parent_span_id – 16 hex chars, assumed present for most spans (32 bytes)\n * - status \"ok\" – most common value (8 bytes)\n * = 156 bytes total base\n */\n let weight = 156;\n weight += span.name.length * 2;\n weight += estimateTypedAttributesSizeInBytes(span.attributes);\n if (span.links && span.links.length > 0) {\n // Assumption: Links are roughly equal in number of attributes\n // probably not always true but allows us to cut down on runtime\n const firstLink = span.links[0];\n const attributes = firstLink?.attributes;\n // Fixed size 100 due to span_id, trace_id and sampled flag (see above)\n const linkWeight = 100 + (attributes ? estimateTypedAttributesSizeInBytes(attributes) : 0);\n weight += linkWeight * span.links.length;\n }\n return weight;\n}\n"],"names":["estimateTypedAttributesSizeInBytes","attributes"],"mappings":";;;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,iCAAiC,CAAC,IAAI,EAAkC;AACxF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE,IAAI,MAAA,GAAS,GAAG;AAClB,EAAE,MAAA,IAAU,IAAI,CAAC,IAAI,CAAC,MAAA,GAAS,CAAC;AAChC,EAAE,UAAUA,6CAAkC,CAAC,IAAI,CAAC,UAAU,CAAC;AAC/D,EAAE,IAAI,IAAI,CAAC,KAAA,IAAS,IAAI,CAAC,KAAK,CAAC,MAAA,GAAS,CAAC,EAAE;AAC3C;AACA;AACA,IAAI,MAAM,YAAY,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AACnC,IAAI,MAAMC,YAAA,GAAa,SAAS,EAAE,UAAU;AAC5C;AACA,IAAI,MAAM,UAAA,GAAa,GAAA,IAAOA,YAAA,GAAaD,6CAAkC,CAACC,YAAU,CAAA,GAAI,CAAC,CAAC;AAC9F,IAAI,MAAA,IAAU,UAAA,GAAa,IAAI,CAAC,KAAK,CAAC,MAAM;AAC5C,EAAE;AACF,EAAE,OAAO,MAAM;AACf;;;;"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Determines if span streaming is enabled for the given client
|
|
5
|
+
*/
|
|
6
|
+
function hasSpanStreamingEnabled(client) {
|
|
7
|
+
return client.getOptions().traceLifecycle === 'stream';
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
exports.hasSpanStreamingEnabled = hasSpanStreamingEnabled;
|
|
11
|
+
//# sourceMappingURL=hasSpanStreamingEnabled.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hasSpanStreamingEnabled.js","sources":["../../../../src/tracing/spans/hasSpanStreamingEnabled.ts"],"sourcesContent":["import type { Client } from '../../client';\n\n/**\n * Determines if span streaming is enabled for the given client\n */\nexport function hasSpanStreamingEnabled(client: Client): boolean {\n return client.getOptions().traceLifecycle === 'stream';\n}\n"],"names":[],"mappings":";;AAEA;AACA;AACA;AACO,SAAS,uBAAuB,CAAC,MAAM,EAAmB;AACjE,EAAE,OAAO,MAAM,CAAC,UAAU,EAAE,CAAC,cAAA,KAAmB,QAAQ;AACxD;;;;"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const debugBuild = require('../../debug-build.js');
|
|
4
|
+
const debugLogger = require('../../utils/debug-logger.js');
|
|
5
|
+
const timer = require('../../utils/timer.js');
|
|
6
|
+
const dynamicSamplingContext = require('../dynamicSamplingContext.js');
|
|
7
|
+
const envelope = require('./envelope.js');
|
|
8
|
+
const estimateSize = require('./estimateSize.js');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* We must not send more than 1000 spans in one envelope.
|
|
12
|
+
* Otherwise the envelope is dropped by Relay.
|
|
13
|
+
*/
|
|
14
|
+
const MAX_SPANS_PER_ENVELOPE = 1000;
|
|
15
|
+
|
|
16
|
+
const MAX_TRACE_WEIGHT_IN_BYTES = 5000000;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* A buffer for serialized streamed span JSON objects that flushes them to Sentry in Span v2 envelopes.
|
|
20
|
+
* Handles per-trace timeout-based flushing, size thresholds, and graceful shutdown.
|
|
21
|
+
* Also handles computation of the Dynamic Sampling Context (DSC) for the trace, if it wasn't yet
|
|
22
|
+
* frozen onto the segment span.
|
|
23
|
+
*
|
|
24
|
+
* For this, we need the reference to the segment span instance, from
|
|
25
|
+
* which we compute the DSC. Doing this in the buffer ensures that we compute the DSC as late as possible,
|
|
26
|
+
* allowing span name and data updates up to this point. Worth noting here that the segment span is likely
|
|
27
|
+
* still active and modifyable when child spans are added to the buffer.
|
|
28
|
+
*/
|
|
29
|
+
class SpanBuffer {
|
|
30
|
+
/* Bucket spans by their trace id, along with accumulated size and a per-trace flush timeout */
|
|
31
|
+
|
|
32
|
+
constructor(client, options) {
|
|
33
|
+
this._traceBuckets = new Map();
|
|
34
|
+
this._client = client;
|
|
35
|
+
|
|
36
|
+
const { maxSpanLimit, flushInterval, maxTraceWeightInBytes } = options ?? {};
|
|
37
|
+
|
|
38
|
+
this._maxSpanLimit =
|
|
39
|
+
maxSpanLimit && maxSpanLimit > 0 && maxSpanLimit <= MAX_SPANS_PER_ENVELOPE
|
|
40
|
+
? maxSpanLimit
|
|
41
|
+
: MAX_SPANS_PER_ENVELOPE;
|
|
42
|
+
this._flushInterval = flushInterval && flushInterval > 0 ? flushInterval : 5000;
|
|
43
|
+
this._maxTraceWeight =
|
|
44
|
+
maxTraceWeightInBytes && maxTraceWeightInBytes > 0 ? maxTraceWeightInBytes : MAX_TRACE_WEIGHT_IN_BYTES;
|
|
45
|
+
|
|
46
|
+
this._client.on('flush', () => {
|
|
47
|
+
this.drain();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
this._client.on('close', () => {
|
|
51
|
+
// No need to drain the buffer here as `Client.close()` internally already calls `Client.flush()`
|
|
52
|
+
// which already invokes the `flush` hook and thus drains the buffer.
|
|
53
|
+
this._traceBuckets.forEach(bucket => {
|
|
54
|
+
clearTimeout(bucket.timeout);
|
|
55
|
+
});
|
|
56
|
+
this._traceBuckets.clear();
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Add a span to the buffer.
|
|
62
|
+
*/
|
|
63
|
+
add(spanJSON) {
|
|
64
|
+
const traceId = spanJSON.trace_id;
|
|
65
|
+
let bucket = this._traceBuckets.get(traceId);
|
|
66
|
+
|
|
67
|
+
if (!bucket) {
|
|
68
|
+
bucket = {
|
|
69
|
+
spans: new Set(),
|
|
70
|
+
size: 0,
|
|
71
|
+
timeout: timer.safeUnref(
|
|
72
|
+
setTimeout(() => {
|
|
73
|
+
this.flush(traceId);
|
|
74
|
+
}, this._flushInterval),
|
|
75
|
+
),
|
|
76
|
+
};
|
|
77
|
+
this._traceBuckets.set(traceId, bucket);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
bucket.spans.add(spanJSON);
|
|
81
|
+
bucket.size += estimateSize.estimateSerializedSpanSizeInBytes(spanJSON);
|
|
82
|
+
|
|
83
|
+
if (bucket.spans.size >= this._maxSpanLimit || bucket.size >= this._maxTraceWeight) {
|
|
84
|
+
this.flush(traceId);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Drain and flush all buffered traces.
|
|
90
|
+
*/
|
|
91
|
+
drain() {
|
|
92
|
+
if (!this._traceBuckets.size) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
debugBuild.DEBUG_BUILD && debugLogger.debug.log(`Flushing span tree map with ${this._traceBuckets.size} traces`);
|
|
97
|
+
|
|
98
|
+
this._traceBuckets.forEach((_, traceId) => {
|
|
99
|
+
this.flush(traceId);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Flush spans of a specific trace.
|
|
105
|
+
* In contrast to {@link SpanBuffer.drain}, this method does not flush all traces, but only the one with the given traceId.
|
|
106
|
+
*/
|
|
107
|
+
flush(traceId) {
|
|
108
|
+
const bucket = this._traceBuckets.get(traceId);
|
|
109
|
+
if (!bucket) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (!bucket.spans.size) {
|
|
114
|
+
// we should never get here, given we always add a span when we create a new bucket
|
|
115
|
+
// and delete the bucket once we flush out the trace
|
|
116
|
+
this._removeTrace(traceId);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const spans = Array.from(bucket.spans);
|
|
121
|
+
|
|
122
|
+
const segmentSpan = spans[0]?._segmentSpan;
|
|
123
|
+
if (!segmentSpan) {
|
|
124
|
+
debugBuild.DEBUG_BUILD && debugLogger.debug.warn('No segment span reference found on span JSON, cannot compute DSC');
|
|
125
|
+
this._removeTrace(traceId);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const dsc = dynamicSamplingContext.getDynamicSamplingContextFromSpan(segmentSpan);
|
|
130
|
+
|
|
131
|
+
const cleanedSpans = spans.map(spanJSON => {
|
|
132
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
133
|
+
const { _segmentSpan, ...cleanSpanJSON } = spanJSON;
|
|
134
|
+
return cleanSpanJSON;
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const envelope$1 = envelope.createStreamedSpanEnvelope(cleanedSpans, dsc, this._client);
|
|
138
|
+
|
|
139
|
+
debugBuild.DEBUG_BUILD && debugLogger.debug.log(`Sending span envelope for trace ${traceId} with ${cleanedSpans.length} spans`);
|
|
140
|
+
|
|
141
|
+
this._client.sendEnvelope(envelope$1).then(null, reason => {
|
|
142
|
+
debugBuild.DEBUG_BUILD && debugLogger.debug.error('Error while sending streamed span envelope:', reason);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
this._removeTrace(traceId);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
_removeTrace(traceId) {
|
|
149
|
+
const bucket = this._traceBuckets.get(traceId);
|
|
150
|
+
if (bucket) {
|
|
151
|
+
clearTimeout(bucket.timeout);
|
|
152
|
+
}
|
|
153
|
+
this._traceBuckets.delete(traceId);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
exports.SpanBuffer = SpanBuffer;
|
|
158
|
+
//# sourceMappingURL=spanBuffer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spanBuffer.js","sources":["../../../../src/tracing/spans/spanBuffer.ts"],"sourcesContent":["import type { Client } from '../../client';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport type { SerializedStreamedSpan } from '../../types-hoist/span';\nimport { debug } from '../../utils/debug-logger';\nimport { safeUnref } from '../../utils/timer';\nimport { getDynamicSamplingContextFromSpan } from '../dynamicSamplingContext';\nimport type { SerializedStreamedSpanWithSegmentSpan } from './captureSpan';\nimport { createStreamedSpanEnvelope } from './envelope';\nimport { estimateSerializedSpanSizeInBytes } from './estimateSize';\n\n/**\n * We must not send more than 1000 spans in one envelope.\n * Otherwise the envelope is dropped by Relay.\n */\nconst MAX_SPANS_PER_ENVELOPE = 1000;\n\nconst MAX_TRACE_WEIGHT_IN_BYTES = 5_000_000;\n\ninterface TraceBucket {\n spans: Set<SerializedStreamedSpanWithSegmentSpan>;\n size: number;\n timeout: ReturnType<typeof setTimeout>;\n}\n\nexport interface SpanBufferOptions {\n /**\n * Max spans per trace before auto-flush\n * Must not exceed 1000.\n *\n * @default 1_000\n */\n maxSpanLimit?: number;\n\n /**\n * Per-trace flush timeout in ms. A timeout is started when a trace bucket is first created\n * and fires flush() for that specific trace when it expires.\n * Must be greater than 0.\n *\n * @default 5_000\n */\n flushInterval?: number;\n\n /**\n * Max accumulated byte weight of spans per trace before auto-flush.\n * Size is estimated, not exact. Uses 2 bytes per character for strings (UTF-16).\n *\n * @default 5_000_000 (5 MB)\n */\n maxTraceWeightInBytes?: number;\n}\n\n/**\n * A buffer for serialized streamed span JSON objects that flushes them to Sentry in Span v2 envelopes.\n * Handles per-trace timeout-based flushing, size thresholds, and graceful shutdown.\n * Also handles computation of the Dynamic Sampling Context (DSC) for the trace, if it wasn't yet\n * frozen onto the segment span.\n *\n * For this, we need the reference to the segment span instance, from\n * which we compute the DSC. Doing this in the buffer ensures that we compute the DSC as late as possible,\n * allowing span name and data updates up to this point. Worth noting here that the segment span is likely\n * still active and modifyable when child spans are added to the buffer.\n */\nexport class SpanBuffer {\n /* Bucket spans by their trace id, along with accumulated size and a per-trace flush timeout */\n private _traceBuckets: Map<string, TraceBucket>;\n\n private _client: Client;\n private _maxSpanLimit: number;\n private _flushInterval: number;\n private _maxTraceWeight: number;\n\n public constructor(client: Client, options?: SpanBufferOptions) {\n this._traceBuckets = new Map();\n this._client = client;\n\n const { maxSpanLimit, flushInterval, maxTraceWeightInBytes } = options ?? {};\n\n this._maxSpanLimit =\n maxSpanLimit && maxSpanLimit > 0 && maxSpanLimit <= MAX_SPANS_PER_ENVELOPE\n ? maxSpanLimit\n : MAX_SPANS_PER_ENVELOPE;\n this._flushInterval = flushInterval && flushInterval > 0 ? flushInterval : 5_000;\n this._maxTraceWeight =\n maxTraceWeightInBytes && maxTraceWeightInBytes > 0 ? maxTraceWeightInBytes : MAX_TRACE_WEIGHT_IN_BYTES;\n\n this._client.on('flush', () => {\n this.drain();\n });\n\n this._client.on('close', () => {\n // No need to drain the buffer here as `Client.close()` internally already calls `Client.flush()`\n // which already invokes the `flush` hook and thus drains the buffer.\n this._traceBuckets.forEach(bucket => {\n clearTimeout(bucket.timeout);\n });\n this._traceBuckets.clear();\n });\n }\n\n /**\n * Add a span to the buffer.\n */\n public add(spanJSON: SerializedStreamedSpanWithSegmentSpan): void {\n const traceId = spanJSON.trace_id;\n let bucket = this._traceBuckets.get(traceId);\n\n if (!bucket) {\n bucket = {\n spans: new Set(),\n size: 0,\n timeout: safeUnref(\n setTimeout(() => {\n this.flush(traceId);\n }, this._flushInterval),\n ),\n };\n this._traceBuckets.set(traceId, bucket);\n }\n\n bucket.spans.add(spanJSON);\n bucket.size += estimateSerializedSpanSizeInBytes(spanJSON);\n\n if (bucket.spans.size >= this._maxSpanLimit || bucket.size >= this._maxTraceWeight) {\n this.flush(traceId);\n }\n }\n\n /**\n * Drain and flush all buffered traces.\n */\n public drain(): void {\n if (!this._traceBuckets.size) {\n return;\n }\n\n DEBUG_BUILD && debug.log(`Flushing span tree map with ${this._traceBuckets.size} traces`);\n\n this._traceBuckets.forEach((_, traceId) => {\n this.flush(traceId);\n });\n }\n\n /**\n * Flush spans of a specific trace.\n * In contrast to {@link SpanBuffer.drain}, this method does not flush all traces, but only the one with the given traceId.\n */\n public flush(traceId: string): void {\n const bucket = this._traceBuckets.get(traceId);\n if (!bucket) {\n return;\n }\n\n if (!bucket.spans.size) {\n // we should never get here, given we always add a span when we create a new bucket\n // and delete the bucket once we flush out the trace\n this._removeTrace(traceId);\n return;\n }\n\n const spans = Array.from(bucket.spans);\n\n const segmentSpan = spans[0]?._segmentSpan;\n if (!segmentSpan) {\n DEBUG_BUILD && debug.warn('No segment span reference found on span JSON, cannot compute DSC');\n this._removeTrace(traceId);\n return;\n }\n\n const dsc = getDynamicSamplingContextFromSpan(segmentSpan);\n\n const cleanedSpans: SerializedStreamedSpan[] = spans.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 = createStreamedSpanEnvelope(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 streamed span envelope:', reason);\n });\n\n this._removeTrace(traceId);\n }\n\n private _removeTrace(traceId: string): void {\n const bucket = this._traceBuckets.get(traceId);\n if (bucket) {\n clearTimeout(bucket.timeout);\n }\n this._traceBuckets.delete(traceId);\n }\n}\n"],"names":["safeUnref","estimateSerializedSpanSizeInBytes","DEBUG_BUILD","debug","getDynamicSamplingContextFromSpan","envelope","createStreamedSpanEnvelope"],"mappings":"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"}
|
|
@@ -9,6 +9,8 @@ const baggage = require('../utils/baggage.js');
|
|
|
9
9
|
const debugLogger = require('../utils/debug-logger.js');
|
|
10
10
|
const handleCallbackErrors = require('../utils/handleCallbackErrors.js');
|
|
11
11
|
const hasSpansEnabled = require('../utils/hasSpansEnabled.js');
|
|
12
|
+
const shouldIgnoreSpan = require('../utils/should-ignore-span.js');
|
|
13
|
+
const hasSpanStreamingEnabled = require('./spans/hasSpanStreamingEnabled.js');
|
|
12
14
|
const parseSampleRate = require('../utils/parseSampleRate.js');
|
|
13
15
|
const propagationContext = require('../utils/propagationContext.js');
|
|
14
16
|
const randomSafeContext = require('../utils/randomSafeContext.js');
|
|
@@ -69,7 +71,12 @@ function startSpan(options, callback) {
|
|
|
69
71
|
scope,
|
|
70
72
|
});
|
|
71
73
|
|
|
72
|
-
|
|
74
|
+
// Ignored root spans still need to be set on scope so that `getActiveSpan()` returns them
|
|
75
|
+
// and descendants are also non-recording. Ignored child spans don't need this because
|
|
76
|
+
// the parent span is already on scope.
|
|
77
|
+
if (!_isIgnoredSpan(activeSpan) || !parentSpan) {
|
|
78
|
+
spanOnScope._setSpanForScope(scope, activeSpan);
|
|
79
|
+
}
|
|
73
80
|
|
|
74
81
|
return handleCallbackErrors.handleCallbackErrors(
|
|
75
82
|
() => callback(activeSpan),
|
|
@@ -127,7 +134,11 @@ function startSpanManual(options, callback) {
|
|
|
127
134
|
scope,
|
|
128
135
|
});
|
|
129
136
|
|
|
130
|
-
|
|
137
|
+
// We don't set ignored child spans onto the scope because there likely is an active,
|
|
138
|
+
// unignored span on the scope already.
|
|
139
|
+
if (!_isIgnoredSpan(activeSpan) || !parentSpan) {
|
|
140
|
+
spanOnScope._setSpanForScope(scope, activeSpan);
|
|
141
|
+
}
|
|
131
142
|
|
|
132
143
|
return handleCallbackErrors.handleCallbackErrors(
|
|
133
144
|
// We pass the `finish` function to the callback, so the user can finish the span manually
|
|
@@ -328,6 +339,20 @@ function createChildOrRootSpan({
|
|
|
328
339
|
return span;
|
|
329
340
|
}
|
|
330
341
|
|
|
342
|
+
const client = currentScopes.getClient();
|
|
343
|
+
if (_shouldIgnoreStreamedSpan(client, spanArguments)) {
|
|
344
|
+
if (!_isTracingSuppressed(scope)) {
|
|
345
|
+
// if tracing is actively suppressed (Sentry.suppressTracing(...)),
|
|
346
|
+
// we don't want to record a client outcome for the ignored span
|
|
347
|
+
client?.recordDroppedEvent('ignored', 'span');
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return new sentryNonRecordingSpan.SentryNonRecordingSpan({
|
|
351
|
+
dropReason: 'ignored',
|
|
352
|
+
traceId: parentSpan?.spanContext().traceId ?? scope.getPropagationContext().traceId,
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
|
|
331
356
|
const isolationScope = currentScopes.getIsolationScope();
|
|
332
357
|
|
|
333
358
|
let span;
|
|
@@ -427,9 +452,9 @@ function _startRootSpan(spanArguments, scope, parentSampled) {
|
|
|
427
452
|
const finalAttributes = mutableSpanSamplingData.spanAttributes;
|
|
428
453
|
|
|
429
454
|
const currentPropagationContext = scope.getPropagationContext();
|
|
430
|
-
const
|
|
431
|
-
|
|
432
|
-
]
|
|
455
|
+
const isTracingSuppressed = _isTracingSuppressed(scope);
|
|
456
|
+
|
|
457
|
+
const [sampled, sampleRate, localSampleRateWasApplied] = isTracingSuppressed
|
|
433
458
|
? [false]
|
|
434
459
|
: sampling.sampleSpan(
|
|
435
460
|
options,
|
|
@@ -453,9 +478,9 @@ function _startRootSpan(spanArguments, scope, parentSampled) {
|
|
|
453
478
|
sampled,
|
|
454
479
|
});
|
|
455
480
|
|
|
456
|
-
if (!sampled && client) {
|
|
481
|
+
if (!sampled && client && !isTracingSuppressed) {
|
|
457
482
|
debugBuild.DEBUG_BUILD && debugLogger.debug.log('[Tracing] Discarding root span because its trace was not chosen to be sampled.');
|
|
458
|
-
client.recordDroppedEvent('sample_rate', 'transaction');
|
|
483
|
+
client.recordDroppedEvent('sample_rate', hasSpanStreamingEnabled.hasSpanStreamingEnabled(client) ? 'span' : 'transaction');
|
|
459
484
|
}
|
|
460
485
|
|
|
461
486
|
if (client) {
|
|
@@ -471,7 +496,8 @@ function _startRootSpan(spanArguments, scope, parentSampled) {
|
|
|
471
496
|
*/
|
|
472
497
|
function _startChildSpan(parentSpan, scope, spanArguments) {
|
|
473
498
|
const { spanId, traceId } = parentSpan.spanContext();
|
|
474
|
-
const
|
|
499
|
+
const isTracingSuppressed = _isTracingSuppressed(scope);
|
|
500
|
+
const sampled = isTracingSuppressed ? false : spanUtils.spanIsSampled(parentSpan);
|
|
475
501
|
|
|
476
502
|
const childSpan = sampled
|
|
477
503
|
? new sentrySpan.SentrySpan({
|
|
@@ -485,14 +511,33 @@ function _startChildSpan(parentSpan, scope, spanArguments) {
|
|
|
485
511
|
spanUtils.addChildSpanToSpan(parentSpan, childSpan);
|
|
486
512
|
|
|
487
513
|
const client = currentScopes.getClient();
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
514
|
+
|
|
515
|
+
if (!client) {
|
|
516
|
+
return childSpan;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
if (hasSpanStreamingEnabled.hasSpanStreamingEnabled(client) && childSpan instanceof sentryNonRecordingSpan.SentryNonRecordingSpan) {
|
|
520
|
+
if (parentSpan instanceof sentryNonRecordingSpan.SentryNonRecordingSpan && parentSpan.dropReason) {
|
|
521
|
+
// We land here if the parent span was a segment span that was ignored (`ignoreSpans`).
|
|
522
|
+
// In this case, the child was also ignored (see `sampled` above) but we need to
|
|
523
|
+
// record a client outcome for the child.
|
|
524
|
+
childSpan.dropReason = parentSpan.dropReason;
|
|
525
|
+
client.recordDroppedEvent(parentSpan.dropReason, 'span');
|
|
526
|
+
} else if (!isTracingSuppressed) {
|
|
527
|
+
// Otherwise, the child is not sampled due to sampling of the parent span,
|
|
528
|
+
// hence we record a sample_rate client outcome for the child.
|
|
529
|
+
childSpan.dropReason = 'sample_rate';
|
|
530
|
+
client.recordDroppedEvent('sample_rate', 'span');
|
|
493
531
|
}
|
|
494
532
|
}
|
|
495
533
|
|
|
534
|
+
client.emit('spanStart', childSpan);
|
|
535
|
+
// If it has an endTimestamp, it's already ended
|
|
536
|
+
if (spanArguments.endTimestamp) {
|
|
537
|
+
client.emit('spanEnd', childSpan);
|
|
538
|
+
client.emit('afterSpanEnd', childSpan);
|
|
539
|
+
}
|
|
540
|
+
|
|
496
541
|
return childSpan;
|
|
497
542
|
}
|
|
498
543
|
|
|
@@ -530,6 +575,31 @@ function getActiveSpanWrapper(parentSpan) {
|
|
|
530
575
|
: (callback) => callback();
|
|
531
576
|
}
|
|
532
577
|
|
|
578
|
+
/* Checks if `ignoreSpans` applies (extracted for bundle size)*/
|
|
579
|
+
function _shouldIgnoreStreamedSpan(client, spanArguments) {
|
|
580
|
+
const ignoreSpans = client?.getOptions().ignoreSpans;
|
|
581
|
+
|
|
582
|
+
if (!client || !hasSpanStreamingEnabled.hasSpanStreamingEnabled(client) || !ignoreSpans?.length) {
|
|
583
|
+
return false;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
return shouldIgnoreSpan.shouldIgnoreSpan(
|
|
587
|
+
{
|
|
588
|
+
description: spanArguments.name || '',
|
|
589
|
+
op: spanArguments.attributes?.[semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_OP] || spanArguments.op,
|
|
590
|
+
},
|
|
591
|
+
ignoreSpans,
|
|
592
|
+
);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
function _isIgnoredSpan(span) {
|
|
596
|
+
return span instanceof sentryNonRecordingSpan.SentryNonRecordingSpan && span.dropReason === 'ignored';
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
function _isTracingSuppressed(scope) {
|
|
600
|
+
return scope.getScopeData().sdkProcessingMetadata[SUPPRESS_TRACING_KEY] === true;
|
|
601
|
+
}
|
|
602
|
+
|
|
533
603
|
exports.continueTrace = continueTrace;
|
|
534
604
|
exports.startInactiveSpan = startInactiveSpan;
|
|
535
605
|
exports.startNewTrace = startNewTrace;
|