Skip to content

Merge master into 2.0 branch #2805

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

Merged
10 changes: 9 additions & 1 deletion .github/workflows/test-integrations-data-processing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.6","3.7","3.8","3.11","3.12"]
python-version: ["3.6","3.7","3.8","3.9","3.11","3.12"]
# python3.6 reached EOL and is no longer being supported on
# new versions of hosted runners on Github Actions
# ubuntu-20.04 is the last version that supported python3.6
Expand Down Expand Up @@ -58,6 +58,10 @@ jobs:
run: |
set -x # print commands that are executed
./scripts/runtox.sh "py${{ matrix.python-version }}-huey-latest" --cov=tests --cov=sentry_sdk --cov-report= --cov-branch
- name: Test openai latest
run: |
set -x # print commands that are executed
./scripts/runtox.sh "py${{ matrix.python-version }}-openai-latest" --cov=tests --cov=sentry_sdk --cov-report= --cov-branch
- name: Test rq latest
run: |
set -x # print commands that are executed
Expand Down Expand Up @@ -110,6 +114,10 @@ jobs:
run: |
set -x # print commands that are executed
./scripts/runtox.sh --exclude-latest "py${{ matrix.python-version }}-huey" --cov=tests --cov=sentry_sdk --cov-report= --cov-branch
- name: Test openai pinned
run: |
set -x # print commands that are executed
./scripts/runtox.sh --exclude-latest "py${{ matrix.python-version }}-openai" --cov=tests --cov=sentry_sdk --cov-report= --cov-branch
- name: Test rq pinned
run: |
set -x # print commands that are executed
Expand Down
2 changes: 2 additions & 0 deletions mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ ignore_missing_imports = True
ignore_missing_imports = True
[mypy-huey.*]
ignore_missing_imports = True
[mypy-openai.*]
ignore_missing_imports = True
[mypy-arq.*]
ignore_missing_imports = True
[mypy-grpc.*]
Expand Down
1 change: 1 addition & 0 deletions scripts/split-tox-gh-actions/split-tox-gh-actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
"beam",
"celery",
"huey",
"openai",
"rq",
],
"Databases": [
Expand Down
64 changes: 62 additions & 2 deletions sentry_sdk/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@


if TYPE_CHECKING:
from collections.abc import MutableMapping

from datetime import datetime

from types import TracebackType
from typing import Any
from typing import Callable
Expand All @@ -19,13 +23,69 @@
from typing import Tuple
from typing import Type
from typing import Union
from typing_extensions import Literal
from typing_extensions import Literal, TypedDict

# "critical" is an alias of "fatal" recognized by Relay
LogLevelStr = Literal["fatal", "critical", "error", "warning", "info", "debug"]

Event = TypedDict(
"Event",
{
"breadcrumbs": dict[
Literal["values"], list[dict[str, Any]]
], # TODO: We can expand on this type
"check_in_id": str,
"contexts": dict[str, dict[str, object]],
"dist": str,
"duration": Optional[float],
"environment": str,
"errors": list[dict[str, Any]], # TODO: We can expand on this type
"event_id": str,
"exception": dict[
Literal["values"], list[dict[str, Any]]
], # TODO: We can expand on this type
"extra": MutableMapping[str, object],
"fingerprint": list[str],
"level": LogLevelStr,
"logentry": Mapping[str, object],
"logger": str,
"measurements": dict[str, object],
"message": str,
"modules": dict[str, str],
"monitor_config": Mapping[str, object],
"monitor_slug": Optional[str],
"platform": Literal["python"],
"profile": object, # Should be sentry_sdk.profiler.Profile, but we can't import that here due to circular imports
"release": str,
"request": dict[str, object],
"sdk": Mapping[str, object],
"server_name": str,
"spans": list[dict[str, object]],
"stacktrace": dict[
str, object
], # We access this key in the code, but I am unsure whether we ever set it
"start_timestamp": datetime,
"status": Optional[str],
"tags": MutableMapping[
str, str
], # Tags must be less than 200 characters each
"threads": dict[
Literal["values"], list[dict[str, Any]]
], # TODO: We can expand on this type
"timestamp": Optional[datetime], # Must be set before sending the event
"transaction": str,
"transaction_info": Mapping[str, Any], # TODO: We can expand on this type
"type": Literal["check_in", "transaction"],
"user": dict[str, object],
"_metrics_summary": dict[str, object],
},
total=False,
)

ExcInfo = Tuple[
Optional[Type[BaseException]], Optional[BaseException], Optional[TracebackType]
]

Event = Dict[str, Any]
Hint = Dict[str, Any]

Breadcrumb = Dict[str, Any]
Expand Down
5 changes: 3 additions & 2 deletions sentry_sdk/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
BreadcrumbHint,
ExcInfo,
MeasurementUnit,
LogLevelStr,
)
from sentry_sdk.scope import StartTransactionKwargs
from sentry_sdk.tracing import Span
Expand Down Expand Up @@ -122,7 +123,7 @@ def capture_event(
@scopemethod
def capture_message(
message, # type: str
level=None, # type: Optional[str]
level=None, # type: Optional[LogLevelStr]
scope=None, # type: Optional[Any]
**scope_kwargs, # type: Any
):
Expand Down Expand Up @@ -257,7 +258,7 @@ def set_user(value):

@scopemethod
def set_level(value):
# type: (str) -> None
# type: (LogLevelStr) -> None
return Scope.get_isolation_scope().set_level(value)


Expand Down
18 changes: 12 additions & 6 deletions sentry_sdk/client.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
try:
from collections.abc import Mapping
except ImportError:
from collections import Mapping # type: ignore[attr-defined]

import os
import uuid
import random
Expand Down Expand Up @@ -32,7 +37,7 @@
from sentry_sdk.utils import ContextVar
from sentry_sdk.sessions import SessionFlusher
from sentry_sdk.envelope import Envelope
from sentry_sdk.profiler import has_profiling_enabled, setup_profiler
from sentry_sdk.profiler import has_profiling_enabled, Profile, setup_profiler
from sentry_sdk.scrubber import EventScrubber
from sentry_sdk.monitor import Monitor
from sentry_sdk.spotlight import setup_spotlight
Expand Down Expand Up @@ -460,7 +465,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 @@ -634,15 +639,16 @@ def _update_session_from_event(
errored = True
for error in exceptions:
mechanism = error.get("mechanism")
if mechanism and mechanism.get("handled") is False:
if isinstance(mechanism, Mapping) and mechanism.get("handled") is False:
crashed = True
break

user = event.get("user")

if session.user_agent is None:
headers = (event.get("request") or {}).get("headers")
for k, v in (headers or {}).items():
headers_dict = headers if isinstance(headers, dict) else {}
for k, v in headers_dict.items():
if k.lower() == "user-agent":
user_agent = v
break
Expand Down Expand Up @@ -714,15 +720,15 @@ def capture_event(
headers = {
"event_id": event_opt["event_id"],
"sent_at": format_timestamp(datetime.now(timezone.utc)),
}
} # type: dict[str, object]

if dynamic_sampling_context:
headers["trace"] = dynamic_sampling_context

envelope = Envelope(headers=headers)

if is_transaction:
if profile is not None:
if isinstance(profile, Profile):
envelope.add_profile(profile.to_json(event_opt, self.options))
envelope.add_transaction(event_opt)
elif is_checkin:
Expand Down
2 changes: 2 additions & 0 deletions sentry_sdk/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,8 @@ class OP:
MIDDLEWARE_STARLITE = "middleware.starlite"
MIDDLEWARE_STARLITE_RECEIVE = "middleware.starlite.receive"
MIDDLEWARE_STARLITE_SEND = "middleware.starlite.send"
OPENAI_CHAT_COMPLETIONS_CREATE = "ai.chat_completions.create.openai"
OPENAI_EMBEDDINGS_CREATE = "ai.embeddings.create.openai"
QUEUE_SUBMIT_ARQ = "queue.submit.arq"
QUEUE_TASK_ARQ = "queue.task.arq"
QUEUE_SUBMIT_CELERY = "queue.submit.celery"
Expand Down
5 changes: 3 additions & 2 deletions sentry_sdk/crons/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

if TYPE_CHECKING:
from typing import Any, Dict, Optional
from sentry_sdk._types import Event


def _create_check_in_event(
Expand All @@ -15,7 +16,7 @@ def _create_check_in_event(
duration_s=None,
monitor_config=None,
):
# type: (Optional[str], Optional[str], Optional[str], Optional[float], Optional[Dict[str, Any]]) -> Dict[str, Any]
# type: (Optional[str], Optional[str], Optional[str], Optional[float], Optional[Dict[str, Any]]) -> Event
options = Hub.current.client.options if Hub.current.client else {}
check_in_id = check_in_id or uuid.uuid4().hex # type: str

Expand All @@ -27,7 +28,7 @@ def _create_check_in_event(
"duration": duration_s,
"environment": options.get("environment", None),
"release": options.get("release", None),
}
} # type: Event

if monitor_config:
check_in["monitor_config"] = monitor_config
Expand Down
3 changes: 2 additions & 1 deletion sentry_sdk/hub.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
Breadcrumb,
BreadcrumbHint,
ExcInfo,
LogLevelStr,
)
from sentry_sdk.consts import ClientConstructor
from sentry_sdk.scope import StartTransactionKwargs
Expand Down Expand Up @@ -347,7 +348,7 @@ def capture_event(self, event, hint=None, scope=None, **scope_kwargs):
return last_event_id

def capture_message(self, message, level=None, scope=None, **scope_kwargs):
# type: (str, Optional[str], Optional[Scope], Any) -> Optional[str]
# type: (str, Optional[LogLevelStr], Optional[Scope], Any) -> Optional[str]
"""
.. deprecated:: 2.0.0
This function is deprecated and will be removed in a future release.
Expand Down
1 change: 1 addition & 0 deletions sentry_sdk/integrations/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ def iter_default_integrations(with_auto_enabling_integrations):
"sentry_sdk.integrations.httpx.HttpxIntegration",
"sentry_sdk.integrations.huey.HueyIntegration",
"sentry_sdk.integrations.loguru.LoguruIntegration",
"sentry_sdk.integrations.openai.OpenAIIntegration",
"sentry_sdk.integrations.pymongo.PyMongoIntegration",
"sentry_sdk.integrations.pyramid.PyramidIntegration",
"sentry_sdk.integrations.quart.QuartIntegration",
Expand Down
3 changes: 2 additions & 1 deletion sentry_sdk/integrations/_wsgi_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from typing import Mapping
from typing import Optional
from typing import Union
from sentry_sdk._types import Event


SENSITIVE_ENV_KEYS = (
Expand Down Expand Up @@ -65,7 +66,7 @@ def __init__(self, request):
self.request = request

def extract_into_event(self, event):
# type: (Dict[str, Any]) -> None
# type: (Event) -> None
client = Hub.current.client
if client is None:
return
Expand Down
9 changes: 4 additions & 5 deletions sentry_sdk/integrations/aiohttp.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,12 @@
from aiohttp import TraceRequestStartParams, TraceRequestEndParams
from types import SimpleNamespace
from typing import Any
from typing import Dict
from typing import Optional
from typing import Tuple
from typing import Union

from sentry_sdk.utils import ExcInfo
from sentry_sdk._types import EventProcessor
from sentry_sdk._types import Event, EventProcessor


TRANSACTION_STYLE_VALUES = ("handler_name", "method_and_path_pattern")
Expand Down Expand Up @@ -256,10 +255,10 @@ async def on_request_end(session, trace_config_ctx, params):
def _make_request_processor(weak_request):
# type: (weakref.ReferenceType[Request]) -> EventProcessor
def aiohttp_processor(
event, # type: Dict[str, Any]
hint, # type: Dict[str, Tuple[type, BaseException, Any]]
event, # type: Event
hint, # type: dict[str, Tuple[type, BaseException, Any]]
):
# type: (...) -> Dict[str, Any]
# type: (...) -> Event
request = weak_request()
if request is None:
return event
Expand Down
6 changes: 3 additions & 3 deletions sentry_sdk/integrations/ariadne.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from typing import Any, Dict, List, Optional
from ariadne.types import GraphQLError, GraphQLResult, GraphQLSchema, QueryParser # type: ignore
from graphql.language.ast import DocumentNode # type: ignore
from sentry_sdk._types import EventProcessor
from sentry_sdk._types import Event, EventProcessor


class AriadneIntegration(Integration):
Expand Down Expand Up @@ -131,7 +131,7 @@ def _make_request_event_processor(data):
"""Add request data and api_target to events."""

def inner(event, hint):
# type: (Dict[str, Any], Dict[str, Any]) -> Dict[str, Any]
# type: (Event, dict[str, Any]) -> Event
if not isinstance(data, dict):
return event

Expand Down Expand Up @@ -163,7 +163,7 @@ def _make_response_event_processor(response):
"""Add response data to the event's response context."""

def inner(event, hint):
# type: (Dict[str, Any], Dict[str, Any]) -> Dict[str, Any]
# type: (Event, dict[str, Any]) -> Event
with capture_internal_exceptions():
if _should_send_default_pii() and response.get("errors"):
contexts = event.setdefault("contexts", {})
Expand Down
2 changes: 1 addition & 1 deletion sentry_sdk/integrations/bottle.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ def _make_request_event_processor(app, request, integration):
# type: (Bottle, LocalRequest, BottleIntegration) -> EventProcessor

def event_processor(event, hint):
# type: (Dict[str, Any], Dict[str, Any]) -> Dict[str, Any]
# type: (Event, dict[str, Any]) -> Event
_set_transaction_name_and_source(event, integration.transaction_style, request)

with capture_internal_exceptions():
Expand Down
4 changes: 2 additions & 2 deletions sentry_sdk/integrations/django/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ def sentry_patched_get_response(self, request):
def _make_wsgi_request_event_processor(weak_request, integration):
# type: (Callable[[], WSGIRequest], DjangoIntegration) -> EventProcessor
def wsgi_request_event_processor(event, hint):
# type: (Dict[str, Any], Dict[str, Any]) -> Dict[str, Any]
# type: (Event, dict[str, Any]) -> Event
# if the request is gone we are fine not logging the data from
# it. This might happen if the processor is pushed away to
# another thread.
Expand Down Expand Up @@ -565,7 +565,7 @@ def parsed_body(self):


def _set_user_info(request, event):
# type: (WSGIRequest, Dict[str, Any]) -> None
# type: (WSGIRequest, Event) -> None
user_info = event.setdefault("user", {})

user = getattr(request, "user", None)
Expand Down
4 changes: 2 additions & 2 deletions sentry_sdk/integrations/django/asgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@
from django.core.handlers.asgi import ASGIRequest
from django.http.response import HttpResponse

from sentry_sdk._types import EventProcessor
from sentry_sdk._types import Event, EventProcessor


def _make_asgi_request_event_processor(request):
# type: (ASGIRequest) -> EventProcessor
def asgi_request_event_processor(event, hint):
# type: (dict[str, Any], dict[str, Any]) -> dict[str, Any]
# type: (Event, dict[str, Any]) -> Event
# if the request is gone we are fine not logging the data from
# it. This might happen if the processor is pushed away to
# another thread.
Expand Down
Loading