Skip to content

Commit 57166a4

Browse files
committed
Merge branch 'master' into potel-base
2 parents a576bdc + aee87fb commit 57166a4

File tree

17 files changed

+561
-18
lines changed

17 files changed

+561
-18
lines changed

.github/workflows/test-integrations-data-processing.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ jobs:
6767
run: |
6868
set -x # print commands that are executed
6969
./scripts/runtox.sh "py${{ matrix.python-version }}-huey-latest"
70+
- name: Test ray latest
71+
run: |
72+
set -x # print commands that are executed
73+
./scripts/runtox.sh "py${{ matrix.python-version }}-ray-latest"
7074
- name: Test rq latest
7175
run: |
7276
set -x # print commands that are executed
@@ -139,6 +143,10 @@ jobs:
139143
run: |
140144
set -x # print commands that are executed
141145
./scripts/runtox.sh --exclude-latest "py${{ matrix.python-version }}-huey"
146+
- name: Test ray pinned
147+
run: |
148+
set -x # print commands that are executed
149+
./scripts/runtox.sh --exclude-latest "py${{ matrix.python-version }}-ray"
142150
- name: Test rq pinned
143151
run: |
144152
set -x # print commands that are executed

CHANGELOG.md

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,91 @@
11
# Changelog
22

3+
## 2.13.0
4+
5+
### Various fixes & improvements
6+
7+
- **New integration:** [Ray](https://docs.sentry.io/platforms/python/integrations/ray/) (#2400) (#2444) by @glowskir
8+
9+
Usage: (add the RayIntegration to your `sentry_sdk.init()` call and make sure it is called in the worker processes)
10+
```python
11+
import ray
12+
13+
import sentry_sdk
14+
from sentry_sdk.integrations.ray import RayIntegration
15+
16+
def init_sentry():
17+
sentry_sdk.init(
18+
dsn="...",
19+
traces_sample_rate=1.0,
20+
integrations=[RayIntegration()],
21+
)
22+
23+
init_sentry()
24+
25+
ray.init(
26+
runtime_env=dict(worker_process_setup_hook=init_sentry),
27+
)
28+
```
29+
For more information, see the documentation for the [Ray integration](https://docs.sentry.io/platforms/python/integrations/ray/).
30+
31+
- **New integration:** [Litestar](https://docs.sentry.io/platforms/python/integrations/litestar/) (#2413) (#3358) by @KellyWalker
32+
33+
Usage: (add the LitestarIntegration to your `sentry_sdk.init()`)
34+
```python
35+
from litestar import Litestar, get
36+
37+
import sentry_sdk
38+
from sentry_sdk.integrations.litestar import LitestarIntegration
39+
40+
sentry_sdk.init(
41+
dsn="...",
42+
traces_sample_rate=1.0,
43+
integrations=[LitestarIntegration()],
44+
)
45+
46+
@get("/")
47+
async def index() -> str:
48+
return "Hello, world!"
49+
50+
app = Litestar(...)
51+
```
52+
For more information, see the documentation for the [Litestar integration](https://docs.sentry.io/platforms/python/integrations/litestar/).
53+
54+
- **New integration:** [Dramatiq](https://docs.sentry.io/platforms/python/integrations/dramatiq/) from @jacobsvante (#3397) by @antonpirker
55+
Usage: (add the DramatiqIntegration to your `sentry_sdk.init()`)
56+
```python
57+
import dramatiq
58+
59+
import sentry_sdk
60+
from sentry_sdk.integrations.dramatiq import DramatiqIntegration
61+
62+
sentry_sdk.init(
63+
dsn="...",
64+
traces_sample_rate=1.0,
65+
integrations=[DramatiqIntegration()],
66+
)
67+
68+
@dramatiq.actor(max_retries=0)
69+
def dummy_actor(x, y):
70+
return x / y
71+
72+
dummy_actor.send(12, 0)
73+
```
74+
75+
For more information, see the documentation for the [Dramatiq integration](https://docs.sentry.io/platforms/python/integrations/dramatiq/).
76+
77+
- **New config option:** Expose `custom_repr` function that precedes `safe_repr` invocation in serializer (#3438) by @sl0thentr0py
78+
79+
See: https://docs.sentry.io/platforms/python/configuration/options/#custom-repr
80+
81+
- Profiling: Add client SDK info to profile chunk (#3386) by @Zylphrex
82+
- Serialize vars early to avoid living references (#3409) by @sl0thentr0py
83+
- Deprecate hub-based `sessions.py` logic (#3419) by @szokeasaurusrex
84+
- Deprecate `is_auto_session_tracking_enabled` (#3428) by @szokeasaurusrex
85+
- Add note to generated yaml files (#3423) by @sentrivana
86+
- Slim down PR template (#3382) by @sentrivana
87+
- Use new banner in readme (#3390) by @sentrivana
88+
389
## 2.12.0
490

591
### Various fixes & improvements

docs/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
copyright = "2019-{}, Sentry Team and Contributors".format(datetime.now().year)
2929
author = "Sentry Team and Contributors"
3030

31-
release = "2.12.0"
31+
release = "2.13.0"
3232
version = ".".join(release.split(".")[:2]) # The short X.Y version.
3333

3434

scripts/split-tox-gh-actions/split-tox-gh-actions.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
"celery",
8383
"dramatiq",
8484
"huey",
85+
"ray",
8586
"rq",
8687
"spark",
8788
],

sentry_sdk/client.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,7 @@ def _prepare_event(
526526
cast("Dict[str, Any]", event),
527527
max_request_body_size=self.options.get("max_request_body_size"),
528528
max_value_length=self.options.get("max_value_length"),
529+
custom_repr=self.options.get("custom_repr"),
529530
),
530531
)
531532

sentry_sdk/consts.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,8 @@ class OP:
460460
QUEUE_TASK_RQ = "queue.task.rq"
461461
QUEUE_SUBMIT_HUEY = "queue.submit.huey"
462462
QUEUE_TASK_HUEY = "queue.task.huey"
463+
QUEUE_SUBMIT_RAY = "queue.submit.ray"
464+
QUEUE_TASK_RAY = "queue.task.ray"
463465
SUBPROCESS = "subprocess"
464466
SUBPROCESS_WAIT = "subprocess.wait"
465467
SUBPROCESS_COMMUNICATE = "subprocess.communicate"
@@ -533,6 +535,7 @@ def __init__(
533535
spotlight=None, # type: Optional[Union[bool, str]]
534536
cert_file=None, # type: Optional[str]
535537
key_file=None, # type: Optional[str]
538+
custom_repr=None, # type: Optional[Callable[..., Optional[str]]]
536539
):
537540
# type: (...) -> None
538541
pass
@@ -558,4 +561,4 @@ def _get_default_options():
558561
del _get_default_options
559562

560563

561-
VERSION = "2.12.0"
564+
VERSION = "2.13.0"
Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
1-
from .server import ServerInterceptor # noqa: F401
2-
from .client import ClientInterceptor # noqa: F401
1+
from .server import ServerInterceptor
2+
from .client import ClientInterceptor
3+
4+
__all__ = [
5+
"ClientInterceptor",
6+
"ServerInterceptor",
7+
]
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
from sentry_sdk.integrations.opentelemetry.span_processor import ( # noqa: F401
2-
SentrySpanProcessor,
3-
)
1+
from sentry_sdk.integrations.opentelemetry.span_processor import SentrySpanProcessor
2+
from sentry_sdk.integrations.opentelemetry.propagator import SentryPropagator
43

5-
from sentry_sdk.integrations.opentelemetry.propagator import ( # noqa: F401
6-
SentryPropagator,
7-
)
4+
__all__ = [
5+
"SentryPropagator",
6+
"SentrySpanProcessor",
7+
]

sentry_sdk/integrations/ray.py

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
import inspect
2+
import sys
3+
4+
import sentry_sdk
5+
from sentry_sdk.consts import OP, SPANSTATUS
6+
from sentry_sdk.integrations import DidNotEnable, Integration
7+
from sentry_sdk.tracing import TRANSACTION_SOURCE_TASK
8+
from sentry_sdk.utils import (
9+
event_from_exception,
10+
logger,
11+
package_version,
12+
qualname_from_function,
13+
reraise,
14+
)
15+
16+
try:
17+
import ray # type: ignore[import-not-found]
18+
except ImportError:
19+
raise DidNotEnable("Ray not installed.")
20+
import functools
21+
22+
from typing import TYPE_CHECKING
23+
24+
if TYPE_CHECKING:
25+
from collections.abc import Callable
26+
from typing import Any, Optional
27+
from sentry_sdk.utils import ExcInfo
28+
29+
30+
def _check_sentry_initialized():
31+
# type: () -> None
32+
if sentry_sdk.get_client().is_active():
33+
return
34+
35+
logger.debug(
36+
"[Tracing] Sentry not initialized in ray cluster worker, performance data will be discarded."
37+
)
38+
39+
40+
def _patch_ray_remote():
41+
# type: () -> None
42+
old_remote = ray.remote
43+
44+
@functools.wraps(old_remote)
45+
def new_remote(f, *args, **kwargs):
46+
# type: (Callable[..., Any], *Any, **Any) -> Callable[..., Any]
47+
if inspect.isclass(f):
48+
# Ray Actors
49+
# (https://docs.ray.io/en/latest/ray-core/actors.html)
50+
# are not supported
51+
# (Only Ray Tasks are supported)
52+
return old_remote(f, *args, *kwargs)
53+
54+
def _f(*f_args, _tracing=None, **f_kwargs):
55+
# type: (Any, Optional[dict[str, Any]], Any) -> Any
56+
"""
57+
Ray Worker
58+
"""
59+
_check_sentry_initialized()
60+
61+
transaction = sentry_sdk.continue_trace(
62+
_tracing or {},
63+
op=OP.QUEUE_TASK_RAY,
64+
name=qualname_from_function(f),
65+
origin=RayIntegration.origin,
66+
source=TRANSACTION_SOURCE_TASK,
67+
)
68+
69+
with sentry_sdk.start_transaction(transaction) as transaction:
70+
try:
71+
result = f(*f_args, **f_kwargs)
72+
transaction.set_status(SPANSTATUS.OK)
73+
except Exception:
74+
transaction.set_status(SPANSTATUS.INTERNAL_ERROR)
75+
exc_info = sys.exc_info()
76+
_capture_exception(exc_info)
77+
reraise(*exc_info)
78+
79+
return result
80+
81+
rv = old_remote(_f, *args, *kwargs)
82+
old_remote_method = rv.remote
83+
84+
def _remote_method_with_header_propagation(*args, **kwargs):
85+
# type: (*Any, **Any) -> Any
86+
"""
87+
Ray Client
88+
"""
89+
with sentry_sdk.start_span(
90+
op=OP.QUEUE_SUBMIT_RAY,
91+
description=qualname_from_function(f),
92+
origin=RayIntegration.origin,
93+
) as span:
94+
tracing = {
95+
k: v
96+
for k, v in sentry_sdk.get_current_scope().iter_trace_propagation_headers()
97+
}
98+
try:
99+
result = old_remote_method(*args, **kwargs, _tracing=tracing)
100+
span.set_status(SPANSTATUS.OK)
101+
except Exception:
102+
span.set_status(SPANSTATUS.INTERNAL_ERROR)
103+
exc_info = sys.exc_info()
104+
_capture_exception(exc_info)
105+
reraise(*exc_info)
106+
107+
return result
108+
109+
rv.remote = _remote_method_with_header_propagation
110+
111+
return rv
112+
113+
ray.remote = new_remote
114+
115+
116+
def _capture_exception(exc_info, **kwargs):
117+
# type: (ExcInfo, **Any) -> None
118+
client = sentry_sdk.get_client()
119+
120+
event, hint = event_from_exception(
121+
exc_info,
122+
client_options=client.options,
123+
mechanism={
124+
"handled": False,
125+
"type": RayIntegration.identifier,
126+
},
127+
)
128+
sentry_sdk.capture_event(event, hint=hint)
129+
130+
131+
class RayIntegration(Integration):
132+
identifier = "ray"
133+
origin = f"auto.queue.{identifier}"
134+
135+
@staticmethod
136+
def setup_once():
137+
# type: () -> None
138+
version = package_version("ray")
139+
140+
if version is None:
141+
raise DidNotEnable("Unparsable ray version: {}".format(version))
142+
143+
if version < (2, 7, 0):
144+
raise DidNotEnable("Ray 2.7.0 or newer required")
145+
146+
_patch_ray_remote()

0 commit comments

Comments
 (0)