sf-veritas 0.11.10__cp314-cp314-manylinux_2_28_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. sf_veritas/__init__.py +46 -0
  2. sf_veritas/_auto_preload.py +73 -0
  3. sf_veritas/_sfconfig.c +162 -0
  4. sf_veritas/_sfconfig.cpython-314-x86_64-linux-gnu.so +0 -0
  5. sf_veritas/_sfcrashhandler.c +267 -0
  6. sf_veritas/_sfcrashhandler.cpython-314-x86_64-linux-gnu.so +0 -0
  7. sf_veritas/_sffastlog.c +953 -0
  8. sf_veritas/_sffastlog.cpython-314-x86_64-linux-gnu.so +0 -0
  9. sf_veritas/_sffastnet.c +994 -0
  10. sf_veritas/_sffastnet.cpython-314-x86_64-linux-gnu.so +0 -0
  11. sf_veritas/_sffastnetworkrequest.c +727 -0
  12. sf_veritas/_sffastnetworkrequest.cpython-314-x86_64-linux-gnu.so +0 -0
  13. sf_veritas/_sffuncspan.c +2791 -0
  14. sf_veritas/_sffuncspan.cpython-314-x86_64-linux-gnu.so +0 -0
  15. sf_veritas/_sffuncspan_config.c +730 -0
  16. sf_veritas/_sffuncspan_config.cpython-314-x86_64-linux-gnu.so +0 -0
  17. sf_veritas/_sfheadercheck.c +341 -0
  18. sf_veritas/_sfheadercheck.cpython-314-x86_64-linux-gnu.so +0 -0
  19. sf_veritas/_sfnetworkhop.c +1454 -0
  20. sf_veritas/_sfnetworkhop.cpython-314-x86_64-linux-gnu.so +0 -0
  21. sf_veritas/_sfservice.c +1223 -0
  22. sf_veritas/_sfservice.cpython-314-x86_64-linux-gnu.so +0 -0
  23. sf_veritas/_sfteepreload.c +6227 -0
  24. sf_veritas/app_config.py +57 -0
  25. sf_veritas/cli.py +336 -0
  26. sf_veritas/constants.py +10 -0
  27. sf_veritas/custom_excepthook.py +304 -0
  28. sf_veritas/custom_log_handler.py +146 -0
  29. sf_veritas/custom_output_wrapper.py +153 -0
  30. sf_veritas/custom_print.py +153 -0
  31. sf_veritas/django_app.py +5 -0
  32. sf_veritas/env_vars.py +186 -0
  33. sf_veritas/exception_handling_middleware.py +18 -0
  34. sf_veritas/exception_metaclass.py +69 -0
  35. sf_veritas/fast_frame_info.py +116 -0
  36. sf_veritas/fast_network_hop.py +293 -0
  37. sf_veritas/frame_tools.py +112 -0
  38. sf_veritas/funcspan_config_loader.py +693 -0
  39. sf_veritas/function_span_profiler.py +1313 -0
  40. sf_veritas/get_preload_path.py +34 -0
  41. sf_veritas/import_hook.py +62 -0
  42. sf_veritas/infra_details/__init__.py +3 -0
  43. sf_veritas/infra_details/get_infra_details.py +24 -0
  44. sf_veritas/infra_details/kubernetes/__init__.py +3 -0
  45. sf_veritas/infra_details/kubernetes/get_cluster_name.py +147 -0
  46. sf_veritas/infra_details/kubernetes/get_details.py +7 -0
  47. sf_veritas/infra_details/running_on/__init__.py +17 -0
  48. sf_veritas/infra_details/running_on/kubernetes.py +11 -0
  49. sf_veritas/interceptors.py +543 -0
  50. sf_veritas/libsfnettee.so +0 -0
  51. sf_veritas/local_env_detect.py +118 -0
  52. sf_veritas/package_metadata.py +6 -0
  53. sf_veritas/patches/__init__.py +0 -0
  54. sf_veritas/patches/_patch_tracker.py +74 -0
  55. sf_veritas/patches/concurrent_futures.py +19 -0
  56. sf_veritas/patches/constants.py +1 -0
  57. sf_veritas/patches/exceptions.py +82 -0
  58. sf_veritas/patches/multiprocessing.py +32 -0
  59. sf_veritas/patches/network_libraries/__init__.py +99 -0
  60. sf_veritas/patches/network_libraries/aiohttp.py +294 -0
  61. sf_veritas/patches/network_libraries/curl_cffi.py +363 -0
  62. sf_veritas/patches/network_libraries/http_client.py +670 -0
  63. sf_veritas/patches/network_libraries/httpcore.py +580 -0
  64. sf_veritas/patches/network_libraries/httplib2.py +315 -0
  65. sf_veritas/patches/network_libraries/httpx.py +557 -0
  66. sf_veritas/patches/network_libraries/niquests.py +218 -0
  67. sf_veritas/patches/network_libraries/pycurl.py +399 -0
  68. sf_veritas/patches/network_libraries/requests.py +595 -0
  69. sf_veritas/patches/network_libraries/ssl_socket.py +822 -0
  70. sf_veritas/patches/network_libraries/tornado.py +360 -0
  71. sf_veritas/patches/network_libraries/treq.py +270 -0
  72. sf_veritas/patches/network_libraries/urllib_request.py +483 -0
  73. sf_veritas/patches/network_libraries/utils.py +598 -0
  74. sf_veritas/patches/os.py +17 -0
  75. sf_veritas/patches/threading.py +231 -0
  76. sf_veritas/patches/web_frameworks/__init__.py +54 -0
  77. sf_veritas/patches/web_frameworks/aiohttp.py +798 -0
  78. sf_veritas/patches/web_frameworks/async_websocket_consumer.py +337 -0
  79. sf_veritas/patches/web_frameworks/blacksheep.py +532 -0
  80. sf_veritas/patches/web_frameworks/bottle.py +513 -0
  81. sf_veritas/patches/web_frameworks/cherrypy.py +683 -0
  82. sf_veritas/patches/web_frameworks/cors_utils.py +122 -0
  83. sf_veritas/patches/web_frameworks/django.py +963 -0
  84. sf_veritas/patches/web_frameworks/eve.py +401 -0
  85. sf_veritas/patches/web_frameworks/falcon.py +931 -0
  86. sf_veritas/patches/web_frameworks/fastapi.py +738 -0
  87. sf_veritas/patches/web_frameworks/flask.py +526 -0
  88. sf_veritas/patches/web_frameworks/klein.py +501 -0
  89. sf_veritas/patches/web_frameworks/litestar.py +616 -0
  90. sf_veritas/patches/web_frameworks/pyramid.py +440 -0
  91. sf_veritas/patches/web_frameworks/quart.py +841 -0
  92. sf_veritas/patches/web_frameworks/robyn.py +708 -0
  93. sf_veritas/patches/web_frameworks/sanic.py +874 -0
  94. sf_veritas/patches/web_frameworks/starlette.py +742 -0
  95. sf_veritas/patches/web_frameworks/strawberry.py +1446 -0
  96. sf_veritas/patches/web_frameworks/tornado.py +485 -0
  97. sf_veritas/patches/web_frameworks/utils.py +170 -0
  98. sf_veritas/print_override.py +13 -0
  99. sf_veritas/regular_data_transmitter.py +444 -0
  100. sf_veritas/request_interceptor.py +401 -0
  101. sf_veritas/request_utils.py +550 -0
  102. sf_veritas/segfault_handler.py +116 -0
  103. sf_veritas/server_status.py +1 -0
  104. sf_veritas/shutdown_flag.py +11 -0
  105. sf_veritas/subprocess_startup.py +3 -0
  106. sf_veritas/test_cli.py +145 -0
  107. sf_veritas/thread_local.py +1319 -0
  108. sf_veritas/timeutil.py +114 -0
  109. sf_veritas/transmit_exception_to_sailfish.py +28 -0
  110. sf_veritas/transmitter.py +132 -0
  111. sf_veritas/types.py +47 -0
  112. sf_veritas/unified_interceptor.py +1678 -0
  113. sf_veritas/utils.py +39 -0
  114. sf_veritas-0.11.10.dist-info/METADATA +97 -0
  115. sf_veritas-0.11.10.dist-info/RECORD +141 -0
  116. sf_veritas-0.11.10.dist-info/WHEEL +5 -0
  117. sf_veritas-0.11.10.dist-info/entry_points.txt +2 -0
  118. sf_veritas-0.11.10.dist-info/top_level.txt +1 -0
  119. sf_veritas.libs/libbrotlicommon-6ce2a53c.so.1.0.6 +0 -0
  120. sf_veritas.libs/libbrotlidec-811d1be3.so.1.0.6 +0 -0
  121. sf_veritas.libs/libcom_err-730ca923.so.2.1 +0 -0
  122. sf_veritas.libs/libcrypt-52aca757.so.1.1.0 +0 -0
  123. sf_veritas.libs/libcrypto-bdaed0ea.so.1.1.1k +0 -0
  124. sf_veritas.libs/libcurl-eaa3cf66.so.4.5.0 +0 -0
  125. sf_veritas.libs/libgssapi_krb5-323bbd21.so.2.2 +0 -0
  126. sf_veritas.libs/libidn2-2f4a5893.so.0.3.6 +0 -0
  127. sf_veritas.libs/libk5crypto-9a74ff38.so.3.1 +0 -0
  128. sf_veritas.libs/libkeyutils-2777d33d.so.1.6 +0 -0
  129. sf_veritas.libs/libkrb5-a55300e8.so.3.3 +0 -0
  130. sf_veritas.libs/libkrb5support-e6594cfc.so.0.1 +0 -0
  131. sf_veritas.libs/liblber-2-d20824ef.4.so.2.10.9 +0 -0
  132. sf_veritas.libs/libldap-2-cea2a960.4.so.2.10.9 +0 -0
  133. sf_veritas.libs/libnghttp2-39367a22.so.14.17.0 +0 -0
  134. sf_veritas.libs/libpcre2-8-516f4c9d.so.0.7.1 +0 -0
  135. sf_veritas.libs/libpsl-99becdd3.so.5.3.1 +0 -0
  136. sf_veritas.libs/libsasl2-7de4d792.so.3.0.0 +0 -0
  137. sf_veritas.libs/libselinux-d0805dcb.so.1 +0 -0
  138. sf_veritas.libs/libssh-c11d285b.so.4.8.7 +0 -0
  139. sf_veritas.libs/libssl-60250281.so.1.1.1k +0 -0
  140. sf_veritas.libs/libunistring-05abdd40.so.2.1.0 +0 -0
  141. sf_veritas.libs/libuuid-95b83d40.so.1.3.0 +0 -0
