Adicionar src/renatoxsr-py/logger.py
This commit is contained in:
@@ -0,0 +1,242 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# vim: set ft=python ts=4 sw=4 et: fileencoding=utf-8
|
||||||
|
# SPDX-FileCopyrightText: 2025-present RenatoXSR <renatoxsr@gmail.com>
|
||||||
|
# SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||||
|
"""Create a logger object (stdout) and optionally a logfile."""
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
from enum import StrEnum
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
from platform import node, platform, system
|
||||||
|
import sys
|
||||||
|
import colorlog
|
||||||
|
|
||||||
|
|
||||||
|
from renatoxsr.const import COLORS, INVALID
|
||||||
|
# Defaults
|
||||||
|
FORMAT = f"[%(name)s:%(levelname)s:%(filename)s:%(funcName)s:%(lineno)d][%(process)d] %(message)s"
|
||||||
|
now = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
|
||||||
|
default_logfile = Path.cwd() / "logs" / f"{now}-{__name__}.log"
|
||||||
|
|
||||||
|
def get_formatter(format: str = FORMAT) -> logging.Formatter:
|
||||||
|
"""Return a new logger formatter.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
format (str, optional): [description]. Defaults to None.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
logging.Formatter: [description].
|
||||||
|
|
||||||
|
"""
|
||||||
|
formatter = logging.Formatter(format)
|
||||||
|
return formatter
|
||||||
|
|
||||||
|
|
||||||
|
def set_logfile(
|
||||||
|
*,
|
||||||
|
name: str | None = None,
|
||||||
|
formatter: logging.Formatter | None = None,
|
||||||
|
format: str | None = None,
|
||||||
|
logfile: Path | None = None,
|
||||||
|
) -> logging.Handler:
|
||||||
|
"""Log a message to a file .
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name (str, optional): [description]. Defaults to None.
|
||||||
|
formatter (logging.Formatter, optional): [description]. Defaults to None.
|
||||||
|
format (str, optional): [description]. Defaults to None.
|
||||||
|
logfile (Path, optional): [description]. Defaults to None.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
logging.Handler: [description].
|
||||||
|
|
||||||
|
"""
|
||||||
|
# file handler
|
||||||
|
now_str = now
|
||||||
|
|
||||||
|
if name is None:
|
||||||
|
name = __name__
|
||||||
|
|
||||||
|
if formatter is None:
|
||||||
|
if format is not None:
|
||||||
|
formatter = get_formatter(format)
|
||||||
|
else:
|
||||||
|
formatter = get_formatter()
|
||||||
|
|
||||||
|
if logfile is None:
|
||||||
|
logfile = default_logfile
|
||||||
|
|
||||||
|
if logfile.is_file():
|
||||||
|
logfile.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
file_handler = logging.FileHandler(logfile, mode="a", encoding="utf-8")
|
||||||
|
|
||||||
|
if logfile.is_dir():
|
||||||
|
logfile.mkdir(parents=True, exist_ok=True)
|
||||||
|
file_handler = logging.FileHandler(
|
||||||
|
logfile / f"{name}.log", mode="a", encoding="utf-8"
|
||||||
|
)
|
||||||
|
|
||||||
|
file_handler.setFormatter(formatter)
|
||||||
|
|
||||||
|
return file_handler
|
||||||
|
|
||||||
|
|
||||||
|
def set_loglevel(logger_instance: logging.Logger | None = None, logLevel="") -> int:
|
||||||
|
"""Set the loglevel of a logger instance .
|
||||||
|
|
||||||
|
Args:
|
||||||
|
logger_instance (logging.Logger, optional): [description]. Defaults to None.
|
||||||
|
logLevel (str, optional): logging.[DEBUG|INFO|etc]. Defaults to "".
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
logging.setLevel or None
|
||||||
|
int: EffectiveLoglevel()
|
||||||
|
|
||||||
|
"""
|
||||||
|
if logger_instance:
|
||||||
|
logger_instance.setLevel(getattr(logging, logLevel, "INFO"))
|
||||||
|
elif logLevel:
|
||||||
|
logger.setLevel(getattr(logging, logLevel, "INFO"))
|
||||||
|
return logger.getEffectiveLevel()
|
||||||
|
|
||||||
|
|
||||||
|
def set_logger(
|
||||||
|
*,
|
||||||
|
name: str | None = None,
|
||||||
|
formatter: logging.Formatter | None = None,
|
||||||
|
format: str | None = None,
|
||||||
|
loglevel: str | None = None,
|
||||||
|
logfile: Path | None = None,
|
||||||
|
log_to_file: bool = False,
|
||||||
|
) -> logging.Logger:
|
||||||
|
"""Create and return a logger.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name (str): logger name.
|
||||||
|
formatter (logging.Formatter): formatter to use.
|
||||||
|
format (str): format string to create a formatter.
|
||||||
|
loglevel (str): log level to select.
|
||||||
|
logfile (Path): logfile path.
|
||||||
|
log_to_file (bool): whether to log to file.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
logging.Logger: configured logger.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if name is None:
|
||||||
|
name = __name__
|
||||||
|
|
||||||
|
if formatter is None:
|
||||||
|
if isinstance(format, str):
|
||||||
|
formatter = get_formatter(format)
|
||||||
|
else:
|
||||||
|
formatter = get_formatter()
|
||||||
|
|
||||||
|
stdout_handler = colorlog.StreamHandler()
|
||||||
|
stdout_handler.setFormatter(colorlog.ColoredFormatter(
|
||||||
|
"%(log_color)s" + FORMAT,
|
||||||
|
reset=True,
|
||||||
|
log_colors={
|
||||||
|
'DEBUG': 'cyan',
|
||||||
|
'INFO': 'green',
|
||||||
|
'WARNING': 'yellow',
|
||||||
|
'ERROR': 'red',
|
||||||
|
'CRITICAL': 'red,bg_white',
|
||||||
|
},
|
||||||
|
secondary_log_colors={},
|
||||||
|
style ='%',
|
||||||
|
))
|
||||||
|
|
||||||
|
# stdout handler
|
||||||
|
#stdout_handler = logging.StreamHandler()
|
||||||
|
#stdout_handler.setFormatter(formatter)
|
||||||
|
|
||||||
|
logger = logging.getLogger(name)
|
||||||
|
logger.addHandler(stdout_handler)
|
||||||
|
|
||||||
|
# file handler
|
||||||
|
if logfile:
|
||||||
|
log_to_file = True
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if log_to_file:
|
||||||
|
file_handler = set_logfile(
|
||||||
|
name=name,
|
||||||
|
formatter=formatter,
|
||||||
|
format=format,
|
||||||
|
logfile=logfile,
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.addHandler(file_handler)
|
||||||
|
|
||||||
|
if loglevel is None:
|
||||||
|
loglevel = os.getenv("LOGLEVEL", "INFO")
|
||||||
|
# if logging.getLevelNamesMapping().get(loglevel.upper()) is None:
|
||||||
|
if loglevel not in logging.getLevelNamesMapping():
|
||||||
|
loglevel = "INFO"
|
||||||
|
|
||||||
|
logger.setLevel(loglevel)
|
||||||
|
|
||||||
|
logger.debug("Loglevel: %s", os.getenv("LOGLEVEL"))
|
||||||
|
return logger
|
||||||
|
|
||||||
|
|
||||||
|
# upon import:
|
||||||
|
loglevel = "INFO"
|
||||||
|
for arg in [a for a in sys.argv if a.startswith("--log")]:
|
||||||
|
if arg.startswith("--loglevel="):
|
||||||
|
loglevel = arg.split("=", 1)[1]
|
||||||
|
if arg.startswith("--logfile="):
|
||||||
|
log_to_file = arg.split("=", 1)[1]
|
||||||
|
if arg == "--debug":
|
||||||
|
loglevel = "DEBUG"
|
||||||
|
logger = set_logger()
|
||||||
|
logger.setLevel(loglevel)
|
||||||
|
|
||||||
|
|
||||||
|
# CRITICAL = 50
|
||||||
|
# FATAL = CRITICAL
|
||||||
|
# ERROR = 40
|
||||||
|
# WARNING = 30
|
||||||
|
# WARN = WARNING
|
||||||
|
# INFO = 20
|
||||||
|
# DEBUG = 10
|
||||||
|
# NOTSET = 0
|
||||||
|
|
||||||
|
# _levelToName = {
|
||||||
|
# CRITICAL: 'CRITICAL',
|
||||||
|
# ERROR: 'ERROR',
|
||||||
|
# WARNING: 'WARNING',
|
||||||
|
# INFO: 'INFO',
|
||||||
|
# DEBUG: 'DEBUG',
|
||||||
|
# NOTSET: 'NOTSET',
|
||||||
|
# }
|
||||||
|
# _nameToLevel = {
|
||||||
|
# 'CRITICAL': CRITICAL,
|
||||||
|
# 'FATAL': FATAL,
|
||||||
|
# 'ERROR': ERROR,
|
||||||
|
# 'WARN': WARNING,
|
||||||
|
# 'WARNING': WARNING,
|
||||||
|
# 'INFO': INFO,
|
||||||
|
# 'DEBUG': DEBUG,
|
||||||
|
# 'NOTSET': NOTSET,
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# def log(level, msg, *args, **kwargs):
|
||||||
|
# logger.log(level, f"{COLORS.level}" + msg + f"{COLORS.RESET}", *args, **kwargs)
|
||||||
|
|
||||||
|
# def debug(msg, *args, **kwargs):
|
||||||
|
# logger.log("DEBUG", msg, *args, **kwargs)
|
||||||
|
|
||||||
|
# def info(msg, *args, **kwargs):
|
||||||
|
# logger.log("INFO", msg, *args, **kwargs)
|
||||||
|
|
||||||
|
# def error(msg, *args, **kwargs):
|
||||||
|
# logger.log("ERROR", msg, *args, **kwargs)
|
||||||
|
|
||||||
|
# def warning(msg, *args, **kwargs):
|
||||||
|
# logger.log("WARNING", msg, *args, **kwargs)
|
||||||
Reference in New Issue
Block a user