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,315 @@
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
+ from ...constants import SAILFISH_TRACING_HEADER, PARENT_SESSION_ID_HEADER
13
+ from ...env_vars import SF_DEBUG
14
+ from ...thread_local import trace_id_ctx
15
+ from .utils import (
16
+ init_fast_header_check,
17
+ inject_headers_ultrafast,
18
+ record_network_request,
19
+ is_ssl_socket_active,
20
+ has_sailfish_header,
21
+ )
22
+
23
+ # JSON serialization - try fast orjson first, fallback to stdlib json
24
+ try:
25
+ import orjson
26
+
27
+ HAS_ORJSON = True
28
+ except ImportError:
29
+ import json
30
+
31
+ HAS_ORJSON = False
32
+
33
+
34
+ def _tee_preload_active() -> bool:
35
+ """Detect if LD_PRELOAD tee is active (same logic as http_client.py)."""
36
+ if os.getenv("SF_TEE_PRELOAD_ONLY", "0") == "1":
37
+ return True
38
+ ld = os.getenv("LD_PRELOAD", "")
39
+ return "libsfnettee.so" in ld or "_sfteepreload" in ld
40
+
41
+
42
+ def patch_httplib2(domains_to_not_propagate_headers_to: Optional[List[str]] = None):
43
+ """
44
+ Monkey-patch httplib2.Http.request so that:
45
+ 1. We skip header injection for configured domains.
46
+ 2. We inject SAILFISH_TRACING_HEADER + FUNCSPAN_OVERRIDE_HEADER (fast: <20ns).
47
+ 3. We call NetworkRequestTransmitter().do_send via record_network_request() UNLESS LD_PRELOAD active.
48
+ 4. All HTTP methods (GET, POST, etc.) continue to work as before.
49
+
50
+ When LD_PRELOAD is active: ULTRA-FAST path with <10ns overhead (header injection only).
51
+ When LD_PRELOAD is NOT active: Full capture path with body/header recording.
52
+
53
+ CRITICAL: If http.client is already patched, httplib2 only does header injection
54
+ to avoid double-capture (httplib2 uses http.client.HTTPConnection underneath).
55
+ """
56
+ TRACE_HEADER_LOWER = SAILFISH_TRACING_HEADER.lower()
57
+ PARENT_HEADER_LOWER = PARENT_SESSION_ID_HEADER.lower()
58
+
59
+ def _log_headers(stage: str, hdrs: Optional[dict]) -> None:
60
+ if not (SF_DEBUG and hdrs):
61
+ return
62
+ try:
63
+ snapshot = {}
64
+ for key, value in hdrs.items():
65
+ if not isinstance(key, str):
66
+ continue
67
+ key_lower = key.lower()
68
+ if key_lower in (TRACE_HEADER_LOWER, PARENT_HEADER_LOWER):
69
+ snapshot[key] = value
70
+ print(f"[httplib2.patch] {stage} headers={snapshot}", log=False)
71
+ except Exception as exc: # pragma: no cover - debug logging only
72
+ print(f"[httplib2.patch] {stage} header log failed: {exc}", log=False)
73
+
74
+ try:
75
+ import httplib2
76
+ except ImportError:
77
+ return
78
+
79
+ original_conn_request = getattr(httplib2.Http, "_conn_request", None)
80
+ if (
81
+ original_conn_request
82
+ and not getattr(original_conn_request, "_sf_debug_logged", False)
83
+ and SF_DEBUG
84
+ ):
85
+ def _logged_conn_request(self, conn, request_uri, method, body, headers):
86
+ _log_headers(
87
+ f"conn_request:{method}:{request_uri}",
88
+ headers or {},
89
+ )
90
+ return original_conn_request(self, conn, request_uri, method, body, headers)
91
+
92
+ _logged_conn_request._sf_debug_logged = True # type: ignore[attr-defined]
93
+ httplib2.Http._conn_request = _logged_conn_request
94
+
95
+ skip = domains_to_not_propagate_headers_to or []
96
+ preload_active = _tee_preload_active()
97
+
98
+ # CRITICAL: Check if http.client is already patched (handles capture for us)
99
+ # httplib2 uses http.client.HTTPConnection underneath, so if http_client patch
100
+ # is active, we should ONLY do header injection to avoid double-capture
101
+ http_client_patched = False
102
+ try:
103
+ import http.client as _hc
104
+ # Check if request method has been wrapped (indicates http_client patch is active)
105
+ http_client_patched = hasattr(_hc.HTTPConnection.request, '__wrapped__') or \
106
+ getattr(_hc.HTTPConnection.request, '__name__', '') == 'patched_request'
107
+ except Exception:
108
+ pass
109
+
110
+ # Initialize C extension for ultra-fast header checking (if available)
111
+ if preload_active or http_client_patched:
112
+ init_fast_header_check(skip)
113
+
114
+ # Store original for both fast and slow paths
115
+ original_request = httplib2.Http.request
116
+
117
+ # Use fast path (header injection only) if LD_PRELOAD is active OR http.client is already patched
118
+ use_fast_path = preload_active or http_client_patched
119
+
120
+ if use_fast_path:
121
+ # ========== ULTRA-FAST PATH: Header injection only ==========
122
+ # Used when: LD_PRELOAD is active OR http.client is already patched
123
+ # This avoids double-capture since http.client handles it for us
124
+ if HAS_WRAPT:
125
+ # FASTEST: Use wrapt directly (OTEL-style for minimal overhead)
126
+ def instrumented_request(wrapped, instance, args, kwargs):
127
+ """Ultra-fast header injection using inject_headers_ultrafast() via wrapt."""
128
+ # args = (uri, method, ...), kwargs = {body, headers, ...}
129
+ uri = args[0] if len(args) > 0 else kwargs.get("uri", "")
130
+
131
+ # Ensure headers dict exists
132
+ headers = kwargs.get("headers")
133
+ if not headers:
134
+ headers = {}
135
+ elif not isinstance(headers, dict):
136
+ headers = dict(headers)
137
+
138
+ if SF_DEBUG:
139
+ _log_headers("pre-inject", headers)
140
+
141
+ # Check if headers are already injected (avoid double-injection with http.client)
142
+ # Fast O(1) check for common cases, fallback to O(n) for rare mixed-case variants
143
+ if not has_sailfish_header(headers):
144
+ # ULTRA-FAST: inject_headers_ultrafast does domain filtering + header injection (~100ns)
145
+ inject_headers_ultrafast(headers, uri, skip)
146
+ if SF_DEBUG:
147
+ _log_headers("post-inject", headers)
148
+ elif SF_DEBUG:
149
+ dup_snapshot = {
150
+ k: headers[k]
151
+ for k in headers
152
+ if isinstance(k, str) and k.lower() == TRACE_HEADER_LOWER
153
+ }
154
+ print(f"[httplib2.patch] Skip inject (wrapt) - existing headers={dup_snapshot}", log=False)
155
+
156
+ kwargs["headers"] = headers
157
+
158
+ # Immediately call original and return - NO timing, NO capture!
159
+ return wrapped(*args, **kwargs)
160
+
161
+ wrapt.wrap_function_wrapper(
162
+ "httplib2", "Http.request", instrumented_request
163
+ )
164
+ else:
165
+ # Fallback: Direct patching if wrapt not available
166
+ def patched_request(
167
+ self, uri, method="GET", body=None, headers=None, **kwargs
168
+ ):
169
+ # Ensure headers dict exists
170
+ if not headers:
171
+ headers = {}
172
+ elif not isinstance(headers, dict):
173
+ headers = dict(headers)
174
+
175
+ if SF_DEBUG:
176
+ _log_headers("pre-inject", headers)
177
+
178
+ # Check if headers are already injected (avoid double-injection with http.client)
179
+ # Fast O(1) check for common cases, fallback to O(n) for rare mixed-case variants
180
+ if not has_sailfish_header(headers):
181
+ # ULTRA-FAST: inject_headers_ultrafast does domain filtering + header injection (~100ns)
182
+ inject_headers_ultrafast(headers, uri, skip)
183
+ if SF_DEBUG:
184
+ _log_headers("post-inject", headers)
185
+ elif SF_DEBUG:
186
+ dup_snapshot = {
187
+ k: headers[k]
188
+ for k in headers
189
+ if isinstance(k, str) and k.lower() == TRACE_HEADER_LOWER
190
+ }
191
+ print(f"[httplib2.patch] Skip inject (fallback) - existing headers={dup_snapshot}", log=False)
192
+
193
+ # Immediately call original and return - NO timing, NO capture!
194
+ return original_request(
195
+ self, uri, method, body=body, headers=headers, **kwargs
196
+ )
197
+
198
+ httplib2.Http.request = patched_request
199
+
200
+ else:
201
+ # ========== FULL CAPTURE PATH: When neither LD_PRELOAD nor http.client patch is active ==========
202
+ # Only used when httplib2 needs to handle capture itself (rare case)
203
+ def patched_request(self, uri, method="GET", body=None, headers=None, **kwargs):
204
+ start_ts = int(time.time() * 1_000)
205
+
206
+ # Ensure headers dict exists
207
+ if not headers:
208
+ headers = {}
209
+ elif not isinstance(headers, dict):
210
+ headers = dict(headers)
211
+
212
+ if SF_DEBUG:
213
+ _log_headers("pre-inject-full", headers)
214
+
215
+ # Check if headers are already injected (avoid double-injection with http.client)
216
+ # Fast O(1) check for common cases, fallback to O(n) for rare mixed-case variants
217
+ if not has_sailfish_header(headers):
218
+ # ULTRA-FAST: inject_headers_ultrafast does domain filtering + header injection (~100ns)
219
+ inject_headers_ultrafast(headers, uri, skip)
220
+ if SF_DEBUG:
221
+ _log_headers("post-inject-full", headers)
222
+ elif SF_DEBUG:
223
+ dup_snapshot = {
224
+ k: headers[k]
225
+ for k in headers
226
+ if isinstance(k, str) and k.lower() == TRACE_HEADER_LOWER
227
+ }
228
+ print(f"[httplib2.patch] Skip inject (full path) - existing headers={dup_snapshot}", log=False)
229
+
230
+ # Skip capture for HTTPS when ssl_socket.py is active (avoids double-capture)
231
+ # ssl_socket.py captures ALL SSL traffic at socket layer when enabled
232
+ is_https = uri.startswith("https://")
233
+ if is_https and is_ssl_socket_active():
234
+ # ssl_socket.py will handle capture, just make the request
235
+ return original_request(self, uri, method, body=body, headers=headers, **kwargs)
236
+
237
+ # Get trace_id for capture
238
+ trace_id = trace_id_ctx.get(None) or ""
239
+
240
+ # Capture request data
241
+ req_data = b""
242
+ req_headers = b""
243
+ try:
244
+ if body:
245
+ if isinstance(body, bytes):
246
+ req_data = body
247
+ elif isinstance(body, str):
248
+ req_data = body.encode("utf-8")
249
+
250
+ # Capture request headers
251
+ if HAS_ORJSON:
252
+ req_headers = orjson.dumps({str(k): str(v) for k, v in headers.items()})
253
+ else:
254
+ req_headers = json.dumps({str(k): str(v) for k, v in headers.items()}).encode("utf-8")
255
+ except Exception: # noqa: BLE001
256
+ pass
257
+
258
+ try:
259
+ # perform the actual HTTP call
260
+ response, content = original_request(
261
+ self, uri, method, body=body, headers=headers, **kwargs
262
+ )
263
+ status_code = getattr(response, "status", None) or getattr(
264
+ response, "status_code", None
265
+ )
266
+ success = isinstance(status_code, int) and 200 <= status_code < 400
267
+
268
+ # Capture response data and headers
269
+ resp_data = b""
270
+ resp_headers = b""
271
+
272
+ # content is already the response body in httplib2
273
+ resp_data = content if isinstance(content, bytes) else b""
274
+ # Capture response headers
275
+ if HAS_ORJSON:
276
+ resp_headers = orjson.dumps({str(k): str(v) for k, v in response.items()})
277
+ else:
278
+ resp_headers = json.dumps({str(k): str(v) for k, v in response.items()}).encode("utf-8")
279
+
280
+ # record success (only when LD_PRELOAD is NOT active)
281
+ record_network_request(
282
+ trace_id,
283
+ uri,
284
+ method,
285
+ status_code,
286
+ success,
287
+ timestamp_start=start_ts,
288
+ timestamp_end=int(time.time() * 1_000),
289
+ request_data=req_data,
290
+ response_data=resp_data,
291
+ request_headers=req_headers,
292
+ response_headers=resp_headers,
293
+ )
294
+
295
+ return response, content
296
+
297
+ except Exception as e:
298
+ # record failures (only when LD_PRELOAD is NOT active)
299
+ record_network_request(
300
+ trace_id,
301
+ uri,
302
+ method,
303
+ 0,
304
+ False,
305
+ error=str(e)[:255],
306
+ timestamp_start=start_ts,
307
+ timestamp_end=int(time.time() * 1_000),
308
+ request_data=req_data,
309
+ request_headers=req_headers,
310
+ )
311
+ raise
312
+
313
+ # apply our patch (only if not using wrapt in fast path)
314
+ if not (use_fast_path and HAS_WRAPT):
315
+ httplib2.Http.request = patched_request