Tune Gunicorn log output
- keep access logs on stdout/stderr - filter static, Socket.IO, and boot noise - align Gunicorn rows with app log format
This commit is contained in:
parent
9619a63e4e
commit
8b9284f414
3 changed files with 81 additions and 2 deletions
|
|
@ -11,7 +11,9 @@ timeout = 120
|
||||||
# Keep shutdowns under Docker's stop window so container restarts stay graceful.
|
# Keep shutdowns under Docker's stop window so container restarts stay graceful.
|
||||||
graceful_timeout = 8
|
graceful_timeout = 8
|
||||||
|
|
||||||
# Logging goes to stdout/stderr so Docker can collect it.
|
# Logging goes to stdout/stderr and is filtered by the custom logger class.
|
||||||
accesslog = "-"
|
accesslog = "-"
|
||||||
errorlog = "-"
|
errorlog = "-"
|
||||||
|
access_log_format = '%(h)s - - "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'
|
||||||
loglevel = "info"
|
loglevel = "info"
|
||||||
|
logger_class = "utils.gunicorn_logger.FilteredGunicornLogger"
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,10 @@ timeout = 120
|
||||||
# Don't let local reloads wait too long for shutdown.
|
# Don't let local reloads wait too long for shutdown.
|
||||||
graceful_timeout = 1
|
graceful_timeout = 1
|
||||||
|
|
||||||
# Logging goes to stdout/stderr so the shell launcher can collect it.
|
# Logging goes to stdout/stderr and is filtered by the custom logger class.
|
||||||
accesslog = "-"
|
accesslog = "-"
|
||||||
errorlog = "-"
|
errorlog = "-"
|
||||||
|
# Mimic process log format
|
||||||
|
access_log_format = '%(h)s - - "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'
|
||||||
loglevel = "info"
|
loglevel = "info"
|
||||||
|
logger_class = "utils.gunicorn_logger.FilteredGunicornLogger"
|
||||||
|
|
|
||||||
74
utils/gunicorn_logger.py
Normal file
74
utils/gunicorn_logger.py
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
"""Gunicorn logger tweaks for SoulSync."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from gunicorn.glogging import Logger as GunicornLogger
|
||||||
|
from utils.logging_config import ColoredFormatter
|
||||||
|
|
||||||
|
|
||||||
|
class FilteredGunicornLogger(GunicornLogger):
|
||||||
|
"""Gunicorn logger that skips noisy static and Socket.IO access logs."""
|
||||||
|
|
||||||
|
_STATIC_PREFIXES = (
|
||||||
|
"/static/",
|
||||||
|
"/assets/",
|
||||||
|
"/socket.io",
|
||||||
|
"/favicon.ico",
|
||||||
|
"/robots.txt",
|
||||||
|
)
|
||||||
|
|
||||||
|
_STATIC_SUFFIXES = (
|
||||||
|
".css",
|
||||||
|
".js",
|
||||||
|
".map",
|
||||||
|
".png",
|
||||||
|
".jpg",
|
||||||
|
".jpeg",
|
||||||
|
".gif",
|
||||||
|
".svg",
|
||||||
|
".ico",
|
||||||
|
".woff",
|
||||||
|
".woff2",
|
||||||
|
".ttf",
|
||||||
|
".eot",
|
||||||
|
)
|
||||||
|
|
||||||
|
def _should_skip_access_log(self, environ) -> bool:
|
||||||
|
path = environ.get("PATH_INFO") or ""
|
||||||
|
if not path:
|
||||||
|
return False
|
||||||
|
|
||||||
|
normalized = path if path.startswith("/") else f"/{path}"
|
||||||
|
lower_path = normalized.lower()
|
||||||
|
|
||||||
|
if any(
|
||||||
|
lower_path == prefix.rstrip("/") or lower_path.startswith(prefix)
|
||||||
|
for prefix in self._STATIC_PREFIXES
|
||||||
|
):
|
||||||
|
return True
|
||||||
|
|
||||||
|
return any(lower_path.endswith(suffix) for suffix in self._STATIC_SUFFIXES)
|
||||||
|
|
||||||
|
def access(self, resp, req, environ, request_time):
|
||||||
|
if self._should_skip_access_log(environ):
|
||||||
|
return
|
||||||
|
super().access(resp, req, environ, request_time)
|
||||||
|
|
||||||
|
def setup(self, cfg):
|
||||||
|
super().setup(cfg)
|
||||||
|
|
||||||
|
app_like_formatter = ColoredFormatter(
|
||||||
|
fmt="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
||||||
|
datefmt="%Y-%m-%d %H:%M:%S",
|
||||||
|
)
|
||||||
|
error_level = getattr(logging, cfg.loglevel.upper(), logging.INFO)
|
||||||
|
|
||||||
|
for handler in self.access_log.handlers:
|
||||||
|
handler.setFormatter(app_like_formatter)
|
||||||
|
handler.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
for handler in self.error_log.handlers:
|
||||||
|
handler.setFormatter(app_like_formatter)
|
||||||
|
handler.setLevel(error_level)
|
||||||
Loading…
Reference in a new issue