Skip to content

Commit 3303afe

Browse files
urllib instrumentation + span stauts error updates
1 parent 8b803ab commit 3303afe

File tree

19 files changed

+1588
-14
lines changed

19 files changed

+1588
-14
lines changed

drift/core/content_type_utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"application/vnd.api+json": DecodedType.JSON,
1818
# Plain Text (ALLOWED)
1919
"text/plain": DecodedType.PLAIN_TEXT,
20-
# HTML (BLOCKED)
20+
# HTML
2121
"text/html": DecodedType.HTML,
2222
"application/xhtml+xml": DecodedType.HTML,
2323
# CSS (BLOCKED)
@@ -113,7 +113,7 @@
113113

114114
# Only JSON and plain text are acceptable (matches Node SDK)
115115
# All other content types will cause trace blocking
116-
ACCEPTABLE_DECODED_TYPES = {DecodedType.JSON, DecodedType.PLAIN_TEXT}
116+
ACCEPTABLE_DECODED_TYPES = {DecodedType.JSON, DecodedType.PLAIN_TEXT, DecodedType.HTML}
117117

118118

119119
def get_decoded_type(content_type: str | None) -> DecodedType | None:

drift/core/drift_sdk.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,16 @@ def _init_auto_instrumentations(self) -> None:
406406
except ImportError:
407407
pass
408408

409+
try:
410+
import urllib.request
411+
412+
from ..instrumentation.urllib import UrllibInstrumentation
413+
414+
_ = UrllibInstrumentation()
415+
logger.debug("urllib instrumentation initialized")
416+
except ImportError:
417+
pass
418+
409419
# Initialize PostgreSQL instrumentation before Django
410420
# Instrument BOTH psycopg2 and psycopg if available
411421
# This allows apps to use either or both

drift/core/mock_utils.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,9 @@ def find_mock_response_sync(
183183
mock_response = sdk.request_mock_sync(mock_request)
184184

185185
if not mock_response or not mock_response.found:
186-
logger.debug(f"No matching mock found for {trace_id} with input value: {input_value}")
186+
logger.debug(
187+
f"No matching mock found for {trace_id} with input value: {input_value}, input schema: {input_schema_merges}, input schema hash: {outbound_span.input_schema_hash}, input value hash: {outbound_span.input_value_hash}"
188+
)
187189
return None
188190

189191
logger.debug(f"Found mock response for {trace_id}")

drift/core/trace_blocking_manager.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ def should_block_span(span: CleanSpanData) -> bool:
204204
"""Check if a span should be blocked due to size or server error status.
205205
206206
Blocks the trace if:
207-
1. The span is a SERVER span with ERROR status (e.g., HTTP >= 300)
207+
1. The span is a SERVER span with ERROR status (e.g., HTTP >= 400)
208208
2. The span exceeds the maximum size limit (1MB)
209209
210210
This matches Node SDK behavior in TdSpanExporter.ts.
@@ -221,7 +221,7 @@ def should_block_span(span: CleanSpanData) -> bool:
221221
span_name = span.name
222222
blocking_manager = TraceBlockingManager.get_instance()
223223

224-
# Check 1: Block SERVER spans with ERROR status (e.g., HTTP >= 300)
224+
# Check 1: Block SERVER spans with ERROR status (e.g., HTTP >= 400)
225225
if span.kind == SpanKind.SERVER and span.status.code == StatusCode.ERROR:
226226
logger.debug(f"Blocking trace {trace_id} - server span '{span_name}' has error status")
227227
blocking_manager.block_trace(trace_id, reason="server_error")

drift/instrumentation/django/middleware.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -390,8 +390,8 @@ def dict_to_schema_merges(merges_dict):
390390
duration_seconds = duration_ns // 1_000_000_000
391391
duration_nanos = duration_ns % 1_000_000_000
392392

393-
# Match Node SDK: >= 300 is considered an error (redirects, client errors, server errors)
394-
if status_code >= 300:
393+
# Match Node SDK: >= 400 is considered an error
394+
if status_code >= 400:
395395
status = SpanStatus(code=StatusCode.ERROR, message=f"HTTP {status_code}")
396396
else:
397397
status = SpanStatus(code=StatusCode.OK, message="")

drift/instrumentation/fastapi/instrumentation.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -530,8 +530,8 @@ def _finalize_span(
530530
TuskDrift.get_instance()
531531

532532
status_code = response_data.get("status_code", 200)
533-
# Match Node SDK: >= 300 is considered an error (redirects, client errors, server errors)
534-
if status_code >= 300:
533+
# Match Node SDK: >= 400 is considered an error
534+
if status_code >= 400:
535535
span_info.span.set_status(Status(OTelStatusCode.ERROR, f"HTTP {status_code}"))
536536
else:
537537
span_info.span.set_status(Status(OTelStatusCode.OK))

drift/instrumentation/pyjwt/instrumentation.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@
2222
class PyJWTInstrumentation(InstrumentationBase):
2323
"""Patches PyJWT to disable verification in REPLAY mode."""
2424

25-
def __init__(
26-
self, mode: TuskDriftMode = TuskDriftMode.DISABLED, enabled: bool = True
27-
) -> None:
25+
def __init__(self, mode: TuskDriftMode = TuskDriftMode.DISABLED, enabled: bool = True) -> None:
2826
self.mode = mode
2927
should_enable = enabled and mode == TuskDriftMode.REPLAY
3028

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
"""urllib.request instrumentation module."""
2+
3+
from .instrumentation import UrllibInstrumentation
4+
5+
__all__ = ["UrllibInstrumentation"]
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
version: 1
2+
3+
service:
4+
id: "urllib-e2e-test-id"
5+
name: "urllib-e2e-test"
6+
port: 8000
7+
start:
8+
command: "python src/app.py"
9+
readiness_check:
10+
command: "curl -f http://localhost:8000/health"
11+
timeout: 45s
12+
interval: 5s
13+
14+
tusk_api:
15+
url: "http://localhost:8000"
16+
17+
test_execution:
18+
concurrent_limit: 10
19+
batch_size: 10
20+
timeout: 30s
21+
22+
recording:
23+
sampling_rate: 1.0
24+
export_spans: false
25+
26+
replay:
27+
enable_telemetry: false
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
FROM python-e2e-base:latest
2+
3+
# Copy SDK source for editable install
4+
COPY . /sdk
5+
6+
# Copy test files
7+
COPY drift/instrumentation/urllib/e2e-tests /app
8+
9+
WORKDIR /app
10+
11+
# Install dependencies (requirements.txt uses -e /sdk for SDK)
12+
RUN pip install -q -r requirements.txt
13+
14+
# Make entrypoint executable
15+
RUN chmod +x entrypoint.py
16+
17+
# Create .tusk directories
18+
RUN mkdir -p /app/.tusk/traces /app/.tusk/logs
19+
20+
# Run entrypoint
21+
ENTRYPOINT ["python", "entrypoint.py"]

0 commit comments

Comments
 (0)