Repository: getsentry/sentry-python

Issue:
Add `include_source_context` option
### Problem Statement

Some users do not like the source context to be there and want to disable it.

### Solution Brainstorm

For this we need to add a SDK option `include_source_context` that defaults to `True`.
If set to false, the source context should not be included.

Here is probably the place where to decide whether to add the source context or not: 
https://github.com/getsentry/sentry-python/blob/antonpirker/celery-beat-wo-restart/sentry_sdk/utils.py#L614-L625

Discussion:
antonpirker: Hey @farhat-nawaz !

Thanks for the contribution! Looks good!

Now we also need the `include_source_context` option in `ClientConstructor` class at the end and need to pass this option along so that all calls to `serialize_frame` are given the option set in `ClientConstructor`. (you can see   `include_local_variables` for a similar option)
antonpirker: If you do not have time it is also possible that we merge this and take over the rest of the implementation. Should we do this?
farhat-nawaz: @antonpirker Sure, I can add those changes, no problem.
sentrivana: Hey @farhat-nawaz, thanks again for contributing! Did you already have time to start on the changes that Anton proposed? If not, I'm happy to take it from here and finish it.
sentrivana: Hi @farhat-nawaz, the PR looks good to me, I will merge it now as is and we'll add the missing stuff. Thank you for contributing! 🙏 

Patch:
diff --git a/sentry_sdk/utils.py b/sentry_sdk/utils.py
index e1a0273e..fc9ec194 100644
--- a/sentry_sdk/utils.py
+++ b/sentry_sdk/utils.py
@@ -594,8 +594,10 @@ def filename_for_module(module, abs_path):
         return abs_path
 
 
-def serialize_frame(frame, tb_lineno=None, include_local_variables=True):
-    # type: (FrameType, Optional[int], bool) -> Dict[str, Any]
+def serialize_frame(
+    frame, tb_lineno=None, include_local_variables=True, include_source_context=True
+):
+    # type: (FrameType, Optional[int], bool, bool) -> Dict[str, Any]
     f_code = getattr(frame, "f_code", None)
     if not f_code:
         abs_path = None
@@ -611,18 +613,19 @@ def serialize_frame(frame, tb_lineno=None, include_local_variables=True):
     if tb_lineno is None:
         tb_lineno = frame.f_lineno
 
-    pre_context, context_line, post_context = get_source_context(frame, tb_lineno)
-
     rv = {
         "filename": filename_for_module(module, abs_path) or None,
         "abs_path": os.path.abspath(abs_path) if abs_path else None,
         "function": function or "<unknown>",
         "module": module,
         "lineno": tb_lineno,
-        "pre_context": pre_context,
-        "context_line": context_line,
-        "post_context": post_context,
     }  # type: Dict[str, Any]
+
+    if include_source_context:
+        rv["pre_context"], rv["context_line"], rv["post_context"] = get_source_context(
+            frame, tb_lineno
+        )
+
     if include_local_variables:
         rv["vars"] = frame.f_locals
 
@@ -1240,7 +1243,6 @@ ParsedUrl = namedtuple("ParsedUrl", ["url", "query", "fragment"])
 
 
 def parse_url(url, sanitize=True):
-
     # type: (str, bool) -> ParsedUrl
     """
     Splits a URL into a url (including path), query and fragment. If sanitize is True, the query


Test patch:
diff --git a/tests/test_utils.py b/tests/test_utils.py
index 7578e625..aa88d26c 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -1,7 +1,14 @@
 import pytest
 import re
+import sys
 
-from sentry_sdk.utils import is_valid_sample_rate, logger, parse_url, sanitize_url
+from sentry_sdk.utils import (
+    is_valid_sample_rate,
+    logger,
+    parse_url,
+    sanitize_url,
+    serialize_frame,
+)
 
 try:
     from unittest import mock  # python 3.3 and above
@@ -221,3 +228,16 @@ def test_warns_on_invalid_sample_rate(rate, StringContaining):  # noqa: N803
         result = is_valid_sample_rate(rate, source="Testing")
         logger.warning.assert_any_call(StringContaining("Given sample rate is invalid"))
         assert result is False
+
+
+@pytest.mark.parametrize(
+    "include_source_context",
+    [True, False],
+)
+def test_include_source_context_when_serializing_frame(include_source_context):
+    frame = sys._getframe()
+    result = serialize_frame(frame, include_source_context=include_source_context)
+
+    assert include_source_context ^ ("pre_context" in result) ^ True
+    assert include_source_context ^ ("context_line" in result) ^ True
+    assert include_source_context ^ ("post_context" in result) ^ True