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.

Files changed (132) hide show
  1. sf_veritas/__init__.py +20 -0
  2. sf_veritas/_sffastlog.c +889 -0
  3. sf_veritas/_sffastlog.cpython-311-x86_64-linux-gnu.so +0 -0
  4. sf_veritas/_sffastnet.c +924 -0
  5. sf_veritas/_sffastnet.cpython-311-x86_64-linux-gnu.so +0 -0
  6. sf_veritas/_sffastnetworkrequest.c +730 -0
  7. sf_veritas/_sffastnetworkrequest.cpython-311-x86_64-linux-gnu.so +0 -0
  8. sf_veritas/_sffuncspan.c +2155 -0
  9. sf_veritas/_sffuncspan.cpython-311-x86_64-linux-gnu.so +0 -0
  10. sf_veritas/_sffuncspan_config.c +617 -0
  11. sf_veritas/_sffuncspan_config.cpython-311-x86_64-linux-gnu.so +0 -0
  12. sf_veritas/_sfheadercheck.c +341 -0
  13. sf_veritas/_sfheadercheck.cpython-311-x86_64-linux-gnu.so +0 -0
  14. sf_veritas/_sfnetworkhop.c +1451 -0
  15. sf_veritas/_sfnetworkhop.cpython-311-x86_64-linux-gnu.so +0 -0
  16. sf_veritas/_sfservice.c +1175 -0
  17. sf_veritas/_sfservice.cpython-311-x86_64-linux-gnu.so +0 -0
  18. sf_veritas/_sfteepreload.c +5167 -0
  19. sf_veritas/app_config.py +49 -0
  20. sf_veritas/cli.py +336 -0
  21. sf_veritas/constants.py +10 -0
  22. sf_veritas/custom_excepthook.py +304 -0
  23. sf_veritas/custom_log_handler.py +129 -0
  24. sf_veritas/custom_output_wrapper.py +144 -0
  25. sf_veritas/custom_print.py +146 -0
  26. sf_veritas/django_app.py +5 -0
  27. sf_veritas/env_vars.py +186 -0
  28. sf_veritas/exception_handling_middleware.py +18 -0
  29. sf_veritas/exception_metaclass.py +69 -0
  30. sf_veritas/fast_frame_info.py +116 -0
  31. sf_veritas/fast_network_hop.py +293 -0
  32. sf_veritas/frame_tools.py +112 -0
  33. sf_veritas/funcspan_config_loader.py +556 -0
  34. sf_veritas/function_span_profiler.py +1174 -0
  35. sf_veritas/import_hook.py +62 -0
  36. sf_veritas/infra_details/__init__.py +3 -0
  37. sf_veritas/infra_details/get_infra_details.py +24 -0
  38. sf_veritas/infra_details/kubernetes/__init__.py +3 -0
  39. sf_veritas/infra_details/kubernetes/get_cluster_name.py +147 -0
  40. sf_veritas/infra_details/kubernetes/get_details.py +7 -0
  41. sf_veritas/infra_details/running_on/__init__.py +17 -0
  42. sf_veritas/infra_details/running_on/kubernetes.py +11 -0
  43. sf_veritas/interceptors.py +497 -0
  44. sf_veritas/libsfnettee.so +0 -0
  45. sf_veritas/local_env_detect.py +118 -0
  46. sf_veritas/package_metadata.py +6 -0
  47. sf_veritas/patches/__init__.py +0 -0
  48. sf_veritas/patches/concurrent_futures.py +19 -0
  49. sf_veritas/patches/constants.py +1 -0
  50. sf_veritas/patches/exceptions.py +82 -0
  51. sf_veritas/patches/multiprocessing.py +32 -0
  52. sf_veritas/patches/network_libraries/__init__.py +76 -0
  53. sf_veritas/patches/network_libraries/aiohttp.py +281 -0
  54. sf_veritas/patches/network_libraries/curl_cffi.py +363 -0
  55. sf_veritas/patches/network_libraries/http_client.py +419 -0
  56. sf_veritas/patches/network_libraries/httpcore.py +515 -0
  57. sf_veritas/patches/network_libraries/httplib2.py +204 -0
  58. sf_veritas/patches/network_libraries/httpx.py +515 -0
  59. sf_veritas/patches/network_libraries/niquests.py +211 -0
  60. sf_veritas/patches/network_libraries/pycurl.py +385 -0
  61. sf_veritas/patches/network_libraries/requests.py +633 -0
  62. sf_veritas/patches/network_libraries/tornado.py +341 -0
  63. sf_veritas/patches/network_libraries/treq.py +270 -0
  64. sf_veritas/patches/network_libraries/urllib_request.py +468 -0
  65. sf_veritas/patches/network_libraries/utils.py +398 -0
  66. sf_veritas/patches/os.py +17 -0
  67. sf_veritas/patches/threading.py +218 -0
  68. sf_veritas/patches/web_frameworks/__init__.py +54 -0
  69. sf_veritas/patches/web_frameworks/aiohttp.py +793 -0
  70. sf_veritas/patches/web_frameworks/async_websocket_consumer.py +317 -0
  71. sf_veritas/patches/web_frameworks/blacksheep.py +527 -0
  72. sf_veritas/patches/web_frameworks/bottle.py +502 -0
  73. sf_veritas/patches/web_frameworks/cherrypy.py +678 -0
  74. sf_veritas/patches/web_frameworks/cors_utils.py +122 -0
  75. sf_veritas/patches/web_frameworks/django.py +944 -0
  76. sf_veritas/patches/web_frameworks/eve.py +395 -0
  77. sf_veritas/patches/web_frameworks/falcon.py +926 -0
  78. sf_veritas/patches/web_frameworks/fastapi.py +724 -0
  79. sf_veritas/patches/web_frameworks/flask.py +520 -0
  80. sf_veritas/patches/web_frameworks/klein.py +501 -0
  81. sf_veritas/patches/web_frameworks/litestar.py +551 -0
  82. sf_veritas/patches/web_frameworks/pyramid.py +428 -0
  83. sf_veritas/patches/web_frameworks/quart.py +824 -0
  84. sf_veritas/patches/web_frameworks/robyn.py +697 -0
  85. sf_veritas/patches/web_frameworks/sanic.py +857 -0
  86. sf_veritas/patches/web_frameworks/starlette.py +723 -0
  87. sf_veritas/patches/web_frameworks/strawberry.py +813 -0
  88. sf_veritas/patches/web_frameworks/tornado.py +481 -0
  89. sf_veritas/patches/web_frameworks/utils.py +91 -0
  90. sf_veritas/print_override.py +13 -0
  91. sf_veritas/regular_data_transmitter.py +409 -0
  92. sf_veritas/request_interceptor.py +401 -0
  93. sf_veritas/request_utils.py +550 -0
  94. sf_veritas/server_status.py +1 -0
  95. sf_veritas/shutdown_flag.py +11 -0
  96. sf_veritas/subprocess_startup.py +3 -0
  97. sf_veritas/test_cli.py +145 -0
  98. sf_veritas/thread_local.py +970 -0
  99. sf_veritas/timeutil.py +114 -0
  100. sf_veritas/transmit_exception_to_sailfish.py +28 -0
  101. sf_veritas/transmitter.py +132 -0
  102. sf_veritas/types.py +47 -0
  103. sf_veritas/unified_interceptor.py +1580 -0
  104. sf_veritas/utils.py +39 -0
  105. sf_veritas-0.10.3.dist-info/METADATA +97 -0
  106. sf_veritas-0.10.3.dist-info/RECORD +132 -0
  107. sf_veritas-0.10.3.dist-info/WHEEL +5 -0
  108. sf_veritas-0.10.3.dist-info/entry_points.txt +2 -0
  109. sf_veritas-0.10.3.dist-info/top_level.txt +1 -0
  110. sf_veritas.libs/libbrotlicommon-6ce2a53c.so.1.0.6 +0 -0
  111. sf_veritas.libs/libbrotlidec-811d1be3.so.1.0.6 +0 -0
  112. sf_veritas.libs/libcom_err-730ca923.so.2.1 +0 -0
  113. sf_veritas.libs/libcrypt-52aca757.so.1.1.0 +0 -0
  114. sf_veritas.libs/libcrypto-bdaed0ea.so.1.1.1k +0 -0
  115. sf_veritas.libs/libcurl-eaa3cf66.so.4.5.0 +0 -0
  116. sf_veritas.libs/libgssapi_krb5-323bbd21.so.2.2 +0 -0
  117. sf_veritas.libs/libidn2-2f4a5893.so.0.3.6 +0 -0
  118. sf_veritas.libs/libk5crypto-9a74ff38.so.3.1 +0 -0
  119. sf_veritas.libs/libkeyutils-2777d33d.so.1.6 +0 -0
  120. sf_veritas.libs/libkrb5-a55300e8.so.3.3 +0 -0
  121. sf_veritas.libs/libkrb5support-e6594cfc.so.0.1 +0 -0
  122. sf_veritas.libs/liblber-2-d20824ef.4.so.2.10.9 +0 -0
  123. sf_veritas.libs/libldap-2-cea2a960.4.so.2.10.9 +0 -0
  124. sf_veritas.libs/libnghttp2-39367a22.so.14.17.0 +0 -0
  125. sf_veritas.libs/libpcre2-8-516f4c9d.so.0.7.1 +0 -0
  126. sf_veritas.libs/libpsl-99becdd3.so.5.3.1 +0 -0
  127. sf_veritas.libs/libsasl2-7de4d792.so.3.0.0 +0 -0
  128. sf_veritas.libs/libselinux-d0805dcb.so.1 +0 -0
  129. sf_veritas.libs/libssh-c11d285b.so.4.8.7 +0 -0
  130. sf_veritas.libs/libssl-60250281.so.1.1.1k +0 -0
  131. sf_veritas.libs/libunistring-05abdd40.so.2.1.0 +0 -0
  132. 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)