Adicionar src/renatoxsr-py/logger.py

This commit is contained in:
2026-09-17 10:26:23 -03:00
parent 5151725030
commit e93787c647
+242
View File
@@ -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)