sentry-sdk 0.18.0__py2.py3-none-any.whl → 2.46.0__py2.py3-none-any.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.
- sentry_sdk/__init__.py +48 -6
- sentry_sdk/_compat.py +64 -56
- sentry_sdk/_init_implementation.py +84 -0
- sentry_sdk/_log_batcher.py +172 -0
- sentry_sdk/_lru_cache.py +47 -0
- sentry_sdk/_metrics_batcher.py +167 -0
- sentry_sdk/_queue.py +81 -19
- sentry_sdk/_types.py +311 -11
- sentry_sdk/_werkzeug.py +98 -0
- sentry_sdk/ai/__init__.py +7 -0
- sentry_sdk/ai/monitoring.py +137 -0
- sentry_sdk/ai/utils.py +144 -0
- sentry_sdk/api.py +409 -67
- sentry_sdk/attachments.py +75 -0
- sentry_sdk/client.py +849 -103
- sentry_sdk/consts.py +1389 -34
- sentry_sdk/crons/__init__.py +10 -0
- sentry_sdk/crons/api.py +62 -0
- sentry_sdk/crons/consts.py +4 -0
- sentry_sdk/crons/decorator.py +135 -0
- sentry_sdk/debug.py +12 -15
- sentry_sdk/envelope.py +112 -61
- sentry_sdk/feature_flags.py +71 -0
- sentry_sdk/hub.py +442 -386
- sentry_sdk/integrations/__init__.py +228 -58
- sentry_sdk/integrations/_asgi_common.py +108 -0
- sentry_sdk/integrations/_wsgi_common.py +131 -40
- sentry_sdk/integrations/aiohttp.py +221 -72
- sentry_sdk/integrations/anthropic.py +439 -0
- sentry_sdk/integrations/argv.py +4 -6
- sentry_sdk/integrations/ariadne.py +161 -0
- sentry_sdk/integrations/arq.py +247 -0
- sentry_sdk/integrations/asgi.py +237 -135
- sentry_sdk/integrations/asyncio.py +144 -0
- sentry_sdk/integrations/asyncpg.py +208 -0
- sentry_sdk/integrations/atexit.py +13 -18
- sentry_sdk/integrations/aws_lambda.py +233 -80
- sentry_sdk/integrations/beam.py +27 -35
- sentry_sdk/integrations/boto3.py +137 -0
- sentry_sdk/integrations/bottle.py +91 -69
- sentry_sdk/integrations/celery/__init__.py +529 -0
- sentry_sdk/integrations/celery/beat.py +293 -0
- sentry_sdk/integrations/celery/utils.py +43 -0
- sentry_sdk/integrations/chalice.py +35 -28
- sentry_sdk/integrations/clickhouse_driver.py +177 -0
- sentry_sdk/integrations/cloud_resource_context.py +280 -0
- sentry_sdk/integrations/cohere.py +274 -0
- sentry_sdk/integrations/dedupe.py +32 -8
- sentry_sdk/integrations/django/__init__.py +343 -89
- sentry_sdk/integrations/django/asgi.py +201 -22
- sentry_sdk/integrations/django/caching.py +204 -0
- sentry_sdk/integrations/django/middleware.py +80 -32
- sentry_sdk/integrations/django/signals_handlers.py +91 -0
- sentry_sdk/integrations/django/templates.py +69 -2
- sentry_sdk/integrations/django/transactions.py +39 -14
- sentry_sdk/integrations/django/views.py +69 -16
- sentry_sdk/integrations/dramatiq.py +226 -0
- sentry_sdk/integrations/excepthook.py +19 -13
- sentry_sdk/integrations/executing.py +5 -6
- sentry_sdk/integrations/falcon.py +128 -65
- sentry_sdk/integrations/fastapi.py +141 -0
- sentry_sdk/integrations/flask.py +114 -75
- sentry_sdk/integrations/gcp.py +67 -36
- sentry_sdk/integrations/gnu_backtrace.py +14 -22
- sentry_sdk/integrations/google_genai/__init__.py +301 -0
- sentry_sdk/integrations/google_genai/consts.py +16 -0
- sentry_sdk/integrations/google_genai/streaming.py +155 -0
- sentry_sdk/integrations/google_genai/utils.py +576 -0
- sentry_sdk/integrations/gql.py +162 -0
- sentry_sdk/integrations/graphene.py +151 -0
- sentry_sdk/integrations/grpc/__init__.py +168 -0
- sentry_sdk/integrations/grpc/aio/__init__.py +7 -0
- sentry_sdk/integrations/grpc/aio/client.py +95 -0
- sentry_sdk/integrations/grpc/aio/server.py +100 -0
- sentry_sdk/integrations/grpc/client.py +91 -0
- sentry_sdk/integrations/grpc/consts.py +1 -0
- sentry_sdk/integrations/grpc/server.py +66 -0
- sentry_sdk/integrations/httpx.py +178 -0
- sentry_sdk/integrations/huey.py +174 -0
- sentry_sdk/integrations/huggingface_hub.py +378 -0
- sentry_sdk/integrations/langchain.py +1132 -0
- sentry_sdk/integrations/langgraph.py +337 -0
- sentry_sdk/integrations/launchdarkly.py +61 -0
- sentry_sdk/integrations/litellm.py +287 -0
- sentry_sdk/integrations/litestar.py +315 -0
- sentry_sdk/integrations/logging.py +261 -85
- sentry_sdk/integrations/loguru.py +213 -0
- sentry_sdk/integrations/mcp.py +566 -0
- sentry_sdk/integrations/modules.py +6 -33
- sentry_sdk/integrations/openai.py +725 -0
- sentry_sdk/integrations/openai_agents/__init__.py +61 -0
- sentry_sdk/integrations/openai_agents/consts.py +1 -0
- sentry_sdk/integrations/openai_agents/patches/__init__.py +5 -0
- sentry_sdk/integrations/openai_agents/patches/agent_run.py +140 -0
- sentry_sdk/integrations/openai_agents/patches/error_tracing.py +77 -0
- sentry_sdk/integrations/openai_agents/patches/models.py +50 -0
- sentry_sdk/integrations/openai_agents/patches/runner.py +45 -0
- sentry_sdk/integrations/openai_agents/patches/tools.py +77 -0
- sentry_sdk/integrations/openai_agents/spans/__init__.py +5 -0
- sentry_sdk/integrations/openai_agents/spans/agent_workflow.py +21 -0
- sentry_sdk/integrations/openai_agents/spans/ai_client.py +42 -0
- sentry_sdk/integrations/openai_agents/spans/execute_tool.py +48 -0
- sentry_sdk/integrations/openai_agents/spans/handoff.py +19 -0
- sentry_sdk/integrations/openai_agents/spans/invoke_agent.py +86 -0
- sentry_sdk/integrations/openai_agents/utils.py +199 -0
- sentry_sdk/integrations/openfeature.py +35 -0
- sentry_sdk/integrations/opentelemetry/__init__.py +7 -0
- sentry_sdk/integrations/opentelemetry/consts.py +5 -0
- sentry_sdk/integrations/opentelemetry/integration.py +58 -0
- sentry_sdk/integrations/opentelemetry/propagator.py +117 -0
- sentry_sdk/integrations/opentelemetry/span_processor.py +391 -0
- sentry_sdk/integrations/otlp.py +82 -0
- sentry_sdk/integrations/pure_eval.py +20 -11
- sentry_sdk/integrations/pydantic_ai/__init__.py +47 -0
- sentry_sdk/integrations/pydantic_ai/consts.py +1 -0
- sentry_sdk/integrations/pydantic_ai/patches/__init__.py +4 -0
- sentry_sdk/integrations/pydantic_ai/patches/agent_run.py +215 -0
- sentry_sdk/integrations/pydantic_ai/patches/graph_nodes.py +110 -0
- sentry_sdk/integrations/pydantic_ai/patches/model_request.py +40 -0
- sentry_sdk/integrations/pydantic_ai/patches/tools.py +98 -0
- sentry_sdk/integrations/pydantic_ai/spans/__init__.py +3 -0
- sentry_sdk/integrations/pydantic_ai/spans/ai_client.py +246 -0
- sentry_sdk/integrations/pydantic_ai/spans/execute_tool.py +49 -0
- sentry_sdk/integrations/pydantic_ai/spans/invoke_agent.py +112 -0
- sentry_sdk/integrations/pydantic_ai/utils.py +223 -0
- sentry_sdk/integrations/pymongo.py +214 -0
- sentry_sdk/integrations/pyramid.py +71 -60
- sentry_sdk/integrations/quart.py +237 -0
- sentry_sdk/integrations/ray.py +165 -0
- sentry_sdk/integrations/redis/__init__.py +48 -0
- sentry_sdk/integrations/redis/_async_common.py +116 -0
- sentry_sdk/integrations/redis/_sync_common.py +119 -0
- sentry_sdk/integrations/redis/consts.py +19 -0
- sentry_sdk/integrations/redis/modules/__init__.py +0 -0
- sentry_sdk/integrations/redis/modules/caches.py +118 -0
- sentry_sdk/integrations/redis/modules/queries.py +65 -0
- sentry_sdk/integrations/redis/rb.py +32 -0
- sentry_sdk/integrations/redis/redis.py +69 -0
- sentry_sdk/integrations/redis/redis_cluster.py +107 -0
- sentry_sdk/integrations/redis/redis_py_cluster_legacy.py +50 -0
- sentry_sdk/integrations/redis/utils.py +148 -0
- sentry_sdk/integrations/rq.py +62 -52
- sentry_sdk/integrations/rust_tracing.py +284 -0
- sentry_sdk/integrations/sanic.py +248 -114
- sentry_sdk/integrations/serverless.py +13 -22
- sentry_sdk/integrations/socket.py +96 -0
- sentry_sdk/integrations/spark/spark_driver.py +115 -62
- sentry_sdk/integrations/spark/spark_worker.py +42 -50
- sentry_sdk/integrations/sqlalchemy.py +82 -37
- sentry_sdk/integrations/starlette.py +737 -0
- sentry_sdk/integrations/starlite.py +292 -0
- sentry_sdk/integrations/statsig.py +37 -0
- sentry_sdk/integrations/stdlib.py +100 -58
- sentry_sdk/integrations/strawberry.py +394 -0
- sentry_sdk/integrations/sys_exit.py +70 -0
- sentry_sdk/integrations/threading.py +142 -38
- sentry_sdk/integrations/tornado.py +68 -53
- sentry_sdk/integrations/trytond.py +15 -20
- sentry_sdk/integrations/typer.py +60 -0
- sentry_sdk/integrations/unleash.py +33 -0
- sentry_sdk/integrations/unraisablehook.py +53 -0
- sentry_sdk/integrations/wsgi.py +126 -125
- sentry_sdk/logger.py +96 -0
- sentry_sdk/metrics.py +81 -0
- sentry_sdk/monitor.py +120 -0
- sentry_sdk/profiler/__init__.py +49 -0
- sentry_sdk/profiler/continuous_profiler.py +730 -0
- sentry_sdk/profiler/transaction_profiler.py +839 -0
- sentry_sdk/profiler/utils.py +195 -0
- sentry_sdk/scope.py +1542 -112
- sentry_sdk/scrubber.py +177 -0
- sentry_sdk/serializer.py +152 -210
- sentry_sdk/session.py +177 -0
- sentry_sdk/sessions.py +202 -179
- sentry_sdk/spotlight.py +242 -0
- sentry_sdk/tracing.py +1202 -294
- sentry_sdk/tracing_utils.py +1236 -0
- sentry_sdk/transport.py +693 -189
- sentry_sdk/types.py +52 -0
- sentry_sdk/utils.py +1395 -228
- sentry_sdk/worker.py +30 -17
- sentry_sdk-2.46.0.dist-info/METADATA +268 -0
- sentry_sdk-2.46.0.dist-info/RECORD +189 -0
- {sentry_sdk-0.18.0.dist-info → sentry_sdk-2.46.0.dist-info}/WHEEL +1 -1
- sentry_sdk-2.46.0.dist-info/entry_points.txt +2 -0
- sentry_sdk-2.46.0.dist-info/licenses/LICENSE +21 -0
- sentry_sdk/_functools.py +0 -66
- sentry_sdk/integrations/celery.py +0 -275
- sentry_sdk/integrations/redis.py +0 -103
- sentry_sdk-0.18.0.dist-info/LICENSE +0 -9
- sentry_sdk-0.18.0.dist-info/METADATA +0 -66
- sentry_sdk-0.18.0.dist-info/RECORD +0 -65
- {sentry_sdk-0.18.0.dist-info → sentry_sdk-2.46.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
from functools import partial
|
|
2
|
+
|
|
3
|
+
import sentry_sdk
|
|
4
|
+
from sentry_sdk.consts import OP, SPANDATA
|
|
5
|
+
from sentry_sdk.integrations import _check_minimum_version, Integration, DidNotEnable
|
|
6
|
+
from sentry_sdk.tracing import Span
|
|
7
|
+
from sentry_sdk.utils import (
|
|
8
|
+
capture_internal_exceptions,
|
|
9
|
+
ensure_integration_enabled,
|
|
10
|
+
parse_url,
|
|
11
|
+
parse_version,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
from typing import TYPE_CHECKING
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from typing import Any
|
|
18
|
+
from typing import Dict
|
|
19
|
+
from typing import Optional
|
|
20
|
+
from typing import Type
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
from botocore import __version__ as BOTOCORE_VERSION # type: ignore
|
|
24
|
+
from botocore.client import BaseClient # type: ignore
|
|
25
|
+
from botocore.response import StreamingBody # type: ignore
|
|
26
|
+
from botocore.awsrequest import AWSRequest # type: ignore
|
|
27
|
+
except ImportError:
|
|
28
|
+
raise DidNotEnable("botocore is not installed")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class Boto3Integration(Integration):
|
|
32
|
+
identifier = "boto3"
|
|
33
|
+
origin = f"auto.http.{identifier}"
|
|
34
|
+
|
|
35
|
+
@staticmethod
|
|
36
|
+
def setup_once():
|
|
37
|
+
# type: () -> None
|
|
38
|
+
version = parse_version(BOTOCORE_VERSION)
|
|
39
|
+
_check_minimum_version(Boto3Integration, version, "botocore")
|
|
40
|
+
|
|
41
|
+
orig_init = BaseClient.__init__
|
|
42
|
+
|
|
43
|
+
def sentry_patched_init(self, *args, **kwargs):
|
|
44
|
+
# type: (Type[BaseClient], *Any, **Any) -> None
|
|
45
|
+
orig_init(self, *args, **kwargs)
|
|
46
|
+
meta = self.meta
|
|
47
|
+
service_id = meta.service_model.service_id.hyphenize()
|
|
48
|
+
meta.events.register(
|
|
49
|
+
"request-created",
|
|
50
|
+
partial(_sentry_request_created, service_id=service_id),
|
|
51
|
+
)
|
|
52
|
+
meta.events.register("after-call", _sentry_after_call)
|
|
53
|
+
meta.events.register("after-call-error", _sentry_after_call_error)
|
|
54
|
+
|
|
55
|
+
BaseClient.__init__ = sentry_patched_init
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@ensure_integration_enabled(Boto3Integration)
|
|
59
|
+
def _sentry_request_created(service_id, request, operation_name, **kwargs):
|
|
60
|
+
# type: (str, AWSRequest, str, **Any) -> None
|
|
61
|
+
description = "aws.%s.%s" % (service_id, operation_name)
|
|
62
|
+
span = sentry_sdk.start_span(
|
|
63
|
+
op=OP.HTTP_CLIENT,
|
|
64
|
+
name=description,
|
|
65
|
+
origin=Boto3Integration.origin,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
with capture_internal_exceptions():
|
|
69
|
+
parsed_url = parse_url(request.url, sanitize=False)
|
|
70
|
+
span.set_data("aws.request.url", parsed_url.url)
|
|
71
|
+
span.set_data(SPANDATA.HTTP_QUERY, parsed_url.query)
|
|
72
|
+
span.set_data(SPANDATA.HTTP_FRAGMENT, parsed_url.fragment)
|
|
73
|
+
|
|
74
|
+
span.set_tag("aws.service_id", service_id)
|
|
75
|
+
span.set_tag("aws.operation_name", operation_name)
|
|
76
|
+
span.set_data(SPANDATA.HTTP_METHOD, request.method)
|
|
77
|
+
|
|
78
|
+
# We do it in order for subsequent http calls/retries be
|
|
79
|
+
# attached to this span.
|
|
80
|
+
span.__enter__()
|
|
81
|
+
|
|
82
|
+
# request.context is an open-ended data-structure
|
|
83
|
+
# where we can add anything useful in request life cycle.
|
|
84
|
+
request.context["_sentrysdk_span"] = span
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _sentry_after_call(context, parsed, **kwargs):
|
|
88
|
+
# type: (Dict[str, Any], Dict[str, Any], **Any) -> None
|
|
89
|
+
span = context.pop("_sentrysdk_span", None) # type: Optional[Span]
|
|
90
|
+
|
|
91
|
+
# Span could be absent if the integration is disabled.
|
|
92
|
+
if span is None:
|
|
93
|
+
return
|
|
94
|
+
span.__exit__(None, None, None)
|
|
95
|
+
|
|
96
|
+
body = parsed.get("Body")
|
|
97
|
+
if not isinstance(body, StreamingBody):
|
|
98
|
+
return
|
|
99
|
+
|
|
100
|
+
streaming_span = span.start_child(
|
|
101
|
+
op=OP.HTTP_CLIENT_STREAM,
|
|
102
|
+
name=span.description,
|
|
103
|
+
origin=Boto3Integration.origin,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
orig_read = body.read
|
|
107
|
+
orig_close = body.close
|
|
108
|
+
|
|
109
|
+
def sentry_streaming_body_read(*args, **kwargs):
|
|
110
|
+
# type: (*Any, **Any) -> bytes
|
|
111
|
+
try:
|
|
112
|
+
ret = orig_read(*args, **kwargs)
|
|
113
|
+
if not ret:
|
|
114
|
+
streaming_span.finish()
|
|
115
|
+
return ret
|
|
116
|
+
except Exception:
|
|
117
|
+
streaming_span.finish()
|
|
118
|
+
raise
|
|
119
|
+
|
|
120
|
+
body.read = sentry_streaming_body_read
|
|
121
|
+
|
|
122
|
+
def sentry_streaming_body_close(*args, **kwargs):
|
|
123
|
+
# type: (*Any, **Any) -> None
|
|
124
|
+
streaming_span.finish()
|
|
125
|
+
orig_close(*args, **kwargs)
|
|
126
|
+
|
|
127
|
+
body.close = sentry_streaming_body_close
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _sentry_after_call_error(context, exception, **kwargs):
|
|
131
|
+
# type: (Dict[str, Any], Type[BaseException], **Any) -> None
|
|
132
|
+
span = context.pop("_sentrysdk_span", None) # type: Optional[Span]
|
|
133
|
+
|
|
134
|
+
# Span could be absent if the integration is disabled.
|
|
135
|
+
if span is None:
|
|
136
|
+
return
|
|
137
|
+
span.__exit__(type(exception), exception, None)
|
|
@@ -1,18 +1,28 @@
|
|
|
1
|
-
|
|
1
|
+
import functools
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import sentry_sdk
|
|
4
|
+
from sentry_sdk.tracing import SOURCE_FOR_STYLE
|
|
4
5
|
from sentry_sdk.utils import (
|
|
5
6
|
capture_internal_exceptions,
|
|
7
|
+
ensure_integration_enabled,
|
|
6
8
|
event_from_exception,
|
|
9
|
+
parse_version,
|
|
7
10
|
transaction_from_function,
|
|
8
11
|
)
|
|
9
|
-
from sentry_sdk.integrations import
|
|
12
|
+
from sentry_sdk.integrations import (
|
|
13
|
+
Integration,
|
|
14
|
+
DidNotEnable,
|
|
15
|
+
_DEFAULT_FAILED_REQUEST_STATUS_CODES,
|
|
16
|
+
_check_minimum_version,
|
|
17
|
+
)
|
|
10
18
|
from sentry_sdk.integrations.wsgi import SentryWsgiMiddleware
|
|
11
19
|
from sentry_sdk.integrations._wsgi_common import RequestExtractor
|
|
12
20
|
|
|
13
|
-
from
|
|
21
|
+
from typing import TYPE_CHECKING
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from collections.abc import Set
|
|
14
25
|
|
|
15
|
-
if MYPY:
|
|
16
26
|
from sentry_sdk.integrations.wsgi import _ScopedResponse
|
|
17
27
|
from typing import Any
|
|
18
28
|
from typing import Dict
|
|
@@ -20,14 +30,14 @@ if MYPY:
|
|
|
20
30
|
from typing import Optional
|
|
21
31
|
from bottle import FileUpload, FormsDict, LocalRequest # type: ignore
|
|
22
32
|
|
|
23
|
-
from sentry_sdk._types import EventProcessor
|
|
33
|
+
from sentry_sdk._types import EventProcessor, Event
|
|
24
34
|
|
|
25
35
|
try:
|
|
26
36
|
from bottle import (
|
|
27
37
|
Bottle,
|
|
38
|
+
HTTPResponse,
|
|
28
39
|
Route,
|
|
29
40
|
request as bottle_request,
|
|
30
|
-
HTTPResponse,
|
|
31
41
|
__version__ as BOTTLE_VERSION,
|
|
32
42
|
)
|
|
33
43
|
except ImportError:
|
|
@@ -39,11 +49,17 @@ TRANSACTION_STYLE_VALUES = ("endpoint", "url")
|
|
|
39
49
|
|
|
40
50
|
class BottleIntegration(Integration):
|
|
41
51
|
identifier = "bottle"
|
|
52
|
+
origin = f"auto.http.{identifier}"
|
|
42
53
|
|
|
43
|
-
transaction_style =
|
|
54
|
+
transaction_style = ""
|
|
44
55
|
|
|
45
|
-
def __init__(
|
|
46
|
-
|
|
56
|
+
def __init__(
|
|
57
|
+
self,
|
|
58
|
+
transaction_style="endpoint", # type: str
|
|
59
|
+
*,
|
|
60
|
+
failed_request_status_codes=_DEFAULT_FAILED_REQUEST_STATUS_CODES, # type: Set[int]
|
|
61
|
+
):
|
|
62
|
+
# type: (...) -> None
|
|
47
63
|
|
|
48
64
|
if transaction_style not in TRANSACTION_STYLE_VALUES:
|
|
49
65
|
raise ValueError(
|
|
@@ -51,93 +67,73 @@ class BottleIntegration(Integration):
|
|
|
51
67
|
% (transaction_style, TRANSACTION_STYLE_VALUES)
|
|
52
68
|
)
|
|
53
69
|
self.transaction_style = transaction_style
|
|
70
|
+
self.failed_request_status_codes = failed_request_status_codes
|
|
54
71
|
|
|
55
72
|
@staticmethod
|
|
56
73
|
def setup_once():
|
|
57
74
|
# type: () -> None
|
|
75
|
+
version = parse_version(BOTTLE_VERSION)
|
|
76
|
+
_check_minimum_version(BottleIntegration, version)
|
|
58
77
|
|
|
59
|
-
try:
|
|
60
|
-
version = tuple(map(int, BOTTLE_VERSION.split(".")))
|
|
61
|
-
except (TypeError, ValueError):
|
|
62
|
-
raise DidNotEnable("Unparsable Bottle version: {}".format(version))
|
|
63
|
-
|
|
64
|
-
if version < (0, 12):
|
|
65
|
-
raise DidNotEnable("Bottle 0.12 or newer required.")
|
|
66
|
-
|
|
67
|
-
# monkey patch method Bottle.__call__
|
|
68
78
|
old_app = Bottle.__call__
|
|
69
79
|
|
|
80
|
+
@ensure_integration_enabled(BottleIntegration, old_app)
|
|
70
81
|
def sentry_patched_wsgi_app(self, environ, start_response):
|
|
71
82
|
# type: (Any, Dict[str, str], Callable[..., Any]) -> _ScopedResponse
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if integration is None:
|
|
76
|
-
return old_app(self, environ, start_response)
|
|
77
|
-
|
|
78
|
-
return SentryWsgiMiddleware(lambda *a, **kw: old_app(self, *a, **kw))(
|
|
79
|
-
environ, start_response
|
|
83
|
+
middleware = SentryWsgiMiddleware(
|
|
84
|
+
lambda *a, **kw: old_app(self, *a, **kw),
|
|
85
|
+
span_origin=BottleIntegration.origin,
|
|
80
86
|
)
|
|
81
87
|
|
|
88
|
+
return middleware(environ, start_response)
|
|
89
|
+
|
|
82
90
|
Bottle.__call__ = sentry_patched_wsgi_app
|
|
83
91
|
|
|
84
|
-
# monkey patch method Bottle._handle
|
|
85
92
|
old_handle = Bottle._handle
|
|
86
93
|
|
|
94
|
+
@functools.wraps(old_handle)
|
|
87
95
|
def _patched_handle(self, environ):
|
|
88
96
|
# type: (Bottle, Dict[str, Any]) -> Any
|
|
89
|
-
|
|
90
|
-
integration = hub.get_integration(BottleIntegration)
|
|
97
|
+
integration = sentry_sdk.get_client().get_integration(BottleIntegration)
|
|
91
98
|
if integration is None:
|
|
92
99
|
return old_handle(self, environ)
|
|
93
100
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
scope._name = "bottle"
|
|
101
|
-
scope.add_event_processor(
|
|
102
|
-
_make_request_event_processor(app, bottle_request, integration)
|
|
103
|
-
)
|
|
104
|
-
res = old_handle(self, environ)
|
|
101
|
+
scope = sentry_sdk.get_isolation_scope()
|
|
102
|
+
scope._name = "bottle"
|
|
103
|
+
scope.add_event_processor(
|
|
104
|
+
_make_request_event_processor(self, bottle_request, integration)
|
|
105
|
+
)
|
|
106
|
+
res = old_handle(self, environ)
|
|
105
107
|
|
|
106
|
-
# scope cleanup
|
|
107
108
|
return res
|
|
108
109
|
|
|
109
110
|
Bottle._handle = _patched_handle
|
|
110
111
|
|
|
111
|
-
# monkey patch method Route._make_callback
|
|
112
112
|
old_make_callback = Route._make_callback
|
|
113
113
|
|
|
114
|
+
@functools.wraps(old_make_callback)
|
|
114
115
|
def patched_make_callback(self, *args, **kwargs):
|
|
115
116
|
# type: (Route, *object, **object) -> Any
|
|
116
|
-
hub = Hub.current
|
|
117
|
-
integration = hub.get_integration(BottleIntegration)
|
|
118
117
|
prepared_callback = old_make_callback(self, *args, **kwargs)
|
|
118
|
+
|
|
119
|
+
integration = sentry_sdk.get_client().get_integration(BottleIntegration)
|
|
119
120
|
if integration is None:
|
|
120
121
|
return prepared_callback
|
|
121
122
|
|
|
122
|
-
# If an integration is there, a client has to be there.
|
|
123
|
-
client = hub.client # type: Any
|
|
124
|
-
|
|
125
123
|
def wrapped_callback(*args, **kwargs):
|
|
126
124
|
# type: (*object, **object) -> Any
|
|
127
|
-
|
|
128
125
|
try:
|
|
129
126
|
res = prepared_callback(*args, **kwargs)
|
|
130
|
-
except HTTPResponse:
|
|
131
|
-
raise
|
|
132
127
|
except Exception as exception:
|
|
133
|
-
|
|
134
|
-
exception,
|
|
135
|
-
client_options=client.options,
|
|
136
|
-
mechanism={"type": "bottle", "handled": False},
|
|
137
|
-
)
|
|
138
|
-
hub.capture_event(event, hint=hint)
|
|
128
|
+
_capture_exception(exception, handled=False)
|
|
139
129
|
raise exception
|
|
140
130
|
|
|
131
|
+
if (
|
|
132
|
+
isinstance(res, HTTPResponse)
|
|
133
|
+
and res.status_code in integration.failed_request_status_codes
|
|
134
|
+
):
|
|
135
|
+
_capture_exception(res, handled=True)
|
|
136
|
+
|
|
141
137
|
return res
|
|
142
138
|
|
|
143
139
|
return wrapped_callback
|
|
@@ -176,24 +172,50 @@ class BottleRequestExtractor(RequestExtractor):
|
|
|
176
172
|
return file.content_length
|
|
177
173
|
|
|
178
174
|
|
|
179
|
-
def
|
|
180
|
-
# type: (
|
|
181
|
-
|
|
182
|
-
|
|
175
|
+
def _set_transaction_name_and_source(event, transaction_style, request):
|
|
176
|
+
# type: (Event, str, Any) -> None
|
|
177
|
+
name = ""
|
|
178
|
+
|
|
179
|
+
if transaction_style == "url":
|
|
180
|
+
try:
|
|
181
|
+
name = request.route.rule or ""
|
|
182
|
+
except RuntimeError:
|
|
183
|
+
pass
|
|
183
184
|
|
|
185
|
+
elif transaction_style == "endpoint":
|
|
184
186
|
try:
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
except Exception:
|
|
187
|
+
name = (
|
|
188
|
+
request.route.name
|
|
189
|
+
or transaction_from_function(request.route.callback)
|
|
190
|
+
or ""
|
|
191
|
+
)
|
|
192
|
+
except RuntimeError:
|
|
192
193
|
pass
|
|
193
194
|
|
|
195
|
+
event["transaction"] = name
|
|
196
|
+
event["transaction_info"] = {"source": SOURCE_FOR_STYLE[transaction_style]}
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def _make_request_event_processor(app, request, integration):
|
|
200
|
+
# type: (Bottle, LocalRequest, BottleIntegration) -> EventProcessor
|
|
201
|
+
|
|
202
|
+
def event_processor(event, hint):
|
|
203
|
+
# type: (Event, dict[str, Any]) -> Event
|
|
204
|
+
_set_transaction_name_and_source(event, integration.transaction_style, request)
|
|
205
|
+
|
|
194
206
|
with capture_internal_exceptions():
|
|
195
207
|
BottleRequestExtractor(request).extract_into_event(event)
|
|
196
208
|
|
|
197
209
|
return event
|
|
198
210
|
|
|
199
|
-
return
|
|
211
|
+
return event_processor
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def _capture_exception(exception, handled):
|
|
215
|
+
# type: (BaseException, bool) -> None
|
|
216
|
+
event, hint = event_from_exception(
|
|
217
|
+
exception,
|
|
218
|
+
client_options=sentry_sdk.get_client().options,
|
|
219
|
+
mechanism={"type": "bottle", "handled": handled},
|
|
220
|
+
)
|
|
221
|
+
sentry_sdk.capture_event(event, hint=hint)
|