Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions MIGRATION_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ Looking to upgrade from Sentry SDK 2.x to 3.x? Here's a comprehensive list of wh
- Dropped support for Sanic below 22.0.
- Removed the possibility to supply a specific client to the LaunchDarklyIntegration.
- The `enable_tracing` option was removed. Use `traces_sample_rate=1.0` instead.
- The deprecated `@ai_track` decorator was removed.
- The deprecated `push_scope` and `configure_scope` APIs have been removed. Use `with new_scope():` to push a new scope and `scope = get_current_scope()` to retrieve the current scope instead.
- Transaction profiling and related code was removed.
- Removed the deprecated Hub class and all uses of hub throughout the SDK in arguments, options, etc. Use a scope instead.
Expand Down
162 changes: 0 additions & 162 deletions sentry_sdk/ai/monitoring.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
import inspect
import sys
import warnings
from contextvars import ContextVar
from functools import wraps
from typing import TYPE_CHECKING

import sentry_sdk.utils
from sentry_sdk import start_span
from sentry_sdk.ai.utils import _set_span_data_attribute
from sentry_sdk.consts import SPANDATA
from sentry_sdk.traces import StreamedSpan
from sentry_sdk.tracing import Span
from sentry_sdk.tracing_utils import has_span_streaming_enabled
from sentry_sdk.utils import capture_internal_exceptions, reraise

if TYPE_CHECKING:
from typing import Any, Awaitable, Callable, Optional, TypeVar, Union
Expand All @@ -32,160 +24,6 @@ def get_ai_pipeline_name() -> "Optional[str]":
return _ai_pipeline_name.get()


def ai_track(description: str, **span_kwargs: "Any") -> "Callable[[F], F]":
warnings.warn(
"sentry_sdk.ai.ai_track is deprecated and will be removed in version 3.0 of sentry-sdk. "
"Use the manual span API instead, e.g. sentry_sdk.start_span().",
DeprecationWarning,
stacklevel=2,
)

def decorator(f: "F") -> "F":
def sync_wrapped(*args: "Any", **kwargs: "Any") -> "Any":
client = sentry_sdk.get_client()

curr_pipeline = _ai_pipeline_name.get()
op = span_kwargs.pop("op", "ai.run" if curr_pipeline else "ai.pipeline")

if has_span_streaming_enabled(client.options):
with sentry_sdk.traces.start_span(
name=description, attributes={"sentry.op": op}
) as span:
for k, v in kwargs.pop("sentry_tags", {}).items():
span.set_attribute(k, v)
for k, v in kwargs.pop("sentry_data", {}).items():
span.set_attribute(k, v)

if curr_pipeline:
span.set_attribute(SPANDATA.GEN_AI_PIPELINE_NAME, curr_pipeline)
return f(*args, **kwargs)
else:
_ai_pipeline_name.set(description)
try:
res = f(*args, **kwargs)
except Exception as e:
exc_info = sys.exc_info()
with capture_internal_exceptions():
event, hint = sentry_sdk.utils.event_from_exception(
e,
client_options=sentry_sdk.get_client().options,
mechanism={
"type": "ai_monitoring",
"handled": False,
},
)
sentry_sdk.capture_event(event, hint=hint)
reraise(*exc_info)
finally:
_ai_pipeline_name.set(None)
return res

else:
with start_span(name=description, op=op, **span_kwargs) as span:
for k, v in kwargs.pop("sentry_tags", {}).items():
span.set_tag(k, v)
for k, v in kwargs.pop("sentry_data", {}).items():
span.set_data(k, v)
if curr_pipeline:
span.set_data(SPANDATA.GEN_AI_PIPELINE_NAME, curr_pipeline)
return f(*args, **kwargs)
else:
_ai_pipeline_name.set(description)
try:
res = f(*args, **kwargs)
except Exception as e:
exc_info = sys.exc_info()
with capture_internal_exceptions():
event, hint = sentry_sdk.utils.event_from_exception(
e,
client_options=sentry_sdk.get_client().options,
mechanism={
"type": "ai_monitoring",
"handled": False,
},
)
sentry_sdk.capture_event(event, hint=hint)
reraise(*exc_info)
finally:
_ai_pipeline_name.set(None)
return res

