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
|
# Standard Library
|
||||||
import sys
|
import logging
|
||||||
|
|
||||||
# Third Party
|
# Third Party
|
||||||
import uvloop
|
import uvloop
|
||||||
|
import rich.traceback
|
||||||
|
|
||||||
# Project
|
# Project
|
||||||
|
from hyperglass.log import _get_rich
|
||||||
from hyperglass.util import set_app_path
|
from hyperglass.util import set_app_path
|
||||||
from hyperglass.constants import METADATA
|
from hyperglass.constants import METADATA
|
||||||
|
|
||||||
try:
|
# Use Rich for traceback formatting.
|
||||||
# Third Party
|
rich.traceback.install()
|
||||||
import stackprinter
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
if sys.stdout.isatty():
|
|
||||||
_style = "darkbg2"
|
|
||||||
else:
|
|
||||||
_style = "plaintext"
|
|
||||||
stackprinter.set_excepthook(style=_style)
|
|
||||||
|
|
||||||
|
# Set Rich as the default logging handler.
|
||||||
|
logging.getLogger().handlers = [_get_rich(True)]
|
||||||
|
|
||||||
|
# Find hyperglass application directory.
|
||||||
set_app_path()
|
set_app_path()
|
||||||
|
|
||||||
|
# Use Uvloop for performance.
|
||||||
uvloop.install()
|
uvloop.install()
|
||||||
|
|
||||||
__name__, __version__, __author__, __copyright__, __license__ = METADATA
|
__name__, __version__, __author__, __copyright__, __license__ = METADATA
|
||||||
|
@@ -123,7 +123,8 @@ def start(build, direct, workers):
|
|||||||
start(**kwargs)
|
start(**kwargs)
|
||||||
elif not build and direct:
|
elif not build and direct:
|
||||||
uvicorn_start(**kwargs)
|
uvicorn_start(**kwargs)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
error("Stopping hyperglass due to keyboard interrupt.")
|
||||||
except BaseException as err:
|
except BaseException as err:
|
||||||
error(str(err))
|
error(str(err))
|
||||||
|
|
||||||
|
@@ -54,6 +54,23 @@ def _get_rich(debug: bool = False) -> RichHandler:
|
|||||||
return RichHandler(**rich_kwargs)
|
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():
|
def base_logger():
|
||||||
"""Initialize hyperglass logging instance."""
|
"""Initialize hyperglass logging instance."""
|
||||||
_loguru_logger.remove()
|
_loguru_logger.remove()
|
||||||
@@ -75,31 +92,6 @@ def _log_success(self, message, *a, **kw):
|
|||||||
|
|
||||||
logging.Logger.success = _log_success
|
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):
|
def set_log_level(logger, debug):
|
||||||
"""Set log level based on debug state."""
|
"""Set log level based on debug state."""
|
||||||
|
@@ -4,14 +4,16 @@
|
|||||||
import sys
|
import sys
|
||||||
import math
|
import math
|
||||||
import shutil
|
import shutil
|
||||||
|
import logging
|
||||||
import platform
|
import platform
|
||||||
|
|
||||||
# Third Party
|
# Third Party
|
||||||
from gunicorn.arbiter import Arbiter
|
from gunicorn.arbiter import Arbiter
|
||||||
from gunicorn.app.base import BaseApplication
|
from gunicorn.app.base import BaseApplication
|
||||||
|
from gunicorn.glogging import Logger
|
||||||
|
|
||||||
# Project
|
# Project
|
||||||
from hyperglass.log import log
|
from hyperglass.log import log, setup_lib_logging
|
||||||
from hyperglass.constants import MIN_PYTHON_VERSION, __version__
|
from hyperglass.constants import MIN_PYTHON_VERSION, __version__
|
||||||
|
|
||||||
pretty_version = ".".join(tuple(str(v) for v in MIN_PYTHON_VERSION))
|
pretty_version = ".".join(tuple(str(v) for v in MIN_PYTHON_VERSION))
|
||||||
@@ -45,6 +47,23 @@ else:
|
|||||||
loglevel = "WARNING"
|
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:
|
def check_redis_instance() -> bool:
|
||||||
"""Ensure Redis is running before starting server."""
|
"""Ensure Redis is running before starting server."""
|
||||||
|
|
||||||
@@ -93,6 +112,8 @@ def cache_config():
|
|||||||
def on_starting(server: Arbiter):
|
def on_starting(server: Arbiter):
|
||||||
"""Gunicorn pre-start tasks."""
|
"""Gunicorn pre-start tasks."""
|
||||||
|
|
||||||
|
setup_lib_logging(params.debug)
|
||||||
|
|
||||||
python_version = platform.python_version()
|
python_version = platform.python_version()
|
||||||
required = ".".join((str(v) for v in MIN_PYTHON_VERSION))
|
required = ".".join((str(v) for v in MIN_PYTHON_VERSION))
|
||||||
log.info("Python {} detected ({} required)", python_version, required)
|
log.info("Python {} detected ({} required)", python_version, required)
|
||||||
@@ -173,7 +194,10 @@ def start(**kwargs):
|
|||||||
"timeout": math.ceil(params.request_timeout * 1.25),
|
"timeout": math.ceil(params.request_timeout * 1.25),
|
||||||
"on_starting": on_starting,
|
"on_starting": on_starting,
|
||||||
"on_exit": on_exit,
|
"on_exit": on_exit,
|
||||||
"raw_env": ["testing=test"],
|
"logger_class": StubbedGunicornLogger,
|
||||||
|
"accesslog": "-",
|
||||||
|
"errorlog": "-",
|
||||||
|
"logconfig_dict": {"formatters": {"generic": {"format": "%(message)s"}}},
|
||||||
**kwargs,
|
**kwargs,
|
||||||
},
|
},
|
||||||
).run()
|
).run()
|
||||||
|
Reference in New Issue
Block a user