diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index 87a81313eb..d05b617e4c 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -26,6 +26,7 @@ Looking to upgrade from Sentry SDK 2.x to 3.x? Here's a comprehensive list of wh - `sentry_sdk.init` now returns `None` instead of a context manager. - The `sampling_context` argument of `traces_sampler` and `profiles_sampler` now additionally contains all span attributes known at span start. - We updated how we handle `ExceptionGroup`s. You will now get more data if ExceptionGroups are appearing in chained exceptions. It could happen that after updating the SDK the grouping of issues change because of this. So eventually you will see the same exception in two Sentry issues (one from before the update, one from after the update) +- The integration for Python `logging` module does not send Sentry issues by default anymore when calling `logging.error()`, `logging.critical()` or `logging.exception()`. If you want to preserve the old behavior use `sentry_sdk.init(integrations=[LoggingIntegration(event_level="ERROR")])`. - The integration-specific content of the `sampling_context` argument of `traces_sampler` and `profiles_sampler` now looks different. - The Celery integration doesn't add the `celery_job` dictionary anymore. Instead, the individual keys are now available as: diff --git a/sentry_sdk/integrations/logging.py b/sentry_sdk/integrations/logging.py index 0647740d1f..6caa6dab34 100644 --- a/sentry_sdk/integrations/logging.py +++ b/sentry_sdk/integrations/logging.py @@ -23,7 +23,7 @@ from typing import Optional DEFAULT_LEVEL = logging.INFO -DEFAULT_EVENT_LEVEL = logging.ERROR +DEFAULT_EVENT_LEVEL = None # None means no events are captured LOGGING_TO_EVENT_LEVEL = { logging.NOTSET: "notset", logging.DEBUG: "debug", diff --git a/tests/integrations/flask/test_flask.py b/tests/integrations/flask/test_flask.py index 4e92df7e7c..a95393c585 100644 --- a/tests/integrations/flask/test_flask.py +++ b/tests/integrations/flask/test_flask.py @@ -285,7 +285,7 @@ def index(): try: raise ValueError("stuff") except Exception: - logging.exception("stuff happened") + sentry_sdk.capture_exception() 1 / 0 envelopes = capture_envelopes() @@ -875,7 +875,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="ERROR"), + ] + ) @app.route("/", methods=["POST"]) def index(): diff --git a/tests/integrations/logging/test_logging.py b/tests/integrations/logging/test_logging.py index 8c325bc86c..13135f8e47 100644 --- a/tests/integrations/logging/test_logging.py +++ b/tests/integrations/logging/test_logging.py @@ -15,42 +15,71 @@ def reset_level(): logger.setLevel(logging.DEBUG) -@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")]) +@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") - (event,) = events - assert event["level"] == "fatal" - assert not event["logentry"]["params"] - assert event["logentry"]["message"] == "LOL" - assert any(crumb["message"] == "bread" for crumb in event["breadcrumbs"]["values"]) + logger.error("error") + logger.critical("LOL", **kwargs) + + assert len(events) == 0 -@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) +def test_logging_basic(sentry_init, capture_events, kwargs): + sentry_init(integrations=[LoggingIntegration(event_level=logging.ERROR)]) events = capture_events() logger.info("bread") + logger.error("error") logger.critical("LOL", **kwargs) - (event,) = events + (error_event, critical_event) = events - assert event["level"] == "fatal" - assert any(crumb["message"] == "bread" for crumb in event["breadcrumbs"]["values"]) + assert error_event["level"] == "error" + assert any( + crumb["message"] == "bread" for crumb in error_event["breadcrumbs"]["values"] + ) assert not any( - crumb["message"] == "LOL" for crumb in event["breadcrumbs"]["values"] + crumb["message"] == "LOL" for crumb in error_event["breadcrumbs"]["values"] ) - assert "threads" not in event + assert "threads" not in error_event + + assert critical_event["level"] == "fatal" + assert any( + crumb["message"] == "bread" for crumb in critical_event["breadcrumbs"]["values"] + ) + assert not any( + crumb["message"] == "LOL" for crumb in critical_event["breadcrumbs"]["values"] + ) + assert "threads" not in critical_event + + +@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")]) + events = capture_events() + + logger.info("bread") + logger.critical("LOL") + (event,) = events + assert event["level"] == "fatal" + assert not event["logentry"]["params"] + assert event["logentry"]["message"] == "LOL" + assert any(crumb["message"] == "bread" for crumb in event["breadcrumbs"]["values"]) def test_logging_extra_data(sentry_init, capture_events): - sentry_init(integrations=[LoggingIntegration()], default_integrations=False) + sentry_init( + integrations=[LoggingIntegration(event_level=logging.ERROR)], + default_integrations=False, + ) events = capture_events() logger.info("bread", extra=dict(foo=42)) @@ -67,7 +96,10 @@ 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) + sentry_init( + integrations=[LoggingIntegration(event_level=logging.ERROR)], + default_integrations=False, + ) events = capture_events() logger.critical("integer in extra keys", extra={1: 1}) @@ -85,7 +117,10 @@ def test_logging_extra_data_integer_keys(sentry_init, capture_events): ), ) def test_logging_stack_trace(sentry_init, capture_events, enable_stack_trace_kwarg): - sentry_init(integrations=[LoggingIntegration()], default_integrations=False) + sentry_init( + integrations=[LoggingIntegration(event_level=logging.ERROR)], + default_integrations=False, + ) events = capture_events() logger.error("first", **enable_stack_trace_kwarg) @@ -104,7 +139,10 @@ def test_logging_stack_trace(sentry_init, capture_events, enable_stack_trace_kwa def test_logging_level(sentry_init, capture_events): - sentry_init(integrations=[LoggingIntegration()], default_integrations=False) + sentry_init( + integrations=[LoggingIntegration(event_level=logging.ERROR)], + default_integrations=False, + ) events = capture_events() logger.setLevel(logging.WARNING) @@ -158,7 +196,10 @@ def test_custom_log_level_names(sentry_init, capture_events): def test_logging_filters(sentry_init, capture_events): - sentry_init(integrations=[LoggingIntegration()], default_integrations=False) + sentry_init( + integrations=[LoggingIntegration(event_level=logging.ERROR)], + default_integrations=False, + ) events = capture_events() should_log = False @@ -210,7 +251,10 @@ def test_logging_captured_warnings(sentry_init, capture_events, recwarn): def test_ignore_logger(sentry_init, capture_events): - sentry_init(integrations=[LoggingIntegration()], default_integrations=False) + sentry_init( + integrations=[LoggingIntegration(event_level=logging.ERROR)], + default_integrations=False, + ) events = capture_events() ignore_logger("testfoo") @@ -221,7 +265,10 @@ def test_ignore_logger(sentry_init, capture_events): def test_ignore_logger_wildcard(sentry_init, capture_events): - sentry_init(integrations=[LoggingIntegration()], default_integrations=False) + sentry_init( + integrations=[LoggingIntegration(event_level=logging.ERROR)], + default_integrations=False, + ) events = capture_events() ignore_logger("testfoo.*") diff --git a/tests/integrations/starlette/test_starlette.py b/tests/integrations/starlette/test_starlette.py index a3c289590b..bf89729b35 100644 --- a/tests/integrations/starlette/test_starlette.py +++ b/tests/integrations/starlette/test_starlette.py @@ -13,6 +13,7 @@ from sentry_sdk import capture_message, get_baggage, get_traceparent from sentry_sdk.integrations.asgi import SentryAsgiMiddleware +from sentry_sdk.integrations.logging import LoggingIntegration from sentry_sdk.integrations.starlette import ( StarletteIntegration, StarletteRequestExtractor, @@ -943,7 +944,9 @@ def test_active_thread_id(sentry_init, capture_envelopes, teardown_profiling, en def test_original_request_not_scrubbed(sentry_init, capture_events): - sentry_init(integrations=[StarletteIntegration()]) + sentry_init( + integrations=[StarletteIntegration(), LoggingIntegration(event_level="ERROR")] + ) events = capture_events() diff --git a/tests/test_logs.py b/tests/test_logs.py index 01fe574726..584fdcc608 100644 --- a/tests/test_logs.py +++ b/tests/test_logs.py @@ -331,7 +331,10 @@ def test_logging_errors(sentry_init, capture_envelopes): """ The python logger module should be able to log errors without erroring """ - sentry_init(_experiments={"enable_logs": True}) + sentry_init( + _experiments={"enable_logs": True}, + integrations=[LoggingIntegration(event_level="ERROR")], + ) envelopes = capture_envelopes() python_logger = logging.Logger("test-logger") diff --git a/tests/test_scrubber.py b/tests/test_scrubber.py index ee209da4b1..cc99411778 100644 --- a/tests/test_scrubber.py +++ b/tests/test_scrubber.py @@ -2,6 +2,7 @@ import logging from sentry_sdk import capture_exception, capture_event, start_span +from sentry_sdk.integrations.logging import LoggingIntegration from sentry_sdk.utils import event_from_exception from sentry_sdk.scrubber import EventScrubber from tests.conftest import ApproxDict @@ -119,7 +120,10 @@ 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(event_level="ERROR")], + ) events = capture_events() logger.info("breadcrumb 1", extra=dict(foo=1, password="secret")) logger.info("breadcrumb 2", extra=dict(bar=2, auth="secret"))