async def async_wrapped(*args: "Any", **kwargs: "Any") -> "Any":
client = sentry_sdk.get_client()

curr_pipeline = _ai_pipeline_name.get()
op = span_kwargs.pop("op", "ai.run" if curr_pipeline else "ai.pipeline")

if has_span_streaming_enabled(client.options):
with sentry_sdk.traces.start_span(
name=description, attributes={"sentry.op": op}
) as span:
for k, v in kwargs.pop("sentry_tags", {}).items():
span.set_attribute(k, v)
for k, v in kwargs.pop("sentry_data", {}).items():
span.set_attribute(k, v)

if curr_pipeline:
span.set_attribute(SPANDATA.GEN_AI_PIPELINE_NAME, curr_pipeline)
return await f(*args, **kwargs)
else:
_ai_pipeline_name.set(description)
try:
res = await f(*args, **kwargs)
except Exception as e:
exc_info = sys.exc_info()
with capture_internal_exceptions():
event, hint = sentry_sdk.utils.event_from_exception(
e,
client_options=sentry_sdk.get_client().options,
mechanism={
"type": "ai_monitoring",
"handled": False,
},
)
sentry_sdk.capture_event(event, hint=hint)
reraise(*exc_info)
finally:
_ai_pipeline_name.set(None)
return res
else:
with start_span(name=description, op=op, **span_kwargs) as span:
for k, v in kwargs.pop("sentry_tags", {}).items():
span.set_tag(k, v)
for k, v in kwargs.pop("sentry_data", {}).items():
span.set_data(k, v)
if curr_pipeline:
span.set_data(SPANDATA.GEN_AI_PIPELINE_NAME, curr_pipeline)
return await f(*args, **kwargs)
else:
_ai_pipeline_name.set(description)
try:
res = await f(*args, **kwargs)
except Exception as e:
exc_info = sys.exc_info()
with capture_internal_exceptions():
event, hint = sentry_sdk.utils.event_from_exception(
e,
client_options=sentry_sdk.get_client().options,
mechanism={
"type": "ai_monitoring",
"handled": False,
},
)
sentry_sdk.capture_event(event, hint=hint)
reraise(*exc_info)
finally:
_ai_pipeline_name.set(None)
return res

if inspect.iscoroutinefunction(f):
return wraps(f)(async_wrapped) # type: ignore
else:
return wraps(f)(sync_wrapped) # type: ignore

return decorator


def record_token_usage(
span: "Union[Span, StreamedSpan]",
input_tokens: "Optional[int]" = None,
Expand Down
23 changes: 3 additions & 20 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,6 @@
except ImportError:
gevent = None

try:
import eventlet
except ImportError:
eventlet = None

import sentry_sdk
import sentry_sdk.utils
from sentry_sdk.envelope import Envelope, parse_json
Expand Down Expand Up @@ -523,23 +518,11 @@ def read_flush(self):
# scope=session ensures that fixture is run earlier
@pytest.fixture(
scope="session",
params=[None, "eventlet", "gevent"],
ids=("threads", "eventlet", "greenlet"),
params=[None, "gevent"],
ids=("threads", "greenlet"),
)
def maybe_monkeypatched_threading(request):
if request.param == "eventlet":
if eventlet is None:
pytest.skip("no eventlet installed")

try:
eventlet.monkey_patch()
except AttributeError as e:
if "'thread.RLock' object has no attribute" in str(e):
# https://bitbucket.org/pypy/pypy/issues/2962/gevent-cannot-patch-rlock-under-pypy-27-7
pytest.skip("https://github.com/eventlet/eventlet/issues/546")
else:
raise
elif request.param == "gevent":
if request.param == "gevent":
if gevent is None:
pytest.skip("no gevent installed")
try:
Expand Down
Loading
Loading