8000 Merge remote-tracking branch 'origin/master' · mxrcooo/sentry-python@d4a30b5 · GitHub
[go: up one dir, main page]

Skip to content

Commit d4a30b5

Browse files
committed
Merge remote-tracking branch 'origin/master'
2 parents ad70add + 00f8140 commit d4a30b5

22 files changed

+1016
-187
lines changed

CONTRIBUTING-aws-lambda.md

Lines changed: 0 additions & 21 deletions
This file was deleted.

CONTRIBUTING.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,3 +172,24 @@ sentry-sdk==2.4.0
172172
```
173173

174174
A major release `N` implies the previous release `N-1` will no longer receive updates. We generally do not backport bugfixes to older versions unless they are security relevant. However, feel free to ask for backports of specific commits on the bugtracker.
175+
176+
177+
## Contributing to Sentry AWS Lambda Layer
178+
179+
### Development environment
180+
181+
You need to have an AWS account and AWS CLI installed and setup.
182+
183+
We put together two helper functions that can help you with development:
184+
185+
- `./scripts/aws-deploy-local-layer.sh`
186+
187+
This script [scripts/aws-deploy-local-layer.sh](scripts/aws-deploy-local-layer.sh) will take the code you have checked out locally, create a Lambda layer out of it and deploy it to the `eu-central-1` region of your configured AWS account using `aws` CLI.
188+
189+
The Lambda layer will have the name `SentryPythonServerlessSDK-local-dev`
190+
191+
- `./scripts/aws-attach-layer-to-lambda-function.sh`
192+
193+
You can use this script [scripts/aws-attach-layer-to-lambda-function.sh](scripts/aws-attach-layer-to-lambda-function.sh) to attach the Lambda layer you just deployed (using the first script) onto one of your existing Lambda functions. You will have to give the name of the Lambda function to attach onto as an argument. (See the script for details.)
194+
195+
With these two helper scripts it should be easy to rapidly iterate your development on the Lambda layer.

Makefile

Lines changed: 2 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,11 @@ VENV_PATH = .venv
55
help:
66
@echo "Thanks for your interest in the Sentry Python SDK!"
77
@echo
8-
@echo "make lint: Run linters"
9-
@echo "make test: Run basic tests (not testing most integrations)"
10-
@echo "make test-all: Run ALL tests (slow, closest to CI)"
11-
@echo "make format: Run code formatters (destructive)"
8+
@echo "make apidocs: Build the API documentation"
129
@echo "make aws-lambda-layer: Build AWS Lambda layer directory for serverless integration"
1310
@echo
1411
@echo "Also make sure to read ./CONTRIBUTING.md"
12+
@echo
1513
@false
1614

1715
.venv:
@@ -24,42 +22,13 @@ dist: .venv
2422
$(VENV_PATH)/bin/python setup.py sdist bdist_wheel
2523
.PHONY: dist
2624

27-
format: .venv
28-
$(VENV_PATH)/bin/tox -e linters --notest
29-
.tox/linters/bin/black .
30-
.PHONY: format
31-
32-
test: .venv
33-
@$(VENV_PATH)/bin/tox -e py3.12
34-
.PHONY: test
35-
36-
test-all: .venv
37-
@TOXPATH=$(VENV_PATH)/bin/tox sh ./scripts/runtox.sh
38-
.PHONY: test-all
39-
40-
check: lint test
41-
.PHONY: check
42-
43-
lint: .venv
44-
@set -e && $(VENV_PATH)/bin/tox -e linters || ( \
45-
echo "================================"; \
46-
echo "Bad formatting? Run: make format"; \
47-
echo "================================"; \
48-
false)
49-
.PHONY: lint
50-
5125
apidocs: .venv
5226
@$(VENV_PATH)/bin/pip install --editable .
5327
@$(VENV_PATH)/bin/pip install -U -r ./requirements-docs.txt
5428
rm -rf docs/_build
5529
@$(VENV_PATH)/bin/sphinx-build -vv -W -b html docs/ docs/_build
5630
.PHONY: apidocs
5731

58-
apidocs-hotfix: apidocs
59-
@$(VENV_PATH)/bin/pip install ghp-import
60-
@$(VENV_PATH)/bin/ghp-import -pf docs/_build
61-
.PHONY: apidocs-hotfix
62-
6332
aws-lambda-layer: dist
6433
$(VENV_PATH)/bin/pip install -r requirements-aws-lambda-layer.txt
6534
$(VENV_PATH)/bin/python -m scripts.build_aws_lambda_layer

requirements-testing.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,6 @@ executing
1010
asttokens
1111
responses
1212
pysocks
13+
socksio
14+
httpcore[http2]
1315
setuptools

sentry_sdk/client.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
)
2424
from sentry_sdk.serializer import serialize
2525
from sentry_sdk.tracing import trace
26-
from sentry_sdk.transport import HttpTransport, make_transport
26+
from sentry_sdk.transport import BaseHttpTransport, make_transport
2727
from sentry_sdk.consts import (
2828
DEFAULT_MAX_VALUE_LENGTH,
2929
DEFAULT_OPTIONS,
@@ -61,6 +61,7 @@
6161
from sentry_sdk.metrics import MetricsAggregator
6262
from sentry_sdk.scope import Scope
6363
from sentry_sdk.session import Session
64+
from sentry_sdk.spotlight import SpotlightClient
6465
from sentry_sdk.transport import Transport
6566

6667
I = TypeVar("I", bound=Integration) # noqa: E741
@@ -153,6 +154,8 @@ class BaseClient:
153154
The basic definition of a client that is used for sending data to Sentry.
154155
"""
155156

157+
spotlight = None # type: Optional[SpotlightClient]
158+
156159
def __init__(self, options=None):
157160
# type: (Optional[Dict[str, Any]]) -> None
158161
self.options = (
@@ -385,7 +388,6 @@ def _capture_envelope(envelope):
385388
disabled_integrations=self.options["disabled_integrations"],
386389
)
387390

388-
self.spotlight = None
389391
spotlight_config = self.options.get("spotlight")
390392
if spotlight_config is None and "SENTRY_SPOTLIGHT" in os.environ:
391393
spotlight_env_value = os.environ["SENTRY_SPOTLIGHT"]
@@ -427,7 +429,7 @@ def _capture_envelope(envelope):
427429
self.monitor
428430
or self.metrics_aggregator
429431
or has_profiling_enabled(self.options)
430-
or isinstance(self.transport, HttpTransport)
432+
or isinstance(self.transport, BaseHttpTransport)
431433
):
432434
# If we have anything on that could spawn a background thread, we
433435
# need to check if it's safe to use them.

sentry_sdk/consts.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ class EndpointType(Enum):
6060
"otel_powered_performance": Optional[bool],
6161
"transport_zlib_compression_level": Optional[int],
6262
"transport_num_pools": Optional[int],
63+
"transport_http2": Optional[bool],
6364
"enable_metrics": Optional[bool],
6465
"before_emit_metric": Optional[
6566
Callable[[str, MetricValue, MeasurementUnit, MetricTags], bool]

sentry_sdk/integrations/bottle.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
Bottle,
3131
Route,
3232
request as bottle_request,
33-
HTTPResponse,
3433
__version__ as BOTTLE_VERSION,
3534
)
3635
except ImportError:
@@ -114,8 +113,6 @@ def wrapped_callback(*args, **kwargs):
114113

115114
try:
116115
res = prepared_callback(*args, **kwargs)
117-
except HTTPResponse:
118-
raise
119116
except Exception as exception:
120117
event, hint = event_from_exception(
121118
exception,

sentry_sdk/integrations/django/asgi.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,13 +90,15 @@ def patch_django_asgi_handler_impl(cls):
9090

9191
async def sentry_patched_asgi_handler(self, scope, receive, send):
9292
# type: (Any, Any, Any, Any) -> Any
93-
if sentry_sdk.get_client().get_integration(DjangoIntegration) is None:
93+
integration = sentry_sdk.get_client().get_integration(DjangoIntegration)
94+
if integration is None:
9495
return await old_app(self, scope, receive, send)
9596

9697
middleware = SentryAsgiMiddleware(
9798
old_app.__get__(self, cls),
9899
unsafe_context_data=True,
99100
span_origin=DjangoIntegration.origin,
101+
http_methods_to_capture=integration.http_methods_to_capture,
100102
)._run_asgi3
101103

102104
return await middleware(scope, receive, send)
@@ -142,13 +144,15 @@ def patch_channels_asgi_handler_impl(cls):
142144

143145
async def sentry_patched_asgi_handler(self, receive, send):
144146
# type: (Any, Any, Any 1241 ) -> Any
145-
if sentry_sdk.get_client().get_integration(DjangoIntegration) is None:
147+
integration = sentry_sdk.get_client().get_integration(DjangoIntegration)
148+
if integration is None:
146149
return await old_app(self, receive, send)
147150

148151
middleware = SentryAsgiMiddleware(
149152
lambda _scope: old_app.__get__(self, cls),
150153
unsafe_context_data=True,
151154
span_origin=DjangoIntegration.origin,
155+
http_methods_to_capture=integration.http_methods_to_capture,
152156
)
153157

154158
return await middleware(self.scope)(receive, send)

sentry_sdk/spotlight.py

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
import io
2+
import os
3+
import urllib.parse
4+
import urllib.request
5+
import urllib.error
26
import urllib3
37

48
from typing import TYPE_CHECKING
59

610
if TYPE_CHECKING:
711
from typing import Any
12+
from typing import Callable
813
from typing import Dict
914
from typing import Optional
1015

11-
from sentry_sdk.utils import logger
16+
from sentry_sdk.utils import logger, env_to_bool
1217
from sentry_sdk.envelope import Envelope
1318

1419

@@ -46,6 +51,47 @@ def capture_envelope(self, envelope):
4651
logger.warning(str(e))
4752

4853

54+
try:
55+
from django.http import HttpResponseServerError
56+
from django.conf import settings
57+
58+
class SpotlightMiddleware:
59+
def __init__(self, get_response):
60+
# type: (Any, Callable[..., Any]) -> None
61+
self.get_response = get_response
62+
63+
def __call__(self, request):
64+
# type: (Any, Any) -> Any
65+
return self.get_response(request)
66+
67+
def process_exception(self, _request, exception):
68+
# type: (Any, Any, Exception) -> Optional[HttpResponseServerError]
69+
if not settings.DEBUG:
70+
return None
71+
72+
import sentry_sdk.api
73+
74+
spotlight_client = sentry_sdk.api.get_client().spotlight
75+
if spotlight_client is None:
76+
return None
77+
78+
# Spotlight URL has a trailing `/stream` part at the end so split it off
79+
spotlight_url = spotlight_client.url.rsplit("/", 1)[0]
80+
81+
try:
82+
spotlight = (
83+
urllib.request.urlopen(spotlight_url).read().decode("utf-8")
84+
).replace("<html>", f'<html><base href="{spotlight_url}">')
85+
except urllib.error.URLError:
86+
return None
87+
else:
88+
sentry_sdk.api.capture_exception(exception)
89+
return HttpResponseServerError(spotlight)
90+
91+
except ImportError:
92+
settings = None
93+
94+
4995
def setup_spotlight(options):
5096
# type: (Dict[str, Any]) -> Optional[SpotlightClient]
5197

@@ -58,4 +104,9 @@ def setup_spotlight(options):
58104
else:
59105
return None
60106

107+
if settings is not None and env_to_bool(
108+
os.environ.get("SENTRY_SPOTLIGHT_ON_ERROR", "1")
109+
):
110+
settings.MIDDLEWARE.append("sentry_sdk.spotlight.SpotlightMiddleware")
111+
61112
return SpotlightClient(url)

sentry_sdk/tracing_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ def from_options(cls, scope):
532532
sentry_items["public_key"] = Dsn(options["dsn"]).public_key
533533

534534
if options.get("traces_sample_rate"):
535-
sentry_items["sample_rate"] = options["traces_sample_rate"]
535+
sentry_items["sample_rate"] = str(options["traces_sample_rate"])
536536

537537
return Baggage(sentry_items, third_party_items, mutable)
538538

0 commit comments

Comments
 (0)
0