Move verbosity filtering to logger (#2453)

This commit is contained in:
Adam Hopkins 2022-06-16 12:35:49 +03:00 committed by GitHub
parent b87982769f
commit 1668e1532f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 91 additions and 32 deletions

View File

@ -1573,8 +1573,9 @@ class Sanic(BaseSanic, RunnerMixin, metaclass=TouchUpMeta):
"shutdown", "shutdown",
): ):
raise SanicException(f"Invalid server event: {event}") raise SanicException(f"Invalid server event: {event}")
if self.state.verbosity >= 1: logger.debug(
logger.debug(f"Triggering server events: {event}") f"Triggering server events: {event}", extra={"verbosity": 1}
)
reverse = concern == "shutdown" reverse = concern == "shutdown"
if loop is None: if loop is None:
loop = self.loop loop = self.loop

View File

@ -9,7 +9,7 @@ from socket import socket
from ssl import SSLContext from ssl import SSLContext
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Set, Union from typing import TYPE_CHECKING, Any, Dict, List, Optional, Set, Union
from sanic.log import logger from sanic.log import VerbosityFilter, logger
from sanic.server.async_server import AsyncioServer from sanic.server.async_server import AsyncioServer
@ -91,6 +91,9 @@ class ApplicationState:
if getattr(self.app, "configure_logging", False) and self.app.debug: if getattr(self.app, "configure_logging", False) and self.app.debug:
logger.setLevel(logging.DEBUG) logger.setLevel(logging.DEBUG)
def set_verbosity(self, value: int):
VerbosityFilter.verbosity = value
@property @property
def is_debug(self): def is_debug(self):
return self.mode is Mode.DEBUG return self.mode is Mode.DEBUG

View File

@ -25,27 +25,28 @@ class Lifespan:
def __init__(self, asgi_app: ASGIApp) -> None: def __init__(self, asgi_app: ASGIApp) -> None:
self.asgi_app = asgi_app self.asgi_app = asgi_app
if self.asgi_app.sanic_app.state.verbosity > 0: if (
if ( "server.init.before"
"server.init.before" in self.asgi_app.sanic_app.signal_router.name_index
in self.asgi_app.sanic_app.signal_router.name_index ):
): logger.debug(
logger.debug( 'You have set a listener for "before_server_start" '
'You have set a listener for "before_server_start" ' "in ASGI mode. "
"in ASGI mode. " "It will be executed as early as possible, but not before "
"It will be executed as early as possible, but not before " "the ASGI server is started.",
"the ASGI server is started." extra={"verbosity": 1},
) )
if ( if (
"server.shutdown.after" "server.shutdown.after"
in self.asgi_app.sanic_app.signal_router.name_index in self.asgi_app.sanic_app.signal_router.name_index
): ):
logger.debug( logger.debug(
'You have set a listener for "after_server_stop" ' 'You have set a listener for "after_server_stop" '
"in ASGI mode. " "in ASGI mode. "
"It will be executed as late as possible, but not after " "It will be executed as late as possible, but not after "
"the ASGI server is stopped." "the ASGI server is stopped.",
) extra={"verbosity": 1},
)
async def startup(self) -> None: async def startup(self) -> None:
""" """

View File

@ -61,21 +61,36 @@ class Colors(str, Enum): # no cov
END = "\033[0m" END = "\033[0m"
BLUE = "\033[01;34m" BLUE = "\033[01;34m"
GREEN = "\033[01;32m" GREEN = "\033[01;32m"
YELLOW = "\033[01;33m" PURPLE = "\033[01;35m"
RED = "\033[01;31m" RED = "\033[01;31m"
SANIC = "\033[38;2;255;13;104m"
YELLOW = "\033[01;33m"
class VerbosityFilter(logging.Filter):
verbosity: int = 0
def filter(self, record: logging.LogRecord) -> bool:
verbosity = getattr(record, "verbosity", 0)
return verbosity <= self.verbosity
_verbosity_filter = VerbosityFilter()
logger = logging.getLogger("sanic.root") # no cov logger = logging.getLogger("sanic.root") # no cov
logger.addFilter(_verbosity_filter)
""" """
General Sanic logger General Sanic logger
""" """
error_logger = logging.getLogger("sanic.error") # no cov error_logger = logging.getLogger("sanic.error") # no cov
error_logger.addFilter(_verbosity_filter)
""" """
Logger used by Sanic for error logging Logger used by Sanic for error logging
""" """
access_logger = logging.getLogger("sanic.access") # no cov access_logger = logging.getLogger("sanic.access") # no cov
access_logger.addFilter(_verbosity_filter)
""" """
Logger used by Sanic for access logging Logger used by Sanic for access logging
""" """

