diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index 5899af00d9..04c7b5c5ba 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -24,6 +24,41 @@ Looking to upgrade from Sentry SDK 2.x to 3.x? Here's a comprehensive list of wh - The UnraisableHookIntegration is now enabled by default. - We now don't suppress chained exceptions in the ASGI and asyncio integrations by default. The related `suppress_asgi_chained_exceptions` experimental option was removed. +### Logging + +- The standard library logging integration is not auto-enabled by default anymore. To continue using it, add it to the `integrations` list in your `sentry_sdk.init()`: + + ```python + import sentry_sdk + from sentry_sdk.integrations.logging import LoggingIntegration + + sentry_sdk.init( + integrations=[ + LoggingIntegration(), + ] + ) + ``` + +- The `level` integration option is now called `breadcrumb_level`. +- The `sentry_logs_level` integration option is now called `level`. +- The `capture_sentry_logs` option was removed. Use `level=None` to disable log capture. +- The `ignore_logger` helper was renamed to `ignore_logger_for_breadcrumbs_and_events`. +- The `ignore_logger_for_sentry_logs` helper was renamed to `ignore_logger`. +- `SentryHandler` was removed. Use `EventHandler` instead. +- When you enable the integration by adding `LoggingIntegration` to your `sentry_sdk.init()`, it'll start capturing Sentry logs and breadcrumbs. Creating events from logs can be enabled by providing additional integration options. + + | Old name | New name | Old default | New default | Description | + | --- | --- | --- | --- | --- | + | `level` | `breadcrumb_level` | `INFO` | `INFO` | Captures logs of that level and higher as breadcrumbs. | + | `event_level` | `event_level` | `ERROR` | `None` | Captures logs of that level and higher as events. | + | `sentry_logs_level` | `level` | `INFO` | `INFO` | Captures logs of that level and higher as Sentry logs. | + | `capture_sentry_logs` | removed | `False` | n/a | Allows to opt out of instrumenting logs as Sentry logs. Use `level` (previously `sentry_logs_level`) to adjust what should be captured instead. | + | `ignore_logger` | `ignore_logger_for_events` | n/a | n/a | Loggers that match this name will not create breadcrumbs and events. | + | `unignore_logger` | `unignore_logger_for_events` | n/a | n/a | Loggers that match this name will create breadcrumbs and events again. | + | `ignore_logger_for_sentry_logs` | `ignore_logger` | n/a | n/a | Loggers that match this name will not create Sentry logs. | + | `unignore_logger_for_sentry_logs` | `unignore_logger` | n/a | n/a | Loggers that match this name will create Sentry logs again. | + + ## Removed - The SDK no longer supports Python 3.6. The oldest supported version is now 3.7. diff --git a/sentry_sdk/integrations/__init__.py b/sentry_sdk/integrations/__init__.py index 0f674cb4bf..8801cfb41c 100644 --- a/sentry_sdk/integrations/__init__.py +++ b/sentry_sdk/integrations/__init__.py @@ -59,7 +59,6 @@ def iter_default_integrations( "sentry_sdk.integrations.atexit.AtexitIntegration", "sentry_sdk.integrations.dedupe.DedupeIntegration", "sentry_sdk.integrations.excepthook.ExcepthookIntegration", - "sentry_sdk.integrations.logging.LoggingIntegration", "sentry_sdk.integrations.modules.ModulesIntegration", "sentry_sdk.integrations.stdlib.StdlibIntegration", "sentry_sdk.integrations.threading.ThreadingIntegration", diff --git a/sentry_sdk/integrations/aiohttp.py b/sentry_sdk/integrations/aiohttp.py index 3a3ced6094..0888c0072b 100644 --- a/sentry_sdk/integrations/aiohttp.py +++ b/sentry_sdk/integrations/aiohttp.py @@ -18,7 +18,7 @@ _filter_headers, request_body_within_bounds, ) -from sentry_sdk.integrations.logging import ignore_logger +from sentry_sdk.integrations.logging import ignore_logger_for_events from sentry_sdk.scope import Scope, should_send_default_pii from sentry_sdk.sessions import track_session from sentry_sdk.traces import ( @@ -113,7 +113,7 @@ def setup_once() -> None: # accidentally overwrite a status of "ok" with "error". _register_control_flow_exception(HTTPException) - ignore_logger("aiohttp.server") + ignore_logger_for_events("aiohttp.server") old_handle = Application._handle diff --git a/sentry_sdk/integrations/ariadne.py b/sentry_sdk/integrations/ariadne.py index 28d11b51a9..a067df79bc 100644 --- a/sentry_sdk/integrations/ariadne.py +++ b/sentry_sdk/integrations/ariadne.py @@ -4,7 +4,7 @@ from sentry_sdk import capture_event, get_client from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.integrations._wsgi_common import request_body_within_bounds -from sentry_sdk.integrations.logging import ignore_logger +from sentry_sdk.integrations.logging import ignore_logger_for_events from sentry_sdk.scope import should_send_default_pii from sentry_sdk.utils import ( capture_internal_exceptions, @@ -45,7 +45,7 @@ def setup_once() -> None: version = package_version("ariadne") _check_minimum_version(AriadneIntegration, version) - ignore_logger("ariadne") + ignore_logger_for_events("ariadne") _patch_graphql() diff --git a/sentry_sdk/integrations/arq.py b/sentry_sdk/integrations/arq.py index c82a01da31..35c4e52644 100644 --- a/sentry_sdk/integrations/arq.py +++ b/sentry_sdk/integrations/arq.py @@ -3,7 +3,7 @@ import sentry_sdk from sentry_sdk.consts import OP, SPANDATA, SPANSTATUS from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version -from sentry_sdk.integrations.logging import ignore_logger +from sentry_sdk.integrations.logging import ignore_logger_for_events from sentry_sdk.scope import should_send_default_pii from sentry_sdk.traces import SegmentNameSource from sentry_sdk.tracing_utils import has_span_streaming_enabled @@ -64,7 +64,7 @@ def setup_once() -> None: _register_control_flow_exception(ARQ_CONTROL_FLOW_EXCEPTIONS) # type: ignore - ignore_logger("arq.worker") + ignore_logger_for_events("arq.worker") def patch_enqueue_job() -> None: diff --git a/sentry_sdk/integrations/beam.py b/sentry_sdk/integrations/beam.py index 32c8b4cdae..4bce445075 100644 --- a/sentry_sdk/integrations/beam.py +++ b/sentry_sdk/integrations/beam.py @@ -5,7 +5,7 @@ import sentry_sdk from sentry_sdk.integrations import Integration, _check_minimum_version -from sentry_sdk.integrations.logging import ignore_logger +from sentry_sdk.integrations.logging import ignore_logger_for_events from sentry_sdk.utils import ( capture_internal_exceptions, ensure_integration_enabled, @@ -39,8 +39,8 @@ def setup_once() -> None: version = parse_version(BEAM_VERSION) _check_minimum_version(BeamIntegration, version) - ignore_logger("root") - ignore_logger("bundle_processor.create") + ignore_logger_for_events("root") + ignore_logger_for_events("bundle_processor.create") function_patches = ["process", "start_bundle", "finish_bundle", "setup"] for func_name in function_patches: diff --git a/sentry_sdk/integrations/celery/__init__.py b/sentry_sdk/integrations/celery/__init__.py index 51eedf976b..0aefb8969b 100644 --- a/sentry_sdk/integrations/celery/__init__.py +++ b/sentry_sdk/integrations/celery/__init__.py @@ -14,7 +14,7 @@ _setup_celery_beat_signals, ) from sentry_sdk.integrations.celery.utils import _now_seconds_since_epoch -from sentry_sdk.integrations.logging import ignore_logger +from sentry_sdk.integrations.logging import ignore_logger_for_events from sentry_sdk.scope import Scope, should_send_default_pii from sentry_sdk.traces import SegmentNameSource, StreamedSpan, get_current_span from sentry_sdk.tracing import BAGGAGE_HEADER_NAME, Span, TransactionSource @@ -84,12 +84,12 @@ def setup_once() -> None: # This logger logs every status of every task that ran on the worker. # Meaning that every task's breadcrumbs are full of stuff like "Task # raised unexpected ". - ignore_logger("celery.worker.job") - ignore_logger("celery.app.trace") + ignore_logger_for_events("celery.worker.job") + ignore_logger_for_events("celery.app.trace") # This is stdout/err redirected to a logger, can't deal with this # (need event_level=logging.WARN to reproduce) - ignore_logger("celery.redirected") + ignore_logger_for_events("celery.redirected") def _set_status(status: str) -> None: diff --git a/sentry_sdk/integrations/django/__init__.py b/sentry_sdk/integrations/django/__init__.py index 40e2c8b120..7dc574311d 100644 --- a/sentry_sdk/integrations/django/__init__.py +++ b/sentry_sdk/integrations/django/__init__.py @@ -17,7 +17,7 @@ DEFAULT_HTTP_METHODS_TO_CAPTURE, RequestExtractor, ) -from sentry_sdk.integrations.logging import ignore_logger +from sentry_sdk.integrations.logging import ignore_logger_for_events from sentry_sdk.integrations.wsgi import SentryWsgiMiddleware from sentry_sdk.scope import add_global_event_processor, should_send_default_pii from sentry_sdk.serializer import add_global_repr_processor, add_repr_sequence_type @@ -156,8 +156,8 @@ def setup_once() -> None: # Patch in our custom middleware. # logs an error for every 500 - ignore_logger("django.server") - ignore_logger("django.request") + ignore_logger_for_events("django.server") + ignore_logger_for_events("django.request") from django.core.handlers.wsgi import WSGIHandler @@ -889,7 +889,7 @@ def _rollback(self: "BaseDatabaseWrapper") -> None: BaseDatabaseWrapper.connect = connect BaseDatabaseWrapper._commit = _commit BaseDatabaseWrapper._rollback = _rollback - ignore_logger("django.db.backends") + ignore_logger_for_events("django.db.backends") def _set_db_data( diff --git a/sentry_sdk/integrations/litestar.py b/sentry_sdk/integrations/litestar.py index 2632c0a3c7..21aeafccc9 100644 --- a/sentry_sdk/integrations/litestar.py +++ b/sentry_sdk/integrations/litestar.py @@ -11,7 +11,7 @@ _check_minimum_version, ) from sentry_sdk.integrations.asgi import SentryAsgiMiddleware -from sentry_sdk.integrations.logging import ignore_logger +from sentry_sdk.integrations.logging import ignore_logger_for_events from sentry_sdk.scope import should_send_default_pii from sentry_sdk.tracing import SOURCE_FOR_STYLE, TransactionSource from sentry_sdk.tracing_utils import has_span_streaming_enabled @@ -85,7 +85,7 @@ def setup_once() -> None: # The `LitestarIntegration`` provides an after_exception hook (see `patch_app_init` below) to create a Sentry event # from an exception, which ends up being called during step 2 above. However, the Sentry `LoggingIntegration` will # by default create a Sentry event from error logs made in step 1 if we do not prevent it from doing so. - ignore_logger("litestar") + ignore_logger_for_events("litestar") class SentryLitestarASGIMiddleware(SentryAsgiMiddleware): diff --git a/sentry_sdk/integrations/logging.py b/sentry_sdk/integrations/logging.py index e5580441e4..f29fc5f700 100644 --- a/sentry_sdk/integrations/logging.py +++ b/sentry_sdk/integrations/logging.py @@ -19,12 +19,14 @@ if TYPE_CHECKING: from collections.abc import MutableMapping from logging import LogRecord - from typing import Any, Dict, Optional, Union + from typing import Any, Dict, Optional -_SENTINEL = object() +# Logs of this severity and above will be captured as Sentry logs DEFAULT_LEVEL = logging.INFO -DEFAULT_EVENT_LEVEL = logging.ERROR +# Logs of this severity and above will be captured as breadcrumbs +DEFAULT_LEVEL_FOR_BREADCRUMBS = logging.INFO + LOGGING_TO_EVENT_LEVEL = { logging.NOTSET: "notset", logging.DEBUG: "debug", @@ -56,7 +58,7 @@ # Events/breadcrumbs and Sentry Logs have separate ignore lists so that # framework loggers silenced for events (e.g. django.server) can still be # captured as Sentry Logs. -_IGNORED_LOGGERS = set( +_IGNORED_LOGGERS_EVENTS = set( ["sentry_sdk.errors", "urllib3.connectionpool", "urllib3.connection"] ) @@ -65,7 +67,7 @@ ) -def ignore_logger( +def ignore_logger_for_events( name: str, ) -> None: """This disables recording (both in breadcrumbs and as events) calls to @@ -74,14 +76,14 @@ def ignore_logger( to users as a way to quiet spammy loggers. This does **not** affect Sentry Logs — use - :py:func:`ignore_logger_for_sentry_logs` for that. + :py:func:`ignore_logger` for that. :param name: The name of the logger to ignore (same string you would pass to ``logging.getLogger``). """ - _IGNORED_LOGGERS.add(name) + _IGNORED_LOGGERS_EVENTS.add(name) -def ignore_logger_for_sentry_logs( +def ignore_logger( name: str, ) -> None: """This disables recording as Sentry Logs calls to a logger of a @@ -92,21 +94,21 @@ def ignore_logger_for_sentry_logs( _IGNORED_LOGGERS_SENTRY_LOGS.add(name) -def unignore_logger( +def unignore_logger_for_events( name: str, ) -> None: - """Reverts a previous :py:func:`ignore_logger` call, re-enabling + """Reverts a previous :py:func:`ignore_logger_for_events` call, re-enabling recording of breadcrumbs and events for the named logger. :param name: The name of the logger to unignore. """ - _IGNORED_LOGGERS.discard(name) + _IGNORED_LOGGERS_EVENTS.discard(name) -def unignore_logger_for_sentry_logs( +def unignore_logger( name: str, ) -> None: - """Reverts a previous :py:func:`ignore_logger_for_sentry_logs` call, + """Reverts a previous :py:func:`ignore_logger` call, re-enabling recording of Sentry Logs for the named logger. :param name: The name of the logger to unignore. @@ -116,46 +118,56 @@ def unignore_logger_for_sentry_logs( class LoggingIntegration(Integration): identifier = "logging" - capture_sentry_logs: "Optional[Union[bool, object]]" = _SENTINEL def __init__( self, level: "Optional[int]" = DEFAULT_LEVEL, - event_level: "Optional[int]" = DEFAULT_EVENT_LEVEL, - sentry_logs_level: "Optional[int]" = DEFAULT_LEVEL, - capture_sentry_logs: "Optional[Union[bool, object]]" = _SENTINEL, + event_level: "Optional[int]" = None, + breadcrumb_level: "Optional[int]" = DEFAULT_LEVEL_FOR_BREADCRUMBS, ) -> None: - LoggingIntegration.capture_sentry_logs = capture_sentry_logs - - self._handler = None + """ + Initialize the standard library logging integration. + + - `level`: Logs with severity of this level and above will be captured + as Sentry logs. + - `event_level`: Logs with severity of this level and above will be + captured as Sentry events. + - `breadcrumb_level`: Logs with this severity and above will be captured + as breadcrumbs. + """ + self._logs_handler = None + self._event_handler = None self._breadcrumb_handler = None - self._sentry_logs_handler = None if level is not None: - self._breadcrumb_handler = BreadcrumbHandler(level=level) - - if sentry_logs_level is not None: - self._sentry_logs_handler = SentryLogsHandler(level=sentry_logs_level) + self._logs_handler = LogsHandler(level=level) if event_level is not None: - self._handler = EventHandler(level=event_level) + self._event_handler = EventHandler(level=event_level) - def _handle_record(self, record: "LogRecord") -> None: - if self._handler is not None and record.levelno >= self._handler.level: - self._handler.handle(record) + if breadcrumb_level is not None: + self._breadcrumb_handler = BreadcrumbHandler(level=breadcrumb_level) + def _handle_logs_record(self, record: "LogRecord") -> None: if ( - self._breadcrumb_handler is not None - and record.levelno >= self._breadcrumb_handler.level + self._logs_handler is not None + and record.levelno >= self._logs_handler.level ): - self._breadcrumb_handler.handle(record) + self._logs_handler.handle(record) - def _handle_sentry_logs_record(self, record: "LogRecord") -> None: + def _handle_event_record(self, record: "LogRecord") -> None: if ( - self._sentry_logs_handler is not None - and record.levelno >= self._sentry_logs_handler.level + self._event_handler is not None + and record.levelno >= self._event_handler.level ): - self._sentry_logs_handler.handle(record) + self._event_handler.handle(record) + + def _handle_breadcrumb_record(self, record: "LogRecord") -> None: + if ( + self._breadcrumb_handler is not None + and record.levelno >= self._breadcrumb_handler.level + ): + self._breadcrumb_handler.handle(record) @staticmethod def setup_once() -> None: @@ -164,7 +176,7 @@ def setup_once() -> None: def sentry_patched_callhandlers(self: "Any", record: "LogRecord") -> "Any": # keeping a local reference because the # global might be discarded on shutdown - ignored_loggers = _IGNORED_LOGGERS + ignored_loggers_events = _IGNORED_LOGGERS_EVENTS ignored_loggers_sentry_logs = _IGNORED_LOGGERS_SENTRY_LOGS try: @@ -177,7 +189,8 @@ def sentry_patched_callhandlers(self: "Any", record: "LogRecord") -> "Any": name = record.name.strip() handle_events = ( - ignored_loggers is not None and name not in ignored_loggers + ignored_loggers_events is not None + and name not in ignored_loggers_events ) handle_sentry_logs = ( ignored_loggers_sentry_logs is not None @@ -189,10 +202,11 @@ def sentry_patched_callhandlers(self: "Any", record: "LogRecord") -> "Any": LoggingIntegration ) if integration is not None: - if handle_events: - integration._handle_record(record) if handle_sentry_logs: - integration._handle_sentry_logs_record(record) + integration._handle_logs_record(record) + if handle_events: + integration._handle_event_record(record) + integration._handle_breadcrumb_record(record) logging.Logger.callHandlers = sentry_patched_callhandlers # type: ignore @@ -244,14 +258,12 @@ def _extra_from_record(self, record: "LogRecord") -> "MutableMapping[str, object class EventHandler(_BaseHandler): """ - A logging handler that emits Sentry events for each log record - - Note that you do not have to use this class if the logging integration is enabled, which it is by default. + A logging handler that emits Sentry events for each log record. """ def _can_record(self, record: "LogRecord") -> bool: """Prevents ignored loggers from recording""" - for logger in _IGNORED_LOGGERS: + for logger in _IGNORED_LOGGERS_EVENTS: if fnmatch(record.name.strip(), logger): return False return True @@ -337,20 +349,14 @@ def _emit(self, record: "LogRecord") -> None: sentry_sdk.capture_event(event, hint=hint) -# Legacy name -SentryHandler = EventHandler - - class BreadcrumbHandler(_BaseHandler): """ A logging handler that records breadcrumbs for each log record. - - Note that you do not have to use this class if the logging integration is enabled, which it is by default. """ def _can_record(self, record: "LogRecord") -> bool: """Prevents ignored loggers from recording""" - for logger in _IGNORED_LOGGERS: + for logger in _IGNORED_LOGGERS_EVENTS: if fnmatch(record.name.strip(), logger): return False return True @@ -379,11 +385,9 @@ def _breadcrumb_from_record(self, record: "LogRecord") -> "Dict[str, Any]": } -class SentryLogsHandler(_BaseHandler): +class LogsHandler(_BaseHandler): """ A logging handler that records Sentry logs for each Python log record. - - Note that you do not have to use this class if the LoggingIntegration's capture_sentry_logs option is enabled. """ def _can_record(self, record: "LogRecord") -> bool: @@ -403,9 +407,6 @@ def emit(self, record: "LogRecord") -> "Any": if not client.is_active(): return - if LoggingIntegration.capture_sentry_logs is not True: - return - self._capture_log_from_record(client, record) def _capture_log_from_record( diff --git a/sentry_sdk/integrations/rq.py b/sentry_sdk/integrations/rq.py index d1d374618f..445832ac74 100644 --- a/sentry_sdk/integrations/rq.py +++ b/sentry_sdk/integrations/rq.py @@ -4,7 +4,7 @@ import sentry_sdk from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version -from sentry_sdk.integrations.logging import ignore_logger +from sentry_sdk.integrations.logging import ignore_logger_for_events from sentry_sdk.scope import Scope, should_send_default_pii from sentry_sdk.traces import SegmentNameSource from sentry_sdk.tracing_utils import has_span_streaming_enabled @@ -153,7 +153,7 @@ def sentry_patched_enqueue_job( Queue.enqueue_job = sentry_patched_enqueue_job - ignore_logger("rq.worker") + ignore_logger_for_events("rq.worker") def _make_event_processor(weak_job: "Callable[[], Job]") -> "EventProcessor": diff --git a/sentry_sdk/integrations/strawberry.py b/sentry_sdk/integrations/strawberry.py index 73d2028006..d1b4e613a5 100644 --- a/sentry_sdk/integrations/strawberry.py +++ b/sentry_sdk/integrations/strawberry.py @@ -5,7 +5,7 @@ import sentry_sdk from sentry_sdk.consts import OP from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version -from sentry_sdk.integrations.logging import ignore_logger +from sentry_sdk.integrations.logging import ignore_logger_for_events from sentry_sdk.scope import should_send_default_pii from sentry_sdk.traces import SegmentNameSource from sentry_sdk.utils import ( @@ -49,7 +49,7 @@ from sentry_sdk._types import Event, EventProcessor -ignore_logger("strawberry.execution") +ignore_logger_for_events("strawberry.execution") class StrawberryIntegration(Integration): diff --git a/sentry_sdk/integrations/tornado.py b/sentry_sdk/integrations/tornado.py index 780f9333b3..f1cba6bf44 100644 --- a/sentry_sdk/integrations/tornado.py +++ b/sentry_sdk/integrations/tornado.py @@ -11,7 +11,7 @@ _is_json_content_type, request_body_within_bounds, ) -from sentry_sdk.integrations.logging import ignore_logger +from sentry_sdk.integrations.logging import ignore_logger_for_events from sentry_sdk.scope import should_send_default_pii from sentry_sdk.traces import SegmentNameSource from sentry_sdk.utils import ( @@ -46,7 +46,7 @@ class TornadoIntegration(Integration): def setup_once() -> None: _check_minimum_version(TornadoIntegration, TORNADO_VERSION) - ignore_logger("tornado.access") + ignore_logger_for_events("tornado.access") old_execute = RequestHandler._execute diff --git a/tests/integrations/django/test_tasks.py b/tests/integrations/django/test_tasks.py index 674ef53f0e..7456ff9ccb 100644 --- a/tests/integrations/django/test_tasks.py +++ b/tests/integrations/django/test_tasks.py @@ -1,8 +1,11 @@ +import logging + import pytest import sentry_sdk from sentry_sdk.consts import OP from sentry_sdk.integrations.django import DjangoIntegration +from sentry_sdk.integrations.logging import LoggingIntegration try: from django.tasks import task @@ -196,7 +199,10 @@ def test_task_error_reporting( ): """Test that errors in tasks are correctly reported and don't break the span.""" sentry_init( - integrations=[DjangoIntegration()], + integrations=[ + DjangoIntegration(), + LoggingIntegration(event_level=logging.ERROR), + ], traces_sample_rate=1.0, trace_lifecycle="stream" if span_streaming else "static", ) diff --git a/tests/integrations/dramatiq/test_dramatiq.py b/tests/integrations/dramatiq/test_dramatiq.py index 45e3547ee0..686400c1e1 100644 --- a/tests/integrations/dramatiq/test_dramatiq.py +++ b/tests/integrations/dramatiq/test_dramatiq.py @@ -9,10 +9,10 @@ from sentry_sdk import start_transaction from sentry_sdk.consts import SPANDATA, SPANSTATUS from sentry_sdk.integrations.dramatiq import DramatiqIntegration -from sentry_sdk.integrations.logging import ignore_logger +from sentry_sdk.integrations.logging import ignore_logger_for_events from sentry_sdk.tracing import Transaction, TransactionSource -ignore_logger("dramatiq.worker.WorkerThread") +ignore_logger_for_events("dramatiq.worker.WorkerThread") @pytest.fixture(scope="function") diff --git a/tests/integrations/fastapi/test_fastapi.py b/tests/integrations/fastapi/test_fastapi.py index 8f334509cd..ea5e63df77 100644 --- a/tests/integrations/fastapi/test_fastapi.py +++ b/tests/integrations/fastapi/test_fastapi.py @@ -27,6 +27,7 @@ from sentry_sdk.feature_flags import add_feature_flag from sentry_sdk.integrations.asgi import SentryAsgiMiddleware from sentry_sdk.integrations.fastapi import FastApiIntegration +from sentry_sdk.integrations.logging import LoggingIntegration from sentry_sdk.integrations.starlette import StarletteIntegration from sentry_sdk.utils import parse_version @@ -488,7 +489,11 @@ async def test_original_request_not_scrubbed( ): sentry_init( auto_enabling_integrations=False, # Ensure httpx is not auto-enabled; its legacy start_span interferes with streaming mode - integrations=[StarletteIntegration(), FastApiIntegration()], + integrations=[ + StarletteIntegration(), + FastApiIntegration(), + LoggingIntegration(event_level=logging.ERROR), + ], traces_sample_rate=1.0, trace_lifecycle="stream" if span_streaming else "static", ) diff --git a/tests/integrations/fastmcp/test_fastmcp.py b/tests/integrations/fastmcp/test_fastmcp.py index 71d780fa04..4d3784e135 100644 --- a/tests/integrations/fastmcp/test_fastmcp.py +++ b/tests/integrations/fastmcp/test_fastmcp.py @@ -23,12 +23,14 @@ import asyncio import json +import logging from unittest import mock import anyio import pytest import sentry_sdk +from sentry_sdk.integrations.logging import LoggingIntegration from sentry_sdk.utils import package_version, parse_version try: @@ -518,8 +520,10 @@ async def test_fastmcp_tool_with_error( span_streaming, ): """Test that FastMCP tool handler errors are captured properly""" + # TODO: This test doesn't capture errors via the MCP integration, but rather + # via logging. Might be worth another look if that's intended. sentry_init( - integrations=[MCPIntegration()], + integrations=[MCPIntegration(), LoggingIntegration(event_level=logging.ERROR)], traces_sample_rate=1.0, trace_lifecycle="stream" if span_streaming else "static", ) diff --git a/tests/integrations/flask/test_flask.py b/tests/integrations/flask/test_flask.py index 1bb9203566..c6140bfcf0 100644 --- a/tests/integrations/flask/test_flask.py +++ b/tests/integrations/flask/test_flask.py @@ -338,7 +338,10 @@ def index(): def test_flask_session_tracking(sentry_init, capture_envelopes, app): sentry_init( - integrations=[flask_sentry.FlaskIntegration()], + integrations=[ + flask_sentry.FlaskIntegration(), + LoggingIntegration(level=None, event_level=logging.ERROR), + ], release="demo-release", ) @@ -1017,7 +1020,12 @@ def index(): def test_request_not_modified_by_reference(sentry_init, capture_events, app): - sentry_init(integrations=[flask_sentry.FlaskIntegration()]) + sentry_init( + integrations=[ + flask_sentry.FlaskIntegration(), + LoggingIntegration(event_level=logging.ERROR), + ] + ) @app.route("/", methods=["POST"]) def index(): diff --git a/tests/integrations/logging/test_logging.py b/tests/integrations/logging/test_logging.py index 01fd3c282f..ed069efbbb 100644 --- a/tests/integrations/logging/test_logging.py +++ b/tests/integrations/logging/test_logging.py @@ -4,14 +4,15 @@ import pytest +import sentry_sdk from sentry_sdk import get_client from sentry_sdk.consts import VERSION from sentry_sdk.integrations.logging import ( LoggingIntegration, ignore_logger, - ignore_logger_for_sentry_logs, + ignore_logger_for_events, unignore_logger, - unignore_logger_for_sentry_logs, + unignore_logger_for_events, ) other_logger = logging.getLogger("testfoo") @@ -24,9 +25,75 @@ def reset_level(): logger.setLevel(logging.DEBUG) +def test_logging_defaults(sentry_init, capture_events): + sentry_init() + + events = capture_events() + + logger.info("bread", extra=dict(foo=42)) + logger.critical("lol", extra=dict(bar=69)) + + sentry_sdk.capture_message("hello") + + sentry_sdk.flush() + + for event in events: + print(event) + print() + + # Without adding the integration explicitly, only the message should be + # captured (no logs), and it shouldn't have any breadcrumbs + assert len(events) == 1 + (event,) = events + assert not event["breadcrumbs"]["values"] + + +def test_logging_defaults_enabled(sentry_init, capture_items): + sentry_init( + integrations=[LoggingIntegration()], + ) + + items = capture_items() + + logger.info("bread", extra=dict(foo=42)) + logger.critical("lol", extra=dict(bar=69)) + + sentry_sdk.capture_message("hello") + + sentry_sdk.flush() + + assert len(items) == 3 + message, log1, log2 = [item.payload for item in items] + + assert len(message["breadcrumbs"]["values"]) == 2 + crumb1, crumb2 = message["breadcrumbs"]["values"] + + assert crumb1["type"] == "log" + assert crumb1["message"] == "bread" + assert crumb1["data"] == {"foo": 42} + + assert crumb2["type"] == "log" + assert crumb2["message"] == "lol" + assert crumb2["data"] == {"bar": 69} + + assert log1["level"] == "info" + assert log1["attributes"]["sentry.severity_number"] == 9 + assert log1["attributes"]["sentry.severity_text"] == "info" + assert log1["attributes"]["foo"] == 42 + + assert log2["level"] == "fatal" + assert log2["attributes"]["sentry.severity_number"] == 21 + assert log2["attributes"]["sentry.severity_text"] == "fatal" + assert log2["attributes"]["bar"] == 69 + + @pytest.mark.parametrize("logger", [logger, other_logger]) -def test_logging_works_with_many_loggers(sentry_init, capture_events, logger): - sentry_init(integrations=[LoggingIntegration(event_level="ERROR")]) +def test_event_logging_works_with_many_loggers(sentry_init, capture_events, logger): + sentry_init( + integrations=[ + LoggingIntegration(event_level=logging.ERROR, breadcrumb_level=logging.INFO) + ] + ) events = capture_events() logger.info("bread") @@ -39,28 +106,13 @@ def test_logging_works_with_many_loggers(sentry_init, capture_events, logger): assert any(crumb["message"] == "bread" for crumb in event["breadcrumbs"]["values"]) -@pytest.mark.parametrize("integrations", [None, [], [LoggingIntegration()]]) -@pytest.mark.parametrize( - "kwargs", [{"exc_info": None}, {}, {"exc_info": 0}, {"exc_info": False}] -) -def test_logging_defaults(integrations, sentry_init, capture_events, kwargs): - sentry_init(integrations=integrations) - events = capture_events() - - logger.info("bread") - logger.critical("LOL", **kwargs) - (event,) = events - - assert event["level"] == "fatal" - assert any(crumb["message"] == "bread" for crumb in event["breadcrumbs"]["values"]) - assert not any( - crumb["message"] == "LOL" for crumb in event["breadcrumbs"]["values"] +def test_event_logging_extra_data(sentry_init, capture_events): + sentry_init( + integrations=[ + LoggingIntegration(breadcrumb_level=logging.INFO, event_level=logging.ERROR) + ], + default_integrations=False, ) - assert "threads" not in event - - -def test_logging_extra_data(sentry_init, capture_events): - sentry_init(integrations=[LoggingIntegration()], default_integrations=False) events = capture_events() logger.info("bread", extra=dict(foo=42)) @@ -76,8 +128,15 @@ def test_logging_extra_data(sentry_init, capture_events): ) -def test_logging_extra_data_integer_keys(sentry_init, capture_events): - sentry_init(integrations=[LoggingIntegration()], default_integrations=False) +def test_event_logging_extra_data_integer_keys(sentry_init, capture_events): + sentry_init( + integrations=[ + LoggingIntegration( + breadcrumb_level=logging.INFO, event_level=logging.ERROR + ), + ], + default_integrations=False, + ) events = capture_events() logger.critical("integer in extra keys", extra={1: 1}) @@ -94,8 +153,14 @@ def test_logging_extra_data_integer_keys(sentry_init, capture_events): pytest.param({"stack_info": True}, id="stack_info"), ), ) -def test_logging_stack_trace(sentry_init, capture_events, enable_stack_trace_kwarg): - sentry_init(integrations=[LoggingIntegration()], default_integrations=False) +def test_event_logging_stack_trace( + sentry_init, capture_events, enable_stack_trace_kwarg +): + sentry_init( + integrations=[ + LoggingIntegration(breadcrumb_level=logging.INFO, event_level=logging.ERROR) + ], + ) events = capture_events() logger.error("first", **enable_stack_trace_kwarg) @@ -113,8 +178,12 @@ def test_logging_stack_trace(sentry_init, capture_events, enable_stack_trace_kwa assert "threads" not in event_without -def test_logging_level(sentry_init, capture_events): - sentry_init(integrations=[LoggingIntegration()], default_integrations=False) +def test_event_logging_level(sentry_init, capture_events): + sentry_init( + integrations=[ + LoggingIntegration(breadcrumb_level=logging.INFO, event_level=logging.ERROR) + ], + ) events = capture_events() logger.setLevel(logging.WARNING) @@ -131,7 +200,7 @@ def test_logging_level(sentry_init, capture_events): assert not events -def test_custom_log_level_names(sentry_init, capture_events): +def test_event_logging_custom_level_names(sentry_init, capture_events): levels = { logging.DEBUG: "debug", logging.INFO: "info", @@ -155,7 +224,6 @@ def test_custom_log_level_names(sentry_init, capture_events): logger.setLevel(logging_level) sentry_init( integrations=[LoggingIntegration(event_level=logging_level)], - default_integrations=False, ) events = capture_events() @@ -169,8 +237,12 @@ def test_custom_log_level_names(sentry_init, capture_events): del events[:] -def test_logging_filters(sentry_init, capture_events): - sentry_init(integrations=[LoggingIntegration()], default_integrations=False) +def test_event_logging_filters(sentry_init, capture_events): + sentry_init( + integrations=[ + LoggingIntegration(breadcrumb_level=logging.INFO, event_level=logging.ERROR) + ], + ) events = capture_events() should_log = False @@ -192,10 +264,9 @@ def filter(self, record): assert event["logentry"]["formatted"] == "hi" -def test_logging_captured_warnings(sentry_init, capture_events, recwarn): +def test_event_logging_captured_warnings(sentry_init, capture_events, recwarn): sentry_init( integrations=[LoggingIntegration(event_level="WARNING")], - default_integrations=False, ) events = capture_events() @@ -232,27 +303,27 @@ def test_logging_captured_warnings(sentry_init, capture_events, recwarn): def test_sentry_logs_collection_off_by_default(sentry_init, capture_items, request): - """Automatic logs capture by Sentry logs needs explicit opt-in via capture_sentry_logs.""" + """Automatic logs capture by Sentry logs needs explicit opt-in to the integration.""" sentry_init() items = capture_items("log") python_logger = logging.Logger("test-logger") python_logger.warning("this is %s a template %s", "1", "2") - get_client().flush() + sentry_sdk.flush() assert not items def test_sentry_logs_collection_opt_in(sentry_init, capture_items, request): - """Automatic logs capture by Sentry logs needs explicit opt-in via capture_sentry_logs.""" - sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)]) + """Automatic logs capture by Sentry logs needs explicit opt-in to the integration.""" + sentry_init(integrations=[LoggingIntegration()]) items = capture_items("log") python_logger = logging.Logger("test-logger") python_logger.warning("this is %s a template %s", "1", "2") - get_client().flush() + sentry_sdk.flush() assert len(items) == 1 @@ -262,37 +333,45 @@ def test_sentry_logs_collection_opt_in(sentry_init, capture_items, request): assert log["attributes"]["sentry.severity_text"] == "warn" -def test_ignore_logger(sentry_init, capture_events, request): - sentry_init(integrations=[LoggingIntegration()], default_integrations=False) +def test_ignore_logger_for_events(sentry_init, capture_events, request): + sentry_init( + integrations=[LoggingIntegration(event_level=logging.DEBUG)], + ) events = capture_events() - ignore_logger("testfoo") - request.addfinalizer(lambda: unignore_logger("testfoo")) + ignore_logger_for_events("testfoo") + request.addfinalizer(lambda: unignore_logger_for_events("testfoo")) other_logger.error("hi") assert not events -def test_ignore_logger_whitespace_padding(sentry_init, capture_events, request): +def test_ignore_logger_for_events_whitespace_padding( + sentry_init, capture_events, request +): """Here we test insensitivity to whitespace padding of ignored loggers""" - sentry_init(integrations=[LoggingIntegration()], default_integrations=False) + sentry_init( + integrations=[LoggingIntegration(event_level=logging.DEBUG)], + ) events = capture_events() - ignore_logger("testfoo") - request.addfinalizer(lambda: unignore_logger("testfoo")) + ignore_logger_for_events("testfoo") + request.addfinalizer(lambda: unignore_logger_for_events("testfoo")) padded_logger = logging.getLogger(" testfoo ") padded_logger.error("hi") assert not events -def test_ignore_logger_wildcard(sentry_init, capture_events, request): - sentry_init(integrations=[LoggingIntegration()], default_integrations=False) +def test_ignore_logger_for_events_wildcard(sentry_init, capture_events, request): + sentry_init( + integrations=[LoggingIntegration(event_level=logging.DEBUG)], + ) events = capture_events() - ignore_logger("testfoo.*") - request.addfinalizer(lambda: unignore_logger("testfoo.*")) + ignore_logger_for_events("testfoo.*") + request.addfinalizer(lambda: unignore_logger_for_events("testfoo.*")) nested_logger = logging.getLogger("testfoo.submodule") @@ -305,13 +384,15 @@ def test_ignore_logger_wildcard(sentry_init, capture_events, request): assert event["logentry"]["formatted"] == "hi" -def test_ignore_logger_does_not_affect_sentry_logs(sentry_init, capture_items, request): - """ignore_logger should suppress events/breadcrumbs but not Sentry Logs.""" - sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)]) +def test_ignore_logger_for_events_does_not_affect_sentry_logs( + sentry_init, capture_items, request +): + """ignore_logger_for_events should suppress events/breadcrumbs but not Sentry Logs.""" + sentry_init(integrations=[LoggingIntegration(event_level=logging.DEBUG)]) items = capture_items("log") - ignore_logger("testfoo") - request.addfinalizer(lambda: unignore_logger("testfoo")) + ignore_logger_for_events("testfoo") + request.addfinalizer(lambda: unignore_logger_for_events("testfoo")) other_logger.error("hi") get_client().flush() @@ -321,19 +402,17 @@ def test_ignore_logger_does_not_affect_sentry_logs(sentry_init, capture_items, r assert logs[0]["body"] == "hi" -def test_ignore_logger_for_sentry_logs( - sentry_init, capture_envelopes, capture_items, request -): - """ignore_logger_for_sentry_logs should suppress Sentry Logs but not events.""" - sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)]) +def test_ignore_logger(sentry_init, capture_envelopes, capture_items, request): + """ignore_logger should suppress Sentry Logs but not events.""" + sentry_init(integrations=[LoggingIntegration(event_level=logging.ERROR)]) envelopes = capture_envelopes() items = capture_items("log") - ignore_logger_for_sentry_logs("testfoo") - request.addfinalizer(lambda: unignore_logger_for_sentry_logs("testfoo")) + ignore_logger("testfoo") + request.addfinalizer(lambda: unignore_logger("testfoo")) other_logger.error("hi") - get_client().flush() + sentry_sdk.flush() # Event should still be captured event_envelopes = [e for e in envelopes if e.items[0].type == "event"] @@ -344,9 +423,11 @@ def test_ignore_logger_for_sentry_logs( assert len(logs) == 0 -def test_logging_dictionary_interpolation(sentry_init, capture_events): +def test_event_logging_dictionary_interpolation(sentry_init, capture_events): """Here we test an entire dictionary being interpolated into the log message.""" - sentry_init(integrations=[LoggingIntegration()], default_integrations=False) + sentry_init( + integrations=[LoggingIntegration(event_level=logging.ERROR)], + ) events = capture_events() logger.error("this is a log with a dictionary %s", {"foo": "bar"}) @@ -360,9 +441,11 @@ def test_logging_dictionary_interpolation(sentry_init, capture_events): assert event["logentry"]["params"] == {"foo": "bar"} -def test_logging_dictionary_args(sentry_init, capture_events): +def test_event_logging_dictionary_args(sentry_init, capture_events): """Here we test items from a dictionary being interpolated into the log message.""" - sentry_init(integrations=[LoggingIntegration()], default_integrations=False) + sentry_init( + integrations=[LoggingIntegration(event_level=logging.ERROR)], + ) events = capture_events() logger.error( @@ -386,13 +469,13 @@ def test_sentry_logs_warning(sentry_init, capture_items): """ The python logger module should create 'warn' sentry logs if the flag is on. """ - sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)]) + sentry_init(integrations=[LoggingIntegration()]) items = capture_items("log") python_logger = logging.Logger("test-logger") python_logger.warning("this is %s a template %s", "1", "2") - get_client().flush() + sentry_sdk.flush() logs = [item.payload for item in items] attrs = logs[0]["attributes"] assert attrs["sentry.message.template"] == "this is %s a template %s" @@ -411,12 +494,12 @@ def test_sentry_logs_debug(sentry_init, capture_envelopes): """ The python logger module should not create 'debug' sentry logs if the flag is on by default """ - sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)]) + sentry_init(integrations=[LoggingIntegration()]) envelopes = capture_envelopes() python_logger = logging.Logger("test-logger") python_logger.debug("this is %s a template %s", "1", "2") - get_client().flush() + sentry_sdk.flush() assert len(envelopes) == 0 @@ -426,18 +509,14 @@ def test_no_log_infinite_loop(sentry_init, capture_envelopes): If 'debug' mode is true, and you set a low log level in the logging integration, there should be no infinite loops. """ sentry_init( - integrations=[ - LoggingIntegration( - capture_sentry_logs=True, sentry_logs_level=logging.DEBUG - ) - ], + integrations=[LoggingIntegration(level=logging.DEBUG)], debug=True, ) envelopes = capture_envelopes() python_logger = logging.Logger("test-logger") python_logger.debug("this is %s a template %s", "1", "2") - get_client().flush() + sentry_sdk.flush() assert len(envelopes) == 1 @@ -446,14 +525,15 @@ def test_logging_errors(sentry_init, capture_envelopes, capture_items): """ The python logger module should be able to log errors without erroring """ - sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)]) + sentry_init(integrations=[LoggingIntegration(event_level=logging.ERROR)]) envelopes = capture_envelopes() items = capture_items("log") python_logger = logging.Logger("test-logger") python_logger.error(Exception("test exc 1")) python_logger.error("error is %s", Exception("test exc 2")) - get_client().flush() + + sentry_sdk.flush() error_event_1 = envelopes[0].items[0].payload.json assert error_event_1["level"] == "error" @@ -482,7 +562,7 @@ def test_log_strips_project_root(sentry_init, capture_items): """ sentry_init( project_root="/custom/test", - integrations=[LoggingIntegration(capture_sentry_logs=True)], + integrations=[LoggingIntegration()], ) items = capture_items("log") @@ -498,7 +578,7 @@ def test_log_strips_project_root(sentry_init, capture_items): exc_info=None, ) ) - get_client().flush() + sentry_sdk.flush() logs = [item.payload for item in items] assert len(logs) == 1 @@ -510,7 +590,7 @@ def test_logger_with_all_attributes(sentry_init, capture_items): """ The python logger should be able to log all attributes, including extra data. """ - sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)]) + sentry_init(integrations=[LoggingIntegration()]) items = capture_items("log") python_logger = logging.Logger("test-logger") @@ -519,7 +599,7 @@ def test_logger_with_all_attributes(sentry_init, capture_items): 1, extra={"foo": "bar", "numeric": 42, "more_complex": {"nested": "data"}}, ) - get_client().flush() + sentry_sdk.flush() logs = [item.payload for item in items] @@ -587,7 +667,7 @@ def test_sentry_logs_named_parameters(sentry_init, capture_items): """ The python logger module should capture named parameters from dictionary arguments in Sentry logs. """ - sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)]) + sentry_init(integrations=[LoggingIntegration()]) items = capture_items("log") python_logger = logging.Logger("test-logger") @@ -602,7 +682,7 @@ def test_sentry_logs_named_parameters(sentry_init, capture_items): }, ) - get_client().flush() + sentry_sdk.flush() logs = [item.payload for item in items] assert len(logs) == 1 @@ -632,7 +712,7 @@ def test_sentry_logs_named_parameters_complex_values(sentry_init, capture_items) """ The python logger module should handle complex values in named parameters using safe_repr. """ - sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)]) + sentry_init(integrations=[LoggingIntegration()]) items = capture_items("log") python_logger = logging.Logger("test-logger") @@ -645,7 +725,7 @@ def test_sentry_logs_named_parameters_complex_values(sentry_init, capture_items) }, ) - get_client().flush() + sentry_sdk.flush() logs = [item.payload for item in items] assert len(logs) == 1 @@ -666,13 +746,13 @@ def test_sentry_logs_no_parameters_no_template(sentry_init, capture_items): """ There shouldn't be a template if there are no parameters. """ - sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)]) + sentry_init(integrations=[LoggingIntegration()]) items = capture_items("log") python_logger = logging.Logger("test-logger") python_logger.warning("Warning about something without any parameters.") - get_client().flush() + sentry_sdk.flush() logs = [item.payload for item in items] assert len(logs) == 1 diff --git a/tests/integrations/starlette/test_starlette.py b/tests/integrations/starlette/test_starlette.py index d8c6115940..d3bf32f791 100644 --- a/tests/integrations/starlette/test_starlette.py +++ b/tests/integrations/starlette/test_starlette.py @@ -27,6 +27,7 @@ from sentry_sdk._types import SENSITIVE_DATA_SUBSTITUTE from sentry_sdk.consts import SPANDATA from sentry_sdk.integrations.asgi import SentryAsgiMiddleware +from sentry_sdk.integrations.logging import LoggingIntegration from sentry_sdk.integrations.starlette import ( StarletteIntegration, ) @@ -1506,7 +1507,12 @@ def test_transaction_name_is_route_resolved_name_static( def test_original_request_not_scrubbed(sentry_init, capture_events): - sentry_init(integrations=[StarletteIntegration()]) + sentry_init( + integrations=[ + StarletteIntegration(), + LoggingIntegration(event_level=logging.ERROR), + ] + ) events = capture_events() diff --git a/tests/test_scrubber.py b/tests/test_scrubber.py index 211d6336ac..589ea2cd48 100644 --- a/tests/test_scrubber.py +++ b/tests/test_scrubber.py @@ -2,6 +2,7 @@ import sys from sentry_sdk import capture_event, capture_exception, start_span, start_transaction +from sentry_sdk.integrations.logging import LoggingIntegration from sentry_sdk.scrubber import EventScrubber from sentry_sdk.utils import event_from_exception from tests.conftest import ApproxDict @@ -154,8 +155,15 @@ def test_stack_var_scrubbing(sentry_init, capture_events): def test_breadcrumb_extra_scrubbing(sentry_init, capture_events): - sentry_init(max_breadcrumbs=2) + sentry_init( + max_breadcrumbs=2, + integrations=[ + LoggingIntegration(breadcrumb_level=logging.INFO, event_level=logging.ERROR) + ], + ) + events = capture_events() + logger.info("breadcrumb 1", extra=dict(foo=1, password="secret")) logger.info("breadcrumb 2", extra=dict(bar=2, auth="secret")) logger.info("breadcrumb 3", extra=dict(foobar=3, password="secret")) diff --git a/tests/test_transport.py b/tests/test_transport.py index 57f61fbdc5..aa45dde76d 100644 --- a/tests/test_transport.py +++ b/tests/test_transport.py @@ -37,7 +37,7 @@ from sentry_sdk._compat import PY37, PY38 from sentry_sdk.envelope import Envelope, Item, PayloadRef, parse_json from sentry_sdk.integrations.asyncio import AsyncioIntegration -from sentry_sdk.integrations.logging import LoggingIntegration, ignore_logger +from sentry_sdk.integrations.logging import LoggingIntegration, ignore_logger_for_events from sentry_sdk.transport import ( KEEP_ALIVE_SOCKET_OPTIONS, AsyncHttpTransport, @@ -402,15 +402,15 @@ def test_transport_infinite_loop(capturing_server, request, make_client): client = make_client( debug=True, # Make sure we cannot create events from our own logging - integrations=[LoggingIntegration(event_level=logging.DEBUG)], + integrations=[LoggingIntegration(event_level=logging.DEBUG, level=None)], ) # I am not sure why, but "werkzeug" logger makes an INFO log on sending - # the message "hi" and does creates an infinite look. + # the message "hi" and does creates an infinite loop. # Ignoring this for breaking the infinite loop and still we can test # that our own log messages (sent from `_IGNORED_LOGGERS`) are not leading # to an infinite loop - ignore_logger("werkzeug") + ignore_logger_for_events("werkzeug") sentry_sdk.get_global_scope().set_client(client) with isolation_scope():