We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
MLServer to hide http health request logs to avoid polluting the logs
As part of the Seldon Core addition https://github.com/SeldonIO/seldon-core/pull/4028 which moves the TCP ready checks into proper HTTP request ready checks to `v2/health/ready` there is now a lot of noise from the readiness checks every 5 seconds. We should explore ways in which we avoid this noise, perhaps making it completely silent by default, or eventually once the prometheus server is created on a separate server this could also be added (And both of  them could be muted)

![image](https://user-images.githubusercontent.com/1447507/161749439-3e96c417-a630-4208-80d6-5fc5f262fcd3.png)


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `mlserver/rest/server.py`
Content:
```
1 import uvicorn
2 
3 from ..settings import Settings
4 from ..handlers import DataPlane, ModelRepositoryHandlers, get_custom_handlers
5 from ..model import MLModel
6 
7 from .utils import matches
8 from .app import create_app
9 from .logging import logger
10 from typing import Optional
11 
12 
13 class _NoSignalServer(uvicorn.Server):
14     def install_signal_handlers(self):
15         pass
16 
17 
18 class RESTServer:
19     def __init__(
20         self,
21         settings: Settings,
22         data_plane: DataPlane,
23         model_repository_handlers: ModelRepositoryHandlers,
24     ):
25         self._settings = settings
26         self._data_plane = data_plane
27         self._model_repository_handlers = model_repository_handlers
28         self._app = create_app(
29             self._settings,
30             data_plane=self._data_plane,
31             model_repository_handlers=self._model_repository_handlers,
32         )
33 
34     async def add_custom_handlers(self, model: MLModel) -> MLModel:
35         handlers = get_custom_handlers(model)
36         for custom_handler, handler_method in handlers:
37             self._app.add_api_route(
38                 custom_handler.rest_path,
39                 handler_method,
40                 methods=[custom_handler.rest_method],
41             )
42 
43         return model
44 
45     async def delete_custom_handlers(self, model: MLModel) -> MLModel:
46         handlers = get_custom_handlers(model)
47         if len(handlers) == 0:
48             return model
49 
50         # NOTE: Loop in reverse, so that it's quicker to find all the recently
51         # added routes and we can remove routes on-the-fly
52         for i, route in reversed(list(enumerate(self._app.routes))):
53             for j, (custom_handler, handler_method) in enumerate(handlers):
54                 if matches(route, custom_handler, handler_method):  # type: ignore
55                     self._app.routes.pop(i)
56                     handlers.pop(j)
57 
58         return model
59 
60     async def start(self):
61         cfg = self._get_config()
62         self._server = _NoSignalServer(cfg)
63         await self._server.serve()
64 
65     def _get_config(self):
66         kwargs = {}
67 
68         if self._settings._custom_rest_server_settings:
69             logger.warning(
70                 "REST custom configuration is out of support. Use as your own risk"
71             )
72             kwargs.update(self._settings._custom_rest_server_settings)
73 
74         kwargs.update(
75             {
76                 "host": self._settings.host,
77                 "port": self._settings.http_port,
78                 "root_path": self._settings.root_path,
79                 "access_log": self._settings.debug,
80             }
81         )
82 
83         if self._settings.logging_settings:
84             # If not None, use ours. Otherwise, let Uvicorn fall back on its
85             # own config.
86             kwargs.update({"log_config": self._settings.logging_settings})
87 
88         return uvicorn.Config(self._app, **kwargs)
89 
90     async def stop(self, sig: Optional[int] = None):
91         self._server.handle_exit(sig=sig, frame=None)
92
```

Path: `mlserver/rest/logging.py`
Content:
```
1 import logging
2 
3 loggerName = "mlserver.rest"
4 logger = logging.getLogger(loggerName)
5
```
--- 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/mlserver/rest/logging.py b/mlserver/rest/logging.py
--- a/mlserver/rest/logging.py
+++ b/mlserver/rest/logging.py
@@ -1,4 +1,35 @@
 import logging
 
+
+class HealthEndpointFilter(logging.Filter):
+    """
+    Filter to avoid logging health endpoints.
+    From:
+        https://github.com/encode/starlette/issues/864#issuecomment-653076434
+    """
+
+    def filter(self, record: logging.LogRecord) -> bool:
+        if not isinstance(record.args, tuple):
+            return True
+
+        if len(record.args) < 3:
+            return True
+
+        request_method = record.args[1]
+        query_string = record.args[2]
+        if request_method != "GET":
+            return True
+
+        if query_string in ["/v2/health/live", "/v2/health/ready"]:
+            return False
+
+        return True
+
+
+def disable_health_access_logs() -> None:
+    uvicorn_logger = logging.getLogger("uvicorn.access")
+    uvicorn_logger.addFilter(HealthEndpointFilter())
+
+
 loggerName = "mlserver.rest"
 logger = logging.getLogger(loggerName)
diff --git a/mlserver/rest/server.py b/mlserver/rest/server.py
--- a/mlserver/rest/server.py
+++ b/mlserver/rest/server.py
@@ -6,7 +6,7 @@
 
 from .utils import matches
 from .app import create_app
-from .logging import logger
+from .logging import logger, disable_health_access_logs
 from typing import Optional
 
 
@@ -60,6 +60,9 @@
     async def start(self):
         cfg = self._get_config()
         self._server = _NoSignalServer(cfg)
+        if not self._settings.debug:
+            disable_health_access_logs()
+
         await self._server.serve()
 
     def _get_config(self):

{"golden_diff": "diff --git a/mlserver/rest/logging.py b/mlserver/rest/logging.py\n--- a/mlserver/rest/logging.py\n+++ b/mlserver/rest/logging.py\n@@ -1,4 +1,35 @@\n import logging\n \n+\n+class HealthEndpointFilter(logging.Filter):\n+    \"\"\"\n+    Filter to avoid logging health endpoints.\n+    From:\n+        https://github.com/encode/starlette/issues/864#issuecomment-653076434\n+    \"\"\"\n+\n+    def filter(self, record: logging.LogRecord) -> bool:\n+        if not isinstance(record.args, tuple):\n+            return True\n+\n+        if len(record.args) < 3:\n+            return True\n+\n+        request_method = record.args[1]\n+        query_string = record.args[2]\n+        if request_method != \"GET\":\n+            return True\n+\n+        if query_string in [\"/v2/health/live\", \"/v2/health/ready\"]:\n+            return False\n+\n+        return True\n+\n+\n+def disable_health_access_logs() -> None:\n+    uvicorn_logger = logging.getLogger(\"uvicorn.access\")\n+    uvicorn_logger.addFilter(HealthEndpointFilter())\n+\n+\n loggerName = \"mlserver.rest\"\n logger = logging.getLogger(loggerName)\ndiff --git a/mlserver/rest/server.py b/mlserver/rest/server.py\n--- a/mlserver/rest/server.py\n+++ b/mlserver/rest/server.py\n@@ -6,7 +6,7 @@\n \n from .utils import matches\n from .app import create_app\n-from .logging import logger\n+from .logging import logger, disable_health_access_logs\n from typing import Optional\n \n \n@@ -60,6 +60,9 @@\n     async def start(self):\n         cfg = self._get_config()\n         self._server = _NoSignalServer(cfg)\n+        if not self._settings.debug:\n+            disable_health_access_logs()\n+\n         await self._server.serve()\n \n     def _get_config(self):\n", "issue": "MLServer to hide http health request logs to avoid polluting the logs\nAs part of the Seldon Core addition https://github.com/SeldonIO/seldon-core/pull/4028 which moves the TCP ready checks into proper HTTP request ready checks to `v2/health/ready` there is now a lot of noise from the readiness checks every 5 seconds. We should explore ways in which we avoid this noise, perhaps making it completely silent by default, or eventually once the prometheus server is created on a separate server this could also be added (And both of  them could be muted)\r\n\r\n![image](https://user-images.githubusercontent.com/1447507/161749439-3e96c417-a630-4208-80d6-5fc5f262fcd3.png)\r\n\n", "before_files": [{"content": "import uvicorn\n\nfrom ..settings import Settings\nfrom ..handlers import DataPlane, ModelRepositoryHandlers, get_custom_handlers\nfrom ..model import MLModel\n\nfrom .utils import matches\nfrom .app import create_app\nfrom .logging import logger\nfrom typing import Optional\n\n\nclass _NoSignalServer(uvicorn.Server):\n    def install_signal_handlers(self):\n        pass\n\n\nclass RESTServer:\n    def __init__(\n        self,\n        settings: Settings,\n        data_plane: DataPlane,\n        model_repository_handlers: ModelRepositoryHandlers,\n    ):\n        self._settings = settings\n        self._data_plane = data_plane\n        self._model_repository_handlers = model_repository_handlers\n        self._app = create_app(\n            self._settings,\n            data_plane=self._data_plane,\n            model_repository_handlers=self._model_repository_handlers,\n        )\n\n    async def add_custom_handlers(self, model: MLModel) -> MLModel:\n        handlers = get_custom_handlers(model)\n        for custom_handler, handler_method in handlers:\n            self._app.add_api_route(\n                custom_handler.rest_path,\n                handler_method,\n                methods=[custom_handler.rest_method],\n            )\n\n        return model\n\n    async def delete_custom_handlers(self, model: MLModel) -> MLModel:\n        handlers = get_custom_handlers(model)\n        if len(handlers) == 0:\n            return model\n\n        # NOTE: Loop in reverse, so that it's quicker to find all the recently\n        # added routes and we can remove routes on-the-fly\n        for i, route in reversed(list(enumerate(self._app.routes))):\n            for j, (custom_handler, handler_method) in enumerate(handlers):\n                if matches(route, custom_handler, handler_method):  # type: ignore\n                    self._app.routes.pop(i)\n                    handlers.pop(j)\n\n        return model\n\n    async def start(self):\n        cfg = self._get_config()\n        self._server = _NoSignalServer(cfg)\n        await self._server.serve()\n\n    def _get_config(self):\n        kwargs = {}\n\n        if self._settings._custom_rest_server_settings:\n            logger.warning(\n                \"REST custom configuration is out of support. Use as your own risk\"\n            )\n            kwargs.update(self._settings._custom_rest_server_settings)\n\n        kwargs.update(\n            {\n                \"host\": self._settings.host,\n                \"port\": self._settings.http_port,\n                \"root_path\": self._settings.root_path,\n                \"access_log\": self._settings.debug,\n            }\n        )\n\n        if self._settings.logging_settings:\n            # If not None, use ours. Otherwise, let Uvicorn fall back on its\n            # own config.\n            kwargs.update({\"log_config\": self._settings.logging_settings})\n\n        return uvicorn.Config(self._app, **kwargs)\n\n    async def stop(self, sig: Optional[int] = None):\n        self._server.handle_exit(sig=sig, frame=None)\n", "path": "mlserver/rest/server.py"}, {"content": "import logging\n\nloggerName = \"mlserver.rest\"\nlogger = logging.getLogger(loggerName)\n", "path": "mlserver/rest/logging.py"}], "after_files": [{"content": "import uvicorn\n\nfrom ..settings import Settings\nfrom ..handlers import DataPlane, ModelRepositoryHandlers, get_custom_handlers\nfrom ..model import MLModel\n\nfrom .utils import matches\nfrom .app import create_app\nfrom .logging import logger, disable_health_access_logs\nfrom typing import Optional\n\n\nclass _NoSignalServer(uvicorn.Server):\n    def install_signal_handlers(self):\n        pass\n\n\nclass RESTServer:\n    def __init__(\n        self,\n        settings: Settings,\n        data_plane: DataPlane,\n        model_repository_handlers: ModelRepositoryHandlers,\n    ):\n        self._settings = settings\n        self._data_plane = data_plane\n        self._model_repository_handlers = model_repository_handlers\n        self._app = create_app(\n            self._settings,\n            data_plane=self._data_plane,\n            model_repository_handlers=self._model_repository_handlers,\n        )\n\n    async def add_custom_handlers(self, model: MLModel) -> MLModel:\n        handlers = get_custom_handlers(model)\n        for custom_handler, handler_method in handlers:\n            self._app.add_api_route(\n                custom_handler.rest_path,\n                handler_method,\n                methods=[custom_handler.rest_method],\n            )\n\n        return model\n\n    async def delete_custom_handlers(self, model: MLModel) -> MLModel:\n        handlers = get_custom_handlers(model)\n        if len(handlers) == 0:\n            return model\n\n        # NOTE: Loop in reverse, so that it's quicker to find all the recently\n        # added routes and we can remove routes on-the-fly\n        for i, route in reversed(list(enumerate(self._app.routes))):\n            for j, (custom_handler, handler_method) in enumerate(handlers):\n                if matches(route, custom_handler, handler_method):  # type: ignore\n                    self._app.routes.pop(i)\n                    handlers.pop(j)\n\n        return model\n\n    async def start(self):\n        cfg = self._get_config()\n        self._server = _NoSignalServer(cfg)\n        if not self._settings.debug:\n            disable_health_access_logs()\n\n        await self._server.serve()\n\n    def _get_config(self):\n        kwargs = {}\n\n        if self._settings._custom_rest_server_settings:\n            logger.warning(\n                \"REST custom configuration is out of support. Use as your own risk\"\n            )\n            kwargs.update(self._settings._custom_rest_server_settings)\n\n        kwargs.update(\n            {\n                \"host\": self._settings.host,\n                \"port\": self._settings.http_port,\n                \"root_path\": self._settings.root_path,\n                \"access_log\": self._settings.debug,\n            }\n        )\n\n        if self._settings.logging_settings:\n            # If not None, use ours. Otherwise, let Uvicorn fall back on its\n            # own config.\n            kwargs.update({\"log_config\": self._settings.logging_settings})\n\n        return uvicorn.Config(self._app, **kwargs)\n\n    async def stop(self, sig: Optional[int] = None):\n        self._server.handle_exit(sig=sig, frame=None)\n", "path": "mlserver/rest/server.py"}, {"content": "import logging\n\n\nclass HealthEndpointFilter(logging.Filter):\n    \"\"\"\n    Filter to avoid logging health endpoints.\n    From:\n        https://github.com/encode/starlette/issues/864#issuecomment-653076434\n    \"\"\"\n\n    def filter(self, record: logging.LogRecord) -> bool:\n        if not isinstance(record.args, tuple):\n            return True\n\n        if len(record.args) < 3:\n            return True\n\n        request_method = record.args[1]\n        query_string = record.args[2]\n        if request_method != \"GET\":\n            return True\n\n        if query_string in [\"/v2/health/live\", \"/v2/health/ready\"]:\n            return False\n\n        return True\n\n\ndef disable_health_access_logs() -> None:\n    uvicorn_logger = logging.getLogger(\"uvicorn.access\")\n    uvicorn_logger.addFilter(HealthEndpointFilter())\n\n\nloggerName = \"mlserver.rest\"\nlogger = logging.getLogger(loggerName)\n", "path": "mlserver/rest/logging.py"}]}