View File

@ -24,9 +24,7 @@ class OptionalDispatchEvent(BaseScheme):
raw_source = getsource(method) raw_source = getsource(method)
src = dedent(raw_source) src = dedent(raw_source)
tree = parse(src) tree = parse(src)
node = RemoveDispatch( node = RemoveDispatch(self._registered_events).visit(tree)
self._registered_events, self.app.state.verbosity
).visit(tree)
compiled_src = compile(node, method.__name__, "exec") compiled_src = compile(node, method.__name__, "exec")
exec_locals: Dict[str, Any] = {} exec_locals: Dict[str, Any] = {}
exec(compiled_src, module_globals, exec_locals) # nosec exec(compiled_src, module_globals, exec_locals) # nosec
@ -64,9 +62,8 @@ class OptionalDispatchEvent(BaseScheme):
class RemoveDispatch(NodeTransformer): class RemoveDispatch(NodeTransformer):
def __init__(self, registered_events, verbosity: int = 0) -> None: def __init__(self, registered_events) -> None:
self._registered_events = registered_events self._registered_events = registered_events
self._verbosity = verbosity
def visit_Expr(self, node: Expr) -> Any: def visit_Expr(self, node: Expr) -> Any:
call = node.value call = node.value
@ -83,8 +80,10 @@ class RemoveDispatch(NodeTransformer):
if hasattr(event, "s"): if hasattr(event, "s"):
event_name = getattr(event, "value", event.s) event_name = getattr(event, "value", event.s)
if self._not_registered(event_name): if self._not_registered(event_name):
if self._verbosity >= 2: logger.debug(
logger.debug(f"Disabling event: {event_name}") f"Disabling event: {event_name}",
extra={"verbosity": 2},
)
return None return None
return node return node

View File

@ -222,6 +222,7 @@ def test_listeners_triggered_async(app, caplog):
assert after_server_stop assert after_server_stop
app.state.mode = Mode.DEBUG app.state.mode = Mode.DEBUG
app.state.verbosity = 0
with caplog.at_level(logging.DEBUG): with caplog.at_level(logging.DEBUG):
server.run() server.run()

View File

@ -209,3 +209,42 @@ def test_access_log_client_ip_reqip(monkeypatch):
"request": f"GET {request.scheme}://{request.host}/", "request": f"GET {request.scheme}://{request.host}/",
}, },
) )
@pytest.mark.parametrize(
"app_verbosity,log_verbosity,exists",
(
(0, 0, True),
(0, 1, False),
(0, 2, False),
(1, 0, True),
(1, 1, True),
(1, 2, False),
(2, 0, True),
(2, 1, True),
(2, 2, True),
),
)
def test_verbosity(app, caplog, app_verbosity, log_verbosity, exists):
rand_string = str(uuid.uuid4())
@app.get("/")
def log_info(request):
logger.info("DEFAULT")
logger.info(rand_string, extra={"verbosity": log_verbosity})
return text("hello")
with caplog.at_level(logging.INFO):
_ = app.test_client.get(
"/", server_kwargs={"verbosity": app_verbosity}
)
record = ("sanic.root", logging.INFO, rand_string)
if exists:
assert record in caplog.record_tuples
else:
assert record not in caplog.record_tuples
if app_verbosity == 0:
assert ("sanic.root", logging.INFO, "DEFAULT") in caplog.record_tuples