Skip to content

Commit e2c37ac

Browse files
fix sampling
1 parent 1507e10 commit e2c37ac

4 files changed

Lines changed: 37 additions & 11 deletions

File tree

drift/core/tracing/td_span_processor.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,6 @@ def on_end(self, span: ReadableSpan) -> None:
141141
if should_block_span(clean_span):
142142
return
143143

144-
# Apply sampling logic
145-
if not should_sample(self._sampling_rate, self._app_ready):
146-
return
147-
148144
# Validate protobuf serialization
149145
try:
150146
clean_span.to_proto()

drift/instrumentation/django/middleware.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,18 @@ def _record_request(
181181
Returns:
182182
Django HttpResponse object
183183
"""
184+
# Inbound request sampling (only when app is ready)
185+
# Always sample during startup to capture initialization behavior
186+
if not is_pre_app_start:
187+
from ...core.sampling import should_sample
188+
189+
sampling_rate = sdk.get_sampling_rate()
190+
if not should_sample(sampling_rate, is_app_ready=True):
191+
logger.debug(
192+
f"[Django] Request not sampled (rate={sampling_rate}), path={request.path}"
193+
)
194+
return self.get_response(request)
195+
184196
start_time_ns = time.time_ns()
185197

186198
method = request.method

drift/instrumentation/fastapi/instrumentation.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22

33
import base64
44
import json
5+
import logging
56
import time
67
from collections.abc import Callable
78
from functools import wraps
89
from types import ModuleType
910
from typing import TYPE_CHECKING, Any, override
1011

12+
logger = logging.getLogger(__name__)
13+
1114
if TYPE_CHECKING:
1215
from collections.abc import Awaitable
1316

@@ -112,12 +115,8 @@ async def _handle_replay_request(
112115
- Execute the request normally (NOT mocked!)
113116
- Create SERVER span for tracking
114117
"""
115-
import logging
116-
117118
from ...core.types import replay_trace_id_context
118119

119-
logger = logging.getLogger(__name__)
120-
121120
# Extract trace ID from headers (case-insensitive lookup)
122121
request_headers = _extract_headers(scope)
123122
# Convert headers to lowercase for case-insensitive lookup
@@ -258,6 +257,17 @@ async def _record_request(
258257
raw_path: Request path
259258
is_pre_app_start: Whether this request occurred before app was marked ready
260259
"""
260+
# Inbound request sampling (only when app is ready)
261+
# Always sample during startup to capture initialization behavior
262+
if not is_pre_app_start:
263+
from ...core.sampling import should_sample
264+
265+
sdk = TuskDrift.get_instance()
266+
sampling_rate = sdk.get_sampling_rate()
267+
if not should_sample(sampling_rate, is_app_ready=True):
268+
logger.debug(f"[FastAPI] Request not sampled (rate={sampling_rate}), path={raw_path}")
269+
return await original_call(app, scope, receive, send)
270+
261271
start_time_ns = time.time_ns()
262272

263273
# Get route for span name
@@ -489,12 +499,9 @@ def _finalize_span(
489499
output_value["errorName"] = response_data["error_type"] # Match Node SDK field name
490500

491501
# Check if content type should block the trace
492-
import logging
493-
494502
from ...core.content_type_utils import get_decoded_type, should_block_content_type
495503
from ...core.trace_blocking_manager import TraceBlockingManager
496504

497-
logger = logging.getLogger(__name__)
498505
response_headers = response_data.get("headers", {})
499506
content_type = response_headers.get("content-type") or response_headers.get("Content-Type")
500507
decoded_type = get_decoded_type(content_type)

drift/instrumentation/wsgi/handler.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,17 @@ def _create_and_handle_request(
207207
replay_trace_id_context.reset(replay_token)
208208
return original_wsgi_app(app, environ, start_response)
209209

210+
# Inbound request sampling (only RECORD mode + app ready)
211+
# - replay_token is None means RECORD mode (REPLAY mode sets replay_token)
212+
# - not is_pre_app_start means app is ready (always sample during startup)
213+
if replay_token is None and not is_pre_app_start:
214+
from ...core.sampling import should_sample
215+
216+
sampling_rate = sdk.get_sampling_rate()
217+
if not should_sample(sampling_rate, is_app_ready=True):
218+
logger.debug(f"[WSGI] Request not sampled (rate={sampling_rate}), path={path}")
219+
return original_wsgi_app(app, environ, start_response)
220+
210221
span_name = f"{method} {path}"
211222

212223
# Build input value before starting span

0 commit comments

Comments
 (0)