Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix non scope related types #3970

Merged
merged 1 commit into from
Jan 21, 2025
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
2 changes: 2 additions & 0 deletions MIGRATION_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Looking to upgrade from Sentry SDK 2.x to 3.x? Here's a comprehensive list of wh
- You can no longer change the sampled status of a span with `span.sampled = False` after starting it.
- The `Span()` constructor does not accept a `hub` parameter anymore.
- `Span.finish()` does not accept a `hub` parameter anymore.
- `Span.finish()` no longer returns the `event_id` if the event is sent to sentry.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isnt this a problem? I remember that we need the event_id returned by capture_event() or else the user feedback modal can not be used?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

user feedback is for error events, not transactions

- The `Profile()` constructor does not accept a `hub` parameter anymore.
- A `Profile` object does not have a `.hub` property anymore.
- `sentry_sdk.continue_trace` no longer returns a `Transaction` and is now a context manager.
Expand Down Expand Up @@ -146,6 +147,7 @@ Looking to upgrade from Sentry SDK 2.x to 3.x? Here's a comprehensive list of wh
- `continue_from_headers`, `continue_from_environ` and `from_traceparent` have been removed, please use top-level API `sentry_sdk.continue_trace` instead.
- `PropagationContext` constructor no longer takes a `dynamic_sampling_context` but takes a `baggage` object instead.
- `ThreadingIntegration` no longer takes the `propagate_hub` argument.
- `Baggage.populate_from_transaction` has been removed.

### Deprecated

Expand Down
10 changes: 5 additions & 5 deletions sentry_sdk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ def _prepare_event(
)
return None

event = event_
event = event_ # type: Optional[Event] # type: ignore[no-redef]

