1+ import { Attributes , RawAttribute , RawAttributes } from '../attributes' ;
12import type { Client } from '../client' ;
23import { getClient , getGlobalScope } from '../currentScopes' ;
34import { DEBUG_BUILD } from '../debug-build' ;
@@ -16,35 +17,27 @@ import {
1617} from '../semanticAttributes' ;
1718import { getCapturedScopesOnSpan } from '../tracing/utils' ;
1819import type { SerializedAttributes } from '../types-hoist/attributes' ;
20+ import { Contexts } from '../types-hoist/context' ;
1921import type { Span , SpanV2JSON } from '../types-hoist/span' ;
2022import { mergeScopeData } from '../utils/applyScopeDataToEvent' ;
23+ import { isV2BeforeSendSpanCallback } from '../utils/beforeSendSpan' ;
2124import { debug } from '../utils/debug-logger' ;
2225import { INTERNAL_getSegmentSpan , spanToV2JSON } from '../utils/spanUtils' ;
23- import { safeSetSpanJSONAttributes } from './spanFirstUtils' ;
24-
25- /**
26- * A SpanV2JSON with an attached reference to the segment span.
27- * This reference is used to compute dynamic sampling context before sending.
28- * The reference MUST be removed before sending the span envelope.
29- */
30- export interface SpanV2JSONWithSegmentRef extends SpanV2JSON {
31- _segmentSpan : Span ;
32- }
33-
26+ import { applyBeforeSendSpanCallback , safeSetSpanJSONAttributes } from './spanFirstUtils' ;
3427/**
3528 * Captures a span and returns a JSON representation to be enqueued for sending.
3629 *
3730 * IMPORTANT: This function converts the span to JSON immediately to avoid writing
3831 * to an already-ended OTel span instance (which is blocked by the OTel Span class).
3932 */
40- export function captureSpan ( span : Span , client = getClient ( ) ) : SpanV2JSONWithSegmentRef | void {
33+ export function captureSpan ( span : Span , client = getClient ( ) ) : void {
4134 if ( ! client ) {
4235 DEBUG_BUILD && debug . warn ( 'No client available to capture span.' ) ;
4336 return ;
4437 }
4538
4639 // Convert to JSON FIRST - we cannot write to an already-ended span
47- const spanJSON = spanToV2JSON ( span ) as SpanV2JSONWithSegmentRef ;
40+ const spanJSON = spanToV2JSON ( span ) ;
4841
4942 const segmentSpan = INTERNAL_getSegmentSpan ( span ) ;
5043 const serializedSegmentSpan = spanToV2JSON ( segmentSpan ) ;
@@ -60,29 +53,31 @@ export function captureSpan(span: Span, client = getClient()): SpanV2JSONWithSeg
6053 applyScopeToSegmentSpan ( spanJSON , finalScopeData , originalAttributes ) ;
6154 }
6255
63- // Attach segment span reference for DSC generation at send time
64- spanJSON . _segmentSpan = segmentSpan ;
65-
6656 // Allow integrations to add additional data to the span JSON
6757 client . emit ( 'processSpan' , spanJSON , { readOnlySpan : span } ) ;
6858
69- // Enqueue the JSON representation for sending
70- // Note: We now enqueue JSON instead of the span instance to avoid mutating ended spans
71- client . emit ( 'enqueueSpan' , spanJSON ) ;
59+ const beforeSendSpan = client . getOptions ( ) . beforeSendSpan ;
60+ const processedSpan = isV2BeforeSendSpanCallback ( beforeSendSpan )
61+ ? applyBeforeSendSpanCallback ( spanJSON , beforeSendSpan )
62+ : spanJSON ;
7263
73- return spanJSON ;
64+ const spanWithRef = {
65+ ...processedSpan ,
66+ _segmentSpan : segmentSpan ,
67+ } ;
68+
69+ client . emit ( 'enqueueSpan' , spanWithRef ) ;
7470}
7571
7672function applyScopeToSegmentSpan (
7773 segmentSpanJSON : SpanV2JSON ,
7874 scopeData : ScopeData ,
7975 originalAttributes : SerializedAttributes ,
8076) : void {
81- // TODO: Apply all scope data from auto instrumentation (contexts, request) to segment span
82- const { attributes } = scopeData ;
83- if ( attributes ) {
84- safeSetSpanJSONAttributes ( segmentSpanJSON , attributes , originalAttributes ) ;
85- }
77+ // TODO: Apply all scope and request data from auto instrumentation (contexts, request) to segment span
78+ const { contexts } = scopeData ;
79+
80+ safeSetSpanJSONAttributes ( segmentSpanJSON , contextsToAttributes ( contexts ) , originalAttributes ) ;
8681}
8782
8883function applyCommonSpanAttributes (
@@ -113,6 +108,7 @@ function applyCommonSpanAttributes(
113108 [ SEMANTIC_ATTRIBUTE_USER_USERNAME ] : scopeData . user ?. username ,
114109 }
115110 : { } ) ,
111+ ...scopeData . attributes ,
116112 } ,
117113 originalAttributes ,
118114 ) ;
@@ -129,3 +125,13 @@ function getFinalScopeData(isolationScope: Scope | undefined, scope: Scope | und
129125 }
130126 return finalScopeData ;
131127}
128+
129+ function contextsToAttributes ( contexts : Contexts ) : RawAttributes < Record < string , unknown > > {
130+ return {
131+ 'os.build_id' : contexts . os ?. build ,
132+ 'os.name' : contexts . os ?. name ,
133+ 'os.version' : contexts . os ?. version ,
134+ // TODO: Add to Sentry SemConv
135+ 'os.kernel_version' : contexts . os ?. kernel_version ,
136+ } ;
137+ }
0 commit comments