Repository: encode/uvicorn

Issue:
Error integrating with Channels if 'lifespan' is not specified in router
I'm not entirely sure if I should be posting this here or on `channels`.

I'm using v0.3.12 which I believe has already introduced the new `lifespan` protocol defined in asgiref. But this causes an error with `channels`' router

```bash
Traceback (most recent call last):
   File "/usr/local/lib/python3.6/site-packages/uvicorn/lifespan.py", line 29, in run
     await self.asgi(self.receive, self.send)
   File "/usr/local/lib/python3.6/site-packages/uvicorn/middleware/message_logger.py", line 51, in __call__
     inner = self.app(self.scope)
   File "/usr/local/lib/python3.6/site-packages/channels/routing.py", line 58, in __call__
     raise ValueError("No application configured for scope type %r" % scope["type"])
ValueError: No application configured for scope type 'lifespan'
```

My `routing.py` file looks like this:

```python
application = ProtocolTypeRouter({
    # Empty for now (http->django views is added by default)
    'websocket': JWTWebsocketMiddleware(
        URLRouter(urlpatterns)
    )
})
```

**EDIT**: Sorry my workaround wasn't actually working as you'll need at least one `path` in the `URLRouter`, so I've removed it.

To temporarily get around this, I had to downgrade to `v0.3.9`.

Discussion:
tomchristie: This way around we'll get an error immediately if lifespan instantiation is not supported. That will gracefully disable it, and should resolve #222.

Patch:
diff --git a/uvicorn/middleware/message_logger.py b/uvicorn/middleware/message_logger.py
index 3ddc9c9..a33736d 100644
--- a/uvicorn/middleware/message_logger.py
+++ b/uvicorn/middleware/message_logger.py
@@ -36,20 +36,27 @@ class MessageLoggerMiddleware:
 class MessageLoggerResponder:
     def __init__(self, scope, app, logger, task_counter):
         self.scope = scope
-        self.app = app
         self.logger = logger
         self.task_counter = task_counter
         self.client_addr = scope.get('client')
 
+        logged_scope = message_with_placeholders(scope)
+        log_text = '%s - ASGI [%d] Initialized %s'
+        self.logger.debug(log_text, self.client_addr, self.task_counter, logged_scope)
+        try:
+            self.inner = app(scope)
+        except:
+            log_text = '%s - ASGI [%d] Raised exception'
+            self.logger.debug(log_text, self.client_addr, self.task_counter)
+            raise
+
     async def __call__(self, receive, send):
         self._receive = receive
         self._send = send
-        logged_scope = message_with_placeholders(self.scope)
-        log_text = '%s - ASGI [%d] Started %s'
-        self.logger.debug(log_text, self.client_addr, self.task_counter, logged_scope)
+        log_text = '%s - ASGI [%d] Started task'
+        self.logger.debug(log_text, self.client_addr, self.task_counter)
         try:
-            inner = self.app(self.scope)
-            await inner(self.receive, self.send)
+            await self.inner(self.receive, self.send)
         except:
             log_text = '%s - ASGI [%d] Raised exception'
             self.logger.debug(log_text, self.client_addr, self.task_counter)


Test patch:
diff --git a/tests/middleware/test_message_logger.py b/tests/middleware/test_message_logger.py
index 2541dc0..1d07ed6 100644
--- a/tests/middleware/test_message_logger.py
+++ b/tests/middleware/test_message_logger.py
@@ -19,7 +19,8 @@ def test_message_logger(caplog):
     response = client.get("/")
     assert response.status_code == 200
     messages = [record.msg % record.args for record in caplog.records]
-    assert sum(['ASGI [1] Started' in message for message in messages]) == 1
+    assert sum(['ASGI [1] Initialized' in message for message in messages]) == 1
+    assert sum(['ASGI [1] Started task' in message for message in messages]) == 1
     assert sum(['ASGI [1] Sent' in message for message in messages]) == 1
     assert sum(['ASGI [1] Received' in message for message in messages]) == 2
     assert sum(['ASGI [1] Completed' in message for message in messages]) == 1
@@ -39,7 +40,26 @@ def test_message_logger_exc(caplog):
     with pytest.raises(RuntimeError):
         client.get("/")
     messages = [record.msg % record.args for record in caplog.records]
-    assert sum(['ASGI [1] Started' in message for message in messages]) == 1
+    assert sum(['ASGI [1] Initialized' in message for message in messages]) == 1
+    assert sum(['ASGI [1] Started task' in message for message in messages]) == 1
+    assert sum(['ASGI [1] Sent' in message for message in messages]) == 0
+    assert sum(['ASGI [1] Received' in message for message in messages]) == 0
+    assert sum(['ASGI [1] Completed' in message for message in messages]) == 0
+    assert sum(['ASGI [1] Raised exception' in message for message in messages]) == 1
+
+
+def test_message_logger_scope_exc(caplog):
+    def app(scope):
+        raise RuntimeError()
+
+    caplog.set_level(logging.DEBUG)
+    app = MessageLoggerMiddleware(app)
+    client = TestClient(app)
+    with pytest.raises(RuntimeError):
+        client.get("/")
+    messages = [record.msg % record.args for record in caplog.records]
+    assert sum(['ASGI [1] Initialized' in message for message in messages]) == 1
+    assert sum(['ASGI [1] Started task' in message for message in messages]) == 0
     assert sum(['ASGI [1] Sent' in message for message in messages]) == 0
     assert sum(['ASGI [1] Received' in message for message in messages]) == 0
     assert sum(['ASGI [1] Completed' in message for message in messages]) == 0