sf-veritas 0.10.3__cp311-cp311-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.
Potentially problematic release.
This version of sf-veritas might be problematic. Click here for more details.
- sf_veritas/__init__.py +20 -0
- sf_veritas/_sffastlog.c +889 -0
- sf_veritas/_sffastlog.cpython-311-x86_64-linux-gnu.so +0 -0
- sf_veritas/_sffastnet.c +924 -0
- sf_veritas/_sffastnet.cpython-311-x86_64-linux-gnu.so +0 -0
- sf_veritas/_sffastnetworkrequest.c +730 -0
- sf_veritas/_sffastnetworkrequest.cpython-311-x86_64-linux-gnu.so +0 -0
- sf_veritas/_sffuncspan.c +2155 -0
- sf_veritas/_sffuncspan.cpython-311-x86_64-linux-gnu.so +0 -0
- sf_veritas/_sffuncspan_config.c +617 -0
- sf_veritas/_sffuncspan_config.cpython-311-x86_64-linux-gnu.so +0 -0
- sf_veritas/_sfheadercheck.c +341 -0
- sf_veritas/_sfheadercheck.cpython-311-x86_64-linux-gnu.so +0 -0
- sf_veritas/_sfnetworkhop.c +1451 -0
- sf_veritas/_sfnetworkhop.cpython-311-x86_64-linux-gnu.so +0 -0
- sf_veritas/_sfservice.c +1175 -0
- sf_veritas/_sfservice.cpython-311-x86_64-linux-gnu.so +0 -0
- sf_veritas/_sfteepreload.c +5167 -0
- sf_veritas/app_config.py +49 -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 +129 -0
- sf_veritas/custom_output_wrapper.py +144 -0
- sf_veritas/custom_print.py +146 -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 +556 -0
- sf_veritas/function_span_profiler.py +1174 -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 +497 -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/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 +76 -0
- sf_veritas/patches/network_libraries/aiohttp.py +281 -0
- sf_veritas/patches/network_libraries/curl_cffi.py +363 -0
- sf_veritas/patches/network_libraries/http_client.py +419 -0
- sf_veritas/patches/network_libraries/httpcore.py +515 -0
- sf_veritas/patches/network_libraries/httplib2.py +204 -0
- sf_veritas/patches/network_libraries/httpx.py +515 -0
- sf_veritas/patches/network_libraries/niquests.py +211 -0
- sf_veritas/patches/network_libraries/pycurl.py +385 -0
- sf_veritas/patches/network_libraries/requests.py +633 -0
- sf_veritas/patches/network_libraries/tornado.py +341 -0
- sf_veritas/patches/network_libraries/treq.py +270 -0
- sf_veritas/patches/network_libraries/urllib_request.py +468 -0
- sf_veritas/patches/network_libraries/utils.py +398 -0
- sf_veritas/patches/os.py +17 -0
- sf_veritas/patches/threading.py +218 -0
- sf_veritas/patches/web_frameworks/__init__.py +54 -0
- sf_veritas/patches/web_frameworks/aiohttp.py +793 -0
- sf_veritas/patches/web_frameworks/async_websocket_consumer.py +317 -0
- sf_veritas/patches/web_frameworks/blacksheep.py +527 -0
- sf_veritas/patches/web_frameworks/bottle.py +502 -0
- sf_veritas/patches/web_frameworks/cherrypy.py +678 -0
- sf_veritas/patches/web_frameworks/cors_utils.py +122 -0
- sf_veritas/patches/web_frameworks/django.py +944 -0
- sf_veritas/patches/web_frameworks/eve.py +395 -0
- sf_veritas/patches/web_frameworks/falcon.py +926 -0
- sf_veritas/patches/web_frameworks/fastapi.py +724 -0
- sf_veritas/patches/web_frameworks/flask.py +520 -0
- sf_veritas/patches/web_frameworks/klein.py +501 -0
- sf_veritas/patches/web_frameworks/litestar.py +551 -0
- sf_veritas/patches/web_frameworks/pyramid.py +428 -0
- sf_veritas/patches/web_frameworks/quart.py +824 -0
- sf_veritas/patches/web_frameworks/robyn.py +697 -0
- sf_veritas/patches/web_frameworks/sanic.py +857 -0
- sf_veritas/patches/web_frameworks/starlette.py +723 -0
- sf_veritas/patches/web_frameworks/strawberry.py +813 -0
- sf_veritas/patches/web_frameworks/tornado.py +481 -0
- sf_veritas/patches/web_frameworks/utils.py +91 -0
- sf_veritas/print_override.py +13 -0
- sf_veritas/regular_data_transmitter.py +409 -0
- sf_veritas/request_interceptor.py +401 -0
- sf_veritas/request_utils.py +550 -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 +970 -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 +1580 -0
- sf_veritas/utils.py +39 -0
- sf_veritas-0.10.3.dist-info/METADATA +97 -0
- sf_veritas-0.10.3.dist-info/RECORD +132 -0
- sf_veritas-0.10.3.dist-info/WHEEL +5 -0
- sf_veritas-0.10.3.dist-info/entry_points.txt +2 -0
- sf_veritas-0.10.3.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,401 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
import logging
|
|
3
|
+
import os
|
|
4
|
+
import re
|
|
5
|
+
import time
|
|
6
|
+
from typing import Any, Dict, List, Optional
|
|
7
|
+
from uuid import uuid4
|
|
8
|
+
|
|
9
|
+
import requests
|
|
10
|
+
import tldextract
|
|
11
|
+
from requests.adapters import HTTPAdapter
|
|
12
|
+
from requests.sessions import Session
|
|
13
|
+
|
|
14
|
+
from . import app_config
|
|
15
|
+
from .constants import SAILFISH_TRACING_HEADER
|
|
16
|
+
from .env_vars import PRINT_CONFIGURATION_STATUSES, SF_DEBUG
|
|
17
|
+
from .package_metadata import PACKAGE_NAME
|
|
18
|
+
from .regular_data_transmitter import (
|
|
19
|
+
DomainsToNotPassHeaderToTransmitter,
|
|
20
|
+
NetworkHopsTransmitter,
|
|
21
|
+
NetworkRequestTransmitter,
|
|
22
|
+
)
|
|
23
|
+
from .thread_local import (
|
|
24
|
+
activate_reentrancy_guards_exception,
|
|
25
|
+
activate_reentrancy_guards_logging,
|
|
26
|
+
activate_reentrancy_guards_print,
|
|
27
|
+
get_or_set_sf_trace_id,
|
|
28
|
+
is_network_recording_suppressed,
|
|
29
|
+
)
|
|
30
|
+
from .utils import strtobool
|
|
31
|
+
|
|
32
|
+
DOMAINS_TO_NOT_PROPAGATE_HEADER_TO_DEFAULT = [
|
|
33
|
+
"identitytoolkit.googleapis.com",
|
|
34
|
+
]
|
|
35
|
+
DOMAINS_TO_NOT_PROPAGATE_HEADER_TO_ENVIRONMENT = [
|
|
36
|
+
domain
|
|
37
|
+
for domain in os.getenv("DOMAINS_TO_NOT_PROPAGATE_HEADER_TO_ENVIRONMENT", "").split(
|
|
38
|
+
","
|
|
39
|
+
)
|
|
40
|
+
if domain
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
NON_CUSTOMER_CODE_PATHS = (
|
|
44
|
+
"site-packages",
|
|
45
|
+
"dist-packages",
|
|
46
|
+
"venv",
|
|
47
|
+
"/lib/python",
|
|
48
|
+
"\\lib\\python",
|
|
49
|
+
PACKAGE_NAME,
|
|
50
|
+
)
|
|
51
|
+
_TRIPARTITE_TRACE_ID_REGEX = re.compile(r"^([^/]+/[^/]+)/[^/]+$")
|
|
52
|
+
|
|
53
|
+
# This filename is used as a heuristic to locate the user's entry point in the stack trace.
|
|
54
|
+
# It's commonly the main application file in smaller or single-file projects.
|
|
55
|
+
DEFAULT_CUSTOMER_ENTRY_FILENAME = "app.py"
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
logger = logging.getLogger(__name__)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class RequestInterceptor(HTTPAdapter):
|
|
62
|
+
def __init__(self, domains_to_not_propagate_headers_to: List[str]):
|
|
63
|
+
super().__init__()
|
|
64
|
+
self.header_name_tracing = SAILFISH_TRACING_HEADER
|
|
65
|
+
self.header_name_reentryancy_guard_logging_preactive = (
|
|
66
|
+
"reentrancy_guard_logging_preactive"
|
|
67
|
+
)
|
|
68
|
+
self.header_name_reentryancy_guard_print_preactive = (
|
|
69
|
+
"reentrancy_guard_print_preactive"
|
|
70
|
+
)
|
|
71
|
+
self.header_name_reentryancy_guard_exception_preactive = (
|
|
72
|
+
"reentrancy_guard_exception_preactive"
|
|
73
|
+
)
|
|
74
|
+
self.domains_to_not_propagate_headers_to = domains_to_not_propagate_headers_to
|
|
75
|
+
self.network_hop_transmitter = NetworkHopsTransmitter()
|
|
76
|
+
|
|
77
|
+
def check_and_activate_reentrancy_guards(self, headers: Dict[str, Any]) -> None:
|
|
78
|
+
reentryancy_guard_logging_preactive = strtobool(
|
|
79
|
+
headers.get(self.header_name_reentryancy_guard_logging_preactive, "false")
|
|
80
|
+
)
|
|
81
|
+
if reentryancy_guard_logging_preactive:
|
|
82
|
+
activate_reentrancy_guards_logging()
|
|
83
|
+
reentryancy_guard_print_preactive = strtobool(
|
|
84
|
+
headers.get(self.header_name_reentryancy_guard_print_preactive, "false")
|
|
85
|
+
)
|
|
86
|
+
if reentryancy_guard_print_preactive:
|
|
87
|
+
activate_reentrancy_guards_print()
|
|
88
|
+
reentryancy_guard_exception_preactive = strtobool(
|
|
89
|
+
headers.get(self.header_name_reentryancy_guard_exception_preactive, "false")
|
|
90
|
+
)
|
|
91
|
+
if reentryancy_guard_exception_preactive:
|
|
92
|
+
activate_reentrancy_guards_exception()
|
|
93
|
+
|
|
94
|
+
def capture_request_details(self):
|
|
95
|
+
"""
|
|
96
|
+
Identifies the first user-defined frame by walking the call stack manually
|
|
97
|
+
and skipping frames that belong to known non-customer paths.
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
frame_data (dict): Dictionary with line, column, and function name.
|
|
101
|
+
filename (str): The path to the file that initiated the call.
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
frame = inspect.currentframe()
|
|
105
|
+
if frame is None:
|
|
106
|
+
if SF_DEBUG:
|
|
107
|
+
print("capture_request_details: no current frame", log=False)
|
|
108
|
+
return None, None
|
|
109
|
+
|
|
110
|
+
frame = frame.f_back # Skip this function's own frame
|
|
111
|
+
|
|
112
|
+
while frame:
|
|
113
|
+
filename = frame.f_code.co_filename
|
|
114
|
+
|
|
115
|
+
# Inline check to skip known non-customer paths
|
|
116
|
+
skip = False
|
|
117
|
+
for keyword in NON_CUSTOMER_CODE_PATHS:
|
|
118
|
+
if keyword in filename:
|
|
119
|
+
skip = True
|
|
120
|
+
break
|
|
121
|
+
|
|
122
|
+
if not skip:
|
|
123
|
+
lineno = frame.f_lineno
|
|
124
|
+
func_name = frame.f_code.co_name
|
|
125
|
+
if SF_DEBUG:
|
|
126
|
+
print(
|
|
127
|
+
f"Network request initiated at {filename}:{lineno} in {func_name}()",
|
|
128
|
+
log=False,
|
|
129
|
+
)
|
|
130
|
+
return {
|
|
131
|
+
"line": str(lineno),
|
|
132
|
+
"column": "0",
|
|
133
|
+
"name": func_name,
|
|
134
|
+
}, filename
|
|
135
|
+
|
|
136
|
+
frame = frame.f_back
|
|
137
|
+
|
|
138
|
+
if SF_DEBUG:
|
|
139
|
+
print(
|
|
140
|
+
"capture_request_details: no user code found in call stack", log=False
|
|
141
|
+
)
|
|
142
|
+
return None, None
|
|
143
|
+
|
|
144
|
+
def send_network_hops(self):
|
|
145
|
+
frame_data, entrypoint = self.capture_request_details()
|
|
146
|
+
if frame_data and entrypoint:
|
|
147
|
+
_, session_id = get_or_set_sf_trace_id(
|
|
148
|
+
is_associated_with_inbound_request=True
|
|
149
|
+
)
|
|
150
|
+
self.network_hop_transmitter.do_send(
|
|
151
|
+
(
|
|
152
|
+
session_id,
|
|
153
|
+
frame_data["line"],
|
|
154
|
+
frame_data["column"],
|
|
155
|
+
frame_data["name"],
|
|
156
|
+
entrypoint,
|
|
157
|
+
)
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
def activate_preactive_headers(self, headers: Dict[str, Any]) -> None:
|
|
161
|
+
headers[self.header_name_reentryancy_guard_logging_preactive] = "true"
|
|
162
|
+
headers[self.header_name_reentryancy_guard_print_preactive] = "true"
|
|
163
|
+
headers[self.header_name_reentryancy_guard_exception_preactive] = "true"
|
|
164
|
+
|
|
165
|
+
def add_headers(self, request, **kwargs):
|
|
166
|
+
if SF_DEBUG:
|
|
167
|
+
print("RequestInterceptor: add_headers", log=False)
|
|
168
|
+
|
|
169
|
+
self.send_network_hops()
|
|
170
|
+
self.check_and_activate_reentrancy_guards(request.headers)
|
|
171
|
+
|
|
172
|
+
_, sf_trace_id = get_or_set_sf_trace_id()
|
|
173
|
+
request_domain = self.extract_domain(request.url)
|
|
174
|
+
if request_domain not in self.domains_to_not_propagate_headers_to:
|
|
175
|
+
request.headers[self.header_name_tracing] = sf_trace_id
|
|
176
|
+
|
|
177
|
+
if SF_DEBUG:
|
|
178
|
+
print(f"RequestInterceptor: Header value: {sf_trace_id}", log=False)
|
|
179
|
+
|
|
180
|
+
self.activate_preactive_headers(request.headers)
|
|
181
|
+
super().add_headers(request, **kwargs)
|
|
182
|
+
|
|
183
|
+
def process_request_and_get_sf_trace_id_from_header(self, headers: dict):
|
|
184
|
+
if SF_DEBUG:
|
|
185
|
+
print(
|
|
186
|
+
"[[process_request_and_get_sf_trace_id_from_header]] headers=",
|
|
187
|
+
headers,
|
|
188
|
+
log=False,
|
|
189
|
+
)
|
|
190
|
+
self.send_network_hops()
|
|
191
|
+
self.check_and_activate_reentrancy_guards(headers)
|
|
192
|
+
|
|
193
|
+
trace_id = headers.get(self.header_name_tracing)
|
|
194
|
+
if SF_DEBUG:
|
|
195
|
+
print(
|
|
196
|
+
f"[[process_request_and_get_sf_trace_id_from_header]]; trace_id={trace_id}",
|
|
197
|
+
log=False,
|
|
198
|
+
)
|
|
199
|
+
_, trace_id = get_or_set_sf_trace_id(trace_id)
|
|
200
|
+
return trace_id
|
|
201
|
+
|
|
202
|
+
def propagate_header(self, headers: dict, header_value: str):
|
|
203
|
+
if SF_DEBUG:
|
|
204
|
+
print("RequestInterceptor: propagate_header", log=False)
|
|
205
|
+
|
|
206
|
+
if header_value:
|
|
207
|
+
match = _TRIPARTITE_TRACE_ID_REGEX.match(header_value)
|
|
208
|
+
if match:
|
|
209
|
+
header_value = f"{match.group(1)}/{uuid4()}"
|
|
210
|
+
|
|
211
|
+
headers[self.header_name_tracing] = header_value
|
|
212
|
+
self.activate_preactive_headers(headers)
|
|
213
|
+
|
|
214
|
+
if SF_DEBUG:
|
|
215
|
+
print("RequestInterceptor: headers", headers, log=False)
|
|
216
|
+
|
|
217
|
+
return header_value
|
|
218
|
+
|
|
219
|
+
@staticmethod
|
|
220
|
+
def extract_domain(url: str) -> str:
|
|
221
|
+
extracted = tldextract.extract(url)
|
|
222
|
+
if extracted.subdomain:
|
|
223
|
+
return remove_prefix(
|
|
224
|
+
f"{extracted.subdomain}.{extracted.domain}.{extracted.suffix}", "www."
|
|
225
|
+
)
|
|
226
|
+
return remove_prefix(f"{extracted.domain}.{extracted.suffix}", "www.")
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def remove_prefix(text, prefix):
|
|
230
|
+
if text.startswith(prefix):
|
|
231
|
+
return text[len(prefix) :]
|
|
232
|
+
return text
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
# Track if domains mutation has been sent (to avoid duplicate sends)
|
|
236
|
+
_domains_mutation_sent = False
|
|
237
|
+
|
|
238
|
+
def get_domains_to_not_propagate_headers_to(
|
|
239
|
+
domains_to_not_propagate_headers_to: Optional[List[str]] = None,
|
|
240
|
+
) -> List[str]:
|
|
241
|
+
global _domains_mutation_sent
|
|
242
|
+
|
|
243
|
+
if domains_to_not_propagate_headers_to is None:
|
|
244
|
+
domains_to_not_propagate_headers_to = []
|
|
245
|
+
domains_to_not_propagate_headers_to_nondefault_unfiltered = (
|
|
246
|
+
DOMAINS_TO_NOT_PROPAGATE_HEADER_TO_ENVIRONMENT
|
|
247
|
+
+ domains_to_not_propagate_headers_to
|
|
248
|
+
)
|
|
249
|
+
domains_to_not_propagate_headers_to_nondefault = [
|
|
250
|
+
domain
|
|
251
|
+
for domain in domains_to_not_propagate_headers_to_nondefault_unfiltered
|
|
252
|
+
if domain
|
|
253
|
+
]
|
|
254
|
+
|
|
255
|
+
# Only send domains mutation once (not for every patched library)
|
|
256
|
+
if domains_to_not_propagate_headers_to_nondefault and not _domains_mutation_sent:
|
|
257
|
+
_domains_mutation_sent = True
|
|
258
|
+
domains_to_not_pass_header_to_transmitter = (
|
|
259
|
+
DomainsToNotPassHeaderToTransmitter()
|
|
260
|
+
)
|
|
261
|
+
domains_to_not_pass_header_to_transmitter.do_send(
|
|
262
|
+
(domains_to_not_propagate_headers_to_nondefault,)
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
domains_to_not_propagate_headers_to_all = (
|
|
266
|
+
domains_to_not_propagate_headers_to_nondefault
|
|
267
|
+
+ domains_to_not_propagate_headers_to
|
|
268
|
+
)
|
|
269
|
+
return [
|
|
270
|
+
remove_prefix(domain, "www.")
|
|
271
|
+
for domain in domains_to_not_propagate_headers_to_all
|
|
272
|
+
]
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def patch_requests(domains_to_not_propagate_headers_to: Optional[List[str]] = None):
|
|
276
|
+
domains_to_not_propagate_headers_to_final = get_domains_to_not_propagate_headers_to(
|
|
277
|
+
domains_to_not_propagate_headers_to
|
|
278
|
+
)
|
|
279
|
+
if PRINT_CONFIGURATION_STATUSES:
|
|
280
|
+
print("patching requests", log=False)
|
|
281
|
+
original_request = Session.request
|
|
282
|
+
|
|
283
|
+
def custom_request(self, method, url, **kwargs):
|
|
284
|
+
if SF_DEBUG:
|
|
285
|
+
print("[[custom_request]]", log=False)
|
|
286
|
+
start_time = time.time() * 1000 # Start timing
|
|
287
|
+
|
|
288
|
+
headers = (
|
|
289
|
+
kwargs.pop("headers", {}) or {}
|
|
290
|
+
) # Ensure headers dict is always initialized
|
|
291
|
+
trace_id_set, trace_id_alternative = get_or_set_sf_trace_id()
|
|
292
|
+
if SF_DEBUG:
|
|
293
|
+
print(
|
|
294
|
+
f"[[custom_request]] trace_id_set={str(trace_id_set)}, trace_id_alternative={str(trace_id_alternative)}",
|
|
295
|
+
log=False,
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
interceptor = RequestInterceptor(domains_to_not_propagate_headers_to_final)
|
|
299
|
+
trace_id = interceptor.process_request_and_get_sf_trace_id_from_header(headers)
|
|
300
|
+
if SF_DEBUG:
|
|
301
|
+
print(
|
|
302
|
+
f"[[custom_request] trace_id={trace_id}, OR trace_id_alternative={trace_id_alternative}",
|
|
303
|
+
log=False,
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
updated_trace_id = interceptor.propagate_header(headers, trace_id)
|
|
307
|
+
kwargs["headers"] = headers
|
|
308
|
+
|
|
309
|
+
# 1) actually perform the request
|
|
310
|
+
timestamp_start = int(time.time() * 1000)
|
|
311
|
+
response = original_request(self, method, url, **kwargs)
|
|
312
|
+
timestamp_end = int(time.time() * 1000)
|
|
313
|
+
|
|
314
|
+
# 2) decide whether to fire off a NetworkRequest mutation
|
|
315
|
+
# domain = interceptor.extract_domain(url)
|
|
316
|
+
if (
|
|
317
|
+
not is_network_recording_suppressed()
|
|
318
|
+
# and domain not in domains_to_not_propagate_headers_to_final
|
|
319
|
+
):
|
|
320
|
+
# split the tripartite trace‐header into [session, page_visit, request]
|
|
321
|
+
parts = updated_trace_id.split("/")
|
|
322
|
+
recording_session_id = parts[0]
|
|
323
|
+
page_visit_id = parts[1] if len(parts) > 1 else None
|
|
324
|
+
request_id = parts[2] if len(parts) > 2 else None
|
|
325
|
+
|
|
326
|
+
# 3) fire your transmitter
|
|
327
|
+
tx = NetworkRequestTransmitter()
|
|
328
|
+
tx.do_send(
|
|
329
|
+
(
|
|
330
|
+
request_id,
|
|
331
|
+
page_visit_id,
|
|
332
|
+
recording_session_id,
|
|
333
|
+
app_config._service_uuid, # matches your `service_uuid` field
|
|
334
|
+
timestamp_start,
|
|
335
|
+
timestamp_end,
|
|
336
|
+
response.status_code,
|
|
337
|
+
response.ok,
|
|
338
|
+
None if response.ok else response.text[:255],
|
|
339
|
+
url,
|
|
340
|
+
method.upper()
|
|
341
|
+
)
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
return response
|
|
345
|
+
|
|
346
|
+
# Patch requests library
|
|
347
|
+
Session.request = custom_request
|
|
348
|
+
requests.Session.request = custom_request
|
|
349
|
+
|
|
350
|
+
if PRINT_CONFIGURATION_STATUSES:
|
|
351
|
+
print("patching requests...DONE", log=False)
|
|
352
|
+
|
|
353
|
+
# Patch urllib3 (used internally by requests)
|
|
354
|
+
try:
|
|
355
|
+
import urllib3
|
|
356
|
+
|
|
357
|
+
original_urlopen = urllib3.connectionpool.HTTPConnectionPool.urlopen
|
|
358
|
+
|
|
359
|
+
def patched_urlopen(self, method, url, body=None, headers=None, **kwargs):
|
|
360
|
+
headers = headers or {}
|
|
361
|
+
interceptor = RequestInterceptor(domains_to_not_propagate_headers_to_final)
|
|
362
|
+
trace_id = interceptor.process_request_and_get_sf_trace_id_from_header(
|
|
363
|
+
headers
|
|
364
|
+
)
|
|
365
|
+
interceptor.propagate_header(headers, trace_id)
|
|
366
|
+
return original_urlopen(
|
|
367
|
+
self, method, url, body=body, headers=headers, **kwargs
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
urllib3.connectionpool.HTTPConnectionPool.urlopen = patched_urlopen
|
|
371
|
+
if PRINT_CONFIGURATION_STATUSES:
|
|
372
|
+
print("patching urllib3...DONE", log=False)
|
|
373
|
+
except ImportError:
|
|
374
|
+
if PRINT_CONFIGURATION_STATUSES:
|
|
375
|
+
print("urllib3 not found, skipping patch", log=False)
|
|
376
|
+
|
|
377
|
+
# Patch http.client (used by many standard library HTTP calls)
|
|
378
|
+
try:
|
|
379
|
+
import http.client
|
|
380
|
+
|
|
381
|
+
original_http_client_request = http.client.HTTPConnection.request
|
|
382
|
+
|
|
383
|
+
def patched_http_client_request(
|
|
384
|
+
self, method, url, body=None, headers=None, **kwargs
|
|
385
|
+
):
|
|
386
|
+
headers = headers or {}
|
|
387
|
+
interceptor = RequestInterceptor(domains_to_not_propagate_headers_to_final)
|
|
388
|
+
trace_id = interceptor.process_request_and_get_sf_trace_id_from_header(
|
|
389
|
+
headers
|
|
390
|
+
)
|
|
391
|
+
interceptor.propagate_header(headers, trace_id)
|
|
392
|
+
return original_http_client_request(
|
|
393
|
+
self, method, url, body=body, headers=headers, **kwargs
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
http.client.HTTPConnection.request = patched_http_client_request
|
|
397
|
+
if PRINT_CONFIGURATION_STATUSES:
|
|
398
|
+
print("patching http.client...DONE", log=False)
|
|
399
|
+
except ImportError:
|
|
400
|
+
if PRINT_CONFIGURATION_STATUSES:
|
|
401
|
+
print("http.client not found, skipping patch", log=False)
|