sentry-sdk 2.26.1__py2.py3-none-any.whl → 3.0.0a1__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of sentry-sdk might be problematic. Click here for more details.
- sentry_sdk/__init__.py +4 -8
- sentry_sdk/_compat.py +0 -1
- sentry_sdk/_init_implementation.py +6 -44
- sentry_sdk/_log_batcher.py +47 -28
- sentry_sdk/_types.py +8 -64
- sentry_sdk/ai/monitoring.py +14 -10
- sentry_sdk/ai/utils.py +1 -1
- sentry_sdk/api.py +69 -163
- sentry_sdk/client.py +25 -72
- sentry_sdk/consts.py +42 -23
- sentry_sdk/debug.py +0 -10
- sentry_sdk/envelope.py +2 -10
- sentry_sdk/feature_flags.py +5 -1
- sentry_sdk/integrations/__init__.py +5 -2
- sentry_sdk/integrations/_asgi_common.py +3 -3
- sentry_sdk/integrations/_wsgi_common.py +11 -40
- sentry_sdk/integrations/aiohttp.py +104 -57
- sentry_sdk/integrations/anthropic.py +10 -7
- sentry_sdk/integrations/arq.py +24 -13
- sentry_sdk/integrations/asgi.py +103 -83
- sentry_sdk/integrations/asyncio.py +1 -0
- sentry_sdk/integrations/asyncpg.py +45 -30
- sentry_sdk/integrations/aws_lambda.py +109 -92
- sentry_sdk/integrations/boto3.py +38 -9
- sentry_sdk/integrations/bottle.py +1 -1
- sentry_sdk/integrations/celery/__init__.py +48 -38
- sentry_sdk/integrations/clickhouse_driver.py +59 -28
- sentry_sdk/integrations/cohere.py +2 -0
- sentry_sdk/integrations/django/__init__.py +25 -46
- sentry_sdk/integrations/django/asgi.py +6 -2
- sentry_sdk/integrations/django/caching.py +13 -22
- sentry_sdk/integrations/django/middleware.py +1 -0
- sentry_sdk/integrations/django/signals_handlers.py +3 -1
- sentry_sdk/integrations/django/templates.py +8 -12
- sentry_sdk/integrations/django/transactions.py +1 -6
- sentry_sdk/integrations/django/views.py +5 -2
- sentry_sdk/integrations/falcon.py +7 -25
- sentry_sdk/integrations/fastapi.py +3 -3
- sentry_sdk/integrations/flask.py +1 -1
- sentry_sdk/integrations/gcp.py +63 -38
- sentry_sdk/integrations/graphene.py +6 -13
- sentry_sdk/integrations/grpc/aio/client.py +14 -8
- sentry_sdk/integrations/grpc/aio/server.py +19 -21
- sentry_sdk/integrations/grpc/client.py +8 -6
- sentry_sdk/integrations/grpc/server.py +12 -14
- sentry_sdk/integrations/httpx.py +47 -12
- sentry_sdk/integrations/huey.py +26 -22
- sentry_sdk/integrations/huggingface_hub.py +1 -0
- sentry_sdk/integrations/langchain.py +22 -15
- sentry_sdk/integrations/launchdarkly.py +3 -3
- sentry_sdk/integrations/litestar.py +4 -2
- sentry_sdk/integrations/logging.py +12 -3
- sentry_sdk/integrations/openai.py +2 -0
- sentry_sdk/integrations/openfeature.py +3 -5
- sentry_sdk/integrations/pymongo.py +18 -25
- sentry_sdk/integrations/pyramid.py +1 -1
- sentry_sdk/integrations/quart.py +3 -3
- sentry_sdk/integrations/ray.py +23 -17
- sentry_sdk/integrations/redis/_async_common.py +30 -18
- sentry_sdk/integrations/redis/_sync_common.py +28 -18
- sentry_sdk/integrations/redis/modules/caches.py +13 -10
- sentry_sdk/integrations/redis/modules/queries.py +14 -11
- sentry_sdk/integrations/redis/rb.py +4 -4
- sentry_sdk/integrations/redis/redis.py +6 -6
- sentry_sdk/integrations/redis/redis_cluster.py +18 -16
- sentry_sdk/integrations/redis/redis_py_cluster_legacy.py +4 -4
- sentry_sdk/integrations/redis/utils.py +63 -19
- sentry_sdk/integrations/rq.py +68 -23
- sentry_sdk/integrations/rust_tracing.py +28 -43
- sentry_sdk/integrations/sanic.py +23 -13
- sentry_sdk/integrations/socket.py +9 -5
- sentry_sdk/integrations/sqlalchemy.py +8 -8
- sentry_sdk/integrations/starlette.py +11 -31
- sentry_sdk/integrations/starlite.py +4 -2
- sentry_sdk/integrations/stdlib.py +56 -9
- sentry_sdk/integrations/strawberry.py +40 -59
- sentry_sdk/integrations/threading.py +10 -26
- sentry_sdk/integrations/tornado.py +57 -18
- sentry_sdk/integrations/trytond.py +4 -1
- sentry_sdk/integrations/unleash.py +2 -3
- sentry_sdk/integrations/wsgi.py +84 -38
- sentry_sdk/opentelemetry/__init__.py +9 -0
- sentry_sdk/opentelemetry/consts.py +33 -0
- sentry_sdk/opentelemetry/contextvars_context.py +73 -0
- sentry_sdk/{integrations/opentelemetry → opentelemetry}/propagator.py +19 -28
- sentry_sdk/opentelemetry/sampler.py +326 -0
- sentry_sdk/opentelemetry/scope.py +218 -0
- sentry_sdk/opentelemetry/span_processor.py +329 -0
- sentry_sdk/opentelemetry/tracing.py +35 -0
- sentry_sdk/opentelemetry/utils.py +476 -0
- sentry_sdk/profiler/__init__.py +0 -40
- sentry_sdk/profiler/continuous_profiler.py +1 -30
- sentry_sdk/profiler/transaction_profiler.py +5 -56
- sentry_sdk/scope.py +107 -351
- sentry_sdk/sessions.py +0 -87
- sentry_sdk/tracing.py +418 -1134
- sentry_sdk/tracing_utils.py +134 -169
- sentry_sdk/transport.py +4 -104
- sentry_sdk/types.py +26 -2
- sentry_sdk/utils.py +169 -152
- {sentry_sdk-2.26.1.dist-info → sentry_sdk-3.0.0a1.dist-info}/METADATA +3 -5
- sentry_sdk-3.0.0a1.dist-info/RECORD +154 -0
- {sentry_sdk-2.26.1.dist-info → sentry_sdk-3.0.0a1.dist-info}/WHEEL +1 -1
- sentry_sdk-3.0.0a1.dist-info/entry_points.txt +2 -0
- sentry_sdk/hub.py +0 -739
- sentry_sdk/integrations/opentelemetry/__init__.py +0 -7
- sentry_sdk/integrations/opentelemetry/consts.py +0 -5
- sentry_sdk/integrations/opentelemetry/integration.py +0 -58
- sentry_sdk/integrations/opentelemetry/span_processor.py +0 -391
- sentry_sdk/metrics.py +0 -965
- sentry_sdk-2.26.1.dist-info/RECORD +0 -152
- sentry_sdk-2.26.1.dist-info/entry_points.txt +0 -2
- {sentry_sdk-2.26.1.dist-info → sentry_sdk-3.0.0a1.dist-info}/licenses/LICENSE +0 -0
- {sentry_sdk-2.26.1.dist-info → sentry_sdk-3.0.0a1.dist-info}/top_level.txt +0 -0
|
@@ -3,9 +3,9 @@ from copy import deepcopy
|
|
|
3
3
|
from functools import wraps
|
|
4
4
|
|
|
5
5
|
import sentry_sdk
|
|
6
|
+
from sentry_sdk.consts import SOURCE_FOR_STYLE, TransactionSource
|
|
6
7
|
from sentry_sdk.integrations import DidNotEnable
|
|
7
8
|
from sentry_sdk.scope import should_send_default_pii
|
|
8
|
-
from sentry_sdk.tracing import SOURCE_FOR_STYLE, TransactionSource
|
|
9
9
|
from sentry_sdk.utils import (
|
|
10
10
|
transaction_from_function,
|
|
11
11
|
logger,
|
|
@@ -89,8 +89,8 @@ def patch_get_request_handler():
|
|
|
89
89
|
def _sentry_call(*args, **kwargs):
|
|
90
90
|
# type: (*Any, **Any) -> Any
|
|
91
91
|
current_scope = sentry_sdk.get_current_scope()
|
|
92
|
-
if current_scope.
|
|
93
|
-
current_scope.
|
|
92
|
+
if current_scope.root_span is not None:
|
|
93
|
+
current_scope.root_span.update_active_thread()
|
|
94
94
|
|
|
95
95
|
sentry_scope = sentry_sdk.get_isolation_scope()
|
|
96
96
|
if sentry_scope.profile is not None:
|
sentry_sdk/integrations/flask.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import sentry_sdk
|
|
2
|
+
from sentry_sdk.consts import SOURCE_FOR_STYLE
|
|
2
3
|
from sentry_sdk.integrations import _check_minimum_version, DidNotEnable, Integration
|
|
3
4
|
from sentry_sdk.integrations._wsgi_common import (
|
|
4
5
|
DEFAULT_HTTP_METHODS_TO_CAPTURE,
|
|
@@ -6,7 +7,6 @@ from sentry_sdk.integrations._wsgi_common import (
|
|
|
6
7
|
)
|
|
7
8
|
from sentry_sdk.integrations.wsgi import SentryWsgiMiddleware
|
|
8
9
|
from sentry_sdk.scope import should_send_default_pii
|
|
9
|
-
from sentry_sdk.tracing import SOURCE_FOR_STYLE
|
|
10
10
|
from sentry_sdk.utils import (
|
|
11
11
|
capture_internal_exceptions,
|
|
12
12
|
ensure_integration_enabled,
|
sentry_sdk/integrations/gcp.py
CHANGED
|
@@ -5,10 +5,12 @@ from datetime import datetime, timedelta, timezone
|
|
|
5
5
|
from os import environ
|
|
6
6
|
|
|
7
7
|
import sentry_sdk
|
|
8
|
-
from sentry_sdk.api import continue_trace
|
|
9
8
|
from sentry_sdk.consts import OP
|
|
10
9
|
from sentry_sdk.integrations import Integration
|
|
11
|
-
from sentry_sdk.integrations._wsgi_common import
|
|
10
|
+
from sentry_sdk.integrations._wsgi_common import (
|
|
11
|
+
_filter_headers,
|
|
12
|
+
_request_headers_to_span_attributes,
|
|
13
|
+
)
|
|
12
14
|
from sentry_sdk.scope import should_send_default_pii
|
|
13
15
|
from sentry_sdk.tracing import TransactionSource
|
|
14
16
|
from sentry_sdk.utils import (
|
|
@@ -84,42 +86,30 @@ def _wrap_func(func):
|
|
|
84
86
|
if hasattr(gcp_event, "headers"):
|
|
85
87
|
headers = gcp_event.headers
|
|
86
88
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
sentry_event, hint = event_from_exception(
|
|
112
|
-
exc_info,
|
|
113
|
-
client_options=client.options,
|
|
114
|
-
mechanism={"type": "gcp", "handled": False},
|
|
115
|
-
)
|
|
116
|
-
sentry_sdk.capture_event(sentry_event, hint=hint)
|
|
117
|
-
reraise(*exc_info)
|
|
118
|
-
finally:
|
|
119
|
-
if timeout_thread:
|
|
120
|
-
timeout_thread.stop()
|
|
121
|
-
# Flush out the event queue
|
|
122
|
-
client.flush()
|
|
89
|
+
with sentry_sdk.continue_trace(headers):
|
|
90
|
+
with sentry_sdk.start_span(
|
|
91
|
+
op=OP.FUNCTION_GCP,
|
|
92
|
+
name=environ.get("FUNCTION_NAME", ""),
|
|
93
|
+
source=TransactionSource.COMPONENT,
|
|
94
|
+
origin=GcpIntegration.origin,
|
|
95
|
+
attributes=_prepopulate_attributes(gcp_event),
|
|
96
|
+
):
|
|
97
|
+
try:
|
|
98
|
+
return func(functionhandler, gcp_event, *args, **kwargs)
|
|
99
|
+
except Exception:
|
|
100
|
+
exc_info = sys.exc_info()
|
|
101
|
+
sentry_event, hint = event_from_exception(
|
|
102
|
+
exc_info,
|
|
103
|
+
client_options=client.options,
|
|
104
|
+
mechanism={"type": "gcp", "handled": False},
|
|
105
|
+
)
|
|
106
|
+
sentry_sdk.capture_event(sentry_event, hint=hint)
|
|
107
|
+
reraise(*exc_info)
|
|
108
|
+
finally:
|
|
109
|
+
if timeout_thread:
|
|
110
|
+
timeout_thread.stop()
|
|
111
|
+
# Flush out the event queue
|
|
112
|
+
client.flush()
|
|
123
113
|
|
|
124
114
|
return sentry_func # type: ignore
|
|
125
115
|
|
|
@@ -232,3 +222,38 @@ def _get_google_cloud_logs_url(final_time):
|
|
|
232
222
|
)
|
|
233
223
|
|
|
234
224
|
return url
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
ENV_TO_ATTRIBUTE = {
|
|
228
|
+
"FUNCTION_NAME": "faas.name",
|
|
229
|
+
"ENTRY_POINT": "gcp.function.entry_point",
|
|
230
|
+
"FUNCTION_IDENTITY": "gcp.function.identity",
|
|
231
|
+
"FUNCTION_REGION": "faas.region",
|
|
232
|
+
"GCP_PROJECT": "gcp.function.project",
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
EVENT_TO_ATTRIBUTE = {
|
|
236
|
+
"method": "http.request.method",
|
|
237
|
+
"query_string": "url.query",
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def _prepopulate_attributes(gcp_event):
|
|
242
|
+
# type: (Any) -> dict[str, Any]
|
|
243
|
+
attributes = {
|
|
244
|
+
"cloud.provider": "gcp",
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
for key, attr in ENV_TO_ATTRIBUTE.items():
|
|
248
|
+
if environ.get(key):
|
|
249
|
+
attributes[attr] = environ[key]
|
|
250
|
+
|
|
251
|
+
for key, attr in EVENT_TO_ATTRIBUTE.items():
|
|
252
|
+
if getattr(gcp_event, key, None):
|
|
253
|
+
attributes[attr] = getattr(gcp_event, key)
|
|
254
|
+
|
|
255
|
+
if hasattr(gcp_event, "headers"):
|
|
256
|
+
headers = gcp_event.headers
|
|
257
|
+
attributes.update(_request_headers_to_span_attributes(headers))
|
|
258
|
+
|
|
259
|
+
return attributes
|
|
@@ -135,17 +135,10 @@ def graphql_span(schema, source, kwargs):
|
|
|
135
135
|
},
|
|
136
136
|
)
|
|
137
137
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
_graphql_span.set_data("graphql.document", source)
|
|
145
|
-
_graphql_span.set_data("graphql.operation.name", operation_name)
|
|
146
|
-
_graphql_span.set_data("graphql.operation.type", operation_type)
|
|
147
|
-
|
|
148
|
-
try:
|
|
138
|
+
with sentry_sdk.start_span(
|
|
139
|
+
op=op, name=operation_name, only_if_parent=True
|
|
140
|
+
) as graphql_span:
|
|
141
|
+
graphql_span.set_attribute("graphql.document", source)
|
|
142
|
+
graphql_span.set_attribute("graphql.operation.name", operation_name)
|
|
143
|
+
graphql_span.set_attribute("graphql.operation.type", operation_type)
|
|
149
144
|
yield
|
|
150
|
-
finally:
|
|
151
|
-
_graphql_span.finish()
|
|
@@ -44,14 +44,17 @@ class SentryUnaryUnaryClientInterceptor(ClientInterceptor, UnaryUnaryClientInter
|
|
|
44
44
|
request: Message,
|
|
45
45
|
) -> Union[UnaryUnaryCall, Message]:
|
|
46
46
|
method = client_call_details.method
|
|
47
|
+
if isinstance(method, bytes):
|
|
48
|
+
method = method.decode()
|
|
47
49
|
|
|
48
50
|
with sentry_sdk.start_span(
|
|
49
51
|
op=OP.GRPC_CLIENT,
|
|
50
|
-
name="unary unary call to %s" % method
|
|
52
|
+
name="unary unary call to %s" % method,
|
|
51
53
|
origin=SPAN_ORIGIN,
|
|
54
|
+
only_if_parent=True,
|
|
52
55
|
) as span:
|
|
53
|
-
span.
|
|
54
|
-
span.
|
|
56
|
+
span.set_attribute("type", "unary unary")
|
|
57
|
+
span.set_attribute("method", method)
|
|
55
58
|
|
|
56
59
|
client_call_details = self._update_client_call_details_metadata_from_scope(
|
|
57
60
|
client_call_details
|
|
@@ -59,7 +62,7 @@ class SentryUnaryUnaryClientInterceptor(ClientInterceptor, UnaryUnaryClientInter
|
|
|
59
62
|
|
|
60
63
|
response = await continuation(client_call_details, request)
|
|
61
64
|
status_code = await response.code()
|
|
62
|
-
span.
|
|
65
|
+
span.set_attribute("code", status_code.name)
|
|
63
66
|
|
|
64
67
|
return response
|
|
65
68
|
|
|
@@ -74,14 +77,17 @@ class SentryUnaryStreamClientInterceptor(
|
|
|
74
77
|
request: Message,
|
|
75
78
|
) -> Union[AsyncIterable[Any], UnaryStreamCall]:
|
|
76
79
|
method = client_call_details.method
|
|
80
|
+
if isinstance(method, bytes):
|
|
81
|
+
method = method.decode()
|
|
77
82
|
|
|
78
83
|
with sentry_sdk.start_span(
|
|
79
84
|
op=OP.GRPC_CLIENT,
|
|
80
|
-
name="unary stream call to %s" % method
|
|
85
|
+
name="unary stream call to %s" % method,
|
|
81
86
|
origin=SPAN_ORIGIN,
|
|
87
|
+
only_if_parent=True,
|
|
82
88
|
) as span:
|
|
83
|
-
span.
|
|
84
|
-
span.
|
|
89
|
+
span.set_attribute("type", "unary stream")
|
|
90
|
+
span.set_attribute("method", method)
|
|
85
91
|
|
|
86
92
|
client_call_details = self._update_client_call_details_metadata_from_scope(
|
|
87
93
|
client_call_details
|
|
@@ -89,6 +95,6 @@ class SentryUnaryStreamClientInterceptor(
|
|
|
89
95
|
|
|
90
96
|
response = await continuation(client_call_details, request)
|
|
91
97
|
# status_code = await response.code()
|
|
92
|
-
# span.
|
|
98
|
+
# span.set_attribute("code", status_code)
|
|
93
99
|
|
|
94
100
|
return response
|
|
@@ -2,7 +2,7 @@ import sentry_sdk
|
|
|
2
2
|
from sentry_sdk.consts import OP
|
|
3
3
|
from sentry_sdk.integrations import DidNotEnable
|
|
4
4
|
from sentry_sdk.integrations.grpc.consts import SPAN_ORIGIN
|
|
5
|
-
from sentry_sdk.tracing import
|
|
5
|
+
from sentry_sdk.tracing import TransactionSource
|
|
6
6
|
from sentry_sdk.utils import event_from_exception
|
|
7
7
|
|
|
8
8
|
from typing import TYPE_CHECKING
|
|
@@ -44,26 +44,24 @@ class ServerInterceptor(grpc.aio.ServerInterceptor): # type: ignore
|
|
|
44
44
|
return await handler(request, context)
|
|
45
45
|
|
|
46
46
|
# What if the headers are empty?
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
sentry_sdk.capture_event(event, hint=hint)
|
|
66
|
-
raise
|
|
47
|
+
with sentry_sdk.continue_trace(dict(context.invocation_metadata())):
|
|
48
|
+
with sentry_sdk.start_span(
|
|
49
|
+
op=OP.GRPC_SERVER,
|
|
50
|
+
name=name,
|
|
51
|
+
source=TransactionSource.CUSTOM,
|
|
52
|
+
origin=SPAN_ORIGIN,
|
|
53
|
+
):
|
|
54
|
+
try:
|
|
55
|
+
return await handler.unary_unary(request, context)
|
|
56
|
+
except AbortError:
|
|
57
|
+
raise
|
|
58
|
+
except Exception as exc:
|
|
59
|
+
event, hint = event_from_exception(
|
|
60
|
+
exc,
|
|
61
|
+
mechanism={"type": "grpc", "handled": False},
|
|
62
|
+
)
|
|
63
|
+
sentry_sdk.capture_event(event, hint=hint)
|
|
64
|
+
raise
|
|
67
65
|
|
|
68
66
|
elif not handler.request_streaming and handler.response_streaming:
|
|
69
67
|
handler_factory = grpc.unary_stream_rpc_method_handler
|
|
@@ -31,16 +31,17 @@ class ClientInterceptor(
|
|
|
31
31
|
op=OP.GRPC_CLIENT,
|
|
32
32
|
name="unary unary call to %s" % method,
|
|
33
33
|
origin=SPAN_ORIGIN,
|
|
34
|
+
only_if_parent=True,
|
|
34
35
|
) as span:
|
|
35
|
-
span.
|
|
36
|
-
span.
|
|
36
|
+
span.set_attribute("type", "unary unary")
|
|
37
|
+
span.set_attribute("method", method)
|
|
37
38
|
|
|
38
39
|
client_call_details = self._update_client_call_details_metadata_from_scope(
|
|
39
40
|
client_call_details
|
|
40
41
|
)
|
|
41
42
|
|
|
42
43
|
response = continuation(client_call_details, request)
|
|
43
|
-
span.
|
|
44
|
+
span.set_attribute("code", response.code().name)
|
|
44
45
|
|
|
45
46
|
return response
|
|
46
47
|
|
|
@@ -52,9 +53,10 @@ class ClientInterceptor(
|
|
|
52
53
|
op=OP.GRPC_CLIENT,
|
|
53
54
|
name="unary stream call to %s" % method,
|
|
54
55
|
origin=SPAN_ORIGIN,
|
|
56
|
+
only_if_parent=True,
|
|
55
57
|
) as span:
|
|
56
|
-
span.
|
|
57
|
-
span.
|
|
58
|
+
span.set_attribute("type", "unary stream")
|
|
59
|
+
span.set_attribute("method", method)
|
|
58
60
|
|
|
59
61
|
client_call_details = self._update_client_call_details_metadata_from_scope(
|
|
60
62
|
client_call_details
|
|
@@ -64,7 +66,7 @@ class ClientInterceptor(
|
|
|
64
66
|
client_call_details, request
|
|
65
67
|
) # type: UnaryStreamCall
|
|
66
68
|
# Setting code on unary-stream leads to execution getting stuck
|
|
67
|
-
# span.
|
|
69
|
+
# span.set_attribute("code", response.code().name)
|
|
68
70
|
|
|
69
71
|
return response
|
|
70
72
|
|
|
@@ -2,7 +2,7 @@ import sentry_sdk
|
|
|
2
2
|
from sentry_sdk.consts import OP
|
|
3
3
|
from sentry_sdk.integrations import DidNotEnable
|
|
4
4
|
from sentry_sdk.integrations.grpc.consts import SPAN_ORIGIN
|
|
5
|
-
from sentry_sdk.tracing import
|
|
5
|
+
from sentry_sdk.tracing import TransactionSource
|
|
6
6
|
|
|
7
7
|
from typing import TYPE_CHECKING
|
|
8
8
|
|
|
@@ -38,19 +38,17 @@ class ServerInterceptor(grpc.ServerInterceptor): # type: ignore
|
|
|
38
38
|
if name:
|
|
39
39
|
metadata = dict(context.invocation_metadata())
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
except BaseException as e:
|
|
53
|
-
raise e
|
|
41
|
+
with sentry_sdk.continue_trace(metadata):
|
|
42
|
+
with sentry_sdk.start_span(
|
|
43
|
+
op=OP.GRPC_SERVER,
|
|
44
|
+
name=name,
|
|
45
|
+
source=TransactionSource.CUSTOM,
|
|
46
|
+
origin=SPAN_ORIGIN,
|
|
47
|
+
):
|
|
48
|
+
try:
|
|
49
|
+
return handler.unary_unary(request, context)
|
|
50
|
+
except BaseException as e:
|
|
51
|
+
raise e
|
|
54
52
|
else:
|
|
55
53
|
return handler.unary_unary(request, context)
|
|
56
54
|
|
sentry_sdk/integrations/httpx.py
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import sentry_sdk
|
|
2
|
-
from sentry_sdk.consts import OP, SPANDATA
|
|
2
|
+
from sentry_sdk.consts import OP, SPANDATA, BAGGAGE_HEADER_NAME
|
|
3
3
|
from sentry_sdk.integrations import Integration, DidNotEnable
|
|
4
|
-
from sentry_sdk.tracing import BAGGAGE_HEADER_NAME
|
|
5
4
|
from sentry_sdk.tracing_utils import Baggage, should_propagate_trace
|
|
6
5
|
from sentry_sdk.utils import (
|
|
7
6
|
SENSITIVE_DATA_SUBSTITUTE,
|
|
8
7
|
capture_internal_exceptions,
|
|
9
8
|
ensure_integration_enabled,
|
|
9
|
+
http_client_status_to_breadcrumb_level,
|
|
10
10
|
logger,
|
|
11
11
|
parse_url,
|
|
12
|
+
set_thread_info_from_span,
|
|
12
13
|
)
|
|
13
14
|
|
|
14
15
|
from typing import TYPE_CHECKING
|
|
@@ -60,12 +61,20 @@ def _install_httpx_client():
|
|
|
60
61
|
parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE,
|
|
61
62
|
),
|
|
62
63
|
origin=HttpxIntegration.origin,
|
|
64
|
+
only_if_parent=True,
|
|
63
65
|
) as span:
|
|
64
|
-
|
|
66
|
+
data = {
|
|
67
|
+
SPANDATA.HTTP_METHOD: request.method,
|
|
68
|
+
}
|
|
69
|
+
set_thread_info_from_span(data, span)
|
|
70
|
+
|
|
65
71
|
if parsed_url is not None:
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
72
|
+
data["url"] = parsed_url.url
|
|
73
|
+
data[SPANDATA.HTTP_QUERY] = parsed_url.query
|
|
74
|
+
data[SPANDATA.HTTP_FRAGMENT] = parsed_url.fragment
|
|
75
|
+
|
|
76
|
+
for key, value in data.items():
|
|
77
|
+
span.set_attribute(key, value)
|
|
69
78
|
|
|
70
79
|
if should_propagate_trace(sentry_sdk.get_client(), str(request.url)):
|
|
71
80
|
for (
|
|
@@ -86,7 +95,17 @@ def _install_httpx_client():
|
|
|
86
95
|
rv = real_send(self, request, **kwargs)
|
|
87
96
|
|
|
88
97
|
span.set_http_status(rv.status_code)
|
|
89
|
-
span.
|
|
98
|
+
span.set_attribute("reason", rv.reason_phrase)
|
|
99
|
+
|
|
100
|
+
data[SPANDATA.HTTP_STATUS_CODE] = rv.status_code
|
|
101
|
+
data["reason"] = rv.reason_phrase
|
|
102
|
+
|
|
103
|
+
sentry_sdk.add_breadcrumb(
|
|
104
|
+
type="http",
|
|
105
|
+
category="httplib",
|
|
106
|
+
data=data,
|
|
107
|
+
level=http_client_status_to_breadcrumb_level(rv.status_code),
|
|
108
|
+
)
|
|
90
109
|
|
|
91
110
|
return rv
|
|
92
111
|
|
|
@@ -114,12 +133,18 @@ def _install_httpx_async_client():
|
|
|
114
133
|
parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE,
|
|
115
134
|
),
|
|
116
135
|
origin=HttpxIntegration.origin,
|
|
136
|
+
only_if_parent=True,
|
|
117
137
|
) as span:
|
|
118
|
-
|
|
138
|
+
data = {
|
|
139
|
+
SPANDATA.HTTP_METHOD: request.method,
|
|
140
|
+
}
|
|
119
141
|
if parsed_url is not None:
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
142
|
+
data["url"] = parsed_url.url
|
|
143
|
+
data[SPANDATA.HTTP_QUERY] = parsed_url.query
|
|
144
|
+
data[SPANDATA.HTTP_FRAGMENT] = parsed_url.fragment
|
|
145
|
+
|
|
146
|
+
for key, value in data.items():
|
|
147
|
+
span.set_attribute(key, value)
|
|
123
148
|
|
|
124
149
|
if should_propagate_trace(sentry_sdk.get_client(), str(request.url)):
|
|
125
150
|
for (
|
|
@@ -142,7 +167,17 @@ def _install_httpx_async_client():
|
|
|
142
167
|
rv = await real_send(self, request, **kwargs)
|
|
143
168
|
|
|
144
169
|
span.set_http_status(rv.status_code)
|
|
145
|
-
span.
|
|
170
|
+
span.set_attribute("reason", rv.reason_phrase)
|
|
171
|
+
|
|
172
|
+
data[SPANDATA.HTTP_STATUS_CODE] = rv.status_code
|
|
173
|
+
data["reason"] = rv.reason_phrase
|
|
174
|
+
|
|
175
|
+
sentry_sdk.add_breadcrumb(
|
|
176
|
+
type="http",
|
|
177
|
+
category="httplib",
|
|
178
|
+
data=data,
|
|
179
|
+
level=http_client_status_to_breadcrumb_level(rv.status_code),
|
|
180
|
+
)
|
|
146
181
|
|
|
147
182
|
return rv
|
|
148
183
|
|
sentry_sdk/integrations/huey.py
CHANGED
|
@@ -2,15 +2,16 @@ import sys
|
|
|
2
2
|
from datetime import datetime
|
|
3
3
|
|
|
4
4
|
import sentry_sdk
|
|
5
|
-
from sentry_sdk.api import
|
|
6
|
-
from sentry_sdk.consts import
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
from sentry_sdk.tracing import (
|
|
5
|
+
from sentry_sdk.api import get_baggage, get_traceparent
|
|
6
|
+
from sentry_sdk.consts import (
|
|
7
|
+
OP,
|
|
8
|
+
SPANSTATUS,
|
|
10
9
|
BAGGAGE_HEADER_NAME,
|
|
11
10
|
SENTRY_TRACE_HEADER_NAME,
|
|
12
11
|
TransactionSource,
|
|
13
12
|
)
|
|
13
|
+
from sentry_sdk.integrations import DidNotEnable, Integration
|
|
14
|
+
from sentry_sdk.scope import should_send_default_pii
|
|
14
15
|
from sentry_sdk.utils import (
|
|
15
16
|
capture_internal_exceptions,
|
|
16
17
|
ensure_integration_enabled,
|
|
@@ -61,6 +62,7 @@ def patch_enqueue():
|
|
|
61
62
|
op=OP.QUEUE_SUBMIT_HUEY,
|
|
62
63
|
name=task.name,
|
|
63
64
|
origin=HueyIntegration.origin,
|
|
65
|
+
only_if_parent=True,
|
|
64
66
|
):
|
|
65
67
|
if not isinstance(task, PeriodicTask):
|
|
66
68
|
# Attach trace propagation data to task kwargs. We do
|
|
@@ -109,11 +111,13 @@ def _capture_exception(exc_info):
|
|
|
109
111
|
# type: (ExcInfo) -> None
|
|
110
112
|
scope = sentry_sdk.get_current_scope()
|
|
111
113
|
|
|
112
|
-
if
|
|
113
|
-
|
|
114
|
-
|
|
114
|
+
if scope.root_span is not None:
|
|
115
|
+
if exc_info[0] in HUEY_CONTROL_FLOW_EXCEPTIONS:
|
|
116
|
+
scope.root_span.set_status(SPANSTATUS.ABORTED)
|
|
117
|
+
return
|
|
118
|
+
|
|
119
|
+
scope.root_span.set_status(SPANSTATUS.INTERNAL_ERROR)
|
|
115
120
|
|
|
116
|
-
scope.transaction.set_status(SPANSTATUS.INTERNAL_ERROR)
|
|
117
121
|
event, hint = event_from_exception(
|
|
118
122
|
exc_info,
|
|
119
123
|
client_options=sentry_sdk.get_client().options,
|
|
@@ -135,6 +139,10 @@ def _wrap_task_execute(func):
|
|
|
135
139
|
_capture_exception(exc_info)
|
|
136
140
|
reraise(*exc_info)
|
|
137
141
|
|
|
142
|
+
root_span = sentry_sdk.get_current_scope().root_span
|
|
143
|
+
if root_span is not None:
|
|
144
|
+
root_span.set_status(SPANSTATUS.OK)
|
|
145
|
+
|
|
138
146
|
return result
|
|
139
147
|
|
|
140
148
|
return _sentry_execute # type: ignore
|
|
@@ -153,22 +161,18 @@ def patch_execute():
|
|
|
153
161
|
scope.clear_breadcrumbs()
|
|
154
162
|
scope.add_event_processor(_make_event_processor(task))
|
|
155
163
|
|
|
156
|
-
sentry_headers = task.kwargs.pop("sentry_headers", None)
|
|
157
|
-
|
|
158
|
-
transaction = continue_trace(
|
|
159
|
-
sentry_headers or {},
|
|
160
|
-
name=task.name,
|
|
161
|
-
op=OP.QUEUE_TASK_HUEY,
|
|
162
|
-
source=TransactionSource.TASK,
|
|
163
|
-
origin=HueyIntegration.origin,
|
|
164
|
-
)
|
|
165
|
-
transaction.set_status(SPANSTATUS.OK)
|
|
166
|
-
|
|
167
164
|
if not getattr(task, "_sentry_is_patched", False):
|
|
168
165
|
task.execute = _wrap_task_execute(task.execute)
|
|
169
166
|
task._sentry_is_patched = True
|
|
170
167
|
|
|
171
|
-
|
|
172
|
-
|
|
168
|
+
sentry_headers = task.kwargs.pop("sentry_headers", {})
|
|
169
|
+
with sentry_sdk.continue_trace(sentry_headers):
|
|
170
|
+
with sentry_sdk.start_span(
|
|
171
|
+
name=task.name,
|
|
172
|
+
op=OP.QUEUE_TASK_HUEY,
|
|
173
|
+
source=TransactionSource.TASK,
|
|
174
|
+
origin=HueyIntegration.origin,
|
|
175
|
+
):
|
|
176
|
+
return old_execute(self, task, timestamp)
|
|
173
177
|
|
|
174
178
|
Huey._execute = _sentry_execute
|
|
@@ -3,7 +3,7 @@ from functools import wraps
|
|
|
3
3
|
|
|
4
4
|
import sentry_sdk
|
|
5
5
|
from sentry_sdk.ai.monitoring import set_ai_pipeline_name, record_token_usage
|
|
6
|
-
from sentry_sdk.consts import OP, SPANDATA
|
|
6
|
+
from sentry_sdk.consts import OP, SPANDATA, SPANSTATUS
|
|
7
7
|
from sentry_sdk.ai.utils import set_data_normalized
|
|
8
8
|
from sentry_sdk.scope import should_send_default_pii
|
|
9
9
|
from sentry_sdk.tracing import Span
|
|
@@ -72,7 +72,6 @@ class LangchainIntegration(Integration):
|
|
|
72
72
|
|
|
73
73
|
|
|
74
74
|
class WatchedSpan:
|
|
75
|
-
span = None # type: Span
|
|
76
75
|
num_completion_tokens = 0 # type: int
|
|
77
76
|
num_prompt_tokens = 0 # type: int
|
|
78
77
|
no_collect_tokens = False # type: bool
|
|
@@ -123,8 +122,9 @@ class SentryLangchainCallback(BaseCallbackHandler): # type: ignore[misc]
|
|
|
123
122
|
span_data = self.span_map[run_id]
|
|
124
123
|
if not span_data:
|
|
125
124
|
return
|
|
126
|
-
sentry_sdk.capture_exception(error
|
|
127
|
-
span_data.span.
|
|
125
|
+
sentry_sdk.capture_exception(error)
|
|
126
|
+
span_data.span.set_status(SPANSTATUS.INTERNAL_ERROR)
|
|
127
|
+
span_data.span.finish()
|
|
128
128
|
del self.span_map[run_id]
|
|
129
129
|
|
|
130
130
|
def _normalize_langchain_message(self, message):
|
|
@@ -136,21 +136,27 @@ class SentryLangchainCallback(BaseCallbackHandler): # type: ignore[misc]
|
|
|
136
136
|
def _create_span(self, run_id, parent_id, **kwargs):
|
|
137
137
|
# type: (SentryLangchainCallback, UUID, Optional[Any], Any) -> WatchedSpan
|
|
138
138
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
parent_span
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
139
|
+
parent_watched_span = self.span_map.get(parent_id) if parent_id else None
|
|
140
|
+
sentry_span = sentry_sdk.start_span(
|
|
141
|
+
parent_span=parent_watched_span.span if parent_watched_span else None,
|
|
142
|
+
only_if_parent=True,
|
|
143
|
+
**kwargs,
|
|
144
|
+
)
|
|
145
|
+
watched_span = WatchedSpan(sentry_span)
|
|
146
|
+
if parent_watched_span:
|
|
147
|
+
parent_watched_span.children.append(watched_span)
|
|
147
148
|
|
|
148
149
|
if kwargs.get("op", "").startswith("ai.pipeline."):
|
|
149
150
|
if kwargs.get("name"):
|
|
150
151
|
set_ai_pipeline_name(kwargs.get("name"))
|
|
151
152
|
watched_span.is_pipeline = True
|
|
152
153
|
|
|
153
|
-
|
|
154
|
+
# the same run_id is reused for the pipeline it seems
|
|
155
|
+
# so we need to end the older span to avoid orphan spans
|
|
156
|
+
existing_span_data = self.span_map.get(run_id)
|
|
157
|
+
if existing_span_data is not None:
|
|
158
|
+
self._exit_span(existing_span_data, run_id)
|
|
159
|
+
|
|
154
160
|
self.span_map[run_id] = watched_span
|
|
155
161
|
self.gc_span_map()
|
|
156
162
|
return watched_span
|
|
@@ -161,7 +167,8 @@ class SentryLangchainCallback(BaseCallbackHandler): # type: ignore[misc]
|
|
|
161
167
|
if span_data.is_pipeline:
|
|
162
168
|
set_ai_pipeline_name(None)
|
|
163
169
|
|
|
164
|
-
span_data.span.
|
|
170
|
+
span_data.span.set_status(SPANSTATUS.OK)
|
|
171
|
+
span_data.span.finish()
|
|
165
172
|
del self.span_map[run_id]
|
|
166
173
|
|
|
167
174
|
def on_llm_start(
|
|
@@ -222,7 +229,7 @@ class SentryLangchainCallback(BaseCallbackHandler): # type: ignore[misc]
|
|
|
222
229
|
if not model and "anthropic" in all_params.get("_type"):
|
|
223
230
|
model = "claude-2"
|
|
224
231
|
if model:
|
|
225
|
-
span.
|
|
232
|
+
span.set_attribute(SPANDATA.AI_MODEL_ID, model)
|
|
226
233
|
if should_send_default_pii() and self.include_prompts:
|
|
227
234
|
set_data_normalized(
|
|
228
235
|
span,
|