@@ -736,13 +736,25 @@ def __init__(self,
736736 _is_multi_op
737737 and getattr (self ._request_span , '_supports_multi_op_fast_dispatch' , False )
738738 )
739- self ._has_multiple_encoding_spans = (self ._op_name .is_multi_op () or self ._op_name is OpName .MutateIn )
740- self ._encoding_spans_ended = False
741- self ._encoding_spans : Optional [Union [WrappedEncodingSpan , List [WrappedEncodingSpan ]]] = None
742- self ._set_span_attrs (** options )
743- self ._cluster_name : Optional [str ] = None
744- self ._cluster_uuid : Optional [str ] = None
745- self ._end_time_watermark = time .time_ns ()
739+ # When OTel sampler drops a span, is_recording is False and we skip
740+ # all expensive attribute setting, encoding spans, and dispatch span building.
741+ self ._is_recording = getattr (self ._request_span , 'is_recording' , True )
742+ if self ._is_recording :
743+ self ._has_multiple_encoding_spans = (_is_multi_op or self ._op_name is OpName .MutateIn )
744+ self ._encoding_spans_ended = False
745+ self ._encoding_spans : Optional [Union [WrappedEncodingSpan , List [WrappedEncodingSpan ]]] = None
746+ self ._set_span_attrs (** options )
747+ self ._cluster_name : Optional [str ] = None
748+ self ._cluster_uuid : Optional [str ] = None
749+ self ._end_time_watermark = time .time_ns ()
750+ else :
751+ # T10: Minimal init — skip all attribute work for non-recording spans
752+ self ._has_multiple_encoding_spans = False
753+ self ._encoding_spans_ended = True
754+ self ._encoding_spans = None
755+ self ._cluster_name = None
756+ self ._cluster_uuid = None
757+ self ._end_time_watermark = self ._start_time
746758
747759 @property
748760 def cluster_name (self ) -> Optional [str ]:
@@ -752,6 +764,10 @@ def cluster_name(self) -> Optional[str]:
752764 def cluster_uuid (self ) -> Optional [str ]:
753765 return self ._cluster_uuid
754766
767+ @property
768+ def is_recording (self ) -> bool :
769+ return self ._is_recording
770+
755771 @property
756772 def request_span (self ) -> SpanProtocol :
757773 return self ._request_span
@@ -763,7 +779,7 @@ def add_kv_durability_attribute(self, durability: DurabilityLevel) -> None:
763779 def maybe_add_encoding_span (self , encoding_fn : Callable [..., Tuple [bytes , int ]]) -> Tuple [bytes , int ]:
764780 # legacy operations did not create an encoding span; not support now
765781 # we only expect certain ops to have multiple encoding spans
766- if self ._wrapped_tracer .is_legacy or not self ._has_multiple_encoding_spans :
782+ if not self . _is_recording or self ._wrapped_tracer .is_legacy or not self ._has_multiple_encoding_spans :
767783 return encoding_fn ()
768784
769785 if not self ._encoding_spans :
@@ -786,7 +802,7 @@ def maybe_add_encoding_span(self, encoding_fn: Callable[..., Tuple[bytes, int]])
786802 def maybe_create_encoding_span (self , encoding_fn : Callable [..., Tuple [bytes , int ]]) -> Tuple [bytes , int ]:
787803 # legacy operations did not create an encoding span; not support now
788804 # if the op is expected to have multiple encoding spans, maybe_add_encoding_span() should be used instead
789- if self ._wrapped_tracer .is_legacy or self ._has_multiple_encoding_spans :
805+ if not self . _is_recording or self ._wrapped_tracer .is_legacy or self ._has_multiple_encoding_spans :
790806 return encoding_fn ()
791807
792808 encoding_span = self ._wrapped_tracer .tracer .request_span (_ATTR_ENCODING_SPAN_NAME ,
@@ -807,6 +823,10 @@ def maybe_update_end_time_watermark(self, end_time: int) -> None:
807823 self ._end_time_watermark = self ._end_time_watermark if self ._end_time_watermark > end_time else end_time
808824
809825 def process_core_span (self , core_span : CppWrapperSdkSpan ) -> None :
826+ # Skip all core span processing if the span is not recording
827+ if not self ._is_recording :
828+ return
829+
810830 # Guard cluster_[name|uuid] propagation — for multi-op batches, process_core_span
811831 # is called once per sub-op on the same WrappedSpan. cluster_name/uuid are
812832 # identical for every sub-op, so only set them on the first call.
@@ -842,6 +862,10 @@ def record_multi_op_dispatch_span(self, duration: int, attributes: Dict[str, Any
842862 self ._request_span .set_attribute (attr_name , attr_val )
843863
844864 def set_attribute (self , key : str , value : SpanAttributeValue ) -> None :
865+ # Skip setting any attribute if the span is not recording
866+ if not self ._is_recording :
867+ return
868+
845869 if key == _ATTR_CLUSTER_NAME :
846870 self ._cluster_name = value
847871 elif key == _ATTR_CLUSTER_UUID :
@@ -862,6 +886,12 @@ def set_status(self, status: SpanStatusCode) -> None:
862886 self ._request_span .set_status (status )
863887
864888 def end (self , end_time : int ) -> None :
889+ # For non-recording spans, still call end() for OTel context cleanup
890+ # but skip all the heavy processing (encoding spans, watermark, etc.)
891+ if not self ._is_recording :
892+ self ._request_span .end (end_time )
893+ return
894+
865895 self ._end_encoding_spans ()
866896 if self ._wrapped_tracer .is_legacy :
867897 self ._request_span .finish ()
0 commit comments