2626
2727from ...core .drift_sdk import TuskDrift
2828from ...core .json_schema_helper import JsonSchemaHelper , SchemaMerge
29- from ...core .mode_utils import handle_record_mode
29+ from ...core .mode_utils import handle_record_mode , should_record_inbound_http_request
3030from ...core .tracing import TdSpanAttributes
3131from ...core .tracing .span_utils import CreateSpanOptions , SpanInfo , SpanUtils
3232from ...core .types import (
@@ -106,7 +106,7 @@ async def _handle_replay_request(
106106 transform_engine : HttpTransformEngine | None ,
107107 method : str ,
108108 raw_path : str ,
109- target : str ,
109+ headers : dict [ str , str ] ,
110110) -> None :
111111 """Handle FastAPI request in REPLAY mode.
112112
@@ -119,7 +119,7 @@ async def _handle_replay_request(
119119 from ...core .types import replay_trace_id_context
120120
121121 # Extract trace ID from headers (case-insensitive lookup)
122- request_headers = _extract_headers ( scope )
122+ request_headers = headers
123123 # Convert headers to lowercase for case-insensitive lookup
124124 headers_lower = {k .lower (): v for k , v in request_headers .items ()}
125125 replay_trace_id = headers_lower .get ("x-td-trace-id" )
@@ -241,6 +241,8 @@ async def _record_request(
241241 transform_engine : HttpTransformEngine | None ,
242242 method : str ,
243243 raw_path : str ,
244+ target : str ,
245+ headers : dict [str , str ],
244246 is_pre_app_start : bool ,
245247) -> None :
246248 """Handle request in RECORD mode with span creation using SpanUtils.
@@ -254,18 +256,17 @@ async def _record_request(
254256 transform_engine: HTTP transform engine for request/response transforms
255257 method: HTTP method (GET, POST, etc.)
256258 raw_path: Request path
259+ target: Request target (path + query string)
260+ headers: Request headers dictionary
257261 is_pre_app_start: Whether this request occurred before app was marked ready
258262 """
259- # Inbound request sampling (only when app is ready)
260- # Always sample during startup to capture initialization behavior
261- if not is_pre_app_start :
262- from ...core .sampling import should_sample
263-
264- sdk = TuskDrift .get_instance ()
265- sampling_rate = sdk .get_sampling_rate ()
266- if not should_sample (sampling_rate , is_app_ready = True ):
267- logger .debug (f"[FastAPI] Request not sampled (rate={ sampling_rate } ), path={ raw_path } " )
268- return await original_call (app , scope , receive , send )
263+ # Pre-flight check: drop transforms and sampling before body capture
264+ should_record , skip_reason = should_record_inbound_http_request (
265+ method , target , headers , transform_engine , is_pre_app_start
266+ )
267+ if not should_record :
268+ logger .debug (f"[FastAPI] Skipping request ({ skip_reason } ), path={ raw_path } " )
269+ return await original_call (app , scope , receive , send )
269270
270271 start_time_ns = time .time_ns ()
271272
@@ -389,16 +390,8 @@ async def _handle_request(
389390 query_string = query_bytes .decode ("utf-8" , errors = "replace" )
390391 else :
391392 query_string = str (query_bytes )
392- target_for_drop = f"{ raw_path } ?{ query_string } " if query_string else raw_path
393- headers_for_drop = _extract_headers (scope )
394-
395- # Check if request should be dropped by transform engine
396- if transform_engine and transform_engine .should_drop_inbound_request (
397- method ,
398- target_for_drop ,
399- headers_for_drop ,
400- ):
401- return await original_call (app , scope , receive , send )
393+ target = f"{ raw_path } ?{ query_string } " if query_string else raw_path
394+ headers = _extract_headers (scope )
402395
403396 # DISABLED mode - just pass through
404397 if sdk .mode == TuskDriftMode .DISABLED :
@@ -407,14 +400,26 @@ async def _handle_request(
407400 # REPLAY mode - handle trace ID extraction and context setup
408401 if sdk .mode == TuskDriftMode .REPLAY :
409402 return await _handle_replay_request (
410- app , scope , receive , send , original_call , transform_engine , method , raw_path , target_for_drop
403+ app , scope , receive , send , original_call , transform_engine , method , raw_path , headers
411404 )
412405
413406 # RECORD mode - use handle_record_mode for consistent is_pre_app_start logic
407+ # NOTE: Pre-flight check (drop + sample) is done inside _record_request
408+ # to access is_pre_app_start from handle_record_mode
414409 result = handle_record_mode (
415410 original_function_call = lambda : original_call (app , scope , receive , send ),
416411 record_mode_handler = lambda is_pre_app_start : _record_request (
417- app , scope , receive , send , original_call , transform_engine , method , raw_path , is_pre_app_start
412+ app ,
413+ scope ,
414+ receive ,
415+ send ,
416+ original_call ,
417+ transform_engine ,
418+ method ,
419+ raw_path ,
420+ target ,
421+ headers ,
422+ is_pre_app_start ,
418423 ),
419424 span_kind = OTelSpanKind .SERVER ,
420425 )
0 commit comments