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,363 @@
1
+ import os
2
+ import time
3
+ from typing import List, Optional
4
+
5
+ try:
6
+ import wrapt
7
+
8
+ HAS_WRAPT = True
9
+ except ImportError:
10
+ HAS_WRAPT = False
11
+
12
+ import threading
13
+
14
+ from ...thread_local import get_or_set_sf_trace_id, trace_id_ctx
15
+ from ..constants import supported_network_verbs as verbs
16
+ from .utils import (
17
+ init_fast_header_check,
18
+ inject_headers_ultrafast,
19
+ record_network_request,
20
+ )
21
+
22
+ # JSON serialization - try fast orjson first, fallback to stdlib json
23
+ try:
24
+ import orjson
25
+
26
+ HAS_ORJSON = True
27
+ except ImportError:
28
+ import json
29
+
30
+ HAS_ORJSON = False
31
+
32
+
33
+ def _tee_preload_active() -> bool:
34
+ """Detect if LD_PRELOAD tee is active (same logic as http_client.py)."""
35
+ if os.getenv("SF_TEE_PRELOAD_ONLY", "0") == "1":
36
+ return True
37
+ ld = os.getenv("LD_PRELOAD", "")
38
+ return "libsfnettee.so" in ld or "_sfteepreload" in ld
39
+
40
+
41
+ def _capture_and_record_curl_cffi(
42
+ resp,
43
+ trace_id,
44
+ url,
45
+ method,
46
+ status,
47
+ ok,
48
+ start,
49
+ end,
50
+ req_data,
51
+ req_headers,
52
+ preload_active,
53
+ ):
54
+ """Capture response data in background thread AFTER response is returned to user."""
55
+ resp_data = b""
56
+ resp_headers = b""
57
+ error = None
58
+
59
+ try:
60
+ # Capture response body
61
+ try:
62
+ resp_data = getattr(resp, "content", b"")
63
+ except Exception: # noqa: BLE001
64
+ pass
65
+
66
+ # Capture response headers
67
+ if HAS_ORJSON:
68
+ resp_headers = orjson.dumps({str(k): str(v) for k, v in resp.headers.items()})
69
+ else:
70
+ resp_headers = json.dumps({str(k): str(v) for k, v in resp.headers.items()}).encode("utf-8")
71
+
72
+ if not ok and not error:
73
+ try:
74
+ error = getattr(resp, "text", str(resp))[:255]
75
+ except Exception: # noqa: BLE001
76
+ pass
77
+ except Exception: # noqa: BLE001
78
+ pass
79
+
80
+ # Only capture if LD_PRELOAD is NOT active (avoid duplicates)
81
+ if not preload_active:
82
+ record_network_request(
83
+ trace_id,
84
+ url,
85
+ method,
86
+ status,
87
+ ok,
88
+ error,
89
+ timestamp_start=start,
90
+ timestamp_end=end,
91
+ request_data=req_data,
92
+ response_data=resp_data,
93
+ request_headers=req_headers,
94
+ response_headers=resp_headers,
95
+ )
96
+
97
+
98
+ def patch_curl_cffi(domains_to_not_propagate_headers_to: Optional[List[str]] = None):
99
+ """
100
+ Monkey-patch curl_cffi.requests so that EVERY HTTP verb
101
+ injects SAILFISH_TRACING_HEADER (when allowed) and then records the request.
102
+
103
+ When LD_PRELOAD is active: ULTRA-FAST path with <10ns overhead (header injection only).
104
+ When LD_PRELOAD is NOT active: Full capture path with body/header recording.
105
+ """
106
+ try:
107
+ import curl_cffi.requests as ccr
108
+ except ImportError:
109
+ return
110
+
111
+ skip = domains_to_not_propagate_headers_to or []
112
+ preload_active = _tee_preload_active()
113
+
114
+ # Initialize C extension for ultra-fast header checking (if available)
115
+ if preload_active:
116
+ init_fast_header_check(skip)
117
+
118
+ # Preserve original references before any patching
119
+ orig_request = getattr(ccr, "request", None)
120
+ orig_session_request = None
121
+ orig_async_session_request = None
122
+
123
+ Session = getattr(ccr, "Session", None)
124
+ AsyncSession = getattr(ccr, "AsyncSession", None)
125
+ if Session:
126
+ orig_session_request = getattr(Session, "request", None)
127
+ if AsyncSession:
128
+ orig_async_session_request = getattr(AsyncSession, "request", None)
129
+
130
+ if preload_active:
131
+ # ========== ULTRA-FAST PATH: When LD_PRELOAD is active ==========
132
+ # Uses C extension for <10ns overhead (15ns empty list, 25ns with filtering)
133
+ if HAS_WRAPT:
134
+ # FASTEST: Use wrapt for ultra-low overhead
135
+ def make_instrumented(verb_name):
136
+ """Create a wrapt instrumented function for the given verb."""
137
+
138
+ def instrumented(wrapped, instance, args, kwargs):
139
+ """Ultra-fast header injection using C extension via wrapt."""
140
+ # OPTIMIZED: Simplified URL extraction (prioritize kwargs, then positional args)
141
+ url = kwargs.get("url")
142
+ if not url and args:
143
+ # request(method, url) or get(url) - URL is typically first or second arg
144
+ url = (
145
+ args[1]
146
+ if verb_name == "request" and len(args) >= 2
147
+ else (args[0] if args else "")
148
+ )
149
+
150
+ # OPTIMIZED: Pre-allocate headers dict (use or-pattern for None)
151
+ headers = kwargs.get("headers") or {}
152
+ kwargs["headers"] = headers
153
+
154
+ # ULTRA-FAST: inject_headers_ultrafast does domain filtering + header injection (~100ns)
155
+ inject_headers_ultrafast(headers, url or "", skip)
156
+
157
+ # Immediately call original and return - NO timing, NO threads, NO capture!
158
+ return wrapped(*args, **kwargs)
159
+
160
+ return instrumented
161
+
162
+ else:
163
+ # Fallback: Direct patching if wrapt not available
164
+ def make_fast_wrapper(orig_fn, verb_name):
165
+ def fast_wrapper(*args, **kwargs):
166
+ # OPTIMIZED: Simplified URL extraction (same as wrapt path)
167
+ url = kwargs.get("url")
168
+ if not url and args:
169
+ url = (
170
+ args[1]
171
+ if verb_name == "request" and len(args) >= 2
172
+ else (args[0] if args else "")
173
+ )
174
+
175
+ # OPTIMIZED: Pre-allocate headers dict (use or-pattern for None)
176
+ headers = kwargs.get("headers") or {}
177
+ kwargs["headers"] = headers
178
+
179
+ # ULTRA-FAST: inject_headers_ultrafast does domain filtering + header injection (~100ns)
180
+ inject_headers_ultrafast(headers, url or "", skip)
181
+
182
+ # Immediately call original and return - NO timing, NO threads, NO capture!
183
+ return orig_fn(*args, **kwargs)
184
+
185
+ return fast_wrapper
186
+
187
+ else:
188
+ # ========== FULL CAPTURE PATH: When LD_PRELOAD is NOT active ==========
189
+ # Full Python-level capture with body/header recording
190
+ def make_fast_wrapper(orig_fn, verb_name):
191
+ def wrapper(*args, **kwargs):
192
+ # 1) Determine HTTP method and URL safely
193
+ if verb_name == "request":
194
+ # support both request(url) and request(method, url, …)
195
+ if len(args) == 1 and isinstance(args[0], str):
196
+ method, url = "GET", args[0]
197
+ elif len(args) >= 2 and isinstance(args[0], str):
198
+ method, url = args[0].upper(), args[1]
199
+ elif len(args) >= 3:
200
+ # bound Session.request(self, method, url, …)
201
+ method, url = args[1].upper(), args[2]
202
+ else:
203
+ method = kwargs.get("method", "").upper()
204
+ url = kwargs.get("url", "")
205
+ else:
206
+ method = verb_name.upper()
207
+ # for module-level: args[0] == url
208
+ # for bound: args[1] == url
209
+ if len(args) >= 1 and isinstance(args[0], str):
210
+ url = args[0]
211
+ elif len(args) >= 2:
212
+ url = args[1]
213
+ else:
214
+ url = kwargs.get("url", "")
215
+
216
+ # 2) Header injection
217
+ headers = kwargs.get("headers", {}) or {}
218
+
219
+ # ULTRA-FAST: inject_headers_ultrafast does domain filtering + header injection (~100ns)
220
+ inject_headers_ultrafast(headers, url, skip)
221
+
222
+ kwargs["headers"] = headers
223
+
224
+ # Get trace_id for capture
225
+ trace_id = trace_id_ctx.get(None) or ""
226
+
227
+ # Capture request data as bytes
228
+ req_data = b""
229
+ req_headers = b""
230
+ try:
231
+ if "json" in kwargs:
232
+ if HAS_ORJSON:
233
+ req_data = orjson.dumps(kwargs["json"])
234
+ else:
235
+ req_data = json.dumps(kwargs["json"]).encode("utf-8")
236
+ elif "data" in kwargs:
237
+ data = kwargs["data"]
238
+ if isinstance(data, bytes):
239
+ req_data = data
240
+ elif isinstance(data, str):
241
+ req_data = data.encode("utf-8")
242
+ elif "content" in kwargs:
243
+ content = kwargs["content"]
244
+ if isinstance(content, bytes):
245
+ req_data = content
246
+ elif isinstance(content, str):
247
+ req_data = content.encode("utf-8")
248
+
249
+ # Capture request headers
250
+ if HAS_ORJSON:
251
+ req_headers = orjson.dumps({str(k): str(v) for k, v in headers.items()})
252
+ else:
253
+ req_headers = json.dumps({str(k): str(v) for k, v in headers.items()}).encode("utf-8")
254
+ except Exception: # noqa: BLE001
255
+ pass
256
+
257
+ # 3) Perform the real call
258
+ start = int(time.time() * 1_000)
259
+ resp = orig_fn(*args, **kwargs)
260
+ end = int(time.time() * 1_000)
261
+
262
+ # 4) Get status immediately, but DEFER body/header capture
263
+ status = getattr(resp, "status_code", None) or getattr(
264
+ resp, "status", 0
265
+ )
266
+ ok = getattr(resp, "ok", status < 400)
267
+
268
+ # Schedule deferred capture in background thread
269
+ threading.Thread(
270
+ target=_capture_and_record_curl_cffi,
271
+ args=(
272
+ resp,
273
+ trace_id,
274
+ url,
275
+ method,
276
+ status,
277
+ ok,
278
+ start,
279
+ end,
280
+ req_data,
281
+ req_headers,
282
+ False,
283
+ ),
284
+ daemon=True,
285
+ ).start()
286
+
287
+ # CRITICAL: Return response immediately without blocking!
288
+ return resp
289
+
290
+ return wrapper
291
+
292
+ # Patch module-level verbs
293
+ if HAS_WRAPT and preload_active:
294
+ # Use wrapt for ultra-low overhead when LD_PRELOAD is active
295
+ for verb in verbs:
296
+ if getattr(ccr, verb, None):
297
+ wrapt.wrap_function_wrapper(ccr, verb, make_instrumented(verb))
298
+
299
+ # Patch module-level "request" method (not in standard verbs list)
300
+ if orig_request:
301
+ wrapt.wrap_function_wrapper(ccr, "request", make_instrumented("request"))
302
+
303
+ # Patch Session methods
304
+ if Session:
305
+ for verb in verbs:
306
+ if getattr(Session, verb, None):
307
+ wrapt.wrap_function_wrapper(Session, verb, make_instrumented(verb))
308
+ # Also patch "request" method with preserved original
309
+ if orig_session_request:
310
+ wrapt.wrap_function_wrapper(
311
+ Session, "request", make_instrumented("request")
312
+ )
313
+
314
+ # Patch AsyncSession methods
315
+ if AsyncSession:
316
+ for verb in verbs:
317
+ if getattr(AsyncSession, verb, None):
318
+ wrapt.wrap_function_wrapper(
319
+ AsyncSession, verb, make_instrumented(verb)
320
+ )
321
+ # Also patch "request" method with preserved original
322
+ if orig_async_session_request:
323
+ wrapt.wrap_function_wrapper(
324
+ AsyncSession, "request", make_instrumented("request")
325
+ )
326
+ else:
327
+ # Fallback: Direct patching
328
+ for verb in verbs:
329
+ orig = getattr(ccr, verb, None)
330
+ if orig:
331
+ setattr(ccr, verb, make_fast_wrapper(orig, verb))
332
+
333
+ # Patch module-level "request" method (not in standard verbs list)
334
+ if orig_request:
335
+ setattr(ccr, "request", make_fast_wrapper(orig_request, "request"))
336
+
337
+ # Patch Session methods
338
+ if Session:
339
+ for verb in verbs:
340
+ orig = getattr(Session, verb, None)
341
+ if orig:
342
+ setattr(Session, verb, make_fast_wrapper(orig, verb))
343
+ # Also patch "request" method with preserved original
344
+ if orig_session_request:
345
+ setattr(
346
+ Session,
347
+ "request",
348
+ make_fast_wrapper(orig_session_request, "request"),
349
+ )
350
+
351
+ # Patch AsyncSession methods
352
+ if AsyncSession:
353
+ for verb in verbs:
354
+ orig = getattr(AsyncSession, verb, None)
355
+ if orig:
356
+ setattr(AsyncSession, verb, make_fast_wrapper(orig, verb))
357
+ # Also patch "request" method with preserved original
358
+ if orig_async_session_request:
359
+ setattr(
360
+ AsyncSession,
361
+ "request",
362
+ make_fast_wrapper(orig_async_session_request, "request"),
363
+ )