@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.
Files changed (316) hide show
  1. package/build/cjs/attributes.js +43 -0
  2. package/build/cjs/attributes.js.map +1 -1
  3. package/build/cjs/client.js +13 -6
  4. package/build/cjs/client.js.map +1 -1
  5. package/build/cjs/envelope.js +4 -3
  6. package/build/cjs/envelope.js.map +1 -1
  7. package/build/cjs/index.js +44 -13
  8. package/build/cjs/index.js.map +1 -1
  9. package/build/cjs/integration.js +6 -0
  10. package/build/cjs/integration.js.map +1 -1
  11. package/build/cjs/integrations/express/index.js +206 -0
  12. package/build/cjs/integrations/express/index.js.map +1 -0
  13. package/build/cjs/integrations/express/patch-layer.js +251 -0
  14. package/build/cjs/integrations/express/patch-layer.js.map +1 -0
  15. package/build/cjs/integrations/express/request-layer-store.js +25 -0
  16. package/build/cjs/integrations/express/request-layer-store.js.map +1 -0
  17. package/build/cjs/integrations/express/set-sdk-processing-metadata.js +17 -0
  18. package/build/cjs/integrations/express/set-sdk-processing-metadata.js.map +1 -0
  19. package/build/cjs/integrations/express/types.js +17 -0
  20. package/build/cjs/integrations/express/types.js.map +1 -0
  21. package/build/cjs/integrations/express/utils.js +238 -0
  22. package/build/cjs/integrations/express/utils.js.map +1 -0
  23. package/build/cjs/integrations/mcp-server/correlation.js +5 -1
  24. package/build/cjs/integrations/mcp-server/correlation.js.map +1 -1
  25. package/build/cjs/integrations/mcp-server/handlers.js +18 -10
  26. package/build/cjs/integrations/mcp-server/handlers.js.map +1 -1
  27. package/build/cjs/integrations/mcp-server/index.js +2 -1
  28. package/build/cjs/integrations/mcp-server/index.js.map +1 -1
  29. package/build/cjs/integrations/mcp-server/transport.js +1 -1
  30. package/build/cjs/integrations/mcp-server/transport.js.map +1 -1
  31. package/build/cjs/integrations/mcp-server/validation.js +7 -5
  32. package/build/cjs/integrations/mcp-server/validation.js.map +1 -1
  33. package/build/cjs/integrations/spanStreaming.js +48 -0
  34. package/build/cjs/integrations/spanStreaming.js.map +1 -0
  35. package/build/cjs/semanticAttributes.js +35 -3
  36. package/build/cjs/semanticAttributes.js.map +1 -1
  37. package/build/cjs/tracing/ai/gen-ai-attributes.js +9 -65
  38. package/build/cjs/tracing/ai/gen-ai-attributes.js.map +1 -1
  39. package/build/cjs/tracing/ai/utils.js +50 -0
  40. package/build/cjs/tracing/ai/utils.js.map +1 -1
  41. package/build/cjs/tracing/anthropic-ai/index.js +1 -12
  42. package/build/cjs/tracing/anthropic-ai/index.js.map +1 -1
  43. package/build/cjs/tracing/anthropic-ai/streaming.js +2 -100
  44. package/build/cjs/tracing/anthropic-ai/streaming.js.map +1 -1
  45. package/build/cjs/tracing/dynamicSamplingContext.js +2 -1
  46. package/build/cjs/tracing/dynamicSamplingContext.js.map +1 -1
  47. package/build/cjs/tracing/google-genai/constants.js +1 -6
  48. package/build/cjs/tracing/google-genai/constants.js.map +1 -1
  49. package/build/cjs/tracing/google-genai/index.js +24 -30
  50. package/build/cjs/tracing/google-genai/index.js.map +1 -1
  51. package/build/cjs/tracing/google-genai/streaming.js +2 -23
  52. package/build/cjs/tracing/google-genai/streaming.js.map +1 -1
  53. package/build/cjs/tracing/langchain/embeddings.js +132 -0
  54. package/build/cjs/tracing/langchain/embeddings.js.map +1 -0
  55. package/build/cjs/tracing/langchain/index.js.map +1 -1
  56. package/build/cjs/tracing/openai/index.js +2 -29
  57. package/build/cjs/tracing/openai/index.js.map +1 -1
  58. package/build/cjs/tracing/openai/streaming.js +3 -34
  59. package/build/cjs/tracing/openai/streaming.js.map +1 -1
  60. package/build/cjs/tracing/openai/utils.js +78 -204
  61. package/build/cjs/tracing/openai/utils.js.map +1 -1
  62. package/build/cjs/tracing/sentryNonRecordingSpan.js +7 -0
  63. package/build/cjs/tracing/sentryNonRecordingSpan.js.map +1 -1
  64. package/build/cjs/tracing/sentrySpan.js +39 -0
  65. package/build/cjs/tracing/sentrySpan.js.map +1 -1
  66. package/build/cjs/tracing/spans/beforeSendSpan.js +43 -0
  67. package/build/cjs/tracing/spans/beforeSendSpan.js.map +1 -0
  68. package/build/cjs/tracing/spans/captureSpan.js +126 -0
  69. package/build/cjs/tracing/spans/captureSpan.js.map +1 -0
  70. package/build/cjs/tracing/spans/envelope.js +38 -0
  71. package/build/cjs/tracing/spans/envelope.js.map +1 -0
  72. package/build/cjs/tracing/spans/estimateSize.js +41 -0
  73. package/build/cjs/tracing/spans/estimateSize.js.map +1 -0
  74. package/build/cjs/tracing/spans/hasSpanStreamingEnabled.js +11 -0
  75. package/build/cjs/tracing/spans/hasSpanStreamingEnabled.js.map +1 -0
  76. package/build/cjs/tracing/spans/spanBuffer.js +158 -0
  77. package/build/cjs/tracing/spans/spanBuffer.js.map +1 -0
  78. package/build/cjs/tracing/trace.js +83 -13
  79. package/build/cjs/tracing/trace.js.map +1 -1
  80. package/build/cjs/tracing/vercel-ai/utils.js +1 -4
  81. package/build/cjs/tracing/vercel-ai/utils.js.map +1 -1
  82. package/build/cjs/utils/featureFlags.js +6 -0
  83. package/build/cjs/utils/featureFlags.js.map +1 -1
  84. package/build/cjs/utils/object.js +33 -0
  85. package/build/cjs/utils/object.js.map +1 -1
  86. package/build/cjs/utils/spanUtils.js +116 -13
  87. package/build/cjs/utils/spanUtils.js.map +1 -1
  88. package/build/cjs/utils/stacktrace.js +3 -1
  89. package/build/cjs/utils/stacktrace.js.map +1 -1
  90. package/build/cjs/utils/string.js +3 -0
  91. package/build/cjs/utils/string.js.map +1 -1
  92. package/build/cjs/utils/version.js +1 -1
  93. package/build/esm/attributes.js +43 -1
  94. package/build/esm/attributes.js.map +1 -1
  95. package/build/esm/client.js +8 -1
  96. package/build/esm/client.js.map +1 -1
  97. package/build/esm/envelope.js +2 -1
  98. package/build/esm/envelope.js.map +1 -1
  99. package/build/esm/index.js +10 -2
  100. package/build/esm/index.js.map +1 -1
  101. package/build/esm/integration.js +6 -0
  102. package/build/esm/integration.js.map +1 -1
  103. package/build/esm/integrations/express/index.js +202 -0
  104. package/build/esm/integrations/express/index.js.map +1 -0
  105. package/build/esm/integrations/express/patch-layer.js +249 -0
  106. package/build/esm/integrations/express/patch-layer.js.map +1 -0
  107. package/build/esm/integrations/express/request-layer-store.js +22 -0
  108. package/build/esm/integrations/express/request-layer-store.js.map +1 -0
  109. package/build/esm/integrations/express/set-sdk-processing-metadata.js +15 -0
  110. package/build/esm/integrations/express/set-sdk-processing-metadata.js.map +1 -0
  111. package/build/esm/integrations/express/types.js +10 -0
  112. package/build/esm/integrations/express/types.js.map +1 -0
  113. package/build/esm/integrations/express/utils.js +225 -0
  114. package/build/esm/integrations/express/utils.js.map +1 -0
  115. package/build/esm/integrations/mcp-server/correlation.js +5 -1
  116. package/build/esm/integrations/mcp-server/correlation.js.map +1 -1
  117. package/build/esm/integrations/mcp-server/handlers.js +18 -10
  118. package/build/esm/integrations/mcp-server/handlers.js.map +1 -1
  119. package/build/esm/integrations/mcp-server/index.js +2 -1
  120. package/build/esm/integrations/mcp-server/index.js.map +1 -1
  121. package/build/esm/integrations/mcp-server/transport.js +1 -1
  122. package/build/esm/integrations/mcp-server/transport.js.map +1 -1
  123. package/build/esm/integrations/mcp-server/validation.js +7 -5
  124. package/build/esm/integrations/mcp-server/validation.js.map +1 -1
  125. package/build/esm/integrations/spanStreaming.js +46 -0
  126. package/build/esm/integrations/spanStreaming.js.map +1 -0
  127. package/build/esm/package.json +1 -1
  128. package/build/esm/semanticAttributes.js +26 -4
  129. package/build/esm/semanticAttributes.js.map +1 -1
  130. package/build/esm/tracing/ai/gen-ai-attributes.js +8 -56
  131. package/build/esm/tracing/ai/gen-ai-attributes.js.map +1 -1
  132. package/build/esm/tracing/ai/utils.js +51 -2
  133. package/build/esm/tracing/ai/utils.js.map +1 -1
  134. package/build/esm/tracing/anthropic-ai/index.js +2 -13
  135. package/build/esm/tracing/anthropic-ai/index.js.map +1 -1
  136. package/build/esm/tracing/anthropic-ai/streaming.js +3 -101
  137. package/build/esm/tracing/anthropic-ai/streaming.js.map +1 -1
  138. package/build/esm/tracing/dynamicSamplingContext.js +2 -1
  139. package/build/esm/tracing/dynamicSamplingContext.js.map +1 -1
  140. package/build/esm/tracing/google-genai/constants.js +2 -5
  141. package/build/esm/tracing/google-genai/constants.js.map +1 -1
  142. package/build/esm/tracing/google-genai/index.js +25 -31
  143. package/build/esm/tracing/google-genai/index.js.map +1 -1
  144. package/build/esm/tracing/google-genai/streaming.js +2 -23
  145. package/build/esm/tracing/google-genai/streaming.js.map +1 -1
  146. package/build/esm/tracing/langchain/embeddings.js +129 -0
  147. package/build/esm/tracing/langchain/embeddings.js.map +1 -0
  148. package/build/esm/tracing/langchain/index.js.map +1 -1
  149. package/build/esm/tracing/openai/index.js +3 -30
  150. package/build/esm/tracing/openai/index.js.map +1 -1
  151. package/build/esm/tracing/openai/streaming.js +4 -35
  152. package/build/esm/tracing/openai/streaming.js.map +1 -1
  153. package/build/esm/tracing/openai/utils.js +79 -196
  154. package/build/esm/tracing/openai/utils.js.map +1 -1
  155. package/build/esm/tracing/sentryNonRecordingSpan.js +7 -0
  156. package/build/esm/tracing/sentryNonRecordingSpan.js.map +1 -1
  157. package/build/esm/tracing/sentrySpan.js +40 -1
  158. package/build/esm/tracing/sentrySpan.js.map +1 -1
  159. package/build/esm/tracing/spans/beforeSendSpan.js +40 -0
  160. package/build/esm/tracing/spans/beforeSendSpan.js.map +1 -0
  161. package/build/esm/tracing/spans/captureSpan.js +122 -0
  162. package/build/esm/tracing/spans/captureSpan.js.map +1 -0
  163. package/build/esm/tracing/spans/envelope.js +36 -0
  164. package/build/esm/tracing/spans/envelope.js.map +1 -0
  165. package/build/esm/tracing/spans/estimateSize.js +39 -0
  166. package/build/esm/tracing/spans/estimateSize.js.map +1 -0
  167. package/build/esm/tracing/spans/hasSpanStreamingEnabled.js +9 -0
  168. package/build/esm/tracing/spans/hasSpanStreamingEnabled.js.map +1 -0
  169. package/build/esm/tracing/spans/spanBuffer.js +156 -0
  170. package/build/esm/tracing/spans/spanBuffer.js.map +1 -0
  171. package/build/esm/tracing/trace.js +84 -14
  172. package/build/esm/tracing/trace.js.map +1 -1
  173. package/build/esm/tracing/vercel-ai/utils.js +2 -5
  174. package/build/esm/tracing/vercel-ai/utils.js.map +1 -1
  175. package/build/esm/utils/featureFlags.js +6 -0
  176. package/build/esm/utils/featureFlags.js.map +1 -1
  177. package/build/esm/utils/object.js +33 -1
  178. package/build/esm/utils/object.js.map +1 -1
  179. package/build/esm/utils/spanUtils.js +112 -14
  180. package/build/esm/utils/spanUtils.js.map +1 -1
  181. package/build/esm/utils/stacktrace.js +3 -1
  182. package/build/esm/utils/stacktrace.js.map +1 -1
  183. package/build/esm/utils/string.js +3 -0
  184. package/build/esm/utils/string.js.map +1 -1
  185. package/build/esm/utils/version.js +1 -1
  186. package/build/types/attributes.d.ts +5 -0
  187. package/build/types/attributes.d.ts.map +1 -1
  188. package/build/types/client.d.ts +35 -1
  189. package/build/types/client.d.ts.map +1 -1
  190. package/build/types/envelope.d.ts.map +1 -1
  191. package/build/types/index.d.ts +12 -4
  192. package/build/types/index.d.ts.map +1 -1
  193. package/build/types/integration.d.ts.map +1 -1
  194. package/build/types/integrations/express/index.d.ts +75 -0
  195. package/build/types/integrations/express/index.d.ts.map +1 -0
  196. package/build/types/integrations/express/patch-layer.d.ts +32 -0
  197. package/build/types/integrations/express/patch-layer.d.ts.map +1 -0
  198. package/build/types/integrations/express/request-layer-store.d.ts +32 -0
  199. package/build/types/integrations/express/request-layer-store.d.ts.map +1 -0
  200. package/build/types/integrations/express/set-sdk-processing-metadata.d.ts +35 -0
  201. package/build/types/integrations/express/set-sdk-processing-metadata.d.ts.map +1 -0
  202. package/build/types/integrations/express/types.d.ts +154 -0
  203. package/build/types/integrations/express/types.d.ts.map +1 -0
  204. package/build/types/integrations/express/utils.d.ts +93 -0
  205. package/build/types/integrations/express/utils.d.ts.map +1 -0
  206. package/build/types/integrations/mcp-server/correlation.d.ts +2 -1
  207. package/build/types/integrations/mcp-server/correlation.d.ts.map +1 -1
  208. package/build/types/integrations/mcp-server/handlers.d.ts +9 -4
  209. package/build/types/integrations/mcp-server/handlers.d.ts.map +1 -1
  210. package/build/types/integrations/mcp-server/index.d.ts +2 -1
  211. package/build/types/integrations/mcp-server/index.d.ts.map +1 -1
  212. package/build/types/integrations/mcp-server/types.d.ts +40 -7
  213. package/build/types/integrations/mcp-server/types.d.ts.map +1 -1
  214. package/build/types/integrations/mcp-server/validation.d.ts +4 -1
  215. package/build/types/integrations/mcp-server/validation.d.ts.map +1 -1
  216. package/build/types/integrations/spanStreaming.d.ts +2 -0
  217. package/build/types/integrations/spanStreaming.d.ts.map +1 -0
  218. package/build/types/semanticAttributes.d.ts +23 -3
  219. package/build/types/semanticAttributes.d.ts.map +1 -1
  220. package/build/types/tracing/ai/gen-ai-attributes.d.ts +6 -38
  221. package/build/types/tracing/ai/gen-ai-attributes.d.ts.map +1 -1
  222. package/build/types/tracing/ai/utils.d.ts +21 -2
  223. package/build/types/tracing/ai/utils.d.ts.map +1 -1
  224. package/build/types/tracing/anthropic-ai/index.d.ts.map +1 -1
  225. package/build/types/tracing/anthropic-ai/streaming.d.ts.map +1 -1
  226. package/build/types/tracing/dynamicSamplingContext.d.ts.map +1 -1
  227. package/build/types/tracing/google-genai/constants.d.ts +1 -3
  228. package/build/types/tracing/google-genai/constants.d.ts.map +1 -1
  229. package/build/types/tracing/google-genai/index.d.ts.map +1 -1
  230. package/build/types/tracing/google-genai/streaming.d.ts.map +1 -1
  231. package/build/types/tracing/index.d.ts +1 -0
  232. package/build/types/tracing/index.d.ts.map +1 -1
  233. package/build/types/tracing/langchain/embeddings.d.ts +27 -0
  234. package/build/types/tracing/langchain/embeddings.d.ts.map +1 -0
  235. package/build/types/tracing/langchain/index.d.ts +1 -0
  236. package/build/types/tracing/langchain/index.d.ts.map +1 -1
  237. package/build/types/tracing/openai/index.d.ts.map +1 -1
  238. package/build/types/tracing/openai/streaming.d.ts.map +1 -1
  239. package/build/types/tracing/openai/utils.d.ts +4 -49
  240. package/build/types/tracing/openai/utils.d.ts.map +1 -1
  241. package/build/types/tracing/sentryNonRecordingSpan.d.ts +12 -1
  242. package/build/types/tracing/sentryNonRecordingSpan.d.ts.map +1 -1
  243. package/build/types/tracing/sentrySpan.d.ts +10 -1
  244. package/build/types/tracing/sentrySpan.d.ts.map +1 -1
  245. package/build/types/tracing/spans/beforeSendSpan.d.ts +35 -0
  246. package/build/types/tracing/spans/beforeSendSpan.d.ts.map +1 -0
  247. package/build/types/tracing/spans/captureSpan.d.ts +26 -0
  248. package/build/types/tracing/spans/captureSpan.d.ts.map +1 -0
  249. package/build/types/tracing/spans/envelope.d.ts +8 -0
  250. package/build/types/tracing/spans/envelope.d.ts.map +1 -0
  251. package/build/types/tracing/spans/estimateSize.d.ts +12 -0
  252. package/build/types/tracing/spans/estimateSize.d.ts.map +1 -0
  253. package/build/types/tracing/spans/hasSpanStreamingEnabled.d.ts +6 -0
  254. package/build/types/tracing/spans/hasSpanStreamingEnabled.d.ts.map +1 -0
  255. package/build/types/tracing/spans/spanBuffer.d.ts +60 -0
  256. package/build/types/tracing/spans/spanBuffer.d.ts.map +1 -0
  257. package/build/types/tracing/trace.d.ts.map +1 -1
  258. package/build/types/tracing/vercel-ai/utils.d.ts.map +1 -1
  259. package/build/types/types-hoist/envelope.d.ts +22 -2
  260. package/build/types/types-hoist/envelope.d.ts.map +1 -1
  261. package/build/types/types-hoist/integration.d.ts +8 -0
  262. package/build/types/types-hoist/integration.d.ts.map +1 -1
  263. package/build/types/types-hoist/link.d.ts +2 -2
  264. package/build/types/types-hoist/link.d.ts.map +1 -1
  265. package/build/types/types-hoist/options.d.ts +26 -2
  266. package/build/types/types-hoist/options.d.ts.map +1 -1
  267. package/build/types/types-hoist/span.d.ts +35 -0
  268. package/build/types/types-hoist/span.d.ts.map +1 -1
  269. package/build/types/utils/featureFlags.d.ts.map +1 -1
  270. package/build/types/utils/object.d.ts +10 -0
  271. package/build/types/utils/object.d.ts.map +1 -1
  272. package/build/types/utils/spanUtils.d.ts +27 -2
  273. package/build/types/utils/spanUtils.d.ts.map +1 -1
  274. package/build/types/utils/stacktrace.d.ts.map +1 -1
  275. package/build/types/utils/string.d.ts +2 -2
  276. package/build/types/utils/string.d.ts.map +1 -1
  277. package/build/types-ts3.8/attributes.d.ts +5 -0
  278. package/build/types-ts3.8/client.d.ts +35 -1
  279. package/build/types-ts3.8/index.d.ts +12 -4
  280. package/build/types-ts3.8/integrations/express/index.d.ts +75 -0
  281. package/build/types-ts3.8/integrations/express/patch-layer.d.ts +32 -0
  282. package/build/types-ts3.8/integrations/express/request-layer-store.d.ts +32 -0
  283. package/build/types-ts3.8/integrations/express/set-sdk-processing-metadata.d.ts +35 -0
  284. package/build/types-ts3.8/integrations/express/types.d.ts +154 -0
  285. package/build/types-ts3.8/integrations/express/utils.d.ts +96 -0
  286. package/build/types-ts3.8/integrations/mcp-server/correlation.d.ts +2 -1
  287. package/build/types-ts3.8/integrations/mcp-server/handlers.d.ts +9 -4
  288. package/build/types-ts3.8/integrations/mcp-server/index.d.ts +2 -1
  289. package/build/types-ts3.8/integrations/mcp-server/types.d.ts +40 -7
  290. package/build/types-ts3.8/integrations/mcp-server/validation.d.ts +4 -1
  291. package/build/types-ts3.8/integrations/spanStreaming.d.ts +2 -0
  292. package/build/types-ts3.8/semanticAttributes.d.ts +23 -3
  293. package/build/types-ts3.8/tracing/ai/gen-ai-attributes.d.ts +6 -38
  294. package/build/types-ts3.8/tracing/ai/utils.d.ts +21 -2
  295. package/build/types-ts3.8/tracing/google-genai/constants.d.ts +1 -3
  296. package/build/types-ts3.8/tracing/index.d.ts +1 -0
  297. package/build/types-ts3.8/tracing/langchain/embeddings.d.ts +27 -0
  298. package/build/types-ts3.8/tracing/langchain/index.d.ts +1 -0
  299. package/build/types-ts3.8/tracing/openai/utils.d.ts +4 -49
  300. package/build/types-ts3.8/tracing/sentryNonRecordingSpan.d.ts +12 -1
  301. package/build/types-ts3.8/tracing/sentrySpan.d.ts +10 -1
  302. package/build/types-ts3.8/tracing/spans/beforeSendSpan.d.ts +35 -0
  303. package/build/types-ts3.8/tracing/spans/captureSpan.d.ts +26 -0
  304. package/build/types-ts3.8/tracing/spans/envelope.d.ts +8 -0
  305. package/build/types-ts3.8/tracing/spans/estimateSize.d.ts +12 -0
  306. package/build/types-ts3.8/tracing/spans/hasSpanStreamingEnabled.d.ts +6 -0
  307. package/build/types-ts3.8/tracing/spans/spanBuffer.d.ts +60 -0
  308. package/build/types-ts3.8/types-hoist/envelope.d.ts +22 -2
  309. package/build/types-ts3.8/types-hoist/integration.d.ts +8 -0
  310. package/build/types-ts3.8/types-hoist/link.d.ts +2 -2
  311. package/build/types-ts3.8/types-hoist/options.d.ts +26 -2
  312. package/build/types-ts3.8/types-hoist/span.d.ts +35 -0
  313. package/build/types-ts3.8/utils/object.d.ts +10 -0
  314. package/build/types-ts3.8/utils/spanUtils.d.ts +27 -2
  315. package/build/types-ts3.8/utils/string.d.ts +2 -2
  316. package/package.json +1 -1