spans_delta = spans_before - len(event.get("spans", []))
if is_transaction and spans_delta > 0 and self.transport is not None:
Expand Down Expand Up @@ -483,7 +483,7 @@ def _prepare_event(

for key in "release", "environment", "server_name", "dist":
if event.get(key) is None and self.options[key] is not None:
event[key] = str(self.options[key]).strip()
event[key] = str(self.options[key]).strip() # type: ignore[literal-required]
if event.get("sdk") is None:
sdk_info = dict(SDK_INFO)
sdk_info["integrations"] = sorted(self.integrations.keys())
Expand Down Expand Up @@ -523,7 +523,7 @@ def _prepare_event(
and event is not None
and event.get("type") != "transaction"
):
new_event = None
new_event = None # type: Optional[Event]
with capture_internal_exceptions():
new_event = before_send(event, hint or {})
if new_event is None:
Expand All @@ -532,7 +532,7 @@ def _prepare_event(
self.transport.record_lost_event(
"before_send", data_category="error"
)
event = new_event
event = new_event # type: Optional[Event] # type: ignore[no-redef]

before_send_transaction = self.options["before_send_transaction"]
if (
Expand Down Expand Up @@ -562,7 +562,7 @@ def _prepare_event(
reason="before_send", data_category="span", quantity=spans_delta
)

event = new_event
event = new_event # type: Optional[Event] # type: ignore[no-redef]

return event

Expand Down
4 changes: 2 additions & 2 deletions sentry_sdk/integrations/asyncpg.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ async def _inner(*args: Any, **kwargs: Any) -> T:

def _get_db_data(
conn: Any = None,
addr: Optional[tuple[str]] = None,
addr: Optional[tuple[str, ...]] = None,
database: Optional[str] = None,
user: Optional[str] = None,
) -> dict[str, str]:
Expand Down Expand Up @@ -218,6 +218,6 @@ def _get_db_data(
return data


def _set_on_span(span: Span, data: dict[str, Any]):
def _set_on_span(span: Span, data: dict[str, Any]) -> None:
for key, value in data.items():
span.set_attribute(key, value)
21 changes: 13 additions & 8 deletions sentry_sdk/integrations/clickhouse_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
ensure_integration_enabled,
)

from typing import TYPE_CHECKING, Any, Dict, TypeVar
from typing import TYPE_CHECKING, cast, Any, Dict, TypeVar

# Hack to get new Python features working in older versions
# without introducing a hard dependency on `typing_extensions`
Expand Down Expand Up @@ -94,6 +94,7 @@ def _inner(*args: P.args, **kwargs: P.kwargs) -> T:
connection._sentry_span = span # type: ignore[attr-defined]

data = _get_db_data(connection)
data = cast("dict[str, Any]", data)
data["db.query.text"] = query

if query_id:
Expand All @@ -116,9 +117,10 @@ def _inner(*args: P.args, **kwargs: P.kwargs) -> T:
def _wrap_end(f: Callable[P, T]) -> Callable[P, T]:
def _inner_end(*args: P.args, **kwargs: P.kwargs) -> T:
res = f(*args, **kwargs)
connection = args[0].connection
client = cast("clickhouse_driver.client.Client", args[0])
connection = client.connection

span = getattr(connection, "_sentry_span", None) # type: ignore[attr-defined]
span = getattr(connection, "_sentry_span", None)
if span is not None:
data = getattr(connection, "_sentry_db_data", {})

Expand Down Expand Up @@ -148,17 +150,20 @@ def _inner_end(*args: P.args, **kwargs: P.kwargs) -> T:

def _wrap_send_data(f: Callable[P, T]) -> Callable[P, T]:
def _inner_send_data(*args: P.args, **kwargs: P.kwargs) -> T:
connection = args[0].connection
db_params_data = args[2]
client = cast("clickhouse_driver.client.Client", args[0])
connection = client.connection
db_params_data = cast("list[Any]", args[2])
span = getattr(connection, "_sentry_span", None)

if span is not None:
data = _get_db_data(connection)
_set_on_span(span, data)

if should_send_default_pii():
saved_db_data = getattr(connection, "_sentry_db_data", {})
db_params = saved_db_data.get("db.params") or []
saved_db_data = getattr(
connection, "_sentry_db_data", {}
) # type: dict[str, Any]
db_params = saved_db_data.get("db.params") or [] # type: list[Any]
db_params.extend(db_params_data)
saved_db_data["db.params"] = db_params
span.set_attribute("db.params", _serialize_span_attribute(db_params))
Expand All @@ -178,6 +183,6 @@ def _get_db_data(connection: clickhouse_driver.connection.Connection) -> Dict[st
}


def _set_on_span(span: Span, data: Dict[str, Any]):
def _set_on_span(span: Span, data: Dict[str, Any]) -> None:
for key, value in data.items():
span.set_attribute(key, _serialize_span_attribute(value))
4 changes: 2 additions & 2 deletions sentry_sdk/integrations/opentelemetry/integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,10 @@ def _patch_readable_span():
def sentry_patched_readable_span(self):
# type: (Span) -> ReadableSpan
readable_span = old_readable_span(self)
readable_span._sentry_meta = getattr(self, "_sentry_meta", {})
readable_span._sentry_meta = getattr(self, "_sentry_meta", {}) # type: ignore[attr-defined]
return readable_span

Span._readable_span = sentry_patched_readable_span
Span._readable_span = sentry_patched_readable_span # type: ignore[method-assign]


def _setup_sentry_tracing():
Expand Down
24 changes: 15 additions & 9 deletions sentry_sdk/integrations/opentelemetry/sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,15 @@ def should_sample(
# parent_span_context.is_valid means this span has a parent, remote or local
is_root_span = not parent_span_context.is_valid or parent_span_context.is_remote

sample_rate = None

# Explicit sampled value provided at start_span
if attributes.get(SentrySpanAttribute.CUSTOM_SAMPLED) is not None:
custom_sampled = cast(
"Optional[bool]", attributes.get(SentrySpanAttribute.CUSTOM_SAMPLED)
)
if custom_sampled is not None:
if is_root_span:
sample_rate = float(attributes[SentrySpanAttribute.CUSTOM_SAMPLED])
sample_rate = float(custom_sampled)
if sample_rate > 0:
return sampled_result(parent_span_context, attributes, sample_rate)
else:
Expand All @@ -145,8 +150,6 @@ def should_sample(
f"[Tracing] Ignoring sampled param for non-root span {name}"
)

sample_rate = None

# Check if there is a traces_sampler
# Traces_sampler is responsible to check parent sampled to have full transactions.
has_traces_sampler = callable(client.options.get("traces_sampler"))
Expand Down Expand Up @@ -190,16 +193,19 @@ def get_description(self) -> str:


def create_sampling_context(name, attributes, parent_span_context, trace_id):
# type: (str, Attributes, SpanContext, str) -> dict[str, Any]
# type: (str, Attributes, Optional[SpanContext], int) -> dict[str, Any]
sampling_context = {
"transaction_context": {
"name": name,
"op": attributes.get(SentrySpanAttribute.OP),
"source": attributes.get(SentrySpanAttribute.SOURCE),
"op": attributes.get(SentrySpanAttribute.OP) if attributes else None,
"source": (
attributes.get(SentrySpanAttribute.SOURCE) if attributes else None
),
},
"parent_sampled": get_parent_sampled(parent_span_context, trace_id),
}
} # type: dict[str, Any]

sampling_context.update(attributes)
if attributes is not None:
sampling_context.update(attributes)

return sampling_context
8 changes: 6 additions & 2 deletions sentry_sdk/integrations/opentelemetry/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@
import sentry_sdk
from sentry_sdk.utils import Dsn
from sentry_sdk.consts import SPANSTATUS, OP, SPANDATA
from sentry_sdk.tracing import get_span_status_from_http_code, DEFAULT_SPAN_ORIGIN
from sentry_sdk.tracing_utils import Baggage, LOW_QUALITY_TRANSACTION_SOURCES
from sentry_sdk.tracing import (
get_span_status_from_http_code,
DEFAULT_SPAN_ORIGIN,
LOW_QUALITY_TRANSACTION_SOURCES,
)
from sentry_sdk.tracing_utils import Baggage
from sentry_sdk.integrations.opentelemetry.consts import SentrySpanAttribute

from sentry_sdk._types import TYPE_CHECKING
Expand Down
27 changes: 17 additions & 10 deletions sentry_sdk/tracing.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ def finish(
scope=None, # type: Optional[sentry_sdk.Scope]
end_timestamp=None, # type: Optional[Union[float, datetime]]
):
# type: (...) -> Optional[str]
# type: (...) -> None
pass

def set_measurement(self, name, value, unit=""):
Expand Down Expand Up @@ -375,7 +375,9 @@ def __init__(
self.set_status(status)

def __eq__(self, other):
# type: (Span) -> bool
# type: (object) -> bool
if not isinstance(other, Span):
return False
return self._otel_span == other._otel_span

def __repr__(self):
Expand Down Expand Up @@ -526,7 +528,6 @@ def sample_rate(self):
sample_rate = self._otel_span.get_span_context().trace_state.get(
TRACESTATE_SAMPLE_RATE_KEY
)
sample_rate = cast("Optional[str]", sample_rate)
return float(sample_rate) if sample_rate is not None else None

@property
Expand Down Expand Up @@ -668,18 +669,24 @@ def set_data(self, key, value):

def get_attribute(self, name):
# type: (str) -> Optional[Any]
if not isinstance(self._otel_span, ReadableSpan):
if (
not isinstance(self._otel_span, ReadableSpan)
or not self._otel_span.attributes
):
return None
return self._otel_span.attributes.get(name)

def set_attribute(self, key, value):
# type: (str, Any) -> None
# otel doesn't support None as values, preferring to not set the key
# at all instead
if value is None:
# otel doesn't support None as values, preferring to not set the key
# at all instead
return
serialized_value = _serialize_span_attribute(value)
if serialized_value is None:
return

self._otel_span.set_attribute(key, _serialize_span_attribute(value))
self._otel_span.set_attribute(key, serialized_value)

@property
def status(self):
Expand All @@ -690,7 +697,7 @@ def status(self):
Sentry `SPANSTATUS` it can not be guaranteed that the status
set in `set_status()` will be the same as the one returned here.
"""
if not hasattr(self._otel_span, "status"):
if not isinstance(self._otel_span, ReadableSpan):
return None

if self._otel_span.status.status_code == StatusCode.UNSET:
Expand Down Expand Up @@ -740,10 +747,10 @@ def set_http_status(self, http_status):

def is_success(self):
# type: () -> bool
return self._otel_span.status.code == StatusCode.OK
return self.status == SPANSTATUS.OK

def finish(self, end_timestamp=None):
# type: (Optional[Union[float, datetime]]) -> Optional[str]
# type: (Optional[Union[float, datetime]]) -> None
if end_timestamp is not None:
from sentry_sdk.integrations.opentelemetry.utils import (
convert_to_otel_timestamp,
Expand Down
47 changes: 0 additions & 47 deletions sentry_sdk/tracing_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -525,52 +525,6 @@ def from_options(cls, scope):

return Baggage(sentry_items, third_party_items, mutable)

@classmethod
def populate_from_transaction(cls, transaction):
# type: (sentry_sdk.tracing.Transaction) -> Baggage
"""
Populate fresh baggage entry with sentry_items and make it immutable
if this is the head SDK which originates traces.
"""
client = sentry_sdk.get_client()
sentry_items = {} # type: Dict[str, str]

if not client.is_active():
return Baggage(sentry_items)

options = client.options or {}

sentry_items["trace_id"] = transaction.trace_id

if options.get("environment"):
sentry_items["environment"] = options["environment"]

if options.get("release"):
sentry_items["release"] = options["release"]

if options.get("dsn"):
sentry_items["public_key"] = Dsn(options["dsn"]).public_key

if (
transaction.name
and transaction.source not in LOW_QUALITY_TRANSACTION_SOURCES
):
sentry_items["transaction"] = transaction.name

if transaction.sample_rate is not None:
sentry_items["sample_rate"] = str(transaction.sample_rate)

if transaction.sampled is not None:
sentry_items["sampled"] = "true" if transaction.sampled else "false"

# there's an existing baggage but it was mutable,
# which is why we are creating this new baggage.
# However, if by chance the user put some sentry items in there, give them precedence.
if transaction._baggage and transaction._baggage.sentry_items:
sentry_items.update(transaction._baggage.sentry_items)

return Baggage(sentry_items, mutable=False)

def freeze(self):
# type: () -> None
self.mutable = False
Expand Down Expand Up @@ -722,6 +676,5 @@ def get_current_span(scope=None):
# Circular imports
from sentry_sdk.tracing import (
BAGGAGE_HEADER_NAME,
LOW_QUALITY_TRANSACTION_SOURCES,
SENTRY_TRACE_HEADER_NAME,
)
3 changes: 2 additions & 1 deletion sentry_sdk/transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from sentry_sdk.worker import BackgroundWorker
from sentry_sdk.envelope import Envelope, Item, PayloadRef

from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, cast

if TYPE_CHECKING:
from typing import Any
Expand Down Expand Up @@ -179,6 +179,7 @@ def _parse_rate_limits(header, now=None):

retry_after = now + timedelta(seconds=int(retry_after_val))
for category in categories and categories.split(";") or (None,):
category = cast("Optional[EventDataCategory]", category)
yield category, retry_after
except (LookupError, ValueError):
continue
Expand Down
Loading