From 41987c9380a807b29fbe41d00f67a07a4e9d17c4 Mon Sep 17 00:00:00 2001 From: GeoJulien Date: Tue, 23 May 2023 16:14:46 +0200 Subject: [PATCH] Add journalizer module --- geotribu_cli/cli.py | 32 ++++--- geotribu_cli/utils/journalizer.py | 137 ++++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+), 17 deletions(-) create mode 100644 geotribu_cli/utils/journalizer.py diff --git a/geotribu_cli/cli.py b/geotribu_cli/cli.py index 52a959a..afa665c 100644 --- a/geotribu_cli/cli.py +++ b/geotribu_cli/cli.py @@ -36,6 +36,7 @@ parser_search_image, parser_upgrade, ) +from geotribu_cli.utils.journalizer import configure_logger # ############################################################################# # ########## Globals ############### @@ -142,11 +143,18 @@ def main(args: list[str] = None): action="count", default=1, dest="verbosity", - # metavar="GEOTRIBU_LOGS_LEVEL", help="Niveau de verbosité : None = WARNING, -v = INFO, -vv = DEBUG. Réglable " "avec la variable d'environnement GEOTRIBU_LOGS_LEVEL.", ) + main_parser.add_argument( + "--no-logfile", + default=True, + action="store_false", + dest="opt_logfile_disabled", + help="Désactiver les fichiers de journalisation (logs).", + ) + main_parser.add_argument( "-h", "--help", @@ -318,23 +326,13 @@ def main(args: list[str] = None): # just get passed args args = main_parser.parse_args(args) - # set log level depending on verbosity argument - if 0 < args.verbosity < 4: - args.verbosity = 40 - (10 * args.verbosity) - elif args.verbosity >= 4: - # debug is the limit - args.verbosity = 40 - (10 * 3) + # log configuration + if args.opt_logfile_disabled: + configure_logger( + verbosity=args.verbosity, logfile=f"{__title_clean__}_{__version__}.log" + ) else: - args.verbosity = 0 - - logging.basicConfig( - level=args.verbosity, - format="%(asctime)s||%(levelname)s||%(module)s||%(message)s", - datefmt="%Y-%m-%d %H:%M:%S", - ) - - console = logging.StreamHandler() - console.setLevel(args.verbosity) + configure_logger(verbosity=args.verbosity) # add the handler to the root logger logger = logging.getLogger(__title_clean__) diff --git a/geotribu_cli/utils/journalizer.py b/geotribu_cli/utils/journalizer.py new file mode 100644 index 0000000..b008238 --- /dev/null +++ b/geotribu_cli/utils/journalizer.py @@ -0,0 +1,137 @@ +#! python3 # noqa: E265 + +"""Helper to configure logging depending on CLI options.""" + +# ############################################################################ +# ########## IMPORTS ############# +# ################################ + +# standard library +import logging +from getpass import getuser +from logging.handlers import RotatingFileHandler +from os import getenv +from os.path import expanduser, expandvars +from pathlib import Path +from platform import architecture +from platform import platform as opersys +from socket import gethostname + +# package +from geotribu_cli.__about__ import __title__, __version__ +from geotribu_cli.utils.check_path import check_path +from geotribu_cli.utils.proxies import get_proxy_settings + +# ############################################################################ +# ########## GLOBALS ############# +# ################################ + +# logs +logger = logging.getLogger(__name__) + +# ############################################################################ +# ########## FUNCTIONS ########### +# ################################ + + +def configure_logger(verbosity: int = 1, logfile: Path = None): + """Configure logging according to verbosity from CLI. + + Args: + verbosity (int): verbosity level + logfile (Path, optional): file where to store log. Defaults to None. + """ + # handle log level overridden by environment variable + verbosity = getenv("GEOTRIBU_LOGS_LEVEL", verbosity) + try: + verbosity = int(verbosity) + except ValueError as err: + logger.error(f"Bad verbosity value type: {err}. Fallback to 1.") + verbosity = 1 + + # set log level depending on verbosity argument + if 0 < verbosity < 4: + verbosity = 40 - (10 * verbosity) + elif verbosity >= 4: + # debug is the limit + verbosity = 40 - (10 * 3) + else: + verbosity = 0 + + # set console handler + log_console_handler = logging.StreamHandler() + log_console_handler.setLevel(verbosity) + + # set log file + if not logfile: + logging.basicConfig( + level=verbosity, + format="%(asctime)s||%(levelname)s||%(module)s||%(lineno)d||%(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + handlers=[log_console_handler], + ) + + else: + if getenv("GEOTRIBU_LOGS_DIR") and check_path( + input_path=Path(expandvars(expanduser(getenv("GEOTRIBU_LOGS_DIR")))), + must_be_a_file=False, + must_be_a_folder=True, + must_be_writable=True, + raise_error=False, + ): + logs_folder = Path(expandvars(expanduser(getenv("GEOTRIBU_LOGS_DIR")))) + logger.debug( + f"Logs folder set with GEOTRIBU_LOGS_DIR environment variable: {logs_folder}" + ) + else: + logs_folder: Path = Path().home() / ".geotribu/logs/" + logger.debug( + "Logs folder specified in GEOTRIBU_LOGS_DIR environment variable " + f"{getenv('GEOTRIBU_LOGS_DIR')} can't be used (see logs above). Fallback on " + f"default folder: {logs_folder}" + ) + + # make sure folder exists + logs_folder.mkdir(exist_ok=True, parents=True) + logs_filepath = Path(logs_folder, logfile) + + log_file_handler = RotatingFileHandler( + backupCount=10, + delay=True, + encoding="UTF-8", + filename=logs_filepath, + maxBytes=3000000, + mode="a", + ) + # force new file by execution + if logs_filepath.is_file(): + log_file_handler.doRollover() + + logging.basicConfig( + level=verbosity, + format="%(asctime)s||%(levelname)s||%(module)s||%(lineno)d||%(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + handlers=[log_console_handler, log_file_handler], + ) + + logger.info(f"Log file: {logs_filepath}") + + headers() + + +def headers(): + """Basic information to log before other message.""" + # initialize the log + logger.info(f"{'='*10} {__title__} - {__version__} {'='*10}") + logger.debug(f"Operating System: {opersys()}") + logger.debug(f"Architecture: {architecture()[0]}") + logger.debug(f"Computer: {gethostname()}") + logger.debug(f"Launched by user: {getuser()}") + + if getenv("userdomain"): + logger.debug(f"OS Domain: {getenv('userdomain')}") + + if get_proxy_settings(): + logger.debug(f"Network proxies detected: {get_proxy_settings()}") + else: + logger.debug("No network proxies detected")