3131)
3232from sentry_sdk .serializer import serialize
3333from sentry_sdk .tracing import trace
34+ from sentry_sdk .tracing_utils import _generate_sample_rand
3435from sentry_sdk .transport import BaseHttpTransport , make_transport
3536from sentry_sdk .consts import (
3637 SPANDATA ,
@@ -181,7 +182,9 @@ class BaseClient:
181182
182183 def __init__ (self , options = None ):
183184 # type: (Optional[Dict[str, Any]]) -> None
184- self .options = options if options is not None else DEFAULT_OPTIONS # type: Dict[str, Any]
185+ self .options = (
186+ options if options is not None else DEFAULT_OPTIONS
187+ ) # type: Dict[str, Any]
185188
186189 self .transport = None # type: Optional[Transport]
187190 self .monitor = None # type: Optional[Monitor]
@@ -614,7 +617,9 @@ def _prepare_event(
614617 event_scrubber .scrub_event (event )
615618
616619 if scope is not None and scope ._gen_ai_original_message_count :
617- spans = event .get ("spans" , []) # type: List[Dict[str, Any]] | AnnotatedValue
620+ spans = event .get (
621+ "spans" , []
622+ ) # type: List[Dict[str, Any]] | AnnotatedValue
618623 if isinstance (spans , list ):
619624 for span in spans :
620625 span_id = span .get ("span_id" , None )
@@ -1000,6 +1005,50 @@ def _capture_metric(self, metric):
10001005 current_scope = sentry_sdk .get_current_scope ()
10011006 isolation_scope = sentry_sdk .get_isolation_scope ()
10021007
1008+ # Determine trace_id and span_id using the same logic as the original metrics.py
1009+ trace_id = None
1010+ span_id = None
1011+ if current_scope .span is not None :
1012+ trace_id = current_scope .span .trace_id
1013+ span_id = current_scope .span .span_id
1014+ elif current_scope ._propagation_context is not None :
1015+ trace_id = current_scope ._propagation_context .trace_id
1016+ span_id = current_scope ._propagation_context .span_id
1017+
1018+ sample_rate = metric ["attributes" ].get ("sentry.client_sample_rate" )
1019+ if sample_rate is not None :
1020+ sample_rate = float (sample_rate )
1021+
1022+ # Always validate sample_rate range, regardless of trace context
1023+ if sample_rate <= 0.0 or sample_rate > 1.0 :
1024+ if self .transport is not None :
1025+ self .transport .record_lost_event (
1026+ "invalid_sample_rate" ,
1027+ data_category = "trace_metric" ,
1028+ quantity = 1 ,
1029+ )
1030+ return
1031+
1032+ # If there's no trace context, remove the sample_rate attribute and continue
1033+ if trace_id is None :
1034+ del metric ["attributes" ]["sentry.client_sample_rate" ]
1035+ else :
1036+ # There is a trace context, apply sampling logic
1037+ if sample_rate < 1.0 :
1038+ sample_rand = _generate_sample_rand (trace_id )
1039+ if sample_rand >= sample_rate :
1040+ if self .transport is not None :
1041+ self .transport .record_lost_event (
1042+ "sample_rate" ,
1043+ data_category = "trace_metric" ,
1044+ quantity = 1 ,
1045+ )
1046+ return
1047+
1048+ # If sample_rate is 1.0, remove the attribute as it's implied
1049+ if sample_rate == 1.0 :
1050+ del metric ["attributes" ]["sentry.client_sample_rate" ]
1051+
10031052 metric ["attributes" ]["sentry.sdk.name" ] = SDK_INFO ["name" ]
10041053 metric ["attributes" ]["sentry.sdk.version" ] = SDK_INFO ["version" ]
10051054
@@ -1011,10 +1060,6 @@ def _capture_metric(self, metric):
10111060 if release is not None and "sentry.release" not in metric ["attributes" ]:
10121061 metric ["attributes" ]["sentry.release" ] = release
10131062
1014- trace_context = current_scope .get_trace_context ()
1015- trace_id = trace_context .get ("trace_id" )
1016- span_id = trace_context .get ("span_id" )
1017-
10181063 metric ["trace_id" ] = trace_id or "00000000-0000-0000-0000-000000000000"
10191064 if span_id is not None :
10201065 metric ["span_id" ] = span_id
0 commit comments