We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Websocket logger uses sanic.log.error_logger
Hey there,

Why do we see:

    sanic.error - INFO - connection open

via stderr when getting new websocket connections. Shouldn't this go to stdout?

Also, is it possible to add "middleware" so we can properly log websocket connections and disconnects?  Is it possible to get a callback on websocket disconnects? 

Thanks!

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `sanic/server/protocols/websocket_protocol.py`
Content:
```
1 from typing import TYPE_CHECKING, Optional, Sequence, cast
2 
3 from websockets.connection import CLOSED, CLOSING, OPEN
4 from websockets.server import ServerConnection
5 from websockets.typing import Subprotocol
6 
7 from sanic.exceptions import ServerError
8 from sanic.log import error_logger
9 from sanic.server import HttpProtocol
10 
11 from ..websockets.impl import WebsocketImplProtocol
12 
13 
14 if TYPE_CHECKING:  # no cov
15     from websockets import http11
16 
17 
18 class WebSocketProtocol(HttpProtocol):
19     __slots__ = (
20         "websocket",
21         "websocket_timeout",
22         "websocket_max_size",
23         "websocket_ping_interval",
24         "websocket_ping_timeout",
25     )
26 
27     def __init__(
28         self,
29         *args,
30         websocket_timeout: float = 10.0,
31         websocket_max_size: Optional[int] = None,
32         websocket_ping_interval: Optional[float] = 20.0,
33         websocket_ping_timeout: Optional[float] = 20.0,
34         **kwargs,
35     ):
36         super().__init__(*args, **kwargs)
37         self.websocket: Optional[WebsocketImplProtocol] = None
38         self.websocket_timeout = websocket_timeout
39         self.websocket_max_size = websocket_max_size
40         self.websocket_ping_interval = websocket_ping_interval
41         self.websocket_ping_timeout = websocket_ping_timeout
42 
43     def connection_lost(self, exc):
44         if self.websocket is not None:
45             self.websocket.connection_lost(exc)
46         super().connection_lost(exc)
47 
48     def data_received(self, data):
49         if self.websocket is not None:
50             self.websocket.data_received(data)
51         else:
52             # Pass it to HttpProtocol handler first
53             # That will (hopefully) upgrade it to a websocket.
54             super().data_received(data)
55 
56     def eof_received(self) -> Optional[bool]:
57         if self.websocket is not None:
58             return self.websocket.eof_received()
59         else:
60             return False
61 
62     def close(self, timeout: Optional[float] = None):
63         # Called by HttpProtocol at the end of connection_task
64         # If we've upgraded to websocket, we do our own closing
65         if self.websocket is not None:
66             # Note, we don't want to use websocket.close()
67             # That is used for user's application code to send a
68             # websocket close packet. This is different.
69             self.websocket.end_connection(1001)
70         else:
71             super().close()
72 
73     def close_if_idle(self):
74         # Called by Sanic Server when shutting down
75         # If we've upgraded to websocket, shut it down
76         if self.websocket is not None:
77             if self.websocket.connection.state in (CLOSING, CLOSED):
78                 return True
79             elif self.websocket.loop is not None:
80                 self.websocket.loop.create_task(self.websocket.close(1001))
81             else:
82                 self.websocket.end_connection(1001)
83         else:
84             return super().close_if_idle()
85 
86     async def websocket_handshake(
87         self, request, subprotocols: Optional[Sequence[str]] = None
88     ):
89         # let the websockets package do the handshake with the client
90         try:
91             if subprotocols is not None:
92                 # subprotocols can be a set or frozenset,
93                 # but ServerConnection needs a list
94                 subprotocols = cast(
95                     Optional[Sequence[Subprotocol]],
96                     list(
97                         [
98                             Subprotocol(subprotocol)
99                             for subprotocol in subprotocols
100                         ]
101                     ),
102                 )
103             ws_conn = ServerConnection(
104                 max_size=self.websocket_max_size,
105                 subprotocols=subprotocols,
106                 state=OPEN,
107                 logger=error_logger,
108             )
109             resp: "http11.Response" = ws_conn.accept(request)
110         except Exception:
111             msg = (
112                 "Failed to open a WebSocket connection.\n"
113                 "See server log for more information.\n"
114             )
115             raise ServerError(msg, status_code=500)
116         if 100 <= resp.status_code <= 299:
117             first_line = (
118                 f"HTTP/1.1 {resp.status_code} {resp.reason_phrase}\r\n"
119             ).encode()
120             rbody = bytearray(first_line)
121             rbody += (
122                 "".join([f"{k}: {v}\r\n" for k, v in resp.headers.items()])
123             ).encode()
124             rbody += b"\r\n"
125             if resp.body is not None:
126                 rbody += resp.body
127                 rbody += b"\r\n\r\n"
128             await super().send(rbody)
129         else:
130             raise ServerError(resp.body, resp.status_code)
131         self.websocket = WebsocketImplProtocol(
132             ws_conn,
133             ping_interval=self.websocket_ping_interval,
134             ping_timeout=self.websocket_ping_timeout,
135             close_timeout=self.websocket_timeout,
136         )
137         loop = (
138             request.transport.loop
139             if hasattr(request, "transport")
140             and hasattr(request.transport, "loop")
141             else None
142         )
143         await self.websocket.connection_made(self, loop=loop)
144         return self.websocket
145
```
--- 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()

