prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  [0.7.0] `CeleryIntegration` captures retries
  Greetings fellows!
  
  We are having an issue with `CeleryIntegration` in Sentry SDK.
  
  ### Current versions
  Python 3.6.7
  Django 2.1.5
  Celery 4.1.1
  Sentry SDK 0.7.0-0.7.1
  
  ### Current behavior
  In our code (internal and 3rd-party) we are using [Celery tasks retry functionality](http://docs.celeryproject.org/en/latest/userguide/tasks.html#retrying).
  
  > The app.Task.retry() call will raise an exception so any code after the retry won’t be reached. This is the Retry exception, it isn’t handled as an error but rather as a semi-predicate to signify to the worker that the task is to be retried, so that it can store the correct state when a result backend is enabled.
  
  We did switch recently from Raven to Sentry SDK 0.6.9, everything seemed working as before.
  But today we updated it to [0.7.0 release](https://github.com/getsentry/sentry-python/blob/master/CHANGES.md#070) (and later to 0.7.1)
  
  This caused **every [`celery.exceptions.Retry`](http://docs.celeryproject.org/en/latest/reference/celery.exceptions.html#celery.exceptions.Retry) to be sent to Sentry**, which quickly filled Sentry server with thousands of events.
  Previously (in old SDK and Raven), those exceptions were ignored and not sent to Sentry server.
  
  ### Expected behaviour
  `CeleryIntegration` is not flooding Sentry server with every retry exception. Basically, the same behavior as it was in Raven and Sentry SDK<0.7.0.
  
  ### Open questions
  I am not sure if the old behavior was done intentionally or by mistake.
  If that was intended, we should reimplement it in current integration.
  If not, there should be a way to filter/ignore that kind of exceptions (I am not sure if we can filter all retries from internal and 3rd-party code in`before_send` in a clean way).
  
  Could you help me to clarify this issue?
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `sentry_sdk/integrations/celery.py`
  Content:
  ```
  1 from __future__ import absolute_import
  2 
  3 import sys
  4 
  5 from celery.exceptions import SoftTimeLimitExceeded
  6 
  7 from sentry_sdk.hub import Hub
  8 from sentry_sdk.utils import capture_internal_exceptions, event_from_exception
  9 from sentry_sdk._compat import reraise
  10 from sentry_sdk.integrations import Integration
  11 from sentry_sdk.integrations.logging import ignore_logger
  12 
  13 
  14 class CeleryIntegration(Integration):
  15     identifier = "celery"
  16 
  17     @staticmethod
  18     def setup_once():
  19         import celery.app.trace as trace
  20 
  21         old_build_tracer = trace.build_tracer
  22 
  23         def sentry_build_tracer(name, task, *args, **kwargs):
  24             # Need to patch both methods because older celery sometimes
  25             # short-circuits to task.run if it thinks it's safe.
  26             task.__call__ = _wrap_task_call(task.__call__)
  27             task.run = _wrap_task_call(task.run)
  28             return _wrap_tracer(task, old_build_tracer(name, task, *args, **kwargs))
  29 
  30         trace.build_tracer = sentry_build_tracer
  31 
  32         # This logger logs every status of every task that ran on the worker.
  33         # Meaning that every task's breadcrumbs are full of stuff like "Task
  34         # <foo> raised unexpected <bar>".
  35         ignore_logger("celery.worker.job")
  36 
  37 
  38 def _wrap_tracer(task, f):
  39     # Need to wrap tracer for pushing the scope before prerun is sent, and
  40     # popping it after postrun is sent.
  41     #
  42     # This is the reason we don't use signals for hooking in the first place.
  43     # Also because in Celery 3, signal dispatch returns early if one handler
  44     # crashes.
  45     def _inner(*args, **kwargs):
  46         hub = Hub.current
  47         if hub.get_integration(CeleryIntegration) is None:
  48             return f(*args, **kwargs)
  49 
  50         with hub.push_scope() as scope:
  51             scope._name = "celery"
  52             scope.add_event_processor(_make_event_processor(task, *args, **kwargs))
  53 
  54             return f(*args, **kwargs)
  55 
  56     return _inner
  57 
  58 
  59 def _wrap_task_call(f):
  60     # Need to wrap task call because the exception is caught before we get to
  61     # see it. Also celery's reported stacktrace is untrustworthy.
  62     def _inner(*args, **kwargs):
  63         try:
  64             return f(*args, **kwargs)
  65         except Exception:
  66             reraise(*_capture_exception())
  67 
  68     return _inner
  69 
  70 
  71 def _make_event_processor(task, uuid, args, kwargs, request=None):
  72     def event_processor(event, hint):
  73         with capture_internal_exceptions():
  74             event["transaction"] = task.name
  75 
  76         with capture_internal_exceptions():
  77             extra = event.setdefault("extra", {})
  78             extra["celery-job"] = {
  79                 "task_name": task.name,
  80                 "args": args,
  81                 "kwargs": kwargs,
  82             }
  83 
  84         if "exc_info" in hint:
  85             with capture_internal_exceptions():
  86                 if issubclass(hint["exc_info"][0], SoftTimeLimitExceeded):
  87                     event["fingerprint"] = [
  88                         "celery",
  89                         "SoftTimeLimitExceeded",
  90                         getattr(task, "name", task),
  91                     ]
  92 
  93             with capture_internal_exceptions():
  94                 if hasattr(task, "throws") and isinstance(
  95                     hint["exc_info"][1], task.throws
  96                 ):
  97                     return None
  98 
  99         return event
  100 
  101     return event_processor
  102 
  103 
  104 def _capture_exception():
  105     hub = Hub.current
  106     exc_info = sys.exc_info()
  107 
  108     if hub.get_integration(CeleryIntegration) is not None:
  109         event, hint = event_from_exception(
  110             exc_info,
  111             client_options=hub.client.options,
  112             mechanism={"type": "celery", "handled": False},
  113         )
  114         hub.capture_event(event, hint=hint)
  115 
  116     return exc_info
  117
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/sentry_sdk/integrations/celery.py b/sentry_sdk/integrations/celery.py
  --- a/sentry_sdk/integrations/celery.py
  +++ b/sentry_sdk/integrations/celery.py
  @@ -2,7 +2,7 @@
   
   import sys
   
  -from celery.exceptions import SoftTimeLimitExceeded
  +from celery.exceptions import SoftTimeLimitExceeded, Retry
   
   from sentry_sdk.hub import Hub
   from sentry_sdk.utils import capture_internal_exceptions, event_from_exception
  @@ -82,6 +82,15 @@
               }
   
           if "exc_info" in hint:
  +            with capture_internal_exceptions():
  +                if isinstance(hint["exc_info"][1], Retry):
  +                    return None
  +
  +                if hasattr(task, "throws") and isinstance(
  +                    hint["exc_info"][1], task.throws
  +                ):
  +                    return None
  +
               with capture_internal_exceptions():
                   if issubclass(hint["exc_info"][0], SoftTimeLimitExceeded):
                       event["fingerprint"] = [
  @@ -90,12 +99,6 @@
                           getattr(task, "name", task),
                       ]
   
  -            with capture_internal_exceptions():
  -                if hasattr(task, "throws") and isinstance(
  -                    hint["exc_info"][1], task.throws
  -                ):
  -                    return None
  -
           return event
   
       return event_processor
  
verification_info: {"golden_diff": "diff --git a/sentry_sdk/integrations/celery.py b/sentry_sdk/integrations/celery.py\n--- a/sentry_sdk/integrations/celery.py\n+++ b/sentry_sdk/integrations/celery.py\n@@ -2,7 +2,7 @@\n \n import sys\n \n-from celery.exceptions import SoftTimeLimitExceeded\n+from celery.exceptions import SoftTimeLimitExceeded, Retry\n \n from sentry_sdk.hub import Hub\n from sentry_sdk.utils import capture_internal_exceptions, event_from_exception\n@@ -82,6 +82,15 @@\n             }\n \n         if \"exc_info\" in hint:\n+            with capture_internal_exceptions():\n+                if isinstance(hint[\"exc_info\"][1], Retry):\n+                    return None\n+\n+                if hasattr(task, \"throws\") and isinstance(\n+                    hint[\"exc_info\"][1], task.throws\n+                ):\n+                    return None\n+\n             with capture_internal_exceptions():\n                 if issubclass(hint[\"exc_info\"][0], SoftTimeLimitExceeded):\n                     event[\"fingerprint\"] = [\n@@ -90,12 +99,6 @@\n                         getattr(task, \"name\", task),\n                     ]\n \n-            with capture_internal_exceptions():\n-                if hasattr(task, \"throws\") and isinstance(\n-                    hint[\"exc_info\"][1], task.throws\n-                ):\n-                    return None\n-\n         return event\n \n     return event_processor\n", "issue": "[0.7.0] `CeleryIntegration` captures retries\nGreetings fellows!\r\n\r\nWe are having an issue with `CeleryIntegration` in Sentry SDK.\r\n\r\n### Current versions\r\nPython 3.6.7\r\nDjango 2.1.5\r\nCelery 4.1.1\r\nSentry SDK 0.7.0-0.7.1\r\n\r\n### Current behavior\r\nIn our code (internal and 3rd-party) we are using [Celery tasks retry functionality](http://docs.celeryproject.org/en/latest/userguide/tasks.html#retrying).\r\n\r\n> The app.Task.retry() call will raise an exception so any code after the retry won\u2019t be reached. This is the Retry exception, it isn\u2019t handled as an error but rather as a semi-predicate to signify to the worker that the task is to be retried, so that it can store the correct state when a result backend is enabled.\r\n\r\nWe did switch recently from Raven to Sentry SDK 0.6.9, everything seemed working as before.\r\nBut today we updated it to [0.7.0 release](https://github.com/getsentry/sentry-python/blob/master/CHANGES.md#070) (and later to 0.7.1)\r\n\r\nThis caused **every [`celery.exceptions.Retry`](http://docs.celeryproject.org/en/latest/reference/celery.exceptions.html#celery.exceptions.Retry) to be sent to Sentry**, which quickly filled Sentry server with thousands of events.\r\nPreviously (in old SDK and Raven), those exceptions were ignored and not sent to Sentry server.\r\n\r\n### Expected behaviour\r\n`CeleryIntegration` is not flooding Sentry server with every retry exception. Basically, the same behavior as it was in Raven and Sentry SDK<0.7.0.\r\n\r\n### Open questions\r\nI am not sure if the old behavior was done intentionally or by mistake.\r\nIf that was intended, we should reimplement it in current integration.\r\nIf not, there should be a way to filter/ignore that kind of exceptions (I am not sure if we can filter all retries from internal and 3rd-party code in`before_send` in a clean way).\r\n\r\nCould you help me to clarify this issue?\n", "before_files": [{"content": "from __future__ import absolute_import\n\nimport sys\n\nfrom celery.exceptions import SoftTimeLimitExceeded\n\nfrom sentry_sdk.hub import Hub\nfrom sentry_sdk.utils import capture_internal_exceptions, event_from_exception\nfrom sentry_sdk._compat import reraise\nfrom sentry_sdk.integrations import Integration\nfrom sentry_sdk.integrations.logging import ignore_logger\n\n\nclass CeleryIntegration(Integration):\n    identifier = \"celery\"\n\n    @staticmethod\n    def setup_once():\n        import celery.app.trace as trace\n\n        old_build_tracer = trace.build_tracer\n\n        def sentry_build_tracer(name, task, *args, **kwargs):\n            # Need to patch both methods because older celery sometimes\n            # short-circuits to task.run if it thinks it's safe.\n            task.__call__ = _wrap_task_call(task.__call__)\n            task.run = _wrap_task_call(task.run)\n            return _wrap_tracer(task, old_build_tracer(name, task, *args, **kwargs))\n\n        trace.build_tracer = sentry_build_tracer\n\n        # This logger logs every status of every task that ran on the worker.\n        # Meaning that every task's breadcrumbs are full of stuff like \"Task\n        # <foo> raised unexpected <bar>\".\n        ignore_logger(\"celery.worker.job\")\n\n\ndef _wrap_tracer(task, f):\n    # Need to wrap tracer for pushing the scope before prerun is sent, and\n    # popping it after postrun is sent.\n    #\n    # This is the reason we don't use signals for hooking in the first place.\n    # Also because in Celery 3, signal dispatch returns early if one handler\n    # crashes.\n    def _inner(*args, **kwargs):\n        hub = Hub.current\n        if hub.get_integration(CeleryIntegration) is None:\n            return f(*args, **kwargs)\n\n        with hub.push_scope() as scope:\n            scope._name = \"celery\"\n            scope.add_event_processor(_make_event_processor(task, *args, **kwargs))\n\n            return f(*args, **kwargs)\n\n    return _inner\n\n\ndef _wrap_task_call(f):\n    # Need to wrap task call because the exception is caught before we get to\n    # see it. Also celery's reported stacktrace is untrustworthy.\n    def _inner(*args, **kwargs):\n        try:\n            return f(*args, **kwargs)\n        except Exception:\n            reraise(*_capture_exception())\n\n    return _inner\n\n\ndef _make_event_processor(task, uuid, args, kwargs, request=None):\n    def event_processor(event, hint):\n        with capture_internal_exceptions():\n            event[\"transaction\"] = task.name\n\n        with capture_internal_exceptions():\n            extra = event.setdefault(\"extra\", {})\n            extra[\"celery-job\"] = {\n                \"task_name\": task.name,\n                \"args\": args,\n                \"kwargs\": kwargs,\n            }\n\n        if \"exc_info\" in hint:\n            with capture_internal_exceptions():\n                if issubclass(hint[\"exc_info\"][0], SoftTimeLimitExceeded):\n                    event[\"fingerprint\"] = [\n                        \"celery\",\n                        \"SoftTimeLimitExceeded\",\n                        getattr(task, \"name\", task),\n                    ]\n\n            with capture_internal_exceptions():\n                if hasattr(task, \"throws\") and isinstance(\n                    hint[\"exc_info\"][1], task.throws\n                ):\n                    return None\n\n        return event\n\n    return event_processor\n\n\ndef _capture_exception():\n    hub = Hub.current\n    exc_info = sys.exc_info()\n\n    if hub.get_integration(CeleryIntegration) is not None:\n        event, hint = event_from_exception(\n            exc_info,\n            client_options=hub.client.options,\n            mechanism={\"type\": \"celery\", \"handled\": False},\n        )\n        hub.capture_event(event, hint=hint)\n\n    return exc_info\n", "path": "sentry_sdk/integrations/celery.py"}], "after_files": [{"content": "from __future__ import absolute_import\n\nimport sys\n\nfrom celery.exceptions import SoftTimeLimitExceeded, Retry\n\nfrom sentry_sdk.hub import Hub\nfrom sentry_sdk.utils import capture_internal_exceptions, event_from_exception\nfrom sentry_sdk._compat import reraise\nfrom sentry_sdk.integrations import Integration\nfrom sentry_sdk.integrations.logging import ignore_logger\n\n\nclass CeleryIntegration(Integration):\n    identifier = \"celery\"\n\n    @staticmethod\n    def setup_once():\n        import celery.app.trace as trace\n\n        old_build_tracer = trace.build_tracer\n\n        def sentry_build_tracer(name, task, *args, **kwargs):\n            # Need to patch both methods because older celery sometimes\n            # short-circuits to task.run if it thinks it's safe.\n            task.__call__ = _wrap_task_call(task.__call__)\n            task.run = _wrap_task_call(task.run)\n            return _wrap_tracer(task, old_build_tracer(name, task, *args, **kwargs))\n\n        trace.build_tracer = sentry_build_tracer\n\n        # This logger logs every status of every task that ran on the worker.\n        # Meaning that every task's breadcrumbs are full of stuff like \"Task\n        # <foo> raised unexpected <bar>\".\n        ignore_logger(\"celery.worker.job\")\n\n\ndef _wrap_tracer(task, f):\n    # Need to wrap tracer for pushing the scope before prerun is sent, and\n    # popping it after postrun is sent.\n    #\n    # This is the reason we don't use signals for hooking in the first place.\n    # Also because in Celery 3, signal dispatch returns early if one handler\n    # crashes.\n    def _inner(*args, **kwargs):\n        hub = Hub.current\n        if hub.get_integration(CeleryIntegration) is None:\n            return f(*args, **kwargs)\n\n        with hub.push_scope() as scope:\n            scope._name = \"celery\"\n            scope.add_event_processor(_make_event_processor(task, *args, **kwargs))\n\n            return f(*args, **kwargs)\n\n    return _inner\n\n\ndef _wrap_task_call(f):\n    # Need to wrap task call because the exception is caught before we get to\n    # see it. Also celery's reported stacktrace is untrustworthy.\n    def _inner(*args, **kwargs):\n        try:\n            return f(*args, **kwargs)\n        except Exception:\n            reraise(*_capture_exception())\n\n    return _inner\n\n\ndef _make_event_processor(task, uuid, args, kwargs, request=None):\n    def event_processor(event, hint):\n        with capture_internal_exceptions():\n            event[\"transaction\"] = task.name\n\n        with capture_internal_exceptions():\n            extra = event.setdefault(\"extra\", {})\n            extra[\"celery-job\"] = {\n                \"task_name\": task.name,\n                \"args\": args,\n                \"kwargs\": kwargs,\n            }\n\n        if \"exc_info\" in hint:\n            with capture_internal_exceptions():\n                if isinstance(hint[\"exc_info\"][1], Retry):\n                    return None\n\n                if hasattr(task, \"throws\") and isinstance(\n                    hint[\"exc_info\"][1], task.throws\n                ):\n                    return None\n\n            with capture_internal_exceptions():\n                if issubclass(hint[\"exc_info\"][0], SoftTimeLimitExceeded):\n                    event[\"fingerprint\"] = [\n                        \"celery\",\n                        \"SoftTimeLimitExceeded\",\n                        getattr(task, \"name\", task),\n                    ]\n\n        return event\n\n    return event_processor\n\n\ndef _capture_exception():\n    hub = Hub.current\n    exc_info = sys.exc_info()\n\n    if hub.get_integration(CeleryIntegration) is not None:\n        event, hint = event_from_exception(\n            exc_info,\n            client_options=hub.client.options,\n            mechanism={\"type\": \"celery\", \"handled\": False},\n        )\n        hub.capture_event(event, hint=hint)\n\n    return exc_info\n", "path": "sentry_sdk/integrations/celery.py"}]}