Repository: sanic-org/sanic-ext
Pull request #179 (2023-01-06 08:31:52)

Supporting custom logger in the background
Hi, the background logger is an excellent extension helping me log all my messages from a background process, with multiple processes.
But, it's not support to log any other logger backgrounding except `"sanic.access", "sanic.error", "sanic.root"`.

This PR is an attempt to support logging other custom loggers in the background.

to use:
```python
from sanic import Sanic

app = Sanic("MyApp")
app.config.LOGGING = True
app.config.LOGGERS = [
    "my_logger"
]
```

The default value of `app.config.LOGGERS = ["sanic.access", "sanic.error", "sanic.root"]`,
which is the same with `(root_logger, access_logger, error_logger)`



Patch:
diff --git a/sanic_ext/config.py b/sanic_ext/config.py
index 806b8e9..d96f588 100644
--- a/sanic_ext/config.py
+++ b/sanic_ext/config.py
@@ -39,6 +39,7 @@ class Config(SanicConfig):
         injection_load_custom_constants: bool = False,
         logging: bool = False,
         logging_queue_max_size: int = 4096,
+        loggers: List[str] = ["sanic.access", "sanic.error", "sanic.root"],
         oas: bool = True,
         oas_autodoc: bool = True,
         oas_custom_file: Optional[os.PathLike] = None,
@@ -95,6 +96,7 @@ class Config(SanicConfig):
         self.INJECTION_LOAD_CUSTOM_CONSTANTS = injection_load_custom_constants
         self.LOGGING = logging
         self.LOGGING_QUEUE_MAX_SIZE = logging_queue_max_size
+        self.LOGGERS = loggers
         self.OAS = oas
         self.OAS_AUTODOC = oas_autodoc
         self.OAS_CUSTOM_FILE = oas_custom_file
diff --git a/sanic_ext/extensions/logging/logger.py b/sanic_ext/extensions/logging/logger.py
index 2cc4f97..ac795d5 100644
--- a/sanic_ext/extensions/logging/logger.py
+++ b/sanic_ext/extensions/logging/logger.py
@@ -1,3 +1,4 @@
+import logging
 from collections import defaultdict
 from logging import LogRecord
 from logging.handlers import QueueHandler
@@ -5,10 +6,9 @@ from multiprocessing import Manager
 from queue import Empty, Full
 from signal import SIGINT, SIGTERM
 from signal import signal as signal_func
+from typing import List
 
 from sanic import Sanic
-from sanic.log import access_logger, error_logger
-from sanic.log import logger as root_logger
 from sanic.log import server_logger
 
 
@@ -43,7 +43,8 @@ async def setup_server_logging(app: Sanic):
     app.ctx._logger_handlers = defaultdict(list)
     app.ctx._qhandler = qhandler
 
-    for logger_instance in (root_logger, access_logger, error_logger):
+    for logger_name in app.config.LOGGERS:
+        logger_instance = logging.getLogger(logger_name)
         for handler in logger_instance.handlers:
             logger_instance.removeHandler(handler)
         logger_instance.addHandler(qhandler)
@@ -57,11 +58,12 @@ async def remove_server_logging(app: Sanic):
 
 
 class Logger:
+    LOGGERS = []
+
     def __init__(self):
         self.run = True
         self.loggers = {
-            logger.name: logger
-            for logger in (root_logger, access_logger, error_logger)
+            logger: logging.getLogger(logger) for logger in self.LOGGERS
         }
 
     def __call__(self, queue) -> None:
@@ -80,6 +82,10 @@ class Logger:
         if self.run:
             self.run = False
 
+    @classmethod
+    def update_cls_loggers(cls, logger_names: List[str]):
+        cls.LOGGERS = logger_names
+
     @classmethod
     def prepare(cls, app: Sanic):
         sync_manager = Manager()
@@ -87,6 +93,7 @@ class Logger:
             maxsize=app.config.LOGGING_QUEUE_MAX_SIZE
         )
         app.shared_ctx.logger_queue = logger_queue
+        cls.update_cls_loggers(app.config.LOGGERS)
 
     @classmethod
     def setup(cls, app: Sanic):


Test patch:
diff --git a/tests/extensions/logging/__init__.py b/tests/extensions/logging/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/extensions/logging/test_custom_background_logger.py b/tests/extensions/logging/test_custom_background_logger.py
new file mode 100644
index 0000000..ea8afc9
--- /dev/null
+++ b/tests/extensions/logging/test_custom_background_logger.py
@@ -0,0 +1,22 @@
+import pytest
+from sanic import Sanic
+from sanic.response import empty
+
+from sanic_ext.extensions.logging.logger import Logger
+
+
+def test_defult_config(app: Sanic):
+    assert hasattr(app.config, "LOGGERS")
+
+
+def test_custom_background_logger(app: Sanic):
+    assert Logger.LOGGERS == []
+    Logger.prepare(app)
+    assert hasattr(app.shared_ctx, "logger_queue")
+    assert Logger.LOGGERS == app.config.LOGGERS
+    assert "sanic.root" in Logger.LOGGERS
+
+    logger = Logger()
+    assert (
+        len(logger.loggers) == len(Logger.LOGGERS) == len(app.config.LOGGERS)
+    )