Skip to content

Commit 8aacd66

Browse files
Merge branch 'master' into webb/requirements-testing/tomli
2 parents 28f062d + d23563a commit 8aacd66

13 files changed

Lines changed: 204 additions & 115 deletions

File tree

docs/_static/.gitkeep

Whitespace-only changes.

docs/_static/logo-dark.svg

Lines changed: 42 additions & 0 deletions
Loading

docs/_static/logo-light.svg

Lines changed: 41 additions & 0 deletions
Loading

docs/conf.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@
9595
# documentation.
9696
#
9797
html_theme_options = {
98+
"light_logo": "_static/logo-light.svg",
99+
"dark_logo": "_static/logo-dark.svg",
98100
"github_url": "https://github.com/getsentry/sentry-python",
99101
}
100102

requirements-testing.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
pip
21
pytest>=6.0.0
32
pytest-cov
43
pytest-forked
54
pytest-localserver
65
pytest-timeout
7-
pytest-watch
86
jsonschema
97
executing
108
asttokens

sentry_sdk/consts.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,6 +1180,8 @@ class OP:
11801180
COHERE_CHAT_COMPLETIONS_CREATE = "ai.chat_completions.create.cohere"
11811181
COHERE_EMBEDDINGS_CREATE = "ai.embeddings.create.cohere"
11821182
DB = "db"
1183+
DB_CURSOR_ITERATOR = "db.cursor.iter"
1184+
DB_CURSOR_FETCH = "db.cursor.fetch"
11831185
DB_REDIS = "db.redis"
11841186
EVENT_DJANGO = "event.django"
11851187
FUNCTION = "function"

sentry_sdk/integrations/asyncpg.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,12 @@
2020
)
2121

2222
try:
23-
import asyncpg # type: ignore[import-not-found]
24-
from asyncpg.cursor import BaseCursor # type: ignore
23+
import asyncpg # type: ignore
24+
from asyncpg.cursor import ( # type: ignore
25+
BaseCursor,
26+
Cursor,
27+
CursorIterator,
28+
)
2529

2630
except ImportError:
2731
raise DidNotEnable("asyncpg not installed.")
@@ -169,6 +173,13 @@ async def _inner(*args: "Any", **kwargs: "Any") -> "T":
169173
return await f(*args, **kwargs)
170174

171175
cursor = args[0]
176+
if type(cursor) is CursorIterator:
177+
span_op_override_value = OP.DB_CURSOR_ITERATOR
178+
elif type(cursor) is Cursor:
179+
span_op_override_value = OP.DB_CURSOR_FETCH
180+
else:
181+
span_op_override_value = None
182+
172183
query = _normalize_query(cursor._query)
173184
with record_sql_queries(
174185
cursor=cursor,
@@ -178,6 +189,7 @@ async def _inner(*args: "Any", **kwargs: "Any") -> "T":
178189
executemany=False,
179190
record_cursor_repr=True,
180191
span_origin=AsyncPGIntegration.origin,
192+
span_op_override_value=span_op_override_value,
181193
) as span:
182194
_set_db_data(span, cursor._connection)
183195
res = await f(*args, **kwargs)

sentry_sdk/integrations/langchain.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,8 @@ class LangchainIntegration(Integration):
210210
identifier = "langchain"
211211
origin = f"auto.ai.{identifier}"
212212

213+
_ignored_exceptions: "set[type[Exception]]" = set()
214+
213215
def __init__(
214216
self: "LangchainIntegration",
215217
include_prompts: bool = True,
@@ -262,17 +264,22 @@ def gc_span_map(self) -> None:
262264
self._exit_span(span, run_id)
263265

264266
def _handle_error(self, run_id: "UUID", error: "Any") -> None:
267+
is_ignored = isinstance(error, tuple(LangchainIntegration._ignored_exceptions))
268+
265269
with capture_internal_exceptions():
266270
if not run_id or run_id not in self.span_map:
267271
return
268272

269273
span = self.span_map[run_id]
270274

271-
sentry_sdk.capture_exception(
272-
error, span._scope if isinstance(span, StreamedSpan) else span.scope
273-
)
275+
if is_ignored:
276+
span.__exit__(None, None, None)
277+
else:
278+
sentry_sdk.capture_exception(
279+
error, span._scope if isinstance(span, StreamedSpan) else span.scope
280+
)
281+
span.__exit__(type(error), error, error.__traceback__)
274282

275-
span.__exit__(type(error), error, error.__traceback__)
276283
del self.span_map[run_id]
277284

278285
def _normalize_langchain_message(self, message: "BaseMessage") -> "Any":

sentry_sdk/integrations/langgraph.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
)
1111
from sentry_sdk.consts import OP, SPANDATA
1212
from sentry_sdk.integrations import DidNotEnable, Integration
13+
14+
# This is fine because langgraph depends on langchain-base, and LangchainIntegration only imports from langchain-base.
15+
from sentry_sdk.integrations.langchain import LangchainIntegration
1316
from sentry_sdk.scope import should_send_default_pii
1417
from sentry_sdk.traces import StreamedSpan
1518
from sentry_sdk.tracing_utils import (
@@ -19,6 +22,7 @@
1922
from sentry_sdk.utils import safe_serialize
2023

2124
try:
25+
from langgraph.errors import GraphBubbleUp
2226
from langgraph.graph import StateGraph
2327
from langgraph.pregel import Pregel
2428
except ImportError:
@@ -34,6 +38,7 @@ def __init__(self: "LanggraphIntegration", include_prompts: bool = True) -> None
3438

3539
@staticmethod
3640
def setup_once() -> None:
41+
LangchainIntegration._ignored_exceptions.add(GraphBubbleUp)
3742
# LangGraph lets users create agents using a StateGraph or the Functional API.
3843
# StateGraphs are then compiled to a CompiledStateGraph. Both CompiledStateGraph and
3944
# the functional API execute on a Pregel instance. Pregel is the runtime for the graph

sentry_sdk/tracing_utils.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ def record_sql_queries(
134134
executemany: bool,
135135
record_cursor_repr: bool = False,
136136
span_origin: str = "manual",
137+
span_op_override_value: "Optional[str]" = None,
137138
) -> "Generator[Union[sentry_sdk.tracing.Span, sentry_sdk.traces.StreamedSpan], None, None]":
138139
# TODO: Bring back capturing of params by default
139140
client = sentry_sdk.get_client()
@@ -167,13 +168,15 @@ def record_sql_queries(
167168
name="<unknown SQL query>" if query is None else query,
168169
attributes={
169170
"sentry.origin": span_origin,
170-
"sentry.op": OP.DB,
171+
"sentry.op": span_op_override_value
172+
if span_op_override_value
173+
else OP.DB,
171174
},
172175
) as span:
173176
yield span
174177
else:
175178
with sentry_sdk.start_span(
176-
op=OP.DB,
179+
op=span_op_override_value if span_op_override_value is not None else OP.DB,
177180
name=query,
178181
origin=span_origin,
179182
) as span:

0 commit comments

Comments
 (0)