@@ -0,0 +1,595 @@
1
+ """
2
+ Monkey-patch the `requests` stack (requests → urllib3 → http.client):
3
+
4
+ • For every outbound request, propagate the SAILFISH_TRACING_HEADER + FUNCSPAN_OVERRIDE_HEADER
5
+ unless the destination host is in `domains_to_not_propagate_headers_to`.
6
+ • Fire NetworkRequestTransmitter via utils.record_network_request
7
+ so we always capture (url, status, timings, success, error).
8
+ • When LD_PRELOAD is active, ONLY inject headers (skip capture - socket layer handles it).
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import http.client
14
+ import os
15
+ import time
16
+ from typing import Dict, List, Optional, Tuple
17
+
18
+ import requests
19
+ import urllib3
20
+ from requests.sessions import Session
21
+
22
+ import wrapt
23
+
24
+ # JSON serialization - try fast orjson first, fallback to stdlib json
25
+ try:
26
+ import orjson
27
+
28
+ HAS_ORJSON = True
29
+ except ImportError:
30
+ import json
31
+
32
+ HAS_ORJSON = False
33
+
34
+
35
+ from ...constants import FUNCSPAN_OVERRIDE_HEADER, SAILFISH_TRACING_HEADER
36
+ from ...thread_local import (
37
+ activate_reentrancy_guards_exception,
38
+ activate_reentrancy_guards_logging,
39
+ activate_reentrancy_guards_print,
40
+ get_funcspan_override,
41
+ )
42
+ from .utils import (
43
+ get_trace_and_should_propagate,
44
+ get_trace_and_should_propagate_fast,
45
+ init_fast_header_check,
46
+ inject_headers_ultrafast,
47
+ record_network_request,
48
+ is_ssl_socket_active,
49
+ has_sailfish_header,
50
+ )
51
+ from .._patch_tracker import is_already_patched, mark_as_patched
52
+
53
+ ###############################################################################
54
+ # Internal helpers
55
+ ###############################################################################
56
+
57
+ # header names used for re-entrancy guards
58
+ REENTRANCY_GUARD_LOGGING_PREACTIVE = "reentrancy_guard_logging_preactive"
59
+ REENTRANCY_GUARD_PRINT_PREACTIVE = "reentrancy_guard_print_preactive"
60
+ REENTRANCY_GUARD_EXCEPTIONS_PREACTIVE = "reentrancy_guard_exception_preactive"
61
+
62
+
63
+ def _tee_preload_active() -> bool:
64
+ """Detect if LD_PRELOAD tee is active (same logic as http_client.py)."""
65
+ if os.getenv("SF_TEE_PRELOAD_ONLY", "0") == "1":
66
+ return True
67
+ ld = os.getenv("LD_PRELOAD", "")
68
+ return "libsfnettee.so" in ld or "_sfteepreload" in ld
69
+
70
+
71
+ # PERFORMANCE: Reentrancy guards disabled - they add ~10-20μs per request
72
+ # The socket layer (LD_PRELOAD) handles everything we need
73
+ # def _activate_rg(headers: Dict[str, str]) -> None:
74
+ # """Turn the three 'preactive' guard flags ON for downstream hops."""
75
+ # headers[REENTRANCY_GUARD_LOGGING_PREACTIVE] = "true"
76
+ # headers[REENTRANCY_GUARD_PRINT_PREACTIVE] = "true"
77
+ # headers[REENTRANCY_GUARD_EXCEPTIONS_PREACTIVE] = "true"
78
+
79
+
80
+ # def _check_rg(headers: Dict[str, str]) -> None:
81
+ # """If any pre-active guard present, switch the corresponding guard on."""
82
+ # if headers.get(REENTRANCY_GUARD_LOGGING_PREACTIVE, "false").lower() == "true":
83
+ # activate_reentrancy_guards_logging()
84
+ # if headers.get(REENTRANCY_GUARD_PRINT_PREACTIVE, "false").lower() == "true":
85
+ # activate_reentrancy_guards_print()
86
+ # if headers.get(REENTRANCY_GUARD_EXCEPTIONS_PREACTIVE, "false").lower() == "true":
87
+ # activate_reentrancy_guards_exception()
88
+
89
+
90
+ def _prepare(
91
+ url: str,
92
+ domains_to_skip: List[str],
93
+ headers: Optional[Dict[str, str]],
94
+ ) -> Tuple[str, Dict[str, str], int]:
95
+ """
96
+ Inject trace header + funcspan override header (unless excluded) and return:
97
+ trace_id, merged_headers, timestamp_ms
98
+
99
+ ULTRA-FAST: <20ns overhead for header injection.
100
+
101
+ PERFORMANCE: Reentrancy guards removed - saves ~10-20μs per request.
102
+ """
103
+ trace_id, propagate = get_trace_and_should_propagate(url, domains_to_skip)
104
+ hdrs: Dict[str, str] = dict(headers or {})
105
+ # _check_rg(hdrs) # DISABLED for performance
106
+
107
+ # Check if headers are already injected (avoid double-injection with httplib2/http_client)
108
+ # Fast O(1) check for common cases, fallback to O(n) for rare mixed-case variants
109
+ if propagate and not has_sailfish_header(hdrs):
110
+ hdrs[SAILFISH_TRACING_HEADER] = trace_id
111
+
112
+ # Inject funcspan override header if present (ContextVar lookup ~8ns)
113
+ try:
114
+ funcspan_override = get_funcspan_override()
115
+ if funcspan_override is not None:
116
+ hdrs[FUNCSPAN_OVERRIDE_HEADER] = funcspan_override
117
+ except Exception:
118
+ pass
119
+
120
+ # _activate_rg(hdrs) # DISABLED for performance
121
+ return trace_id, hdrs, int(time.time() * 1_000)
122
+
123
+
124
+ def _capture_and_record_requests(
125
+ resp, trace_id, url, method, status, success, err, t0, t1, req_data, hdrs
126
+ ):
127
+ """Capture response data in background thread AFTER response is returned to user."""
128
+ resp_data: bytes = b""
129
+ req_headers: bytes = b""
130
+ resp_headers: bytes = b""
131
+
132
+ try:
133
+ # Capture headers efficiently
134
+ if HAS_ORJSON:
135
+ req_headers = orjson.dumps({str(k): str(v) for k, v in hdrs.items()})
136
+ if resp:
137
+ resp_headers = orjson.dumps({str(k): str(v) for k, v in resp.headers.items()})
138
+ else:
139
+ req_headers = json.dumps({str(k): str(v) for k, v in hdrs.items()}).encode("utf-8")
140
+ if resp:
141
+ resp_headers = json.dumps({str(k): str(v) for k, v in resp.headers.items()}).encode("utf-8")
142
+
143
+ # For response body: check if already cached in _content
144
+ if resp:
145
+ try:
146
+ if hasattr(resp, "_content") and resp._content is not None:
147
+ resp_data = resp._content
148
+ except Exception: # noqa: BLE001
149
+ pass
150
+ except Exception: # noqa: BLE001
151
+ pass
152
+
153
+ # Send to C extension in background
154
+ record_network_request(
155
+ trace_id,
156
+ url,
157
+ method,
158
+ status,
159
+ success,
160
+ err,
161
+ timestamp_start=t0,
162
+ timestamp_end=t1,
163
+ request_data=req_data,
164
+ response_data=resp_data,
165
+ request_headers=req_headers,
166
+ response_headers=resp_headers,
167
+ )
168
+
169
+
170
+ def _capture_and_record_urllib3(
171
+ resp, trace_id, url, method, status, success, err, t0, t1, req_data, hdrs
172
+ ):
173
+ """Capture urllib3 response data in background thread AFTER response is returned to user."""
174
+ resp_data: bytes = b""
175
+ req_headers: bytes = b""
176
+ resp_headers: bytes = b""
177
+
178
+ try:
179
+ # Capture headers efficiently
180
+ if HAS_ORJSON:
181
+ req_headers = orjson.dumps({str(k): str(v) for k, v in hdrs.items()})
182
+ if resp:
183
+ resp_headers = orjson.dumps({str(k): str(v) for k, v in resp.headers.items()})
184
+ else:
185
+ req_headers = json.dumps({str(k): str(v) for k, v in hdrs.items()}).encode("utf-8")
186
+ if resp:
187
+ resp_headers = json.dumps({str(k): str(v) for k, v in resp.headers.items()}).encode("utf-8")
188
+
189
+ # For response body: check if already available in data attribute
190
+ if resp:
191
+ try:
192
+ resp_data = getattr(resp, "data", b"")
193
+ except Exception: # noqa: BLE001
194
+ pass
195
+ except Exception: # noqa: BLE001
196
+ pass
197
+
198
+ # Send to C extension in background
199
+ record_network_request(
200
+ trace_id,
201
+ url,
202
+ method,
203
+ status,
204
+ success,
205
+ err,
206
+ timestamp_start=t0,
207
+ timestamp_end=t1,
208
+ request_data=req_data,
209
+ response_data=resp_data,
210
+ request_headers=req_headers,
211
+ response_headers=resp_headers,
212
+ )
213
+
214
+
215
+ def _capture_and_record_http_client(
216
+ resp, trace_id, url, method, status, success, err, t0, t1, req_data, hdrs
217
+ ):
218
+ """Capture http.client response data in background thread AFTER response is returned to user."""
219
+ resp_data: bytes = b""
220
+ req_headers: bytes = b""
221
+ resp_headers: bytes = b""
222
+
223
+ try:
224
+ # Capture headers efficiently
225
+ if HAS_ORJSON:
226
+ req_headers = orjson.dumps({str(k): str(v) for k, v in hdrs.items()})
227
+ else:
228
+ req_headers = json.dumps({str(k): str(v) for k, v in hdrs.items()}).encode("utf-8")
229
+
230
+ # http.client doesn't easily expose response data, skip body capture
231
+ except Exception: # noqa: BLE001
232
+ pass
233
+
234
+ # Send to C extension in background
235
+ record_network_request(
236
+ trace_id,
237
+ url,
238
+ method,
239
+ status,
240
+ success,
241
+ err,
242
+ timestamp_start=t0,
243
+ timestamp_end=t1,
244
+ request_data=req_data,
245
+ response_data=resp_data,
246
+ request_headers=req_headers,
247
+ response_headers=resp_headers,
248
+ )
249
+
250
+
251
+ ###############################################################################
252
+ # Top-level patch function
253
+ ###############################################################################
254
+ def patch_requests(domains_to_not_propagate_headers_to: Optional[List[str]] = None):
255
+ """
256
+ Apply all monkey-patches. Safe to call multiple times.
257
+
258
+ When LD_PRELOAD is active:
259
+ - ALWAYS inject headers (trace_id + funcspan_override)
260
+ - SKIP capture/emission (LD_PRELOAD handles at socket layer)
261
+ """
262
+ # Idempotency guard: prevent double-patching (handles forks, reloading)
263
+ if is_already_patched("requests"):
264
+ return
265
+ mark_as_patched("requests")
266
+
267
+ exclude = domains_to_not_propagate_headers_to or []
268
+ preload_active = _tee_preload_active()
269
+
270
+ # PERFORMANCE DEBUG: Log preload detection
271
+ SF_DEBUG = os.getenv("SF_DEBUG", "false").lower() == "true"
272
+ if SF_DEBUG:
273
+ ld_preload = os.getenv("LD_PRELOAD", "")
274
+ print(f"[[patch_requests]] LD_PRELOAD={ld_preload}", flush=True)
275
+ print(f"[[patch_requests]] preload_active={preload_active}", flush=True)
276
+ print(
277
+ f"[[patch_requests]] Using {'ULTRA-FAST' if preload_active else 'FULL CAPTURE'} path",
278
+ flush=True,
279
+ )
280
+
281
+ # Initialize C extension for ultra-fast header checking (if available)
282
+ if preload_active:
283
+ init_fast_header_check(exclude)
284
+
285
+ # --------------------------------------------------------------------- #
286
+ # 1. Patch `requests.Session.request`
287
+ # --------------------------------------------------------------------- #
288
+ # Save original function BEFORE any patching
289
+ original_request = Session.request
290
+
291
+ if preload_active:
292
+ # ========== ULTRA-FAST PATH: When LD_PRELOAD is active ==========
293
+ # Use wrapt for minimal overhead (OTEL-style)
294
+ def instrumented_request(wrapped, instance, args, kwargs):
295
+ """ULTRA-FAST header injection (<100ns) via wrapt."""
296
+ # args = (method, url, ...), kwargs = {...}
297
+ url = args[1] if len(args) > 1 else kwargs.get("url", "")
298
+
299
+ # OPTIMIZED: Avoid kwargs.pop() - use get() with or-pattern (10x faster!)
300
+ headers = kwargs.get("headers") or {}
301
+
302
+ # CRITICAL: Skip if already injected (prevents double injection in requests→urllib3→http.client chain)
303
+ # Fast O(1) check for common cases, fallback to O(n) for rare mixed-case variants
304
+ if not has_sailfish_header(headers):
305
+ # ULTRA-FAST: Thread-local cache + direct ContextVar.get() (<100ns!)
306
+ inject_headers_ultrafast(headers, url, exclude)
307
+
308
+ kwargs["headers"] = headers
309
+
310
+ # NO timing, NO capture, NO threads - immediate return!
311
+ return wrapped(*args, **kwargs)
312
+
313
+ wrapt.wrap_function_wrapper(Session, "request", instrumented_request)
314
+
315
+ else:
316
+ # ========== FULL CAPTURE PATH: When LD_PRELOAD is NOT active ==========
317
+ # PERFORMANCE: Removed thread spawning - saves ~50-200μs per request
318
+ # Direct C extension call instead of background threads
319
+ def patched_request(self: Session, method, url, **kwargs): # type: ignore[override]
320
+ if SF_DEBUG:
321
+ print(f"[[patched_request]] INTERCEPTED: {method} {url}", flush=True)
322
+
323
+ # --- header handling / injection --------------------------------- #
324
+ trace_id, hdrs, t0 = _prepare(url, exclude, kwargs.pop("headers", {}))
325
+ kwargs["headers"] = hdrs
326
+
327
+ # Skip capture for HTTPS when ssl_socket.py is active (avoids double-capture)
328
+ is_https = url.startswith("https://")
329
+ if is_https and is_ssl_socket_active():
330
+ # ssl_socket.py will handle capture, just make the request
331
+ return original_request(self, method, url, **kwargs)
332
+
333
+ status: int = 0
334
+ success: bool = False
335
+ err: str | None = None
336
+ req_data: bytes = b""
337
+
338
+ # PERFORMANCE: Skip request body capture - saves ~10-50μs
339
+ # C extension captures everything at socket layer
340
+ # try:
341
+ # if "json" in kwargs:
342
+ # try:
343
+ # import orjson
344
+ # req_data = orjson.dumps(kwargs["json"])
345
+ # except ImportError:
346
+ # import json
347
+ # req_data = json.dumps(kwargs["json"]).encode('utf-8')
348
+ # elif "data" in kwargs:
349
+ # data = kwargs["data"]
350
+ # if isinstance(data, bytes):
351
+ # req_data = data
352
+ # elif isinstance(data, str):
353
+ # req_data = data.encode('utf-8')
354
+ # except Exception: # noqa: BLE001
355
+ # pass
356
+
357
+ try:
358
+ resp = original_request(self, method, url, **kwargs)
359
+ status = resp.status_code
360
+ success = resp.ok
361
+ t1 = int(time.time() * 1_000)
362
+
363
+ if SF_DEBUG:
364
+ print(f"[[patched_request]] Request completed: status={status}, success={success}, calling record_network_request...", flush=True)
365
+
366
+ # PERFORMANCE: Direct C call (NO thread spawning!) - saves ~50-200μs
367
+ record_network_request(
368
+ trace_id,
369
+ url,
370
+ str(method).upper(),
371
+ status,
372
+ success,
373
+ None,
374
+ timestamp_start=t0,
375
+ timestamp_end=t1,
376
+ request_data=req_data,
377
+ response_data=b"",
378
+ request_headers=b"",
379
+ response_headers=b"",
380
+ )
381
+
382
+ if SF_DEBUG:
383
+ print(f"[[patched_request]] ✓ record_network_request() completed successfully", flush=True)
384
+
385
+ return resp
386
+ except Exception as exc: # noqa: BLE001
387
+ err = str(exc)[:255]
388
+ t1 = int(time.time() * 1_000)
389
+ # PERFORMANCE: Direct C call (NO thread spawning!)
390
+ record_network_request(
391
+ trace_id,
392
+ url,
393
+ str(method).upper(),
394
+ status,
395
+ success,
396
+ err,
397
+ timestamp_start=t0,
398
+ timestamp_end=t1,
399
+ request_data=req_data,
400
+ response_data=b"",
401
+ request_headers=b"",
402
+ response_headers=b"",
403
+ )
404
+ raise
405
+
406
+ # CRITICAL: Always apply patch in full capture path, regardless of wrapt availability
407
+ Session.request = patched_request
408
+ requests.Session.request = (
409
+ patched_request # cover direct `requests.Session(...)`
410
+ )
411
+
412
+ # --------------------------------------------------------------------- #
413
+ # 2. Patch urllib3's low-level ConnectionPool.urlopen (used by requests)
414
+ # --------------------------------------------------------------------- #
415
+ # Save original function BEFORE any patching
416
+ original_urlopen = urllib3.connectionpool.HTTPConnectionPool.urlopen
417
+
418
+ if preload_active:
419
+ # ========== ULTRA-FAST PATH: When LD_PRELOAD is active ==========
420
+ # Use wrapt for minimal overhead (OTEL-style)
421
+ def instrumented_urlopen(wrapped, instance, args, kwargs):
422
+ """ULTRA-FAST header injection (<100ns) via wrapt."""
423
+ # args = (method, url, ...), kwargs = {body, headers, ...}
424
+ url = args[1] if len(args) > 1 else kwargs.get("url", "")
425
+
426
+ # OPTIMIZED: Use or-pattern (10x faster!)
427
+ headers = kwargs.get("headers") or {}
428
+
429
+ # CRITICAL: Skip if already injected by requests.Session (prevents double injection)
430
+ # Fast O(1) check for common cases, fallback to O(n) for rare mixed-case variants
431
+ if not has_sailfish_header(headers):
432
+ # ULTRA-FAST: Thread-local cache + direct ContextVar.get() (<100ns!)
433
+ inject_headers_ultrafast(headers, url, exclude)
434
+
435
+ kwargs["headers"] = headers
436
+
437
+ # NO timing, NO capture, NO threads - immediate return!
438
+ return wrapped(*args, **kwargs)
439
+
440
+ wrapt.wrap_function_wrapper(
441
+ urllib3.connectionpool.HTTPConnectionPool,
442
+ "urlopen",
443
+ instrumented_urlopen,
444
+ )
445
+
446
+ else:
447
+ # ========== FULL CAPTURE PATH: When LD_PRELOAD is NOT active ==========
448
+ # PERFORMANCE: Removed thread spawning and body capture
449
+ def patched_urlopen(self, method, url, body=None, headers=None, **kw): # type: ignore[override]
450
+ trace_id, hdrs, t0 = _prepare(url, exclude, headers)
451
+ status: int = 0
452
+ success: bool = False
453
+ err: str | None = None
454
+
455
+ try:
456
+ resp = original_urlopen(
457
+ self, method, url, body=body, headers=hdrs, **kw
458
+ )
459
+ status = getattr(resp, "status", 0)
460
+ success = status < 400
461
+ t1 = int(time.time() * 1_000)
462
+
463
+ # PERFORMANCE: Direct C call (NO thread spawning!)
464
+ record_network_request(
465
+ trace_id,
466
+ url,
467
+ str(method).upper(),
468
+ status,
469
+ success,
470
+ None,
471
+ timestamp_start=t0,
472
+ timestamp_end=t1,
473
+ request_data=b"",
474
+ response_data=b"",
475
+ request_headers=b"",
476
+ response_headers=b"",
477
+ )
478
+
479
+ return resp
480
+ except Exception as exc: # noqa: BLE001
481
+ err = str(exc)[:255]
482
+ t1 = int(time.time() * 1_000)
483
+ record_network_request(
484
+ trace_id,
485
+ url,
486
+ str(method).upper(),
487
+ status,
488
+ success,
489
+ err,
490
+ timestamp_start=t0,
491
+ timestamp_end=t1,
492
+ request_data=b"",
493
+ response_data=b"",
494
+ request_headers=b"",
495
+ response_headers=b"",
496
+ )
497
+ raise
498
+
499
+ # CRITICAL: Always apply patch in full capture path
500
+ urllib3.connectionpool.HTTPConnectionPool.urlopen = patched_urlopen
501
+
502
+ # --------------------------------------------------------------------- #
503
+ # 3. Patch http.client for "raw" stdlib usage (rare but easy to support)
504
+ # --------------------------------------------------------------------- #
505
+ # Save original function BEFORE any patching
506
+ original_http_client_request = http.client.HTTPConnection.request
507
+
508
+ if preload_active:
509
+ # ========== ULTRA-FAST PATH: When LD_PRELOAD is active ==========
510
+ # Use wrapt for minimal overhead (OTEL-style)
511
+ def instrumented_http_request(wrapped, instance, args, kwargs):
512
+ """ULTRA-FAST header injection (<100ns) via wrapt."""
513
+ # args = (method, url, ...), kwargs = {body, headers, encode_chunked, ...}
514
+ url = args[1] if len(args) > 1 else kwargs.get("url", "")
515
+
516
+ # OPTIMIZED: Use or-pattern (10x faster!)
517
+ headers = kwargs.get("headers") or {}
518
+
519
+ # CRITICAL: Skip if already injected by requests/urllib3 (prevents triple injection)
520
+ # Fast O(1) check for common cases, fallback to O(n) for rare mixed-case variants
521
+ if not has_sailfish_header(headers):
522
+ # ULTRA-FAST: Thread-local cache + direct ContextVar.get() (<100ns!)
523
+ inject_headers_ultrafast(headers, url, exclude)
524
+
525
+ kwargs["headers"] = headers
526
+
527
+ # NO timing, NO capture, NO threads - immediate return!
528
+ return wrapped(*args, **kwargs)
529
+
530
+ wrapt.wrap_function_wrapper(
531
+ http.client.HTTPConnection, "request", instrumented_http_request
532
+ )
533
+
534
+ else:
535
+ # ========== FULL CAPTURE PATH: When LD_PRELOAD is NOT active ==========
536
+ # PERFORMANCE: Removed thread spawning and body capture
537
+ def patched_http_request(self, method, url, body=None, headers=None, *, encode_chunked=False): # type: ignore[override]
538
+ trace_id, hdrs, t0 = _prepare(url, exclude, headers)
539
+ status: int = 0
540
+ success: bool = False
541
+ err: str | None = None
542
+
543
+ try:
544
+ resp = original_http_client_request(
545
+ self,
546
+ method,
547
+ url,
548
+ body=body,
549
+ headers=hdrs,
550
+ encode_chunked=encode_chunked,
551
+ )
552
+ status = getattr(
553
+ self, "response", getattr(resp, "status", 0)
554
+ ) # best-effort
555
+ success = bool(status) and status < 400
556
+ t1 = int(time.time() * 1_000)
557
+
558
+ # PERFORMANCE: Direct C call (NO thread spawning!)
559
+ record_network_request(
560
+ trace_id,
561
+ url,
562
+ str(method).upper(),
563
+ status,
564
+ success,
565
+ None,
566
+ timestamp_start=t0,
567
+ timestamp_end=t1,
568
+ request_data=b"",
569
+ response_data=b"",
570
+ request_headers=b"",
571
+ response_headers=b"",
572
+ )
573
+
574
+ return resp
575
+ except Exception as exc: # noqa: BLE001
576
+ err = str(exc)[:255]
577
+ t1 = int(time.time() * 1_000)
578
+ record_network_request(
579
+ trace_id,
580
+ url,
581
+ str(method).upper(),
582
+ status,
583
+ success,
584
+ err,
585
+ timestamp_start=t0,
586
+ timestamp_end=t1,
587
+ request_data=b"",
588
+ response_data=b"",
589
+ request_headers=b"",
590
+ response_headers=b"",
591
+ )
592
+ raise
593
+
594
+ # CRITICAL: Always apply patch in full capture path
595
+ http.client.HTTPConnection.request = patched_http_request