Skip to content

Commit db1cfe6

Browse files
committed
Merge branch 'potel-base' of github.com:getsentry/sentry-python into potel-base
2 parents 7b2cd65 + 5beea99 commit db1cfe6

File tree

10 files changed

+233
-215
lines changed

10 files changed

+233
-215
lines changed

MIGRATION_GUIDE.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,19 @@ Looking to upgrade from Sentry SDK 2.x to 3.x? Here's a comprehensive list of wh
105105
| `aws_event["headers"]["Host"]` | `server.address` |
106106
| `aws_context["function_name"]` | `faas.name` |
107107

108+
- If you're using the GCP integration, the `sampling_context` argument of `traces_sampler` doesn't contain the `gcp_env` and `gcp_event` keys anymore. Instead, the following, if available, is accessible:
109+
110+
| Old sampling context key | New sampling context key |
111+
| --------------------------------- | -------------------------- |
112+
| `gcp_env["function_name"]` | `faas.name` |
113+
| `gcp_env["function_region"]` | `faas.region` |
114+
| `gcp_env["function_project"]` | `gcp.function.project` |
115+
| `gcp_env["function_identity"]` | `gcp.function.identity` |
116+
| `gcp_env["function_entry_point"]` | `gcp.function.entry_point` |
117+
| `gcp_event.method` | `http.request.method` |
118+
| `gcp_event.query_string` | `url.query` |
119+
120+
108121
### Removed
109122

110123
- Spans no longer have a `description`. Use `name` instead.

sentry_sdk/integrations/aws_lambda.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,9 @@ def _event_from_error_json(error_json):
468468

469469

470470
def _prepopulate_attributes(aws_event, aws_context):
471-
attributes = {}
471+
attributes = {
472+
"cloud.provider": "aws",
473+
}
472474

473475
for prop, attr in EVENT_TO_ATTRIBUTES.items():
474476
if aws_event.get(prop) is not None:

sentry_sdk/integrations/gcp.py

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -84,22 +84,12 @@ def sentry_func(functionhandler, gcp_event, *args, **kwargs):
8484
headers = gcp_event.headers
8585

8686
with sentry_sdk.continue_trace(headers):
87-
sampling_context = {
88-
"gcp_env": {
89-
"function_name": environ.get("FUNCTION_NAME"),
90-
"function_entry_point": environ.get("ENTRY_POINT"),
91-
"function_identity": environ.get("FUNCTION_IDENTITY"),
92-
"function_region": environ.get("FUNCTION_REGION"),
93-
"function_project": environ.get("GCP_PROJECT"),
94-
},
95-
"gcp_event": gcp_event,
96-
}
9787
with sentry_sdk.start_transaction(
9888
op=OP.FUNCTION_GCP,
9989
name=environ.get("FUNCTION_NAME", ""),
10090
source=TRANSACTION_SOURCE_COMPONENT,
10191
origin=GcpIntegration.origin,
102-
custom_sampling_context=sampling_context,
92+
attributes=_prepopulate_attributes(gcp_event),
10393
):
10494
try:
10595
return func(functionhandler, gcp_event, *args, **kwargs)
@@ -229,3 +219,33 @@ def _get_google_cloud_logs_url(final_time):
229219
)
230220

231221
return url
222+
223+
224+
ENV_TO_ATTRIBUTE = {
225+
"FUNCTION_NAME": "faas.name",
226+
"ENTRY_POINT": "gcp.function.entry_point",
227+
"FUNCTION_IDENTITY": "gcp.function.identity",
228+
"FUNCTION_REGION": "faas.region",
229+
"GCP_PROJECT": "gcp.function.project",
230+
}
231+
232+
EVENT_TO_ATTRIBUTE = {
233+
"method": "http.request.method",
234+
"query_string": "url.query",
235+
}
236+
237+
238+
def _prepopulate_attributes(gcp_event):
239+
attributes = {
240+
"cloud.provider": "gcp",
241+
}
242+
243+
for key, attr in ENV_TO_ATTRIBUTE.items():
244+
if environ.get(key):
245+
attributes[attr] = environ[key]
246+
247+
for key, attr in EVENT_TO_ATTRIBUTE.items():
248+
if getattr(gcp_event, key, None):
249+
attributes[attr] = getattr(gcp_event, key)
250+
251+
return attributes

sentry_sdk/integrations/opentelemetry/utils.py

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -161,36 +161,43 @@ def span_data_for_http_method(span):
161161
# type: (ReadableSpan) -> OtelExtractedSpanData
162162
span_attributes = span.attributes or {}
163163

