mirror of
https://github.com/checktheroads/hyperglass
synced 2024-05-11 05:55:08 +00:00
improve log handling
This commit is contained in:
@@ -37,29 +37,27 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||
"""
|
||||
|
||||
# Standard Library
|
||||
import sys
|
||||
import logging
|
||||
|
||||
# Third Party
|
||||
import uvloop
|
||||
import rich.traceback
|
||||
|
||||
# Project
|
||||
from hyperglass.log import _get_rich
|
||||
from hyperglass.util import set_app_path
|
||||
from hyperglass.constants import METADATA
|
||||
|
||||
try:
|
||||
# Third Party
|
||||
import stackprinter
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
if sys.stdout.isatty():
|
||||
_style = "darkbg2"
|
||||
else:
|
||||
_style = "plaintext"
|
||||
stackprinter.set_excepthook(style=_style)
|
||||
# Use Rich for traceback formatting.
|
||||
rich.traceback.install()
|
||||
|
||||
# Set Rich as the default logging handler.
|
||||
logging.getLogger().handlers = [_get_rich(True)]
|
||||
|
||||
# Find hyperglass application directory.
|
||||
set_app_path()
|
||||
|
||||
# Use Uvloop for performance.
|
||||
uvloop.install()
|
||||
|
||||
__name__, __version__, __author__, __copyright__, __license__ = METADATA
|
||||
|
@@ -123,7 +123,8 @@ def start(build, direct, workers):
|
||||
start(**kwargs)
|
||||
elif not build and direct:
|
||||
uvicorn_start(**kwargs)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
error("Stopping hyperglass due to keyboard interrupt.")
|
||||
except BaseException as err:
|
||||
error(str(err))
|
||||
|
||||
|
@@ -54,6 +54,23 @@ def _get_rich(debug: bool = False) -> RichHandler:
|
||||
return RichHandler(**rich_kwargs)
|
||||
|
||||
|
||||
def setup_lib_logging(debug: bool = False) -> None:
|
||||
"""Override the logging handlers for dependency libraries."""
|
||||
for name in (
|
||||
"gunicorn",
|
||||
"gunicorn.access",
|
||||
"gunicorn.error",
|
||||
"uvicorn",
|
||||
"uvicorn.access",
|
||||
"uvicorn.error",
|
||||
"uvicorn.asgi",
|
||||
"netmiko",
|
||||
"scrapli",
|
||||
"httpx",
|
||||
):
|
||||
logging.getLogger(name).handlers = [_get_rich(debug)]
|
||||
|
||||
|
||||
def base_logger():
|
||||
"""Initialize hyperglass logging instance."""
|
||||
_loguru_logger.remove()
|
||||
@@ -75,31 +92,6 @@ def _log_success(self, message, *a, **kw):
|
||||
|
||||
logging.Logger.success = _log_success
|
||||
|
||||
builtin_logging_config = {
|
||||
"version": 1,
|
||||
"formatters": {"basic": {"format": "%(message)s"}},
|
||||
"root": {"level": "INFO", "handlers": ["rich"]},
|
||||
"handlers": {
|
||||
"rich": {
|
||||
"level": "INFO",
|
||||
"formatter": "basic",
|
||||
"class": "rich.logging.RichHandler",
|
||||
},
|
||||
"console": {
|
||||
"level": "INFO",
|
||||
"formatter": "basic",
|
||||
"class": "rich.logging.RichHandler",
|
||||
},
|
||||
},
|
||||
"loggers": {
|
||||
"": {"handlers": ["console"], "level": "INFO", "propagate": True},
|
||||
"uvicorn": {"handlers": ["rich"], "level": "INFO", "propagate": True},
|
||||
"uvicorn.access": {"handlers": ["rich"], "level": "INFO", "propagate": True},
|
||||
"uvicorn.error": {"handlers": ["rich"], "level": "ERROR", "propagate": True},
|
||||
"uvicorn.asgi": {"handlers": ["rich"], "level": "INFO", "propagate": True},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def set_log_level(logger, debug):
|
||||
"""Set log level based on debug state."""
|
||||
|
@@ -4,14 +4,16 @@
|
||||
import sys
|
||||
import math
|
||||
import shutil
|
||||
import logging
|
||||
import platform
|
||||
|
||||
# Third Party
|
||||
from gunicorn.arbiter import Arbiter
|
||||
from gunicorn.app.base import BaseApplication
|
||||
from gunicorn.glogging import Logger
|
||||
|
||||
# Project
|
||||
from hyperglass.log import log
|
||||
from hyperglass.log import log, setup_lib_logging
|
||||
from hyperglass.constants import MIN_PYTHON_VERSION, __version__
|
||||
|
||||
pretty_version = ".".join(tuple(str(v) for v in MIN_PYTHON_VERSION))
|
||||
@@ -45,6 +47,23 @@ else:
|
||||
loglevel = "WARNING"
|
||||
|
||||
|
||||
class StubbedGunicornLogger(Logger):
|
||||
"""Custom logging to direct Gunicorn/Uvicorn logs to Loguru/Rich.
|
||||
|
||||
See: https://pawamoy.github.io/posts/unify-logging-for-a-gunicorn-uvicorn-app/
|
||||
"""
|
||||
|
||||
def setup(self, cfg):
|
||||
"""Override Gunicorn setup."""
|
||||
handler = logging.NullHandler()
|
||||
self.error_logger = logging.getLogger("gunicorn.error")
|
||||
self.error_logger.addHandler(handler)
|
||||
self.access_logger = logging.getLogger("gunicorn.access")
|
||||
self.access_logger.addHandler(handler)
|
||||
self.error_logger.setLevel(loglevel)
|
||||
self.access_logger.setLevel(loglevel)
|
||||
|
||||
|
||||
def check_redis_instance() -> bool:
|
||||
"""Ensure Redis is running before starting server."""
|
||||
|
||||
@@ -93,6 +112,8 @@ def cache_config():
|
||||
def on_starting(server: Arbiter):
|
||||
"""Gunicorn pre-start tasks."""
|
||||
|
||||
setup_lib_logging(params.debug)
|
||||
|
||||
python_version = platform.python_version()
|
||||
required = ".".join((str(v) for v in MIN_PYTHON_VERSION))
|
||||
log.info("Python {} detected ({} required)", python_version, required)
|
||||
@@ -173,7 +194,10 @@ def start(**kwargs):
|
||||
"timeout": math.ceil(params.request_timeout * 1.25),
|
||||
"on_starting": on_starting,
|
||||
"on_exit": on_exit,
|
||||
"raw_env": ["testing=test"],
|
||||
"logger_class": StubbedGunicornLogger,
|
||||
"accesslog": "-",
|
||||
"errorlog": "-",
|
||||
"logconfig_dict": {"formatters": {"generic": {"format": "%(message)s"}}},
|
||||
**kwargs,
|
||||
},
|
||||
).run()
|
||||
|
Reference in New Issue
Block a user