Skip to content

Commit 2725322

Browse files
committed
Merge branch 'master' into potel-base
2 parents 245195e + 0fb9606 commit 2725322

File tree

5 files changed

+80
-15
lines changed

5 files changed

+80
-15
lines changed

sentry_sdk/integrations/celery/__init__.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040

4141
try:
4242
from celery import VERSION as CELERY_VERSION # type: ignore
43+
from celery.app.task import Task # type: ignore
4344
from celery.app.trace import task_has_custom
4445
from celery.exceptions import ( # type: ignore
4546
Ignore,
@@ -82,6 +83,7 @@ def setup_once():
8283

8384
_patch_build_tracer()
8485
_patch_task_apply_async()
86+
_patch_celery_send_task()
8587
_patch_worker_exit()
8688
_patch_producer_publish()
8789

@@ -242,7 +244,7 @@ def __exit__(self, exc_type, exc_value, traceback):
242244
return None
243245

244246

245-
def _wrap_apply_async(f):
247+
def _wrap_task_run(f):
246248
# type: (F) -> F
247249
@wraps(f)
248250
@ensure_integration_enabled(CeleryIntegration, f)
@@ -259,14 +261,19 @@ def apply_async(*args, **kwargs):
259261
if not propagate_traces:
260262
return f(*args, **kwargs)
261263

262-
task = args[0]
264+
if isinstance(args[0], Task):
265+
task_name = args[0].name # type: str
266+
elif len(args) > 1 and isinstance(args[1], str):
267+
task_name = args[1]
268+
else:
269+
task_name = "<unknown Celery task>"
263270

264271
task_started_from_beat = sentry_sdk.get_isolation_scope()._name == "celery-beat"
265272

266273
span_mgr = (
267274
sentry_sdk.start_span(
268275
op=OP.QUEUE_SUBMIT_CELERY,
269-
description=task.name,
276+
description=task_name,
270277
origin=CeleryIntegration.origin,
271278
)
272279
if not task_started_from_beat
@@ -425,9 +432,14 @@ def sentry_build_tracer(name, task, *args, **kwargs):
425432

426433
def _patch_task_apply_async():
427434
# type: () -> None
428-
from celery.app.task import Task # type: ignore
435+
Task.apply_async = _wrap_task_run(Task.apply_async)
436+
437+
438+
def _patch_celery_send_task():
439+
# type: () -> None
440+
from celery import Celery
429441

430-
Task.apply_async = _wrap_apply_async(Task.apply_async)
442+
Celery.send_task = _wrap_task_run(Celery.send_task)
431443

432444

433445
def _patch_worker_exit():

sentry_sdk/integrations/django/middleware.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@
3030
"import_string_should_wrap_middleware"
3131
)
3232

33-
if DJANGO_VERSION < (3, 1):
33+
DJANGO_SUPPORTS_ASYNC_MIDDLEWARE = DJANGO_VERSION >= (3, 1)
34+
35+
if not DJANGO_SUPPORTS_ASYNC_MIDDLEWARE:
3436
_asgi_middleware_mixin_factory = lambda _: object
3537
else:
3638
from .asgi import _asgi_middleware_mixin_factory
@@ -123,7 +125,9 @@ def sentry_wrapped_method(*args, **kwargs):
123125
class SentryWrappingMiddleware(
124126
_asgi_middleware_mixin_factory(_check_middleware_span) # type: ignore
125127
):
126-
async_capable = getattr(middleware, "async_capable", False)
128+
async_capable = DJANGO_SUPPORTS_ASYNC_MIDDLEWARE and getattr(
129+
middleware, "async_capable", False
130+
)
127131

128132
def __init__(self, get_response=None, *args, **kwargs):
129133
# type: (Optional[Callable[..., Any]], *Any, **Any) -> None

sentry_sdk/integrations/strawberry.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@
3737
from typing import TYPE_CHECKING
3838

3939
if TYPE_CHECKING:
40-
from typing import Any, Callable, Generator, List, Optional
40+
from typing import Any, Callable, Generator, List, Optional, Union
4141
from graphql import GraphQLError, GraphQLResolveInfo # type: ignore
4242
from strawberry.http import GraphQLHTTPResponse
43-
from strawberry.types import ExecutionContext, ExecutionResult # type: ignore
43+
from strawberry.types import ExecutionContext, ExecutionResult, SubscriptionExecutionResult # type: ignore
4444
from sentry_sdk._types import Event, EventProcessor
4545

4646

@@ -279,13 +279,13 @@ def _patch_execute():
279279
old_execute_sync = strawberry_schema.execute_sync
280280

281281
async def _sentry_patched_execute_async(*args, **kwargs):
282-
# type: (Any, Any) -> ExecutionResult
282+
# type: (Any, Any) -> Union[ExecutionResult, SubscriptionExecutionResult]
283283
result = await old_execute_async(*args, **kwargs)
284284

285285
if sentry_sdk.get_client().get_integration(StrawberryIntegration) is None:
286286
return result
287287

288-
if "execution_context" in kwargs and result.errors:
288+
if "execution_context" in kwargs:
289289
scope = sentry_sdk.get_isolation_scope()
290290
event_processor = _make_request_event_processor(kwargs["execution_context"])
291291
scope.add_event_processor(event_processor)
@@ -297,7 +297,7 @@ def _sentry_patched_execute_sync(*args, **kwargs):
297297
# type: (Any, Any) -> ExecutionResult
298298
result = old_execute_sync(*args, **kwargs)
299299

300-
if "execution_context" in kwargs and result.errors:
300+
if "execution_context" in kwargs:
301301
scope = sentry_sdk.get_isolation_scope()
302302
event_processor = _make_request_event_processor(kwargs["execution_context"])
303303
scope.add_event_processor(event_processor)

tests/integrations/celery/test_celery.py

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from sentry_sdk import start_transaction, get_current_span
1111
from sentry_sdk.integrations.celery import (
1212
CeleryIntegration,
13-
_wrap_apply_async,
13+
_wrap_task_run,
1414
)
1515
from sentry_sdk.integrations.celery.beat import _get_headers
1616
from tests.conftest import ApproxDict
@@ -568,7 +568,7 @@ def dummy_function(*args, **kwargs):
568568
assert "sentry-trace" in headers
569569
assert "baggage" in headers
570570

571-
wrapped = _wrap_apply_async(dummy_function)
571+
wrapped = _wrap_task_run(dummy_function)
572572
wrapped(mock.MagicMock(), (), headers={})
573573

574574

@@ -783,3 +783,51 @@ def task(): ...
783783
assert span["origin"] == "auto.queue.celery"
784784

785785
monkeypatch.setattr(kombu.messaging.Producer, "_publish", old_publish)
786+
787+
788+
@pytest.mark.forked
789+
@mock.patch("celery.Celery.send_task")
790+
def test_send_task_wrapped(
791+
patched_send_task,
792+
sentry_init,
793+
capture_events,
794+
reset_integrations,
795+
):
796+
sentry_init(integrations=[CeleryIntegration()], enable_tracing=True)
797+
celery = Celery(__name__, broker="redis://example.com") # noqa: E231
798+
799+
events = capture_events()
800+
801+
with sentry_sdk.start_transaction(name="custom_transaction"):
802+
celery.send_task("very_creative_task_name", args=(1, 2), kwargs={"foo": "bar"})
803+
804+
(call,) = patched_send_task.call_args_list # We should have exactly one call
805+
(args, kwargs) = call
806+
807+
assert args == (celery, "very_creative_task_name")
808+
assert kwargs["args"] == (1, 2)
809+
assert kwargs["kwargs"] == {"foo": "bar"}
810+
assert set(kwargs["headers"].keys()) == {
811+
"sentry-task-enqueued-time",
812+
"sentry-trace",
813+
"baggage",
814+
"headers",
815+
}
816+
assert set(kwargs["headers"]["headers"].keys()) == {
817+
"sentry-trace",
818+
"baggage",
819+
"sentry-task-enqueued-time",
820+
}
821+
assert (
822+
kwargs["headers"]["sentry-trace"]
823+
== kwargs["headers"]["headers"]["sentry-trace"]
824+
)
825+
826+
(event,) = events # We should have exactly one event (the transaction)
827+
assert event["type"] == "transaction"
828+
assert event["transaction"] == "custom_transaction"
829+
830+
(span,) = event["spans"] # We should have exactly one span
831+
assert span["description"] == "very_creative_task_name"
832+
assert span["op"] == "queue.submit.celery"
833+
assert span["trace_id"] == kwargs["headers"]["sentry-trace"].split("-")[0]

tox.ini

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,8 @@ deps =
361361

362362
# Celery
363363
celery: redis
364+
celery: newrelic
365+
celery: pytest<7
364366
celery-v4: Celery~=4.0
365367
celery-v5.0: Celery~=5.0.0
366368
celery-v5.1: Celery~=5.1.0
@@ -370,7 +372,6 @@ deps =
370372
celery-latest: Celery
371373

372374
{py3.7}-celery: importlib-metadata<5.0
373-
{py3.7,py3.8,py3.9,py3.10,py3.11,py3.12}-celery: newrelic
374375

375376
# Chalice
376377
chalice-v1.16: chalice~=1.16.0

0 commit comments

Comments
 (0)