164-
op = "http"
164+
op = span_attributes.get(SentrySpanAttribute.OP)
165+
if op is None:
166+
op = "http"
165167

166-
if span.kind == SpanKind.SERVER:
167-
op += ".server"
168-
elif span.kind == SpanKind.CLIENT:
169-
op += ".client"
168+
if span.kind == SpanKind.SERVER:
169+
op += ".server"
170+
elif span.kind == SpanKind.CLIENT:
171+
op += ".client"
170172

171173
http_method = span_attributes.get(SpanAttributes.HTTP_METHOD)
172174
route = span_attributes.get(SpanAttributes.HTTP_ROUTE)
173175
target = span_attributes.get(SpanAttributes.HTTP_TARGET)
174176
peer_name = span_attributes.get(SpanAttributes.NET_PEER_NAME)
175177

176-
description = f"{http_method}"
177-
178-
if route:
179-
description = f"{http_method} {route}"
180-
elif target:
181-
description = f"{http_method} {target}"
182-
elif peer_name:
183-
description = f"{http_method} {peer_name}"
184-
else:
185-
url = span_attributes.get(SpanAttributes.HTTP_URL)
186-
url = cast("Optional[str]", url)
187-
188-
if url:
189-
parsed_url = urlparse(url)
190-
url = "{}://{}{}".format(
191-
parsed_url.scheme, parsed_url.netloc, parsed_url.path
192-
)
193-
description = f"{http_method} {url}"
178+
# TODO-neel-potel remove description completely
179+
description = span_attributes.get(
180+
SentrySpanAttribute.DESCRIPTION
181+
) or span_attributes.get(SentrySpanAttribute.NAME)
182+
if description is None:
183+
description = f"{http_method}"
184+
185+
if route:
186+
description = f"{http_method} {route}"
187+
elif target:
188+
description = f"{http_method} {target}"
189+
elif peer_name:
190+
description = f"{http_method} {peer_name}"
191+
else:
192+
url = span_attributes.get(SpanAttributes.HTTP_URL)
193+
url = cast("Optional[str]", url)
194+
195+
if url:
196+
parsed_url = urlparse(url)
197+
url = "{}://{}{}".format(
198+
parsed_url.scheme, parsed_url.netloc, parsed_url.path
199+
)
200+
description = f"{http_method} {url}"
194201

195202
status, http_status = extract_span_status(span)
196203

sentry_sdk/integrations/rust_tracing.py

Lines changed: 27 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,9 @@
3737
import sentry_sdk
3838
from sentry_sdk.integrations import Integration
3939
from sentry_sdk.scope import should_send_default_pii
40-
from sentry_sdk.tracing import Span as SentrySpan
40+
from sentry_sdk.tracing import POTelSpan as SentrySpan
4141
from sentry_sdk.utils import SENSITIVE_DATA_SUBSTITUTE
4242

43-
TraceState = Optional[Tuple[Optional[SentrySpan], SentrySpan]]
44-
4543

4644
class RustTracingLevel(Enum):
4745
Trace: str = "TRACE"
@@ -171,7 +169,7 @@ def _include_tracing_fields(self) -> bool:
171169
else self.include_tracing_fields
172170
)
173171

174-
def on_event(self, event: str, _span_state: TraceState) -> None:
172+
def on_event(self, event: str, _span_state: Optional[SentrySpan]) -> None:
175173
deserialized_event = json.loads(event)
176174
metadata = deserialized_event.get("metadata", {})
177175

@@ -185,7 +183,7 @@ def on_event(self, event: str, _span_state: TraceState) -> None:
185183
elif event_type == EventTypeMapping.Event:
186184
process_event(deserialized_event)
187185

188-
def on_new_span(self, attrs: str, span_id: str) -> TraceState:
186+
def on_new_span(self, attrs: str, span_id: str) -> Optional[SentrySpan]:
189187
attrs = json.loads(attrs)
190188
metadata = attrs.get("metadata", {})
191189

@@ -205,48 +203,35 @@ def on_new_span(self, attrs: str, span_id: str) -> TraceState:
205203
else:
206204
sentry_span_name = "<unknown>"
207205

