Repository: getsentry/sentry-python

Issue:
aiohttp integration ability to use contextvars in logger 
Hi!

I was looking to add a custom [logging filter](https://docs.python.org/3/library/logging.html#logging.Filter) to my aiohttp server during exception that are catched [here](https://github.com/aio-libs/aiohttp/blob/16a49c143fc0abab75163fb78738fff3d3e17f49/aiohttp/web_protocol.py#L387).

It's useful and easy to do, but, it occurs that, in my custom logging filter, I can't find [contextvars](https://docs.python.org/3/library/contextvars.html) that I have created in my request handler task.

Two things caused this problem:
- [aiohttp handled requests in a sub-Task, and catched exceptions in the parent Task](https://github.com/aio-libs/aiohttp/blob/6a5ab96bd9cb404b4abfd5160fe8f34a29d941e5/aiohttp/web_protocol.py#L415-L416).
  → This was fixed in https://github.com/aio-libs/aiohttp/commit/9997cae (because users asked to be able to access `contextvars` -- like us). It was even [backported to aiohttp version 3.7](https://github.com/aio-libs/aiohttp/commit/29eccad84e8200b5c90856c8732da0fdbbcef904).
- [Sentry-aiohttp integration handles requests in a sub-Task too](https://github.com/getsentry/sentry-python/blob/cd646579d04e2fad6a8994304314ac52fec2f83c/sentry_sdk/integrations/aiohttp.py#L113).

Python documentation on Tasks [here](https://docs.python.org/3/library/asyncio-task.html#asyncio.Task). One important thing is that they reset *contextvars*.

To summarize:
```
   aiohttp                               logging exception
      +                                        ^
      |                                        |
      | asyncio.create_task(handle_request())  | contextvars didn't go up again
      |                                        | (it's fixed now)
      |                                        |
      v                                        |
   Sentry                                      |
      +                                        |
      |                                        |
      | asyncio.create_task(handle_request())  | contextvars don't go up
      |                                        |
      v                                        |
I set contextvars        +---------------------+

                                   Exception
```

As long as the issue is not fixed in Sentry, I still can't use `contextvars` to log custom data using the standard Python `logging` library.
The only solution is to disable Sentry, then logging works OK with contextvars.

Any idea how to fix this in Sentry-aiohttp code?
I'd be happy to open a PR, but I'm not familiar enough with Sentry code, or Python in general, thus I need some help at least.


Discussion:
I see, it seems the double-task thing may not be necessary at all assuming all aiohttp versions we care about already create a task. I would be fine with a PR that does not wrap anything in a task at all. This is very likely just cargo-culted from the Sanic integration.

Resolving patch:
diff --git a/sentry_sdk/integrations/aiohttp.py b/sentry_sdk/integrations/aiohttp.py
--- a/sentry_sdk/integrations/aiohttp.py
+++ b/sentry_sdk/integrations/aiohttp.py
@@ -71,46 +71,41 @@ def setup_once():
 
         async def sentry_app_handle(self, request, *args, **kwargs):
             # type: (Any, Request, *Any, **Any) -> Any
-            async def inner():
-                # type: () -> Any
-                hub = Hub.current
-                if hub.get_integration(AioHttpIntegration) is None:
-                    return await old_handle(self, request, *args, **kwargs)
-
-                weak_request = weakref.ref(request)
-
-                with Hub(Hub.current) as hub:
-                    with hub.configure_scope() as scope:
-                        scope.clear_breadcrumbs()
-                        scope.add_event_processor(_make_request_processor(weak_request))
-
-                    span = Span.continue_from_headers(request.headers)
-                    span.op = "http.server"
-                    # If this transaction name makes it to the UI, AIOHTTP's
-                    # URL resolver did not find a route or died trying.
-                    span.transaction = "generic AIOHTTP request"
-
-                    with hub.start_span(span):
-                        try:
-                            response = await old_handle(self, request)
-                        except HTTPException as e:
-                            span.set_http_status(e.status_code)
-                            raise
-                        except asyncio.CancelledError:
-                            span.set_status("cancelled")
-                            raise
-                        except Exception:
-                            # This will probably map to a 500 but seems like we
-                            # have no way to tell. Do not set span status.
-                            reraise(*_capture_exception(hub))
-
-                        span.set_http_status(response.status)
-                        return response
-
-            # Explicitly wrap in task such that current contextvar context is
-            # copied. Just doing `return await inner()` will leak scope data
-            # between requests.
-            return await asyncio.get_event_loop().create_task(inner())
+            hub = Hub.current
+            if hub.get_integration(AioHttpIntegration) is None:
+                return await old_handle(self, request, *args, **kwargs)
+
+            weak_request = weakref.ref(request)
+
+            with Hub(Hub.current) as hub:
+                # Scope data will not leak between requests because aiohttp
+                # create a task to wrap each request.
+                with hub.configure_scope() as scope:
+                    scope.clear_breadcrumbs()
+                    scope.add_event_processor(_make_request_processor(weak_request))
+
+                span = Span.continue_from_headers(request.headers)
+                span.op = "http.server"
+                # If this transaction name makes it to the UI, AIOHTTP's
+                # URL resolver did not find a route or died trying.
+                span.transaction = "generic AIOHTTP request"
+
+                with hub.start_span(span):
+                    try:
+                        response = await old_handle(self, request)
+                    except HTTPException as e:
+                        span.set_http_status(e.status_code)
+                        raise
+                    except asyncio.CancelledError:
+                        span.set_status("cancelled")
+                        raise
+                    except Exception:
+                        # This will probably map to a 500 but seems like we
+                        # have no way to tell. Do not set span status.
+                        reraise(*_capture_exception(hub))
+
+                    span.set_http_status(response.status)
+                    return response
 
         Application._handle = sentry_app_handle
 


Test patch: