Skip to content

Commit 662deba

Browse files
committed
Merge branch 'potel-base' into antonpirker/potel/back-pressure
2 parents 0aba891 + f266415 commit 662deba

28 files changed

+1200
-251
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: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,7 @@ executing
1010
asttokens
1111
responses
1212
pysocks
13+
socksio
14+
httpcore[http2]
1315
setuptools
14-
freezegun
16+
freezegun

sentry_sdk/client.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
)
2323
from sentry_sdk.serializer import serialize
2424
from sentry_sdk.tracing import trace
25-
from sentry_sdk.transport import HttpTransport, make_transport
25+
from sentry_sdk.transport import BaseHttpTransport, make_transport
2626
from sentry_sdk.consts import (
2727
DEFAULT_MAX_VALUE_LENGTH,
2828
DEFAULT_OPTIONS,
@@ -58,6 +58,7 @@
5858
from sentry_sdk.integrations import Integration
5959
from sentry_sdk.scope import Scope
6060
from sentry_sdk.session import Session
61+
from sentry_sdk.spotlight import SpotlightClient
6162
from sentry_sdk.transport import Transport
6263

6364
I = TypeVar("I", bound=Integration) # noqa: E741
@@ -139,6 +140,8 @@ class BaseClient:
139140
The basic definition of a client that is used for sending data to Sentry.
140141
"""
141142

143+
spotlight = None # type: Optional[SpotlightClient]
144+
142145
def __init__(self, options=None):
143146
# type: (Optional[Dict[str, Any]]) -> None
144147
self.options = (
@@ -337,7 +340,6 @@ def _capture_envelope(envelope):
337340
disabled_integrations=self.options["disabled_integrations"],
338341
)
339342

340-
self.spotlight = None
341343
spotlight_config = self.options.get("spotlight")
342344
if spotlight_config is None and "SENTRY_SPOTLIGHT" in os.environ:
343345
spotlight_env_value = os.environ["SENTRY_SPOTLIGHT"]
@@ -378,7 +380,7 @@ def _capture_envelope(envelope):
378380
if (
379381
self.monitor
380382
or has_profiling_enabled(self.options)
381-
or isinstance(self.transport, HttpTransport)
383+
or isinstance(self.transport, BaseHttpTransport)
382384
):
383385
# If we have anything on that could spawn a background thread, we
384386
# 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
@@ -57,6 +57,7 @@ class EndpointType(Enum):
5757
"otel_powered_performance": Optional[bool],
5858
"transport_zlib_compression_level": Optional[int],
5959
"transport_num_pools": Optional[int],
60+
"transport_http2": Optional[bool],
6061
},
6162
total=False,
6263
)

sentry_sdk/integrations/asgi.py

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import asyncio
88
import inspect
9+
from contextlib import nullcontext
910
from copy import deepcopy
1011
from functools import partial
1112

@@ -190,9 +191,10 @@ async def _run_app(self, scope, receive, send, asgi_version):
190191
)
191192

192193
method = scope.get("method", "").upper()
193-
if method in self.http_methods_to_capture:
194-
with sentry_sdk.continue_trace(_get_headers(scope)):
195-
with sentry_sdk.start_transaction(
194+
should_trace = method in self.http_methods_to_capture
195+
with sentry_sdk.continue_trace(_get_headers(scope)):
196+
with (
197+
sentry_sdk.start_transaction(
196198
op=(
197199
OP.WEBSOCKET_SERVER
198200
if ty == "websocket"
@@ -202,37 +204,42 @@ async def _run_app(self, scope, receive, send, asgi_version):
202204
source=transaction_source,
203205
origin=self.span_origin,
204206
custom_sampling_context={"asgi_scope": scope},
205-
) as transaction:
207+
)
208+
if should_trace
209+
else nullcontext()
210+
) as transaction:
211+
if transaction is not None:
206212
logger.debug(
207213
"[ASGI] Started transaction: %s", transaction
208214
)
209215
transaction.set_tag("asgi.type", ty)
210-
try:
211-
212-
async def _sentry_wrapped_send(event):
213-
# type: (Dict[str, Any]) -> Any
214-
is_http_response = (
215-
event.get("type") == "http.response.start"
216-
and "status" in event
217-
)
218-
if is_http_response:
219-
transaction.set_http_status(event["status"])
220-
221-
return await send(event)
222-
223-
if asgi_version == 2:
224-
return await self.app(scope)(
225-
receive, _sentry_wrapped_send
226-
)
227-
else:
228-
return await self.app(
229-
scope, receive, _sentry_wrapped_send
230-
)
231-
except Exception as exc:
232-
_capture_exception(
233-
exc, mechanism_type=self.mechanism_type
216+
try:
217+
218+
async def _sentry_wrapped_send(event):
219+
# type: (Dict[str, Any]) -> Any
220+
is_http_response = (
221+
event.get("type") == "http.response.start"
222+
and transaction is not None
223+
and "status" in event
234224
)
235-
raise exc from None
225+
if is_http_response:
226+
transaction.set_http_status(event["status"])
227+
228+
return await send(event)
229+
230+
if asgi_version == 2:
231+
return await self.app(scope)(
232+
receive, _sentry_wrapped_send
233+
)
234+
else:
235+
return await self.app(
236+
scope, receive, _sentry_wrapped_send
237+
)
238+
except Exception as exc:
239+
_capture_exception(
240+
exc, mechanism_type=self.mechanism_type
241+
)
242+
raise exc from None
236243
finally:
237244
_asgi_middleware_applied.set(False)
238245

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) -> 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/integrations/opentelemetry/consts.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from opentelemetry.context import create_key
2+
from sentry_sdk.tracing_utils import Baggage
23

34

45
# propagation keys
@@ -11,7 +12,8 @@
1112
SENTRY_USE_CURRENT_SCOPE_KEY = create_key("sentry_use_current_scope")
1213
SENTRY_USE_ISOLATION_SCOPE_KEY = create_key("sentry_use_isolation_scope")
1314

14-
SENTRY_TRACE_STATE_DROPPED = "sentry_dropped"
15+
TRACESTATE_SAMPLED_KEY = Baggage.SENTRY_PREFIX + "sampled"
16+
TRACESTATE_SAMPLE_RATE_KEY = Baggage.SENTRY_PREFIX + "sample_rate"
1517

1618
OTEL_SENTRY_CONTEXT = "otel"
1719
SPAN_ORIGIN = "auto.otel"

0 commit comments

Comments
 (0)