@@ -0,0 +1,40 @@
1
+ import { addNonEnumerableProperty } from '../../utils/object.js';
2
+
3
+ /**
4
+ * A wrapper to use the new span format in your `beforeSendSpan` callback.
5
+ *
6
+ * When using `traceLifecycle: 'stream'`, wrap your callback with this function
7
+ * to receive and return {@link StreamedSpanJSON} instead of the standard {@link SpanJSON}.
8
+ *
9
+ * @example
10
+ *
11
+ * Sentry.init({
12
+ * traceLifecycle: 'stream',
13
+ * beforeSendSpan: withStreamedSpan((span) => {
14
+ * // span is of type StreamedSpanJSON
15
+ * return span;
16
+ * }),
17
+ * });
18
+ *
19
+ * @param callback - The callback function that receives and returns a {@link StreamedSpanJSON}.
20
+ * @returns A callback that is compatible with the `beforeSendSpan` option when using `traceLifecycle: 'stream'`.
21
+ */
22
+ function withStreamedSpan(
23
+ callback,
24
+ ) {
25
+ addNonEnumerableProperty(callback, '_streamed', true);
26
+ return callback ;
27
+ }
28
+
29
+ /**
30
+ * Typesafe check to identify if a `beforeSendSpan` callback expects the streamed span JSON format.
31
+ *
32
+ * @param callback - The `beforeSendSpan` callback to check.
33
+ * @returns `true` if the callback was wrapped with {@link withStreamedSpan}.
34
+ */
35
+ function isStreamedBeforeSendSpanCallback(callback) {
36
+ return !!callback && typeof callback === 'function' && '_streamed' in callback && !!callback._streamed;
37
+ }
38
+
39
+ export { isStreamedBeforeSendSpanCallback, withStreamedSpan };
40
+ //# 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":[],"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,EAAE,wBAAwB,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,122 @@
1
+ import { SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 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';
2
+ import { getCombinedScopeData } from '../../utils/scopeData.js';
3
+ import { spanToStreamedSpanJSON, INTERNAL_getSegmentSpan, streamedSpanJsonToSerializedSpan, showSpanDropWarning } from '../../utils/spanUtils.js';
4
+ import { getCapturedScopesOnSpan } from '../utils.js';
5
+ import { isStreamedBeforeSendSpanCallback } from './beforeSendSpan.js';
6
+
7
+ /**
8
+ * Captures a span and returns a JSON representation to be enqueued for sending.
9
+ *
10
+ * IMPORTANT: This function converts the span to JSON immediately to avoid writing
11
+ * to an already-ended OTel span instance (which is blocked by the OTel Span class).
12
+ *
13
+ * @returns the final serialized span with a reference to its segment span. This reference
14
+ * is needed later on to compute the DSC for the span envelope.
15
+ */
16
+ function captureSpan(span, client) {
17
+ // Convert to JSON FIRST - we cannot write to an already-ended span
18
+ const spanJSON = spanToStreamedSpanJSON(span);
19
+
20
+ const segmentSpan = INTERNAL_getSegmentSpan(span);
21
+ const serializedSegmentSpan = spanToStreamedSpanJSON(segmentSpan);
22
+
23
+ const { isolationScope: spanIsolationScope, scope: spanScope } = getCapturedScopesOnSpan(span);
24
+
25
+ const finalScopeData = getCombinedScopeData(spanIsolationScope, spanScope);
26
+
27
+ applyCommonSpanAttributes(spanJSON, serializedSegmentSpan, client, finalScopeData);
28
+
29
+ if (spanJSON.is_segment) {
30
+ // Allow hook subscribers to mutate the segment span JSON
31
+ client.emit('processSegmentSpan', spanJSON);
32
+ }
33
+
34
+ // Allow hook subscribers to mutate the span JSON
35
+ client.emit('processSpan', spanJSON);
36
+
37
+ const { beforeSendSpan } = client.getOptions();
38
+ const processedSpan =
39
+ beforeSendSpan && isStreamedBeforeSendSpanCallback(beforeSendSpan)
40
+ ? applyBeforeSendSpanCallback(spanJSON, beforeSendSpan)
41
+ : spanJSON;
42
+
43
+ // Backfill sentry.span.source from sentry.source. Only `sentry.span.source` is respected by Sentry.
44
+ // TODO(v11): Remove this backfill once we renamed SEMANTIC_ATTRIBUTE_SENTRY_SOURCE to sentry.span.source
45
+ const spanNameSource = processedSpan.attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE];
46
+ if (spanNameSource) {
47
+ safeSetSpanJSONAttributes(processedSpan, {
48
+ // Purposefully not using a constant defined here like in other attributes:
49
+ // This will be the name for SEMANTIC_ATTRIBUTE_SENTRY_SOURCE in v11
50
+ 'sentry.span.source': spanNameSource,
51
+ });
52
+ }
53
+
54
+ return {
55
+ ...streamedSpanJsonToSerializedSpan(processedSpan),
56
+ _segmentSpan: segmentSpan,
57
+ };
58
+ }
59
+
60
+ function applyCommonSpanAttributes(
61
+ spanJSON,
62
+ serializedSegmentSpan,
63
+ client,
64
+ scopeData,
65
+ ) {
66
+ const sdk = client.getSdkMetadata();
67
+ const { release, environment, sendDefaultPii } = client.getOptions();
68
+
69
+ // avoid overwriting any previously set attributes (from users or potentially our SDK instrumentation)
70
+ safeSetSpanJSONAttributes(spanJSON, {
71
+ [SEMANTIC_ATTRIBUTE_SENTRY_RELEASE]: release,
72
+ [SEMANTIC_ATTRIBUTE_SENTRY_ENVIRONMENT]: environment,
73
+ [SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_NAME]: serializedSegmentSpan.name,
74
+ [SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_ID]: serializedSegmentSpan.span_id,
75
+ [SEMANTIC_ATTRIBUTE_SENTRY_SDK_NAME]: sdk?.sdk?.name,
76
+ [SEMANTIC_ATTRIBUTE_SENTRY_SDK_VERSION]: sdk?.sdk?.version,
77
+ ...(sendDefaultPii
78
+ ? {
79
+ [SEMANTIC_ATTRIBUTE_USER_ID]: scopeData.user?.id,
80
+ [SEMANTIC_ATTRIBUTE_USER_EMAIL]: scopeData.user?.email,
81
+ [SEMANTIC_ATTRIBUTE_USER_IP_ADDRESS]: scopeData.user?.ip_address,
82
+ [SEMANTIC_ATTRIBUTE_USER_USERNAME]: scopeData.user?.username,
83
+ }
84
+ : {}),
85
+ ...scopeData.attributes,
86
+ });
87
+ }
88
+
89
+ /**
90
+ * Apply a user-provided beforeSendSpan callback to a span JSON.
91
+ */
92
+ function applyBeforeSendSpanCallback(
93
+ span,
94
+ beforeSendSpan,
95
+ ) {
96
+ const modifedSpan = beforeSendSpan(span);
97
+ if (!modifedSpan) {
98
+ showSpanDropWarning();
99
+ return span;
100
+ }
101
+ return modifedSpan;
102
+ }
103
+
104
+ /**
105
+ * Safely set attributes on a span JSON.
106
+ * If an attribute already exists, it will not be overwritten.
107
+ */
108
+ function safeSetSpanJSONAttributes(
109
+ spanJSON,
110
+ newAttributes,
111
+ ) {
112
+ const originalAttributes = spanJSON.attributes ?? (spanJSON.attributes = {});
113
+
114
+ Object.entries(newAttributes).forEach(([key, value]) => {
115
+ if (value != null && !(key in originalAttributes)) {
116
+ originalAttributes[key] = value;
117
+ }
118
+ });
119
+ }
120
+
121
+ export { applyBeforeSendSpanCallback, captureSpan, safeSetSpanJSONAttributes };
122
+ //# 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":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import { dsnToString } from '../../utils/dsn.js';
2
+ import { getSdkMetadataForEnvelopeHeader, createEnvelope } from '../../utils/envelope.js';
3
+
4
+ /**
5
+ * Creates a span v2 span streaming envelope
6
+ */
7
+ function createStreamedSpanEnvelope(
8
+ serializedSpans,
9
+ dsc,
10
+ client,
11
+ ) {
12
+ const dsn = client.getDsn();
13
+ const tunnel = client.getOptions().tunnel;
14
+ const sdk = getSdkMetadataForEnvelopeHeader(client.getOptions()._metadata);
15
+
16
+ const headers = {
17
+ sent_at: new Date().toISOString(),
18
+ ...(dscHasRequiredProps(dsc) && { trace: dsc }),
19
+ ...(sdk && { sdk }),
20
+ ...(!!tunnel && dsn && { dsn: dsnToString(dsn) }),
21
+ };
22
+
23
+ const spanContainer = [
24
+ { type: 'span', item_count: serializedSpans.length, content_type: 'application/vnd.sentry.items.span.v2+json' },
25
+ { items: serializedSpans },
26
+ ];
27
+
28
+ return createEnvelope(headers, [spanContainer]);
29
+ }
30
+
31
+ function dscHasRequiredProps(dsc) {
32
+ return !!dsc.trace_id && !!dsc.public_key;
33
+ }
34
+
35
+ export { createStreamedSpanEnvelope };
36
+ //# 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":[],"mappings":";;;AAMA;AACA;AACA;AACO,SAAS,0BAA0B;AAC1C,EAAE,eAAe;AACjB,EAAE,GAAG;AACL,EAAE,MAAM;AACR,EAAwB;AACxB,EAAE,MAAM,GAAA,GAAM,MAAM,CAAC,MAAM,EAAE;AAC7B,EAAE,MAAM,SAAS,MAAM,CAAC,UAAU,EAAE,CAAC,MAAM;AAC3C,EAAE,MAAM,GAAA,GAAM,+BAA+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,IAAU,GAAA,IAAO,EAAE,GAAG,EAAE,WAAW,CAAC,GAAG,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,OAAO,cAAc,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,39 @@
1
+ import { estimateTypedAttributesSizeInBytes } from '../../attributes.js';
2
+
3
+ /**
4
+ * Estimates the serialized byte size of a {@link SerializedStreamedSpan}.
5
+ *
6
+ * Uses 2 bytes per character as a UTF-16 approximation, and 8 bytes per number.
7
+ * The estimate is intentionally conservative and may be slightly lower than the
8
+ * actual byte size on the wire.
9
+ * We compensate for this by setting the span buffers internal limit well below the limit
10
+ * of how large an actual span v2 envelope may be.
11
+ */
12
+ function estimateSerializedSpanSizeInBytes(span) {
13
+ /*
14
+ * Fixed-size fields are pre-computed as a constant for performance:
15
+ * - two timestamps (8 bytes each = 16)
16
+ * - is_segment boolean (5 bytes, assumed false for most spans)
17
+ * - trace_id – always 32 hex chars (64 bytes)
18
+ * - span_id – always 16 hex chars (32 bytes)
19
+ * - parent_span_id – 16 hex chars, assumed present for most spans (32 bytes)
20
+ * - status "ok" – most common value (8 bytes)
21
+ * = 156 bytes total base
22
+ */
23
+ let weight = 156;
24
+ weight += span.name.length * 2;
25
+ weight += estimateTypedAttributesSizeInBytes(span.attributes);
26
+ if (span.links && span.links.length > 0) {
27
+ // Assumption: Links are roughly equal in number of attributes
28
+ // probably not always true but allows us to cut down on runtime
29
+ const firstLink = span.links[0];
30
+ const attributes = firstLink?.attributes;
31
+ // Fixed size 100 due to span_id, trace_id and sampled flag (see above)
32
+ const linkWeight = 100 + (attributes ? estimateTypedAttributesSizeInBytes(attributes) : 0);
33
+ weight += linkWeight * span.links.length;
34
+ }
35
+ return weight;
36
+ }
37
+
38
+ export { estimateSerializedSpanSizeInBytes };
39
+ //# 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":[],"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,UAAU,kCAAkC,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,MAAM,UAAA,GAAa,SAAS,EAAE,UAAU;AAC5C;AACA,IAAI,MAAM,UAAA,GAAa,GAAA,IAAO,UAAA,GAAa,kCAAkC,CAAC,UAAU,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,9 @@
1
+ /**
2
+ * Determines if span streaming is enabled for the given client
3
+ */
4
+ function hasSpanStreamingEnabled(client) {
5
+ return client.getOptions().traceLifecycle === 'stream';
6
+ }
7
+
8
+ export { hasSpanStreamingEnabled };
9
+ //# 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,156 @@
1
+ import { DEBUG_BUILD } from '../../debug-build.js';
2
+ import { debug } from '../../utils/debug-logger.js';
3
+ import { safeUnref } from '../../utils/timer.js';
4
+ import { getDynamicSamplingContextFromSpan } from '../dynamicSamplingContext.js';
5
+ import { createStreamedSpanEnvelope } from './envelope.js';
6
+ import { estimateSerializedSpanSizeInBytes } from './estimateSize.js';
7
+
8
+ /**
9
+ * We must not send more than 1000 spans in one envelope.
10
+ * Otherwise the envelope is dropped by Relay.
11
+ */
12
+ const MAX_SPANS_PER_ENVELOPE = 1000;
13
+
14
+ const MAX_TRACE_WEIGHT_IN_BYTES = 5000000;
15
+
16
+ /**
17
+ * A buffer for serialized streamed span JSON objects that flushes them to Sentry in Span v2 envelopes.
18
+ * Handles per-trace timeout-based flushing, size thresholds, and graceful shutdown.
19
+ * Also handles computation of the Dynamic Sampling Context (DSC) for the trace, if it wasn't yet
20
+ * frozen onto the segment span.
21
+ *
22
+ * For this, we need the reference to the segment span instance, from
23
+ * which we compute the DSC. Doing this in the buffer ensures that we compute the DSC as late as possible,
24
+ * allowing span name and data updates up to this point. Worth noting here that the segment span is likely
25
+ * still active and modifyable when child spans are added to the buffer.
26
+ */
27
+ class SpanBuffer {
28
+ /* Bucket spans by their trace id, along with accumulated size and a per-trace flush timeout */
29
+
30
+ constructor(client, options) {
31
+ this._traceBuckets = new Map();
32
+ this._client = client;
33
+
34
+ const { maxSpanLimit, flushInterval, maxTraceWeightInBytes } = options ?? {};
35
+
36
+ this._maxSpanLimit =
37
+ maxSpanLimit && maxSpanLimit > 0 && maxSpanLimit <= MAX_SPANS_PER_ENVELOPE
38
+ ? maxSpanLimit
39
+ : MAX_SPANS_PER_ENVELOPE;
40
+ this._flushInterval = flushInterval && flushInterval > 0 ? flushInterval : 5000;
41
+ this._maxTraceWeight =
42
+ maxTraceWeightInBytes && maxTraceWeightInBytes > 0 ? maxTraceWeightInBytes : MAX_TRACE_WEIGHT_IN_BYTES;
43
+
44
+ this._client.on('flush', () => {
45
+ this.drain();
46
+ });
47
+
48
+ this._client.on('close', () => {
49
+ // No need to drain the buffer here as `Client.close()` internally already calls `Client.flush()`
50
+ // which already invokes the `flush` hook and thus drains the buffer.
51
+ this._traceBuckets.forEach(bucket => {
52
+ clearTimeout(bucket.timeout);
53
+ });
54
+ this._traceBuckets.clear();
55
+ });
56
+ }
57
+
58
+ /**
59
+ * Add a span to the buffer.
60
+ */
61
+ add(spanJSON) {
62
+ const traceId = spanJSON.trace_id;
63
+ let bucket = this._traceBuckets.get(traceId);
64
+
65
+ if (!bucket) {
66
+ bucket = {
67
+ spans: new Set(),
68
+ size: 0,
69
+ timeout: safeUnref(
70
+ setTimeout(() => {
71
+ this.flush(traceId);
72
+ }, this._flushInterval),
73
+ ),
74
+ };
75
+ this._traceBuckets.set(traceId, bucket);
76
+ }
77
+
78
+ bucket.spans.add(spanJSON);
79
+ bucket.size += estimateSerializedSpanSizeInBytes(spanJSON);
80
+
81
+ if (bucket.spans.size >= this._maxSpanLimit || bucket.size >= this._maxTraceWeight) {
82
+ this.flush(traceId);
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Drain and flush all buffered traces.
88
+ */
89
+ drain() {
90
+ if (!this._traceBuckets.size) {
91
+ return;
92
+ }
93
+
94
+ DEBUG_BUILD && debug.log(`Flushing span tree map with ${this._traceBuckets.size} traces`);
95
+
96
+ this._traceBuckets.forEach((_, traceId) => {
97
+ this.flush(traceId);
98
+ });
99
+ }
100
+
101
+ /**
102
+ * Flush spans of a specific trace.
103
+ * In contrast to {@link SpanBuffer.drain}, this method does not flush all traces, but only the one with the given traceId.
104
+ */
105
+ flush(traceId) {
106
+ const bucket = this._traceBuckets.get(traceId);
107
+ if (!bucket) {
108
+ return;
109
+ }
110
+
111
+ if (!bucket.spans.size) {
112
+ // we should never get here, given we always add a span when we create a new bucket
113
+ // and delete the bucket once we flush out the trace
114
+ this._removeTrace(traceId);
115
+ return;
116
+ }
117
+
118
+ const spans = Array.from(bucket.spans);
119
+
120
+ const segmentSpan = spans[0]?._segmentSpan;
121
+ if (!segmentSpan) {
122
+ DEBUG_BUILD && debug.warn('No segment span reference found on span JSON, cannot compute DSC');
123
+ this._removeTrace(traceId);
124
+ return;
125
+ }
126
+
127
+ const dsc = getDynamicSamplingContextFromSpan(segmentSpan);
128
+
129
+ const cleanedSpans = spans.map(spanJSON => {
130
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
131
+ const { _segmentSpan, ...cleanSpanJSON } = spanJSON;
132
+ return cleanSpanJSON;
133
+ });
134
+
135
+ const envelope = createStreamedSpanEnvelope(cleanedSpans, dsc, this._client);
136
+
137
+ DEBUG_BUILD && debug.log(`Sending span envelope for trace ${traceId} with ${cleanedSpans.length} spans`);
138
+
139
+ this._client.sendEnvelope(envelope).then(null, reason => {
140
+ DEBUG_BUILD && debug.error('Error while sending streamed span envelope:', reason);
141
+ });
142
+
143
+ this._removeTrace(traceId);
144
+ }
145
+
146
+ _removeTrace(traceId) {
147
+ const bucket = this._traceBuckets.get(traceId);
148
+ if (bucket) {
149
+ clearTimeout(bucket.timeout);
150
+ }
151
+ this._traceBuckets.delete(traceId);
152
+ }
153
+ }
154
+
155
+ export { SpanBuffer };
156
+ //# 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":[],"mappings":"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"}
@@ -2,11 +2,13 @@ import { getAsyncContextStrategy } from '../asyncContext/index.js';
2
2
  import { getMainCarrier } from '../carrier.js';
3
3
  import { getClient, withScope, getCurrentScope, getIsolationScope } from '../currentScopes.js';
4
4
  import { DEBUG_BUILD } from '../debug-build.js';
5
- import { SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE } from '../semanticAttributes.js';
5
+ import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE } from '../semanticAttributes.js';
6
6
  import { baggageHeaderToDynamicSamplingContext } from '../utils/baggage.js';
7
7
  import { debug } from '../utils/debug-logger.js';
8
8
  import { handleCallbackErrors } from '../utils/handleCallbackErrors.js';
9
9
  import { hasSpansEnabled } from '../utils/hasSpansEnabled.js';
10
+ import { shouldIgnoreSpan } from '../utils/should-ignore-span.js';
11
+ import { hasSpanStreamingEnabled } from './spans/hasSpanStreamingEnabled.js';
10
12
  import { parseSampleRate } from '../utils/parseSampleRate.js';
11
13
  import { generateTraceId } from '../utils/propagationContext.js';
12
14
  import { safeMathRandom } from '../utils/randomSafeContext.js';
@@ -67,7 +69,12 @@ function startSpan(options, callback) {
67
69
  scope,
68
70
  });