208-
kwargs = {
209-
"op": "function",
210-
"name": sentry_span_name,
211-
"origin": self.origin,
212-
}
213-
214-
scope = sentry_sdk.get_current_scope()
215-
parent_sentry_span = scope.span
216-
if parent_sentry_span:
217-
sentry_span = parent_sentry_span.start_child(**kwargs)
218-
else:
219-
sentry_span = scope.start_span(**kwargs)
206+
span = sentry_sdk.start_span(
207+
op="function",
208+
name=sentry_span_name,
209+
origin=self.origin,
210+
only_if_parent=True,
211+
)
212+
span.__enter__()
220213

221214
fields = metadata.get("fields", [])
222215
for field in fields:
223216
if self._include_tracing_fields():
224-
sentry_span.set_data(field, attrs.get(field))
225-
else:
226-
sentry_span.set_data(field, SENSITIVE_DATA_SUBSTITUTE)
227-
228-
scope.span = sentry_span
229-
return (parent_sentry_span, sentry_span)
230-
231-
def on_close(self, span_id: str, span_state: TraceState) -> None:
232-
if span_state is None:
233-
return
234-
235-
parent_sentry_span, sentry_span = span_state
236-
sentry_span.finish()
237-
sentry_sdk.get_current_scope().span = parent_sentry_span
238-
239-
def on_record(self, span_id: str, values: str, span_state: TraceState) -> None:
240-
if span_state is None:
241-
return
242-
_parent_sentry_span, sentry_span = span_state
243-
244-
deserialized_values = json.loads(values)
245-
for key, value in deserialized_values.items():
246-
if self._include_tracing_fields():
247-
sentry_span.set_data(key, value)
217+
span.set_data(field, attrs.get(field))
248218
else:
249-
sentry_span.set_data(key, SENSITIVE_DATA_SUBSTITUTE)
219+
span.set_data(field, SENSITIVE_DATA_SUBSTITUTE)
220+
221+
return span
222+
223+
def on_close(self, span_id: str, span: Optional[SentrySpan]) -> None:
224+
if span is not None:
225+
span.__exit__(None, None, None)
226+
227+
def on_record(self, span_id: str, values: str, span: Optional[SentrySpan]) -> None:
228+
if span is not None:
229+
deserialized_values = json.loads(values)
230+
for key, value in deserialized_values.items():
231+
if self._include_tracing_fields():
232+
span.set_data(key, value)
233+
else:
234+
span.set_data(key, SENSITIVE_DATA_SUBSTITUTE)
250235

251236

252237
class RustTracingIntegration(Integration):

sentry_sdk/integrations/stdlib.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ def putrequest(self, method, url, *args, **kwargs):
9696
origin="auto.http.stdlib.httplib",
9797
only_if_parent=True,
9898
)
99+
span.__enter__()
99100

100101
data = {
101102
SPANDATA.HTTP_METHOD: method,
@@ -152,7 +153,7 @@ def getresponse(self, *args, **kwargs):
152153
span.set_http_status(int(rv.status))
153154
span.set_data("reason", rv.reason)
154155
finally:
155-
span.finish()
156+
span.__exit__(None, None, None)
156157

157158
return rv
158159

sentry_sdk/tracing.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import json
12
import uuid
23
import random
34
import time
@@ -1632,8 +1633,12 @@ def finish(self, end_timestamp=None):
16321633

16331634
def to_json(self):
16341635
# type: () -> dict[str, Any]
1635-
# TODO-neel-potel for sampling context
1636-
pass
1636+
"""
1637+
Only meant for testing. Not used internally anymore.
1638+
"""
1639+
if not isinstance(self._otel_span, ReadableSpan):
1640+
return {}
1641+
return json.loads(self._otel_span.to_json())
16371642

16381643
def get_trace_context(self):
16391644
# type: () -> dict[str, Any]

tests/integrations/gcp/test_gcp.py

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -304,16 +304,12 @@ def cloud_function(functionhandler, event):
304304
try:
305305
traces_sampler.assert_any_call(
306306
DictionaryContaining({
307-
"gcp_env": DictionaryContaining({
308-
"function_name": "chase_into_tree",
309-
"function_region": "dogpark",
310-
"function_project": "SquirrelChasing",
311-
}),
312-
"gcp_event": {
313-
"type": "chase",
314-
"chasers": ["Maisey", "Charlie"],
315-
"num_squirrels": 2,
316-
},
307+
"faas.name": "chase_into_tree",
308+
"faas.region": "dogpark",
309+
"gcp.function.identity": "func_ID",
310+
"gcp.function.entry_point": "cloud_function",
311+
"gcp.function.project": "SquirrelChasing",
312+
"cloud.provider": "gcp",
317313
})
318314
)
319315
except AssertionError:

0 commit comments

Comments
 (0)