diff --git a/poetry.lock b/poetry.lock index e8c00ab..0a1edb8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "certifi" @@ -231,38 +231,45 @@ dev = ["pre-commit", "pytest-asyncio", "tox"] [[package]] name = "sentry-sdk" -version = "1.41.0" +version = "2.17.0" description = "Python client for Sentry (https://sentry.io)" optional = false -python-versions = "*" +python-versions = ">=3.6" files = [ - {file = "sentry-sdk-1.41.0.tar.gz", hash = "sha256:4f2d6c43c07925d8cd10dfbd0970ea7cb784f70e79523cca9dbcd72df38e5a46"}, - {file = "sentry_sdk-1.41.0-py2.py3-none-any.whl", hash = "sha256:be4f8f4b29a80b6a3b71f0f31487beb9e296391da20af8504498a328befed53f"}, + {file = "sentry_sdk-2.17.0-py2.py3-none-any.whl", hash = "sha256:625955884b862cc58748920f9e21efdfb8e0d4f98cca4ab0d3918576d5b606ad"}, + {file = "sentry_sdk-2.17.0.tar.gz", hash = "sha256:dd0a05352b78ffeacced73a94e86f38b32e2eae15fff5f30ca5abb568a72eacf"}, ] [package.dependencies] certifi = "*" -urllib3 = {version = ">=1.26.11", markers = "python_version >= \"3.6\""} +urllib3 = ">=1.26.11" [package.extras] aiohttp = ["aiohttp (>=3.5)"] +anthropic = ["anthropic (>=0.16)"] arq = ["arq (>=0.23)"] asyncpg = ["asyncpg (>=0.23)"] beam = ["apache-beam (>=2.12)"] bottle = ["bottle (>=0.12.13)"] celery = ["celery (>=3)"] +celery-redbeat = ["celery-redbeat (>=2)"] chalice = ["chalice (>=1.16.0)"] clickhouse-driver = ["clickhouse-driver (>=0.2.0)"] django = ["django (>=1.8)"] falcon = ["falcon (>=1.4)"] fastapi = ["fastapi (>=0.79.0)"] flask = ["blinker (>=1.1)", "flask (>=0.11)", "markupsafe"] -grpcio = ["grpcio (>=1.21.1)"] +grpcio = ["grpcio (>=1.21.1)", "protobuf (>=3.8.0)"] +http2 = ["httpcore[http2] (==1.*)"] httpx = ["httpx (>=0.16.0)"] huey = ["huey (>=2)"] +huggingface-hub = ["huggingface-hub (>=0.22)"] +langchain = ["langchain (>=0.0.210)"] +litestar = ["litestar (>=2.0.0)"] loguru = ["loguru (>=0.5)"] +openai = ["openai (>=1.0.0)", "tiktoken (>=0.3.0)"] opentelemetry = ["opentelemetry-distro (>=0.35b0)"] -opentelemetry-experimental = ["opentelemetry-distro (>=0.40b0,<1.0)", "opentelemetry-instrumentation-aiohttp-client (>=0.40b0,<1.0)", "opentelemetry-instrumentation-django (>=0.40b0,<1.0)", "opentelemetry-instrumentation-fastapi (>=0.40b0,<1.0)", "opentelemetry-instrumentation-flask (>=0.40b0,<1.0)", "opentelemetry-instrumentation-requests (>=0.40b0,<1.0)", "opentelemetry-instrumentation-sqlite3 (>=0.40b0,<1.0)", "opentelemetry-instrumentation-urllib (>=0.40b0,<1.0)"] +opentelemetry-experimental = ["opentelemetry-distro"] pure-eval = ["asttokens", "executing", "pure-eval"] pymongo = ["pymongo (>=3.1)"] pyspark = ["pyspark (>=2.4.4)"] @@ -272,7 +279,7 @@ sanic = ["sanic (>=0.8)"] sqlalchemy = ["sqlalchemy (>=1.2)"] starlette = ["starlette (>=0.19.1)"] starlite = ["starlite (>=1.48)"] -tornado = ["tornado (>=5)"] +tornado = ["tornado (>=6)"] [[package]] name = "structlog" @@ -352,4 +359,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" python-versions = "^3.7" -content-hash = "45178895fcc4090e5c42b0794566f588057c76bb2fb0d51e7a90bcf7c2b17c0f" +content-hash = "980182b2f589addc75338e72d08e05b1c77fd6f0d7649adbaec77dacc4705399" diff --git a/pyproject.toml b/pyproject.toml index c6fdb85..dea299e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,7 +27,7 @@ include = ["*.md", "*.toml", "*.txt", "*.yml", "*.yaml", ".coveragerc", "tox.ini [tool.poetry.dependencies] python = "^3.7" -sentry-sdk = "*" +sentry-sdk = "^2.0" structlog = "*" [tool.poetry.dev-dependencies] diff --git a/structlog_sentry/__init__.py b/structlog_sentry/__init__.py index 02a68a1..b1c2fae 100644 --- a/structlog_sentry/__init__.py +++ b/structlog_sentry/__init__.py @@ -6,7 +6,7 @@ from typing import Any, Optional from collections.abc import MutableMapping, Iterable -from sentry_sdk import Hub +from sentry_sdk import Scope, get_isolation_scope from sentry_sdk.integrations.logging import _IGNORED_LOGGERS from sentry_sdk.utils import capture_internal_exceptions, event_from_exception from structlog.types import EventDict, ExcInfo, WrappedLogger @@ -48,7 +48,7 @@ def __init__( tag_keys: list[str] | str | None = None, ignore_loggers: Iterable[str] | None = None, verbose: bool = False, - hub: Hub | None = None, + scope: Scope | None = None, ) -> None: """ :param level: Events of this or higher levels will be reported as @@ -66,7 +66,7 @@ def __init__( :param ignore_loggers: A list of logger names to ignore any events from. :param verbose: Report the action taken by the logger in the `event_dict`. Default is :obj:`False`. - :param hub: Optionally specify :obj:`sentry_sdk.Hub`. + :param scope: Optionally specify :obj:`sentry_sdk.Scope`. """ self.event_level = event_level self.level = level @@ -74,7 +74,7 @@ def __init__( self.tag_keys = tag_keys self.verbose = verbose - self._hub = hub + self._scope = scope self._as_context = as_context self._original_event_dict: dict = {} self.ignore_breadcrumb_data = ignore_breadcrumb_data @@ -107,8 +107,8 @@ def _get_logger_name( return logger_name - def _get_hub(self) -> Hub: - return self._hub or Hub.current + def _get_scope(self) -> Scope: + return self._scope or get_isolation_scope() def _get_event_and_hint(self, event_dict: EventDict) -> tuple[dict, dict]: """Create a sentry event and hint from structlog `event_dict` and sys.exc_info. @@ -119,7 +119,7 @@ def _get_event_and_hint(self, event_dict: EventDict) -> tuple[dict, dict]: has_exc_info = exc_info and exc_info != (None, None, None) if has_exc_info: - client = self._get_hub().client + client = self._get_scope().client options: dict[str, Any] = client.options if client else {} event, hint = event_from_exception( exc_info, @@ -172,7 +172,7 @@ def _can_record(self, logger: WrappedLogger, event_dict: EventDict) -> bool: def _handle_event(self, event_dict: EventDict) -> None: with capture_internal_exceptions(): event, hint = self._get_event_and_hint(event_dict) - sid = self._get_hub().capture_event(event, hint=hint) + sid = self._get_scope().capture_event(event, hint=hint) if sid: event_dict["sentry_id"] = sid if self.verbose: @@ -181,7 +181,7 @@ def _handle_event(self, event_dict: EventDict) -> None: def _handle_breadcrumb(self, event_dict: EventDict) -> None: with capture_internal_exceptions(): event, hint = self._get_breadcrumb_and_hint(event_dict) - self._get_hub().add_breadcrumb(event, hint=hint) + self._get_scope().add_breadcrumb(event, hint=hint) @staticmethod def _get_level_value(level_name: str) -> int: diff --git a/test/test_sentry_processor.py b/test/test_sentry_processor.py index ae2d5c8..07e222c 100644 --- a/test/test_sentry_processor.py +++ b/test/test_sentry_processor.py @@ -34,21 +34,31 @@ def from_request(cls, request): return cls() +class CaptureTransport(sentry_sdk.Transport): + def __init__(self): + super().__init__() + self.events = [] + + def capture_envelope(self, envelope): + event = envelope.get_event() + if event is not None: + self.events.append(event) + + @pytest.fixture def sentry_events(request): params = ClientParams.from_request(request) + transport = CaptureTransport() + client = sentry_sdk.Client( + transport=transport, + integrations=INTEGRATIONS, + auto_enabling_integrations=False, + include_local_variables=params.include_local_variables, + ) - events = [] - with sentry_sdk.Hub() as hub: - hub.bind_client( - sentry_sdk.Client( - transport=events.append, - integrations=INTEGRATIONS, - auto_enabling_integrations=False, - include_local_variables=params.include_local_variables, - ) - ) - yield events + with sentry_sdk.isolation_scope() as scope: + scope.set_client(client) + yield transport.events def assert_event_dict(event_data, sentry_events, number_of_events=1, error=None):