@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,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
- spanOnScope._setSpanForScope(scope, activeSpan);
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
- spanOnScope._setSpanForScope(scope, activeSpan);
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 [sampled, sampleRate, localSampleRateWasApplied] = scope.getScopeData().sdkProcessingMetadata[
431
- SUPPRESS_TRACING_KEY
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 sampled = scope.getScopeData().sdkProcessingMetadata[SUPPRESS_TRACING_KEY] ? false : spanUtils.spanIsSampled(parentSpan);
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
- if (client) {
489
- client.emit('spanStart', childSpan);
490
- // If it has an endTimestamp, it's already ended
491
- if (spanArguments.endTimestamp) {
492
- client.emit('spanEnd', childSpan);
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;