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.
- sf_veritas/__init__.py +46 -0
- sf_veritas/_auto_preload.py +73 -0
- sf_veritas/_sfconfig.c +162 -0
- sf_veritas/_sfconfig.cpython-314-x86_64-linux-gnu.so +0 -0
- sf_veritas/_sfcrashhandler.c +267 -0
- sf_veritas/_sfcrashhandler.cpython-314-x86_64-linux-gnu.so +0 -0
- sf_veritas/_sffastlog.c +953 -0
- sf_veritas/_sffastlog.cpython-314-x86_64-linux-gnu.so +0 -0
- sf_veritas/_sffastnet.c +994 -0
- sf_veritas/_sffastnet.cpython-314-x86_64-linux-gnu.so +0 -0
- sf_veritas/_sffastnetworkrequest.c +727 -0
- sf_veritas/_sffastnetworkrequest.cpython-314-x86_64-linux-gnu.so +0 -0
- sf_veritas/_sffuncspan.c +2791 -0
- sf_veritas/_sffuncspan.cpython-314-x86_64-linux-gnu.so +0 -0
- sf_veritas/_sffuncspan_config.c +730 -0
- sf_veritas/_sffuncspan_config.cpython-314-x86_64-linux-gnu.so +0 -0
- sf_veritas/_sfheadercheck.c +341 -0
- sf_veritas/_sfheadercheck.cpython-314-x86_64-linux-gnu.so +0 -0
- sf_veritas/_sfnetworkhop.c +1454 -0
- sf_veritas/_sfnetworkhop.cpython-314-x86_64-linux-gnu.so +0 -0
- sf_veritas/_sfservice.c +1223 -0
- sf_veritas/_sfservice.cpython-314-x86_64-linux-gnu.so +0 -0
- sf_veritas/_sfteepreload.c +6227 -0
- sf_veritas/app_config.py +57 -0
- sf_veritas/cli.py +336 -0
- sf_veritas/constants.py +10 -0
- sf_veritas/custom_excepthook.py +304 -0
- sf_veritas/custom_log_handler.py +146 -0
- sf_veritas/custom_output_wrapper.py +153 -0
- sf_veritas/custom_print.py +153 -0
- sf_veritas/django_app.py +5 -0
- sf_veritas/env_vars.py +186 -0
- sf_veritas/exception_handling_middleware.py +18 -0
- sf_veritas/exception_metaclass.py +69 -0
- sf_veritas/fast_frame_info.py +116 -0
- sf_veritas/fast_network_hop.py +293 -0
- sf_veritas/frame_tools.py +112 -0
- sf_veritas/funcspan_config_loader.py +693 -0
- sf_veritas/function_span_profiler.py +1313 -0
- sf_veritas/get_preload_path.py +34 -0
- sf_veritas/import_hook.py +62 -0
- sf_veritas/infra_details/__init__.py +3 -0
- sf_veritas/infra_details/get_infra_details.py +24 -0
- sf_veritas/infra_details/kubernetes/__init__.py +3 -0
- sf_veritas/infra_details/kubernetes/get_cluster_name.py +147 -0
- sf_veritas/infra_details/kubernetes/get_details.py +7 -0
- sf_veritas/infra_details/running_on/__init__.py +17 -0
- sf_veritas/infra_details/running_on/kubernetes.py +11 -0
- sf_veritas/interceptors.py +543 -0
- sf_veritas/libsfnettee.so +0 -0
- sf_veritas/local_env_detect.py +118 -0
- sf_veritas/package_metadata.py +6 -0
- sf_veritas/patches/__init__.py +0 -0
- sf_veritas/patches/_patch_tracker.py +74 -0
- sf_veritas/patches/concurrent_futures.py +19 -0
- sf_veritas/patches/constants.py +1 -0
- sf_veritas/patches/exceptions.py +82 -0
- sf_veritas/patches/multiprocessing.py +32 -0
- sf_veritas/patches/network_libraries/__init__.py +99 -0
- sf_veritas/patches/network_libraries/aiohttp.py +294 -0
- sf_veritas/patches/network_libraries/curl_cffi.py +363 -0
- sf_veritas/patches/network_libraries/http_client.py +670 -0
- sf_veritas/patches/network_libraries/httpcore.py +580 -0
- sf_veritas/patches/network_libraries/httplib2.py +315 -0
- sf_veritas/patches/network_libraries/httpx.py +557 -0
- sf_veritas/patches/network_libraries/niquests.py +218 -0
- sf_veritas/patches/network_libraries/pycurl.py +399 -0
- sf_veritas/patches/network_libraries/requests.py +595 -0
- sf_veritas/patches/network_libraries/ssl_socket.py +822 -0
- sf_veritas/patches/network_libraries/tornado.py +360 -0
- sf_veritas/patches/network_libraries/treq.py +270 -0
- sf_veritas/patches/network_libraries/urllib_request.py +483 -0
- sf_veritas/patches/network_libraries/utils.py +598 -0
- sf_veritas/patches/os.py +17 -0
- sf_veritas/patches/threading.py +231 -0
- sf_veritas/patches/web_frameworks/__init__.py +54 -0
- sf_veritas/patches/web_frameworks/aiohttp.py +798 -0
- sf_veritas/patches/web_frameworks/async_websocket_consumer.py +337 -0
- sf_veritas/patches/web_frameworks/blacksheep.py +532 -0
- sf_veritas/patches/web_frameworks/bottle.py +513 -0
- sf_veritas/patches/web_frameworks/cherrypy.py +683 -0
- sf_veritas/patches/web_frameworks/cors_utils.py +122 -0
- sf_veritas/patches/web_frameworks/django.py +963 -0
- sf_veritas/patches/web_frameworks/eve.py +401 -0
- sf_veritas/patches/web_frameworks/falcon.py +931 -0
- sf_veritas/patches/web_frameworks/fastapi.py +738 -0
- sf_veritas/patches/web_frameworks/flask.py +526 -0
- sf_veritas/patches/web_frameworks/klein.py +501 -0
- sf_veritas/patches/web_frameworks/litestar.py +616 -0
- sf_veritas/patches/web_frameworks/pyramid.py +440 -0
- sf_veritas/patches/web_frameworks/quart.py +841 -0
- sf_veritas/patches/web_frameworks/robyn.py +708 -0
- sf_veritas/patches/web_frameworks/sanic.py +874 -0
- sf_veritas/patches/web_frameworks/starlette.py +742 -0
- sf_veritas/patches/web_frameworks/strawberry.py +1446 -0
- sf_veritas/patches/web_frameworks/tornado.py +485 -0
- sf_veritas/patches/web_frameworks/utils.py +170 -0
- sf_veritas/print_override.py +13 -0
- sf_veritas/regular_data_transmitter.py +444 -0
- sf_veritas/request_interceptor.py +401 -0
- sf_veritas/request_utils.py +550 -0
- sf_veritas/segfault_handler.py +116 -0
- sf_veritas/server_status.py +1 -0
- sf_veritas/shutdown_flag.py +11 -0
- sf_veritas/subprocess_startup.py +3 -0
- sf_veritas/test_cli.py +145 -0
- sf_veritas/thread_local.py +1319 -0
- sf_veritas/timeutil.py +114 -0
- sf_veritas/transmit_exception_to_sailfish.py +28 -0
- sf_veritas/transmitter.py +132 -0
- sf_veritas/types.py +47 -0
- sf_veritas/unified_interceptor.py +1678 -0
- sf_veritas/utils.py +39 -0
- sf_veritas-0.11.10.dist-info/METADATA +97 -0
- sf_veritas-0.11.10.dist-info/RECORD +141 -0
- sf_veritas-0.11.10.dist-info/WHEEL +5 -0
- sf_veritas-0.11.10.dist-info/entry_points.txt +2 -0
- sf_veritas-0.11.10.dist-info/top_level.txt +1 -0
- sf_veritas.libs/libbrotlicommon-6ce2a53c.so.1.0.6 +0 -0
- sf_veritas.libs/libbrotlidec-811d1be3.so.1.0.6 +0 -0
- sf_veritas.libs/libcom_err-730ca923.so.2.1 +0 -0
- sf_veritas.libs/libcrypt-52aca757.so.1.1.0 +0 -0
- sf_veritas.libs/libcrypto-bdaed0ea.so.1.1.1k +0 -0
- sf_veritas.libs/libcurl-eaa3cf66.so.4.5.0 +0 -0
- sf_veritas.libs/libgssapi_krb5-323bbd21.so.2.2 +0 -0
- sf_veritas.libs/libidn2-2f4a5893.so.0.3.6 +0 -0
- sf_veritas.libs/libk5crypto-9a74ff38.so.3.1 +0 -0
- sf_veritas.libs/libkeyutils-2777d33d.so.1.6 +0 -0
- sf_veritas.libs/libkrb5-a55300e8.so.3.3 +0 -0
- sf_veritas.libs/libkrb5support-e6594cfc.so.0.1 +0 -0
- sf_veritas.libs/liblber-2-d20824ef.4.so.2.10.9 +0 -0
- sf_veritas.libs/libldap-2-cea2a960.4.so.2.10.9 +0 -0
- sf_veritas.libs/libnghttp2-39367a22.so.14.17.0 +0 -0
- sf_veritas.libs/libpcre2-8-516f4c9d.so.0.7.1 +0 -0
- sf_veritas.libs/libpsl-99becdd3.so.5.3.1 +0 -0
- sf_veritas.libs/libsasl2-7de4d792.so.3.0.0 +0 -0
- sf_veritas.libs/libselinux-d0805dcb.so.1 +0 -0
- sf_veritas.libs/libssh-c11d285b.so.4.8.7 +0 -0
- sf_veritas.libs/libssl-60250281.so.1.1.1k +0 -0
- sf_veritas.libs/libunistring-05abdd40.so.2.1.0 +0 -0
- sf_veritas.libs/libuuid-95b83d40.so.1.3.0 +0 -0
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Ultra-fast network hop sender using C extension with endpoint pre-registration.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from logging import getLogger
|
|
7
|
+
from typing import Optional, Tuple
|
|
8
|
+
|
|
9
|
+
from .regular_data_transmitter import NetworkHopsTransmitter
|
|
10
|
+
from .thread_local import is_network_recording_suppressed
|
|
11
|
+
|
|
12
|
+
logger = getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
# Optional native fast path for network hops (C extension)
|
|
15
|
+
# LAZY IMPORT: Don't import at module level to avoid circular import
|
|
16
|
+
# Import will happen in _ensure_fast_networkhop_initialized() when first needed
|
|
17
|
+
_sfnetworkhop = None
|
|
18
|
+
_NETWORKHOP_FAST_OK = None # None = not yet attempted, True = success, False = failed
|
|
19
|
+
|
|
20
|
+
_FAST_NETWORKHOP_READY = False # one-time guard for native networkhop init
|
|
21
|
+
|
|
22
|
+
# GraphQL mutation string for network hops (with optional body/header capture)
|
|
23
|
+
_COLLECT_NETWORKHOP_MUTATION = (
|
|
24
|
+
"mutation collectNetworkHops("
|
|
25
|
+
"$apiKey: String!,"
|
|
26
|
+
"$sessionId: String!,"
|
|
27
|
+
"$timestampMs: String!,"
|
|
28
|
+
"$line: String!,"
|
|
29
|
+
"$column: String!,"
|
|
30
|
+
"$name: String!,"
|
|
31
|
+
"$entrypoint: String!,"
|
|
32
|
+
"$route: String,"
|
|
33
|
+
"$queryParams: String,"
|
|
34
|
+
"$serviceUuid: String,"
|
|
35
|
+
"$requestHeaders: String,"
|
|
36
|
+
"$requestBody: String,"
|
|
37
|
+
"$responseHeaders: String,"
|
|
38
|
+
"$responseBody: String"
|
|
39
|
+
"){collectNetworkHops("
|
|
40
|
+
"apiKey:$apiKey,sessionId:$sessionId,timestampMs:$timestampMs,"
|
|
41
|
+
"line:$line,column:$column,name:$name,entrypoint:$entrypoint,"
|
|
42
|
+
"route:$route,queryParams:$queryParams,serviceUuid:$serviceUuid,requestHeaders:$requestHeaders,"
|
|
43
|
+
"requestBody:$requestBody,responseHeaders:$responseHeaders,"
|
|
44
|
+
"responseBody:$responseBody)}"
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _ensure_fast_networkhop_initialized() -> bool:
|
|
49
|
+
global _FAST_NETWORKHOP_READY, _sfnetworkhop, _NETWORKHOP_FAST_OK
|
|
50
|
+
|
|
51
|
+
SF_DEBUG = os.getenv("SF_DEBUG", "false").lower() == "true"
|
|
52
|
+
|
|
53
|
+
# PERFORMANCE: Skip network hop extension when testing network library only
|
|
54
|
+
if os.getenv("TESTING_NETWORK_LIBRARY_ONLY", "0") == "1":
|
|
55
|
+
if SF_DEBUG:
|
|
56
|
+
print(
|
|
57
|
+
"[[_ensure_fast_networkhop_initialized]] Network hop extension disabled (TESTING_NETWORK_LIBRARY_ONLY=1)",
|
|
58
|
+
log=False,
|
|
59
|
+
)
|
|
60
|
+
return False
|
|
61
|
+
|
|
62
|
+
# LAZY IMPORT: Try to import C extension on first use
|
|
63
|
+
if _NETWORKHOP_FAST_OK is None:
|
|
64
|
+
try:
|
|
65
|
+
from . import _sfnetworkhop as _sfnh_module
|
|
66
|
+
|
|
67
|
+
_sfnetworkhop = _sfnh_module
|
|
68
|
+
_NETWORKHOP_FAST_OK = True
|
|
69
|
+
if SF_DEBUG:
|
|
70
|
+
print(
|
|
71
|
+
f"[[_ensure_fast_networkhop_initialized]] Successfully imported _sfnetworkhop C extension",
|
|
72
|
+
log=False,
|
|
73
|
+
)
|
|
74
|
+
except Exception as e:
|
|
75
|
+
if SF_DEBUG:
|
|
76
|
+
print(
|
|
77
|
+
f"[[_ensure_fast_networkhop_initialized]] Failed to import _sfnetworkhop C extension: {e}",
|
|
78
|
+
log=False,
|
|
79
|
+
)
|
|
80
|
+
_sfnetworkhop = None
|
|
81
|
+
_NETWORKHOP_FAST_OK = False
|
|
82
|
+
|
|
83
|
+
if not _NETWORKHOP_FAST_OK:
|
|
84
|
+
if SF_DEBUG:
|
|
85
|
+
print(
|
|
86
|
+
f"[[_ensure_fast_networkhop_initialized]] C extension not available (_NETWORKHOP_FAST_OK=False)",
|
|
87
|
+
log=False,
|
|
88
|
+
)
|
|
89
|
+
return False
|
|
90
|
+
|
|
91
|
+
if _FAST_NETWORKHOP_READY:
|
|
92
|
+
if SF_DEBUG:
|
|
93
|
+
print(
|
|
94
|
+
f"[[_ensure_fast_networkhop_initialized]] Already initialized, returning True",
|
|
95
|
+
log=False,
|
|
96
|
+
)
|
|
97
|
+
return True
|
|
98
|
+
|
|
99
|
+
from . import app_config
|
|
100
|
+
|
|
101
|
+
endpoint = getattr(app_config, "_sailfish_graphql_endpoint", None)
|
|
102
|
+
api_key = getattr(app_config, "_sailfish_api_key", None)
|
|
103
|
+
service_uuid = getattr(app_config, "_service_uuid", None)
|
|
104
|
+
http2 = 1 if os.getenv("SF_NBPOST_HTTP2", "0") == "1" else 0
|
|
105
|
+
|
|
106
|
+
if SF_DEBUG:
|
|
107
|
+
print(
|
|
108
|
+
f"[[_ensure_fast_networkhop_initialized]] Config: endpoint={bool(endpoint)}, api_key={bool(api_key)}, service_uuid={bool(service_uuid)}",
|
|
109
|
+
log=False,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
if not (endpoint and api_key and service_uuid):
|
|
113
|
+
if SF_DEBUG:
|
|
114
|
+
print(
|
|
115
|
+
f"[[_ensure_fast_networkhop_initialized]] Missing required config, returning False",
|
|
116
|
+
log=False,
|
|
117
|
+
)
|
|
118
|
+
return False
|
|
119
|
+
|
|
120
|
+
try:
|
|
121
|
+
if SF_DEBUG:
|
|
122
|
+
print(
|
|
123
|
+
f"[[_ensure_fast_networkhop_initialized]] Calling _sfnetworkhop.init() with url={endpoint}",
|
|
124
|
+
log=False,
|
|
125
|
+
)
|
|
126
|
+
ok = _sfnetworkhop.init(
|
|
127
|
+
url=endpoint,
|
|
128
|
+
query=_COLLECT_NETWORKHOP_MUTATION,
|
|
129
|
+
api_key=str(api_key),
|
|
130
|
+
service_uuid=str(service_uuid),
|
|
131
|
+
http2=http2,
|
|
132
|
+
)
|
|
133
|
+
_FAST_NETWORKHOP_READY = bool(ok)
|
|
134
|
+
if SF_DEBUG:
|
|
135
|
+
print(
|
|
136
|
+
f"[[_ensure_fast_networkhop_initialized]] _sfnetworkhop.init() returned {ok}, _FAST_NETWORKHOP_READY={_FAST_NETWORKHOP_READY}",
|
|
137
|
+
log=False,
|
|
138
|
+
)
|
|
139
|
+
except Exception as e:
|
|
140
|
+
if SF_DEBUG:
|
|
141
|
+
print(
|
|
142
|
+
f"[[_ensure_fast_networkhop_initialized]] _sfnetworkhop.init() raised exception: {e}",
|
|
143
|
+
log=False,
|
|
144
|
+
)
|
|
145
|
+
_FAST_NETWORKHOP_READY = False
|
|
146
|
+
|
|
147
|
+
return _FAST_NETWORKHOP_READY
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def register_endpoint(
|
|
151
|
+
line: str, column: str, name: str, entrypoint: str, route: str = None
|
|
152
|
+
) -> int:
|
|
153
|
+
"""
|
|
154
|
+
Register a web framework endpoint's invariant fields once.
|
|
155
|
+
Returns an endpoint_id usable with fast_send_network_hop_fast(...).
|
|
156
|
+
|
|
157
|
+
Args:
|
|
158
|
+
line: Line number where the endpoint is defined
|
|
159
|
+
column: Column number (typically "0")
|
|
160
|
+
name: Function name of the endpoint
|
|
161
|
+
entrypoint: File path where the endpoint is defined
|
|
162
|
+
route: Route pattern (e.g., "/api/users/{id}") - optional
|
|
163
|
+
"""
|
|
164
|
+
SF_DEBUG = os.getenv("SF_DEBUG", "false").lower() == "true"
|
|
165
|
+
|
|
166
|
+
if SF_DEBUG:
|
|
167
|
+
print(
|
|
168
|
+
f"[[register_endpoint]] Called for {name} @ {entrypoint}:{line} (route={route})",
|
|
169
|
+
log=False,
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
if not _ensure_fast_networkhop_initialized():
|
|
173
|
+
if SF_DEBUG:
|
|
174
|
+
print(
|
|
175
|
+
f"[[register_endpoint]] _ensure_fast_networkhop_initialized() returned False, returning -1",
|
|
176
|
+
log=False,
|
|
177
|
+
)
|
|
178
|
+
return -1
|
|
179
|
+
try:
|
|
180
|
+
eid = _sfnetworkhop.register_endpoint(
|
|
181
|
+
line=line, column=column, name=name, entrypoint=entrypoint, route=route
|
|
182
|
+
)
|
|
183
|
+
if SF_DEBUG:
|
|
184
|
+
print(
|
|
185
|
+
f"[[register_endpoint]] _sfnetworkhop.register_endpoint() returned {eid}",
|
|
186
|
+
log=False,
|
|
187
|
+
)
|
|
188
|
+
return int(eid)
|
|
189
|
+
except Exception as e:
|
|
190
|
+
if SF_DEBUG:
|
|
191
|
+
print(
|
|
192
|
+
f"[[register_endpoint]] _sfnetworkhop.register_endpoint() raised exception: {e}",
|
|
193
|
+
log=False,
|
|
194
|
+
)
|
|
195
|
+
return -1
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def fast_send_network_hop_fast(
|
|
199
|
+
session_id: str,
|
|
200
|
+
endpoint_id: int,
|
|
201
|
+
raw_path: str = None,
|
|
202
|
+
raw_query_string: bytes = None,
|
|
203
|
+
request_headers: dict = None,
|
|
204
|
+
request_body: bytes = None,
|
|
205
|
+
response_headers: dict = None,
|
|
206
|
+
response_body: bytes = None,
|
|
207
|
+
) -> None:
|
|
208
|
+
"""
|
|
209
|
+
ULTRA-FAST PATH: Assumes initialization already happened (checked once at startup).
|
|
210
|
+
Optionally accepts request/response headers and body for capture.
|
|
211
|
+
|
|
212
|
+
Args:
|
|
213
|
+
session_id: Unique session identifier
|
|
214
|
+
endpoint_id: Pre-registered endpoint ID
|
|
215
|
+
raw_path: Optional actual request path (e.g., "/log") - passed to C for JSON escaping
|
|
216
|
+
raw_query_string: Optional raw query string bytes (e.g., b"foo=5") - passed to C for decoding/escaping
|
|
217
|
+
request_headers: Optional dict of request headers
|
|
218
|
+
request_body: Optional request body (bytes, str, or list of chunks)
|
|
219
|
+
response_headers: Optional dict of response headers
|
|
220
|
+
response_body: Optional response body (bytes, str, or list of chunks)
|
|
221
|
+
"""
|
|
222
|
+
# Check if network recording is suppressed (e.g., by @skip_network_tracing decorator)
|
|
223
|
+
if is_network_recording_suppressed():
|
|
224
|
+
return
|
|
225
|
+
|
|
226
|
+
# HOT PATH OPTIMIZATION: Skip initialization check after first successful init
|
|
227
|
+
if not _FAST_NETWORKHOP_READY:
|
|
228
|
+
if not _ensure_fast_networkhop_initialized():
|
|
229
|
+
return
|
|
230
|
+
|
|
231
|
+
# Direct C call - no exception handling (C code is bulletproof)
|
|
232
|
+
if endpoint_id >= 0:
|
|
233
|
+
# Check if we need the extended path (with route/query/body/header capture)
|
|
234
|
+
has_extended_data = (
|
|
235
|
+
raw_path is not None
|
|
236
|
+
or raw_query_string is not None
|
|
237
|
+
or request_headers is not None
|
|
238
|
+
or request_body is not None
|
|
239
|
+
or response_headers is not None
|
|
240
|
+
or response_body is not None
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
if has_extended_data:
|
|
244
|
+
# Use extended capture path - C handles all decoding/escaping
|
|
245
|
+
_sfnetworkhop.networkhop_with_bodies(
|
|
246
|
+
session_id=session_id,
|
|
247
|
+
endpoint_id=endpoint_id,
|
|
248
|
+
raw_path=raw_path,
|
|
249
|
+
raw_query_string=raw_query_string,
|
|
250
|
+
request_headers=request_headers,
|
|
251
|
+
request_body=request_body,
|
|
252
|
+
response_headers=response_headers,
|
|
253
|
+
response_body=response_body,
|
|
254
|
+
)
|
|
255
|
+
else:
|
|
256
|
+
# Ultra-fast path with NO extra data
|
|
257
|
+
_sfnetworkhop.networkhop_fast(
|
|
258
|
+
session_id=session_id, endpoint_id=endpoint_id
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def fast_send_network_hop(
|
|
263
|
+
session_id: str, line: str, column: str, name: str, entrypoint: str
|
|
264
|
+
):
|
|
265
|
+
"""
|
|
266
|
+
Backward-compatible API (not used by patched FastAPI; kept for other callers).
|
|
267
|
+
"""
|
|
268
|
+
# Check if network recording is suppressed (e.g., by @skip_network_tracing decorator)
|
|
269
|
+
if is_network_recording_suppressed():
|
|
270
|
+
return
|
|
271
|
+
|
|
272
|
+
if _ensure_fast_networkhop_initialized():
|
|
273
|
+
try:
|
|
274
|
+
# Old slow path in C; kept for compatibility
|
|
275
|
+
_sfnetworkhop.networkhop(
|
|
276
|
+
session_id=session_id,
|
|
277
|
+
line=line,
|
|
278
|
+
column=column,
|
|
279
|
+
name=name,
|
|
280
|
+
entrypoint=entrypoint,
|
|
281
|
+
)
|
|
282
|
+
return
|
|
283
|
+
except Exception:
|
|
284
|
+
pass
|
|
285
|
+
|
|
286
|
+
# Fallback to Python transmitter
|
|
287
|
+
NetworkHopsTransmitter().send(
|
|
288
|
+
session_id=session_id,
|
|
289
|
+
line=line,
|
|
290
|
+
column=column,
|
|
291
|
+
name=name,
|
|
292
|
+
entrypoint=entrypoint,
|
|
293
|
+
)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from typing import Any, Iterable, List
|
|
3
|
+
|
|
4
|
+
from .env_vars import (
|
|
5
|
+
SAILFISH_EXCEPTION_LOCALS_HIDE_DUNDER,
|
|
6
|
+
SAILFISH_EXCEPTION_LOCALS_HIDE_SELF,
|
|
7
|
+
SAILFISH_EXCEPTION_LOCALS_HIDE_SUNDER,
|
|
8
|
+
SAILFISH_EXCEPTION_LOCALS_TYPES_TO_IGNORE,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def import_type(module_name: str, type_name: str):
|
|
13
|
+
try:
|
|
14
|
+
exec( # pylint: disable=exec-used
|
|
15
|
+
f"from {module_name} import {type_name}",
|
|
16
|
+
globals(),
|
|
17
|
+
)
|
|
18
|
+
return globals().get(type_name, None)
|
|
19
|
+
except ImportError:
|
|
20
|
+
return None
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def get_types_from_str(types_str: str) -> List[type]:
|
|
24
|
+
types_list = []
|
|
25
|
+
if types_str:
|
|
26
|
+
for type_path in types_str.split(","):
|
|
27
|
+
type_path_fixed = type_path.replace(" ", "")
|
|
28
|
+
module_name, type_name = type_path_fixed.rsplit(".", 1)
|
|
29
|
+
type_obj = import_type(module_name, type_name)
|
|
30
|
+
if type_obj:
|
|
31
|
+
types_list.append(type_obj)
|
|
32
|
+
return types_list
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
EXCEPTION_LOCALS_TYPES_TO_IGNORE = get_types_from_str(
|
|
36
|
+
SAILFISH_EXCEPTION_LOCALS_TYPES_TO_IGNORE
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def get_current_frame():
|
|
41
|
+
return sys._getframe(1) # pylint: disable=protected-access
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def value_type_to_be_ignored(value: Any) -> bool:
|
|
45
|
+
return any(
|
|
46
|
+
isinstance(value, type_obj) for type_obj in EXCEPTION_LOCALS_TYPES_TO_IGNORE
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def key_is_str_to_be_ignored(
|
|
51
|
+
key: Any, locals_hide_self: bool, locals_hide_dunder: bool, locals_hide_sunder: bool
|
|
52
|
+
) -> bool:
|
|
53
|
+
return (
|
|
54
|
+
(locals_hide_self and key == "self")
|
|
55
|
+
or (locals_hide_dunder and key.startswith("__"))
|
|
56
|
+
or (locals_hide_sunder and key.startswith("_"))
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def filter_locals(
|
|
61
|
+
iter_locals: Iterable[tuple[str, object]],
|
|
62
|
+
locals_hide_self: bool,
|
|
63
|
+
locals_hide_dunder: bool,
|
|
64
|
+
locals_hide_sunder: bool,
|
|
65
|
+
) -> Iterable[tuple[str, object]]:
|
|
66
|
+
for key, value in iter_locals:
|
|
67
|
+
if not isinstance(key, str):
|
|
68
|
+
if value_type_to_be_ignored(value):
|
|
69
|
+
continue
|
|
70
|
+
else:
|
|
71
|
+
if key_is_str_to_be_ignored(
|
|
72
|
+
key, locals_hide_self, locals_hide_dunder, locals_hide_sunder
|
|
73
|
+
):
|
|
74
|
+
continue
|
|
75
|
+
if value_type_to_be_ignored(value):
|
|
76
|
+
continue
|
|
77
|
+
if key in ("args", "field_args") and isinstance(value, list):
|
|
78
|
+
value = list(
|
|
79
|
+
filter_locals(
|
|
80
|
+
enumerate(value),
|
|
81
|
+
locals_hide_self,
|
|
82
|
+
locals_hide_dunder,
|
|
83
|
+
locals_hide_sunder,
|
|
84
|
+
)
|
|
85
|
+
)
|
|
86
|
+
if key in ("kwargs", "field_kwargs") and isinstance(value, dict):
|
|
87
|
+
value = dict(
|
|
88
|
+
filter_locals(
|
|
89
|
+
value.items(),
|
|
90
|
+
locals_hide_self,
|
|
91
|
+
locals_hide_dunder,
|
|
92
|
+
locals_hide_sunder,
|
|
93
|
+
)
|
|
94
|
+
)
|
|
95
|
+
yield key, value
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def get_locals(
|
|
99
|
+
iter_locals: Iterable[tuple[str, object]],
|
|
100
|
+
locals_hide_self: bool = SAILFISH_EXCEPTION_LOCALS_HIDE_SELF,
|
|
101
|
+
locals_hide_dunder: bool = SAILFISH_EXCEPTION_LOCALS_HIDE_DUNDER,
|
|
102
|
+
locals_hide_sunder: bool = SAILFISH_EXCEPTION_LOCALS_HIDE_SUNDER,
|
|
103
|
+
) -> Iterable[tuple[str, object]]:
|
|
104
|
+
"""Extract locals from an iterator of key pairs."""
|
|
105
|
+
if not (locals_hide_dunder or locals_hide_sunder):
|
|
106
|
+
yield from iter_locals
|
|
107
|
+
return
|
|
108
|
+
iter_locals_filtered = filter_locals(
|
|
109
|
+
iter_locals, locals_hide_self, locals_hide_dunder, locals_hide_sunder
|
|
110
|
+
)
|
|
111
|
+
for key, value in iter_locals_filtered:
|
|
112
|
+
yield key, value
|