From 7266945722b37a3d999253198cc8c588a9e7d7b8 Mon Sep 17 00:00:00 2001 From: Roman Inflianskas Date: Thu, 18 Jul 2024 16:57:21 +0300 Subject: [PATCH] fix(tracing): fix logic for setting `in_app` flag Previously, in case packages added in `in_app_include` were installed into a location outside of the project root directory, stack frames from those packages were not marked as `in_app`. Cases include running Python from virtualenv, created outside of the project root directory, or Python packages installed into the system using package managers. This resulted in inconsistency: traces from the same project would have different `in_app` flags depending on the deployment method. Steps to reproduce (virtualenv outside of project root): ``` $ docker run --replace --rm --name sentry-postgres -e POSTGRES_USER=sentry -e POSTGRES_PASSWORD=sentry -d -p 5432:5432 postgres $ distrobox create -i ubuntu:24.04 -n sentry-test-in_app_include-venv $ distrobox enter sentry-test-in_app_include-venv $ python3 -m venv /tmp/.venv-test-in_app_include $ source /tmp/.venv-test-in_app_include/bin/activate $ pytest tests/integrations/django/test_db_query_data.py::test_query_source_with_in_app_include # FAIL ``` Steps to reproduce (system packages): ``` $ docker run --replace --rm --name sentry-postgres -e POSTGRES_USER=sentry -e POSTGRES_PASSWORD=sentry -d -p 5432:5432 postgres $ distrobox create -i ubuntu:24.04 -n sentry-test-in_app_include-os $ distrobox enter sentry-test-in_app_include-os $ sudo apt install python3-django python3-pytest python3-pytest-cov python3-pytest-django python3-jsonschema python3-urllib3 python3-certifi python3-werkzeug python3-psycopg2 $ pytest tests/integrations/django/test_db_query_data.py::test_query_source_with_in_app_include # FAIL ``` In this change, the logic was slightly changed to avoid these discrepancies and conform to the requirements, described in the PR with `in_app` flag introduction: https://github.com/getsentry/sentry-python/pull/1894#issue-1579192436. Note that the `_module_in_list` function returns `False` if `name` is `None`, hence extra check before function call can be omitted to simplify code. --- sentry_sdk/tracing_utils.py | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/sentry_sdk/tracing_utils.py b/sentry_sdk/tracing_utils.py index ba20dc8436..2568ab344c 100644 --- a/sentry_sdk/tracing_utils.py +++ b/sentry_sdk/tracing_utils.py @@ -213,20 +213,16 @@ def add_query_source(span): is_sentry_sdk_frame = namespace is not None and namespace.startswith( "sentry_sdk." ) + should_be_included = in_app_include and _module_in_list( + namespace, in_app_include + ) + should_be_excluded = _is_external_source(abs_path) or ( + in_app_exclude and _module_in_list(namespace, in_app_exclude) + ) - should_be_included = not _is_external_source(abs_path) - if namespace is not None: - if in_app_exclude and _module_in_list(namespace, in_app_exclude): - should_be_included = False - if in_app_include and _module_in_list(namespace, in_app_include): - # in_app_include takes precedence over in_app_exclude, so doing it - # at the end - should_be_included = True - - if ( - abs_path.startswith(project_root) - and should_be_included - and not is_sentry_sdk_frame + if not is_sentry_sdk_frame and ( + should_be_included + or (abs_path.startswith(project_root) and not should_be_excluded) ): break