__ __ __ __ _____ _ _ _____ _ _ _ | \/ | \ \ / / | __ \ (_) | | / ____| | | | | | \ / |_ __\ V / | |__) | __ ___ ____ _| |_ ___ | (___ | |__ ___| | | | |\/| | '__|> < | ___/ '__| \ \ / / _` | __/ _ \ \___ \| '_ \ / _ \ | | | | | | |_ / . \ | | | | | |\ V / (_| | || __/ ____) | | | | __/ | | |_| |_|_(_)_/ \_\ |_| |_| |_| \_/ \__,_|\__\___| |_____/|_| |_|\___V 2.1 if you need WebShell for Seo everyday contact me on Telegram Telegram Address : @jackleetFor_More_Tools:
import sys
from functools import partial
from typing import TYPE_CHECKING
import sentry_sdk
from sentry_sdk._werkzeug import _get_headers, get_host
from sentry_sdk.api import continue_trace
from sentry_sdk.consts import OP, SPANDATA
from sentry_sdk.integrations._wsgi_common import (
DEFAULT_HTTP_METHODS_TO_CAPTURE,
_filter_headers,
nullcontext,
)
from sentry_sdk.scope import Scope, should_send_default_pii, use_isolation_scope
from sentry_sdk.sessions import track_session
from sentry_sdk.traces import SegmentSource, StreamedSpan
from sentry_sdk.tracing import Span, TransactionSource
from sentry_sdk.tracing_utils import has_span_streaming_enabled
from sentry_sdk.utils import (
ContextVar,
capture_internal_exceptions,
event_from_exception,
reraise,
)
if TYPE_CHECKING:
from typing import (
Any,
Callable,
ContextManager,
Dict,
Iterator,
Optional,
Protocol,
Tuple,
TypeVar,
Union,
)
from sentry_sdk._types import Event, EventProcessor
from sentry_sdk.utils import ExcInfo
WsgiResponseIter = TypeVar("WsgiResponseIter")
WsgiResponseHeaders = TypeVar("WsgiResponseHeaders")
WsgiExcInfo = TypeVar("WsgiExcInfo")
class StartResponse(Protocol):
def __call__(
self,
status: str,
response_headers: "WsgiResponseHeaders",
exc_info: "Optional[WsgiExcInfo]" = None,
) -> "WsgiResponseIter": # type: ignore
pass
_wsgi_middleware_applied = ContextVar("sentry_wsgi_middleware_applied")
_DEFAULT_TRANSACTION_NAME = "generic WSGI request"
def wsgi_decoding_dance(s: str, charset: str = "utf-8", errors: str = "replace") -> str:
return s.encode("latin1").decode(charset, errors)
def get_request_url(
environ: "Dict[str, str]", use_x_forwarded_for: bool = False
) -> str:
"""Return the absolute URL without query string for the given WSGI
environment."""
script_name = environ.get("SCRIPT_NAME", "").rstrip("/")
path_info = environ.get("PATH_INFO", "").lstrip("/")
path = f"{script_name}/{path_info}"
scheme = environ.get("wsgi.url_scheme")
if use_x_forwarded_for:
scheme = environ.get("HTTP_X_FORWARDED_PROTO", scheme)
return "%s://%s/%s" % (
scheme,
get_host(environ, use_x_forwarded_for),
wsgi_decoding_dance(path).lstrip("/"),
)
class SentryWsgiMiddleware:
__slots__ = (
"app",
"use_x_forwarded_for",
"span_origin",
"http_methods_to_capture",
)
def __init__(
self,
app: "Callable[[Dict[str, str], Callable[..., Any]], Any]",
use_x_forwarded_for: bool = False,
span_origin: str = "manual",
http_methods_to_capture: "Tuple[str, ...]" = DEFAULT_HTTP_METHODS_TO_CAPTURE,
) -> None:
self.app = app
self.use_x_forwarded_for = use_x_forwarded_for
self.span_origin = span_origin
self.http_methods_to_capture = http_methods_to_capture
def __call__(
self, environ: "Dict[str, str]", start_response: "Callable[..., Any]"
) -> "Any":
if _wsgi_middleware_applied.get(False):
return self.app(environ, start_response)
client = sentry_sdk.get_client()
span_streaming = has_span_streaming_enabled(client.options)
_wsgi_middleware_applied.set(True)
try:
with sentry_sdk.isolation_scope() as scope:
with track_session(scope, session_mode="request"):
with capture_internal_exceptions():
scope.clear_breadcrumbs()
scope._name = "wsgi"
scope.add_event_processor(
_make_wsgi_event_processor(
environ, self.use_x_forwarded_for
)
)
method = environ.get("REQUEST_METHOD", "").upper()
span_ctx: "Optional[ContextManager[Union[Span, StreamedSpan, None]]]" = None
if method in self.http_methods_to_capture:
if span_streaming:
sentry_sdk.traces.continue_trace(
dict(_get_headers(environ))
)
Scope.set_custom_sampling_context({"wsgi_environ": environ})
if should_send_default_pii():
client_ip = get_client_ip(environ)
if client_ip:
scope.set_attribute(
SPANDATA.USER_IP_ADDRESS, client_ip
)
span_ctx = sentry_sdk.traces.start_span(
name=_DEFAULT_TRANSACTION_NAME,
attributes={
"sentry.span.source": SegmentSource.ROUTE,
"sentry.origin": self.span_origin,
"sentry.op": OP.HTTP_SERVER,
},
parent_span=None,
)
else:
transaction = continue_trace(
environ,
op=OP.HTTP_SERVER,
name=_DEFAULT_TRANSACTION_NAME,
source=TransactionSource.ROUTE,
origin=self.span_origin,
)
span_ctx = sentry_sdk.start_transaction(
transaction,
custom_sampling_context={"wsgi_environ": environ},
)
span_ctx = span_ctx or nullcontext()
with span_ctx as span:
if isinstance(span, StreamedSpan):
with capture_internal_exceptions():
for attr, value in _get_request_attributes(
environ, self.use_x_forwarded_for
).items():
span.set_attribute(attr, value)
try:
response = self.app(
environ,
partial(_sentry_start_response, start_response, span),
)
except BaseException:
reraise(*_capture_exception())
finally:
_wsgi_middleware_applied.set(False)
# Within the uWSGI subhandler, the use of the "offload" mechanism for file responses
# is determined by a pointer equality check on the response object
# (see https://github.com/unbit/uwsgi/blob/8d116f7ea2b098c11ce54d0b3a561c54dcd11929/plugins/python/wsgi_subhandler.c#L278).
#
# If we were to return a _ScopedResponse, this would cause the check to always fail
# since it's checking the files are exactly the same.
#
# To avoid this and ensure that the offloading mechanism works as expected when it's
# enabled, we check if the response is a file-like object (determined by the presence
# of `fileno`), if the wsgi.file_wrapper is available in the environment (as if so,
# it would've been used in handling the file in the response).
#
# Even if the offload mechanism is not enabled, there are optimizations that uWSGI does for file-like objects,
# so we want to make sure we don't interfere with those either.
#
# If all conditions are met, we return the original response object directly,
# allowing uWSGI to handle it as intended.
if (
environ.get("wsgi.file_wrapper")
and getattr(response, "fileno", None) is not None
):
return response
return _ScopedResponse(scope, response)
def _sentry_start_response(
old_start_response: "StartResponse",
span: "Optional[Union[Span, StreamedSpan]]",
status: str,
response_headers: "WsgiResponseHeaders",
exc_info: "Optional[WsgiExcInfo]" = None,
) -> "WsgiResponseIter": # type: ignore[type-var]
with capture_internal_exceptions():
status_int = int(status.split(" ", 1)[0])
if span is not None:
if isinstance(span, StreamedSpan):
span.status = "error" if status_int >= 400 else "ok"
span.set_attribute("http.response.status_code", status_int)
else:
span.set_http_status(status_int)
if exc_info is None:
# The Django Rest Framework WSGI test client, and likely other
# (incorrect) implementations, cannot deal with the exc_info argument
# if one is present. Avoid providing a third argument if not necessary.
return old_start_response(status, response_headers)
else:
return old_start_response(status, response_headers, exc_info)
def _get_environ(environ: "Dict[str, str]") -> "Iterator[Tuple[str, str]]":
"""
Returns our explicitly included environment variables we want to
capture (server name, port and remote addr if pii is enabled).
"""
keys = ["SERVER_NAME", "SERVER_PORT"]
if should_send_default_pii():
# make debugging of proxy setup easier. Proxy headers are
# in headers.
keys += ["REMOTE_ADDR"]
for key in keys:
if key in environ:
yield key, environ[key]
def get_client_ip(environ: "Dict[str, str]") -> "Optional[Any]":
"""
Infer the user IP address from various headers. This cannot be used in
security sensitive situations since the value may be forged from a client,
but it's good enough for the event payload.
"""
try:
return environ["HTTP_X_FORWARDED_FOR"].split(",")[0].strip()
except (KeyError, IndexError):
pass
try:
return environ["HTTP_X_REAL_IP"]
except KeyError:
pass
return environ.get("REMOTE_ADDR")
def _capture_exception() -> "ExcInfo":
"""
Captures the current exception and sends it to Sentry.
Returns the ExcInfo tuple to it can be reraised afterwards.
"""
exc_info = sys.exc_info()
e = exc_info[1]
# SystemExit(0) is the only uncaught exception that is expected behavior
should_skip_capture = isinstance(e, SystemExit) and e.code in (0, None)
if not should_skip_capture:
event, hint = event_from_exception(
exc_info,
client_options=sentry_sdk.get_client().options,
mechanism={"type": "wsgi", "handled": False},
)
sentry_sdk.capture_event(event, hint=hint)
return exc_info
class _ScopedResponse:
"""
Users a separate scope for each response chunk.
This will make WSGI apps more tolerant against:
- WSGI servers streaming responses from a different thread/from
different threads than the one that called start_response
- close() not being called
- WSGI servers streaming responses interleaved from the same thread
"""
__slots__ = ("_response", "_scope")
def __init__(
self, scope: "sentry_sdk.scope.Scope", response: "Iterator[bytes]"
) -> None:
self._scope = scope
self._response = response
def __iter__(self) -> "Iterator[bytes]":
iterator = iter(self._response)
while True:
with use_isolation_scope(self._scope):
try:
chunk = next(iterator)
except StopIteration:
break
except BaseException:
reraise(*_capture_exception())
yield chunk
def close(self) -> None:
with use_isolation_scope(self._scope):
try:
self._response.close() # type: ignore
except AttributeError:
pass
except BaseException:
reraise(*_capture_exception())
def _make_wsgi_event_processor(
environ: "Dict[str, str]", use_x_forwarded_for: bool
) -> "EventProcessor":
# It's a bit unfortunate that we have to extract and parse the request data
# from the environ so eagerly, but there are a few good reasons for this.
#
# We might be in a situation where the scope never gets torn down
# properly. In that case we will have an unnecessary strong reference to
# all objects in the environ (some of which may take a lot of memory) when
# we're really just interested in a few of them.
#
# Keeping the environment around for longer than the request lifecycle is
# also not necessarily something uWSGI can deal with:
# https://github.com/unbit/uwsgi/issues/1950
client_ip = get_client_ip(environ)
request_url = get_request_url(environ, use_x_forwarded_for)
query_string = environ.get("QUERY_STRING")
method = environ.get("REQUEST_METHOD")
env = dict(_get_environ(environ))
headers = _filter_headers(dict(_get_headers(environ)))
def event_processor(event: "Event", hint: "Dict[str, Any]") -> "Event":
with capture_internal_exceptions():
# if the code below fails halfway through we at least have some data
request_info = event.setdefault("request", {})
if should_send_default_pii():
user_info = event.setdefault("user", {})
if client_ip:
user_info.setdefault("ip_address", client_ip)
request_info["url"] = request_url
request_info["query_string"] = query_string
request_info["method"] = method
request_info["env"] = env
request_info["headers"] = headers
return event
return event_processor
def _get_request_attributes(
environ: "Dict[str, str]",
use_x_forwarded_for: bool = False,
) -> "Dict[str, Any]":
"""
Return span attributes related to the HTTP request from the WSGI environ.
"""
attributes: "dict[str, Any]" = {}
method = environ.get("REQUEST_METHOD")
if method:
attributes["http.request.method"] = method.upper()
headers = _filter_headers(dict(_get_headers(environ)), use_annotated_value=False)
for header, value in headers.items():
attributes[f"http.request.header.{header.lower()}"] = value
query_string = environ.get("QUERY_STRING")
if query_string:
attributes["http.query"] = query_string
attributes["url.full"] = get_request_url(environ, use_x_forwarded_for)
url_scheme = environ.get("wsgi.url_scheme")
if url_scheme:
attributes["network.protocol.name"] = url_scheme
server_name = environ.get("SERVER_NAME")
if server_name:
attributes["server.address"] = server_name
server_port = environ.get("SERVER_PORT")
if server_port:
try:
attributes["server.port"] = int(server_port)
except ValueError:
pass
if should_send_default_pii():
client_ip = get_client_ip(environ)
if client_ip:
attributes["client.address"] = client_ip
return attributes
| Name | Type | Size | Permission | Actions |
|---|---|---|---|---|
| __pycache__ | Folder | 0755 |
|
|
| celery | Folder | 0755 |
|
|
| django | Folder | 0755 |
|
|
| google_genai | Folder | 0755 |
|
|
| grpc | Folder | 0755 |
|
|
| openai_agents | Folder | 0755 |
|
|
| opentelemetry | Folder | 0755 |
|
|
| pydantic_ai | Folder | 0755 |
|
|
| redis | Folder | 0755 |
|
|
| spark | Folder | 0755 |
|
|
| __init__.py | File | 12.51 KB | 0644 |
|
| _asgi_common.py | File | 4 KB | 0644 |
|
| _wsgi_common.py | File | 7.28 KB | 0644 |
|
| aiohttp.py | File | 19.28 KB | 0644 |
|
| aiomysql.py | File | 9.09 KB | 0644 |
|
| anthropic.py | File | 39 KB | 0644 |
|
| argv.py | File | 876 B | 0644 |
|
| ariadne.py | File | 5.7 KB | 0644 |
|
| arq.py | File | 9.23 KB | 0644 |
|
| asgi.py | File | 20.06 KB | 0644 |
|
| asyncio.py | File | 9.28 KB | 0644 |
|
| asyncpg.py | File | 9.68 KB | 0644 |
|
| atexit.py | File | 1.51 KB | 0644 |
|
| aws_lambda.py | File | 17.41 KB | 0644 |
|
| beam.py | File | 4.91 KB | 0644 |
|
| boto3.py | File | 6.2 KB | 0644 |
|
| bottle.py | File | 7.21 KB | 0644 |
|
| chalice.py | File | 4.51 KB | 0644 |
|
| clickhouse_driver.py | File | 5.85 KB | 0644 |
|
| cloud_resource_context.py | File | 7.49 KB | 0644 |
|
| cohere.py | File | 10.44 KB | 0644 |
|
| dedupe.py | File | 1.86 KB | 0644 |
|
| dramatiq.py | File | 8.02 KB | 0644 |
|
| excepthook.py | File | 2.25 KB | 0644 |
|
| executing.py | File | 1.93 KB | 0644 |
|
| falcon.py | File | 9.04 KB | 0644 |
|
| fastapi.py | File | 5.28 KB | 0644 |
|
| flask.py | File | 8.27 KB | 0644 |
|
| gcp.py | File | 10.57 KB | 0644 |
|
| gnu_backtrace.py | File | 2.72 KB | 0644 |
|
| gql.py | File | 4.93 KB | 0644 |
|
| graphene.py | File | 5.71 KB | 0644 |
|
| httpx.py | File | 9.79 KB | 0644 |
|
| httpx2.py | File | 9.8 KB | 0644 |
|
| huey.py | File | 8.19 KB | 0644 |
|
| huggingface_hub.py | File | 15.28 KB | 0644 |
|
| langchain.py | File | 48.31 KB | 0644 |
|
| langgraph.py | File | 18.13 KB | 0644 |
|
| launchdarkly.py | File | 1.87 KB | 0644 |
|
| litellm.py | File | 13.03 KB | 0644 |
|
| litestar.py | File | 11.46 KB | 0644 |
|
| logging.py | File | 15.69 KB | 0644 |
|
| loguru.py | File | 6.35 KB | 0644 |
|
| mcp.py | File | 23.12 KB | 0644 |
|
| modules.py | File | 787 B | 0644 |
|
| openai.py | File | 53.38 KB | 0644 |
|
| openfeature.py | File | 1.08 KB | 0644 |
|
| otlp.py | File | 7.99 KB | 0644 |
|
| pure_eval.py | File | 4.41 KB | 0644 |
|
| pymongo.py | File | 8.21 KB | 0644 |
|
| pyramid.py | File | 7.42 KB | 0644 |
|
| pyreqwest.py | File | 6.82 KB | 0644 |
|
| quart.py | File | 7.32 KB | 0644 |
|
| ray.py | File | 5.75 KB | 0644 |
|
| rq.py | File | 7.81 KB | 0644 |
|
| rust_tracing.py | File | 9.44 KB | 0644 |
|
| sanic.py | File | 15.25 KB | 0644 |
|
| serverless.py | File | 1.58 KB | 0644 |
|
| socket.py | File | 5.02 KB | 0644 |
|
| sqlalchemy.py | File | 5.24 KB | 0644 |
|
| starlette.py | File | 27.93 KB | 0644 |
|
| starlite.py | File | 11.04 KB | 0644 |
|
| statsig.py | File | 1.19 KB | 0644 |
|
| stdlib.py | File | 14.01 KB | 0644 |
|
| strawberry.py | File | 17.39 KB | 0644 |
|
| sys_exit.py | File | 2.35 KB | 0644 |
|
| threading.py | File | 6.88 KB | 0644 |
|
| tornado.py | File | 10.79 KB | 0644 |
|
| trytond.py | File | 1.67 KB | 0644 |
|
| typer.py | File | 1.72 KB | 0644 |
|
| unleash.py | File | 1.02 KB | 0644 |
|
| unraisablehook.py | File | 1.65 KB | 0644 |
|
| wsgi.py | File | 15.03 KB | 0644 |
|