```

diff --git a/sanic/server/protocols/websocket_protocol.py b/sanic/server/protocols/websocket_protocol.py
--- a/sanic/server/protocols/websocket_protocol.py
+++ b/sanic/server/protocols/websocket_protocol.py
@@ -5,7 +5,7 @@
 from websockets.typing import Subprotocol
 
 from sanic.exceptions import ServerError
-from sanic.log import error_logger
+from sanic.log import logger
 from sanic.server import HttpProtocol
 
 from ..websockets.impl import WebsocketImplProtocol
@@ -104,7 +104,7 @@
                 max_size=self.websocket_max_size,
                 subprotocols=subprotocols,
                 state=OPEN,
-                logger=error_logger,
+                logger=logger,
             )
             resp: "http11.Response" = ws_conn.accept(request)
         except Exception:

{"golden_diff": "diff --git a/sanic/server/protocols/websocket_protocol.py b/sanic/server/protocols/websocket_protocol.py\n--- a/sanic/server/protocols/websocket_protocol.py\n+++ b/sanic/server/protocols/websocket_protocol.py\n@@ -5,7 +5,7 @@\n from websockets.typing import Subprotocol\n \n from sanic.exceptions import ServerError\n-from sanic.log import error_logger\n+from sanic.log import logger\n from sanic.server import HttpProtocol\n \n from ..websockets.impl import WebsocketImplProtocol\n@@ -104,7 +104,7 @@\n                 max_size=self.websocket_max_size,\n                 subprotocols=subprotocols,\n                 state=OPEN,\n-                logger=error_logger,\n+                logger=logger,\n             )\n             resp: \"http11.Response\" = ws_conn.accept(request)\n         except Exception:\n", "issue": "Websocket logger uses sanic.log.error_logger\nHey there,\r\n\r\nWhy do we see:\r\n\r\n    sanic.error - INFO - connection open\r\n\r\nvia stderr when getting new websocket connections. Shouldn't this go to stdout?\r\n\r\nAlso, is it possible to add \"middleware\" so we can properly log websocket connections and disconnects?  Is it possible to get a callback on websocket disconnects? \r\n\r\nThanks!\n", "before_files": [{"content": "from typing import TYPE_CHECKING, Optional, Sequence, cast\n\nfrom websockets.connection import CLOSED, CLOSING, OPEN\nfrom websockets.server import ServerConnection\nfrom websockets.typing import Subprotocol\n\nfrom sanic.exceptions import ServerError\nfrom sanic.log import error_logger\nfrom sanic.server import HttpProtocol\n\nfrom ..websockets.impl import WebsocketImplProtocol\n\n\nif TYPE_CHECKING:  # no cov\n    from websockets import http11\n\n\nclass WebSocketProtocol(HttpProtocol):\n    __slots__ = (\n        \"websocket\",\n        \"websocket_timeout\",\n        \"websocket_max_size\",\n        \"websocket_ping_interval\",\n        \"websocket_ping_timeout\",\n    )\n\n    def __init__(\n        self,\n        *args,\n        websocket_timeout: float = 10.0,\n        websocket_max_size: Optional[int] = None,\n        websocket_ping_interval: Optional[float] = 20.0,\n        websocket_ping_timeout: Optional[float] = 20.0,\n        **kwargs,\n    ):\n        super().__init__(*args, **kwargs)\n        self.websocket: Optional[WebsocketImplProtocol] = None\n        self.websocket_timeout = websocket_timeout\n        self.websocket_max_size = websocket_max_size\n        self.websocket_ping_interval = websocket_ping_interval\n        self.websocket_ping_timeout = websocket_ping_timeout\n\n    def connection_lost(self, exc):\n        if self.websocket is not None:\n            self.websocket.connection_lost(exc)\n        super().connection_lost(exc)\n\n    def data_received(self, data):\n        if self.websocket is not None:\n            self.websocket.data_received(data)\n        else:\n            # Pass it to HttpProtocol handler first\n            # That will (hopefully) upgrade it to a websocket.\n            super().data_received(data)\n\n    def eof_received(self) -> Optional[bool]:\n        if self.websocket is not None:\n            return self.websocket.eof_received()\n        else:\n            return False\n\n    def close(self, timeout: Optional[float] = None):\n        # Called by HttpProtocol at the end of connection_task\n        # If we've upgraded to websocket, we do our own closing\n        if self.websocket is not None:\n            # Note, we don't want to use websocket.close()\n            # That is used for user's application code to send a\n            # websocket close packet. This is different.\n            self.websocket.end_connection(1001)\n        else:\n            super().close()\n\n    def close_if_idle(self):\n        # Called by Sanic Server when shutting down\n        # If we've upgraded to websocket, shut it down\n        if self.websocket is not None:\n            if self.websocket.connection.state in (CLOSING, CLOSED):\n                return True\n            elif self.websocket.loop is not None:\n                self.websocket.loop.create_task(self.websocket.close(1001))\n            else:\n                self.websocket.end_connection(1001)\n        else:\n            return super().close_if_idle()\n\n    async def websocket_handshake(\n        self, request, subprotocols: Optional[Sequence[str]] = None\n    ):\n        # let the websockets package do the handshake with the client\n        try:\n            if subprotocols is not None:\n                # subprotocols can be a set or frozenset,\n                # but ServerConnection needs a list\n                subprotocols = cast(\n                    Optional[Sequence[Subprotocol]],\n                    list(\n                        [\n                            Subprotocol(subprotocol)\n                            for subprotocol in subprotocols\n                        ]\n                    ),\n                )\n            ws_conn = ServerConnection(\n                max_size=self.websocket_max_size,\n                subprotocols=subprotocols,\n                state=OPEN,\n                logger=error_logger,\n            )\n            resp: \"http11.Response\" = ws_conn.accept(request)\n        except Exception:\n            msg = (\n                \"Failed to open a WebSocket connection.\\n\"\n                \"See server log for more information.\\n\"\n            )\n            raise ServerError(msg, status_code=500)\n        if 100 <= resp.status_code <= 299:\n            first_line = (\n                f\"HTTP/1.1 {resp.status_code} {resp.reason_phrase}\\r\\n\"\n            ).encode()\n            rbody = bytearray(first_line)\n            rbody += (\n                \"\".join([f\"{k}: {v}\\r\\n\" for k, v in resp.headers.items()])\n            ).encode()\n            rbody += b\"\\r\\n\"\n            if resp.body is not None:\n                rbody += resp.body\n                rbody += b\"\\r\\n\\r\\n\"\n            await super().send(rbody)\n        else:\n            raise ServerError(resp.body, resp.status_code)\n        self.websocket = WebsocketImplProtocol(\n            ws_conn,\n            ping_interval=self.websocket_ping_interval,\n            ping_timeout=self.websocket_ping_timeout,\n            close_timeout=self.websocket_timeout,\n        )\n        loop = (\n            request.transport.loop\n            if hasattr(request, \"transport\")\n            and hasattr(request.transport, \"loop\")\n            else None\n        )\n        await self.websocket.connection_made(self, loop=loop)\n        return self.websocket\n", "path": "sanic/server/protocols/websocket_protocol.py"}], "after_files": [{"content": "from typing import TYPE_CHECKING, Optional, Sequence, cast\n\nfrom websockets.connection import CLOSED, CLOSING, OPEN\nfrom websockets.server import ServerConnection\nfrom websockets.typing import Subprotocol\n\nfrom sanic.exceptions import ServerError\nfrom sanic.log import logger\nfrom sanic.server import HttpProtocol\n\nfrom ..websockets.impl import WebsocketImplProtocol\n\n\nif TYPE_CHECKING:  # no cov\n    from websockets import http11\n\n\nclass WebSocketProtocol(HttpProtocol):\n    __slots__ = (\n        \"websocket\",\n        \"websocket_timeout\",\n        \"websocket_max_size\",\n        \"websocket_ping_interval\",\n        \"websocket_ping_timeout\",\n    )\n\n    def __init__(\n        self,\n        *args,\n        websocket_timeout: float = 10.0,\n        websocket_max_size: Optional[int] = None,\n        websocket_ping_interval: Optional[float] = 20.0,\n        websocket_ping_timeout: Optional[float] = 20.0,\n        **kwargs,\n    ):\n        super().__init__(*args, **kwargs)\n        self.websocket: Optional[WebsocketImplProtocol] = None\n        self.websocket_timeout = websocket_timeout\n        self.websocket_max_size = websocket_max_size\n        self.websocket_ping_interval = websocket_ping_interval\n        self.websocket_ping_timeout = websocket_ping_timeout\n\n    def connection_lost(self, exc):\n        if self.websocket is not None:\n            self.websocket.connection_lost(exc)\n        super().connection_lost(exc)\n\n    def data_received(self, data):\n        if self.websocket is not None:\n            self.websocket.data_received(data)\n        else:\n            # Pass it to HttpProtocol handler first\n            # That will (hopefully) upgrade it to a websocket.\n            super().data_received(data)\n\n    def eof_received(self) -> Optional[bool]:\n        if self.websocket is not None:\n            return self.websocket.eof_received()\n        else:\n            return False\n\n    def close(self, timeout: Optional[float] = None):\n        # Called by HttpProtocol at the end of connection_task\n        # If we've upgraded to websocket, we do our own closing\n        if self.websocket is not None:\n            # Note, we don't want to use websocket.close()\n            # That is used for user's application code to send a\n            # websocket close packet. This is different.\n            self.websocket.end_connection(1001)\n        else:\n            super().close()\n\n    def close_if_idle(self):\n        # Called by Sanic Server when shutting down\n        # If we've upgraded to websocket, shut it down\n        if self.websocket is not None:\n            if self.websocket.connection.state in (CLOSING, CLOSED):\n                return True\n            elif self.websocket.loop is not None:\n                self.websocket.loop.create_task(self.websocket.close(1001))\n            else:\n                self.websocket.end_connection(1001)\n        else:\n            return super().close_if_idle()\n\n    async def websocket_handshake(\n        self, request, subprotocols: Optional[Sequence[str]] = None\n    ):\n        # let the websockets package do the handshake with the client\n        try:\n            if subprotocols is not None:\n                # subprotocols can be a set or frozenset,\n                # but ServerConnection needs a list\n                subprotocols = cast(\n                    Optional[Sequence[Subprotocol]],\n                    list(\n                        [\n                            Subprotocol(subprotocol)\n                            for subprotocol in subprotocols\n                        ]\n                    ),\n                )\n            ws_conn = ServerConnection(\n                max_size=self.websocket_max_size,\n                subprotocols=subprotocols,\n                state=OPEN,\n                logger=logger,\n            )\n            resp: \"http11.Response\" = ws_conn.accept(request)\n        except Exception:\n            msg = (\n                \"Failed to open a WebSocket connection.\\n\"\n                \"See server log for more information.\\n\"\n            )\n            raise ServerError(msg, status_code=500)\n        if 100 <= resp.status_code <= 299:\n            first_line = (\n                f\"HTTP/1.1 {resp.status_code} {resp.reason_phrase}\\r\\n\"\n            ).encode()\n            rbody = bytearray(first_line)\n            rbody += (\n                \"\".join([f\"{k}: {v}\\r\\n\" for k, v in resp.headers.items()])\n            ).encode()\n            rbody += b\"\\r\\n\"\n            if resp.body is not None:\n                rbody += resp.body\n                rbody += b\"\\r\\n\\r\\n\"\n            await super().send(rbody)\n        else:\n            raise ServerError(resp.body, resp.status_code)\n        self.websocket = WebsocketImplProtocol(\n            ws_conn,\n            ping_interval=self.websocket_ping_interval,\n            ping_timeout=self.websocket_ping_timeout,\n            close_timeout=self.websocket_timeout,\n        )\n        loop = (\n            request.transport.loop\n            if hasattr(request, \"transport\")\n            and hasattr(request.transport, \"loop\")\n            else None\n        )\n        await self.websocket.connection_made(self, loop=loop)\n        return self.websocket\n", "path": "sanic/server/protocols/websocket_protocol.py"}]}