69
71
 
70
- _setSpanForScope(scope, activeSpan);
72
+ // Ignored root spans still need to be set on scope so that `getActiveSpan()` returns them
73
+ // and descendants are also non-recording. Ignored child spans don't need this because
74
+ // the parent span is already on scope.
75
+ if (!_isIgnoredSpan(activeSpan) || !parentSpan) {
76
+ _setSpanForScope(scope, activeSpan);
77
+ }
71
78
 
72
79
  return handleCallbackErrors(
73
80
  () => callback(activeSpan),
@@ -125,7 +132,11 @@ function startSpanManual(options, callback) {
125
132
  scope,
126
133
  });
127
134
 
128
- _setSpanForScope(scope, activeSpan);
135
+ // We don't set ignored child spans onto the scope because there likely is an active,
136
+ // unignored span on the scope already.
137
+ if (!_isIgnoredSpan(activeSpan) || !parentSpan) {
138
+ _setSpanForScope(scope, activeSpan);
139
+ }
129
140
 
130
141
  return handleCallbackErrors(
131
142
  // We pass the `finish` function to the callback, so the user can finish the span manually
@@ -326,6 +337,20 @@ function createChildOrRootSpan({
326
337
  return span;
327
338
  }
328
339
 
340
+ const client = getClient();
341
+ if (_shouldIgnoreStreamedSpan(client, spanArguments)) {
342
+ if (!_isTracingSuppressed(scope)) {
343
+ // if tracing is actively suppressed (Sentry.suppressTracing(...)),
344
+ // we don't want to record a client outcome for the ignored span
345
+ client?.recordDroppedEvent('ignored', 'span');
346
+ }
347
+
348
+ return new SentryNonRecordingSpan({
349
+ dropReason: 'ignored',
350
+ traceId: parentSpan?.spanContext().traceId ?? scope.getPropagationContext().traceId,
351
+ });
352
+ }
353
+
329
354
  const isolationScope = getIsolationScope();
330
355
 
331
356
  let span;
@@ -425,9 +450,9 @@ function _startRootSpan(spanArguments, scope, parentSampled) {
425
450
  const finalAttributes = mutableSpanSamplingData.spanAttributes;
426
451
 
427
452
  const currentPropagationContext = scope.getPropagationContext();
428
- const [sampled, sampleRate, localSampleRateWasApplied] = scope.getScopeData().sdkProcessingMetadata[
429
- SUPPRESS_TRACING_KEY
430
- ]
453
+ const isTracingSuppressed = _isTracingSuppressed(scope);
454
+
455
+ const [sampled, sampleRate, localSampleRateWasApplied] = isTracingSuppressed
431
456
  ? [false]
432
457
  : sampleSpan(
433
458
  options,
@@ -451,9 +476,9 @@ function _startRootSpan(spanArguments, scope, parentSampled) {
451
476
  sampled,
452
477
  });
453
478
 
454
- if (!sampled && client) {
479
+ if (!sampled && client && !isTracingSuppressed) {
455
480
  DEBUG_BUILD && debug.log('[Tracing] Discarding root span because its trace was not chosen to be sampled.');
456
- client.recordDroppedEvent('sample_rate', 'transaction');
481
+ client.recordDroppedEvent('sample_rate', hasSpanStreamingEnabled(client) ? 'span' : 'transaction');
457
482
  }
458
483
 
459
484
  if (client) {
@@ -469,7 +494,8 @@ function _startRootSpan(spanArguments, scope, parentSampled) {
469
494
  */
470
495
  function _startChildSpan(parentSpan, scope, spanArguments) {
471
496
  const { spanId, traceId } = parentSpan.spanContext();
472
- const sampled = scope.getScopeData().sdkProcessingMetadata[SUPPRESS_TRACING_KEY] ? false : spanIsSampled(parentSpan);
497
+ const isTracingSuppressed = _isTracingSuppressed(scope);
498
+ const sampled = isTracingSuppressed ? false : spanIsSampled(parentSpan);
473
499
 
474
500
  const childSpan = sampled
475
501
  ? new SentrySpan({
@@ -483,14 +509,33 @@ function _startChildSpan(parentSpan, scope, spanArguments) {
483
509
  addChildSpanToSpan(parentSpan, childSpan);
484
510
 
485
511
  const client = getClient();
486
- if (client) {
487
- client.emit('spanStart', childSpan);
488
- // If it has an endTimestamp, it's already ended
489
- if (spanArguments.endTimestamp) {
490
- client.emit('spanEnd', childSpan);
512
+
513
+ if (!client) {
514
+ return childSpan;
515
+ }
516
+
517
+ if (hasSpanStreamingEnabled(client) && childSpan instanceof SentryNonRecordingSpan) {
518
+ if (parentSpan instanceof SentryNonRecordingSpan && parentSpan.dropReason) {
519
+ // We land here if the parent span was a segment span that was ignored (`ignoreSpans`).
520
+ // In this case, the child was also ignored (see `sampled` above) but we need to
521
+ // record a client outcome for the child.
522
+ childSpan.dropReason = parentSpan.dropReason;
523
+ client.recordDroppedEvent(parentSpan.dropReason, 'span');
524
+ } else if (!isTracingSuppressed) {
525
+ // Otherwise, the child is not sampled due to sampling of the parent span,
526
+ // hence we record a sample_rate client outcome for the child.
527
+ childSpan.dropReason = 'sample_rate';
528
+ client.recordDroppedEvent('sample_rate', 'span');
491
529
  }
492
530
  }
493
531
 
532
+ client.emit('spanStart', childSpan);
533
+ // If it has an endTimestamp, it's already ended
534
+ if (spanArguments.endTimestamp) {
535
+ client.emit('spanEnd', childSpan);
536
+ client.emit('afterSpanEnd', childSpan);
537
+ }
538
+
494
539
  return childSpan;
495
540
  }
496
541
 
@@ -528,5 +573,30 @@ function getActiveSpanWrapper(parentSpan) {
528
573
  : (callback) => callback();
529
574
  }
530
575
 
576
+ /* Checks if `ignoreSpans` applies (extracted for bundle size)*/
577
+ function _shouldIgnoreStreamedSpan(client, spanArguments) {
578
+ const ignoreSpans = client?.getOptions().ignoreSpans;
579
+
580
+ if (!client || !hasSpanStreamingEnabled(client) || !ignoreSpans?.length) {
581
+ return false;
582
+ }
583
+
584
+ return shouldIgnoreSpan(
585
+ {
586
+ description: spanArguments.name || '',
587
+ op: spanArguments.attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_OP] || spanArguments.op,
588
+ },
589
+ ignoreSpans,
590
+ );
591
+ }
592
+
593
+ function _isIgnoredSpan(span) {
594
+ return span instanceof SentryNonRecordingSpan && span.dropReason === 'ignored';
595
+ }
596
+
597
+ function _isTracingSuppressed(scope) {
598
+ return scope.getScopeData().sdkProcessingMetadata[SUPPRESS_TRACING_KEY] === true;
599
+ }
600
+
531
601
  export { continueTrace, startInactiveSpan, startNewTrace, startSpan, startSpanManual, suppressTracing, withActiveSpan };
532
602
  //# sourceMappingURL=trace.js.map