Logger
This commit is contained in:
@@ -18,6 +18,6 @@ from pathlib import Path
|
|||||||
|
|
||||||
PathLike = Union[str, Path]
|
PathLike = Union[str, Path]
|
||||||
|
|
||||||
from .logger import logger
|
from .logger import logger, loglevel_map
|
||||||
from .utils import DataDict
|
from .utils import DataDict
|
||||||
from .app import App
|
from .app import App
|
||||||
|
|||||||
+84
-87
@@ -27,7 +27,7 @@ from dotenv import load_dotenv
|
|||||||
|
|
||||||
# Local imports
|
# Local imports
|
||||||
from . import tts_aedocw, tts_generic, tts_kokoro
|
from . import tts_aedocw, tts_generic, tts_kokoro
|
||||||
from . import logger, PathLike
|
from . import logger, PathLike, loglevel_map
|
||||||
from . import DataDict
|
from . import DataDict
|
||||||
|
|
||||||
class App(DataDict):
|
class App(DataDict):
|
||||||
@@ -36,7 +36,7 @@ class App(DataDict):
|
|||||||
ENV_FILE_OVERRIDE=False
|
ENV_FILE_OVERRIDE=False
|
||||||
WHICH = ["ffmpeg"] # Needed in $PATH
|
WHICH = ["ffmpeg"] # Needed in $PATH
|
||||||
DEBUG = False
|
DEBUG = False
|
||||||
LOGLEVEL = logging.INFO
|
LOGLEVEL = "WARNING"
|
||||||
BACKENDS = {
|
BACKENDS = {
|
||||||
# keys are the backend names, values are the corresponding TTS classes
|
# keys are the backend names, values are the corresponding TTS classes
|
||||||
"default": tts_generic.GenericTTSBackend,
|
"default": tts_generic.GenericTTSBackend,
|
||||||
@@ -55,77 +55,31 @@ class App(DataDict):
|
|||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args,**kwargs)
|
super().__init__(*args,**kwargs)
|
||||||
self._argv = sys.argv
|
self._argv = sys.argv
|
||||||
|
|
||||||
self._args_list = args if args is not None else self._argv
|
self._args_list = args if args is not None else self._argv
|
||||||
|
|
||||||
|
self.setup_logger()
|
||||||
# Setup logger
|
|
||||||
self.logger = logger
|
|
||||||
self.logger.setLevel(App.LOGLEVEL)
|
|
||||||
if App.DEBUG or "--debug" in self._args_list:
|
|
||||||
self.debug = True
|
|
||||||
self.loglevel = logging.DEBUG
|
|
||||||
logger.info("Loglevel = DEBUG")
|
|
||||||
if "--loglevel" in self._args_list:
|
|
||||||
logger.warning("Ignoring '--loglevel' flag because DEBUG/'--debug' was also set.")
|
|
||||||
if "--verbose" in self._args_list:
|
|
||||||
logger.warning("Ignoring '--verbose' flag because '--debug' was also set.")
|
|
||||||
|
|
||||||
for i, a in enumerate(self._args_list):
|
|
||||||
if a.startswith("--"):
|
|
||||||
match a:
|
|
||||||
case "--env_file":
|
|
||||||
if self.get("env_file", None):
|
|
||||||
self.env_file = self._args_list[i+1]
|
|
||||||
case "--loglevel":
|
|
||||||
self.loglevel = self._args_list[i+1]
|
|
||||||
case "--verbose":
|
|
||||||
self.loglevel = logging.INFO
|
|
||||||
case "--logfile":
|
|
||||||
self.logfile = self._args_list[i+1]
|
|
||||||
|
|
||||||
for var_name in ["env_file","loglevel","logfile"]:
|
|
||||||
flag = f"--{var_name}="
|
|
||||||
if a.startswith(flag):
|
|
||||||
self[var_name] = a.replace(flag, "")
|
|
||||||
|
|
||||||
if "env_file" not in self._data:
|
if "env_file" not in self._data:
|
||||||
self._data["env_file"] = App.DEFAULT_ENV_FILE
|
self._data["env_file"] = App.DEFAULT_ENV_FILE
|
||||||
|
self.logger.debug(self._data["env_file"])
|
||||||
|
|
||||||
|
|
||||||
# for path_flag in ["env_file"]:
|
# for path_flag in ["env_file"]:
|
||||||
# if not Path(self[path_flag]).exists():
|
# if not Path(self[path_flag]).exists():
|
||||||
# self.logger.warning(f"Could not read %s. Ignoring '%s' and using '%s'", path_flag, self[path_flag], App.DEFAULT_ENV_FILE)
|
# self.logger.warning(f"Could not read %s. Ignoring '%s' and using '%s'", path_flag, self[path_flag], App.DEFAULT_ENV_FILE)
|
||||||
# self[path_flag] = App["DEFAULT_" + path_flag.upper()]
|
# self[path_flag] = App["DEFAULT_" + path_flag.upper()]
|
||||||
|
|
||||||
# Set loglevel from laste --loglevel flag found in args/sys.argv
|
|
||||||
if "loglevel" not in self._data:
|
|
||||||
self.loglevel = self.LOGLEVEL
|
|
||||||
self.logger.setLevel(self.loglevel)
|
|
||||||
|
|
||||||
# load .env/env_file
|
# load .env/env_file
|
||||||
load_dotenv(self.env_file, override=os.environ.get("ENV_FILE_OVERRIDE",App.ENV_FILE_OVERRIDE))
|
load_dotenv(self.env_file, override=os.environ.get("ENV_FILE_OVERRIDE",App.ENV_FILE_OVERRIDE))
|
||||||
|
|
||||||
|
|
||||||
# Now we can call argparser with correct defaults and logger/loglevel
|
# Now we can call argparser with correct defaults and logger/loglevel
|
||||||
# Get ArgumentParser and pased *args or read from sys.argv
|
# Get ArgumentParser and pased *args or read from sys.argv
|
||||||
self._parsed_args = self.get_parser().parse_args(args or sys.argv[1:])
|
self._parsed_args = self.get_parser().parse_args(args or sys.argv[1:])
|
||||||
for k,v in self._parsed_args.__dict__.items():
|
for k,v in self._parsed_args.__dict__.items():
|
||||||
self[k] = v
|
self[k] = v
|
||||||
|
|
||||||
if self._parsed_args.loglevel:
|
|
||||||
self.loglevel = self._parsed_args.loglevel
|
|
||||||
self.logger.setLevel(self.loglevel)
|
|
||||||
elif self._parsed_args.verbose:
|
|
||||||
self.loglevel = logging.INFO
|
|
||||||
self.logger.setLevel(self.loglevel)
|
|
||||||
|
|
||||||
if getattr(self, "logfile", None) or getattr(self._parsed_args, "logfile", None):
|
|
||||||
logfile = getattr(self, "logfile", None) or self._parsed_args.logfile
|
|
||||||
fh = logging.FileHandler(logfile)
|
|
||||||
fh.setLevel(self.loglevel)
|
|
||||||
fh.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(message)s"))
|
|
||||||
self.logger.addHandler(fh)
|
|
||||||
|
|
||||||
# Validate and sanitize output
|
# Validate and sanitize output
|
||||||
self.output_path = App.path(self.output)
|
self.output_path = App.path(self.output)
|
||||||
if len(self.input) > 1 and not self.output_path.is_dir():
|
if len(self.input) > 1 and not self.output_path.is_dir():
|
||||||
@@ -136,28 +90,28 @@ class App(DataDict):
|
|||||||
# Validate and sanitize input
|
# Validate and sanitize input
|
||||||
self.input_files = {}
|
self.input_files = {}
|
||||||
self.input_dirs = []
|
self.input_dirs = []
|
||||||
self.info("Paths provided as input: %d", len(self.input))
|
self.logger.info("Paths provided as input: %d", len(self.input))
|
||||||
for i, input_str in enumerate(self.input):
|
for i, input_str in enumerate(self.input):
|
||||||
self.info("[Input %d] %s", i+1, input_str)
|
self.logger.info("[Input %d] %s", i+1, input_str)
|
||||||
input_path = App.path(input_str)
|
input_path = App.path(input_str)
|
||||||
if not input_path.exists():
|
if not input_path.exists():
|
||||||
self.warning("Skipping path (do not exist): '%s'.", input_path)
|
self.logger.warning("Skipping path (do not exist): '%s'.", input_path)
|
||||||
continue
|
continue
|
||||||
if input_path.is_dir():
|
if input_path.is_dir():
|
||||||
self.input_dir.append(input_path)
|
self.input_dir.append(input_path)
|
||||||
self.info("Added directory to queue: '%s'", input_path)
|
self.logger.info("Added directory to queue: '%s'", input_path)
|
||||||
else:
|
else:
|
||||||
self.input_files[input_str] = {"path":input_path}
|
self.input_files[input_str] = {"path":input_path}
|
||||||
self.input_files[input_str]["filename"] = self.input_files[input_str]["path"].name
|
self.input_files[input_str]["filename"] = self.input_files[input_str]["path"].name
|
||||||
self.input_files[input_str]["stem"] = self.input_files[input_str]["path"].stem
|
self.input_files[input_str]["stem"] = self.input_files[input_str]["path"].stem
|
||||||
self.input_files[input_str]["suffix"] = self.input_files[input_str]["path"].suffix
|
self.input_files[input_str]["suffix"] = self.input_files[input_str]["path"].suffix
|
||||||
#self.input_files[input_str]["filetype"] = ebook_meta self.input_files[input_str]["path"]
|
#self.input_files[input_str]["filetype"] = ebook_meta self.input_files[input_str]["path"]
|
||||||
self.info("Added file to queue: %s", self.input_files[input_str])
|
self.logger.info("Added file to queue: %s", self.input_files[input_str])
|
||||||
del self._data["input"]
|
del self._data["input"]
|
||||||
|
|
||||||
|
|
||||||
# Sanitize replace_map
|
# Sanitize replace_map
|
||||||
self.debug(self.replace)
|
self.logger.debug(self.replace)
|
||||||
if self.replace and len(self.replace) % 2 == 0:
|
if self.replace and len(self.replace) % 2 == 0:
|
||||||
self.replace_map = { old: new for old, new in self.replace}
|
self.replace_map = { old: new for old, new in self.replace}
|
||||||
del self.replace
|
del self.replace
|
||||||
@@ -170,41 +124,73 @@ class App(DataDict):
|
|||||||
if self._parsed_args.check_env:
|
if self._parsed_args.check_env:
|
||||||
self.check_env()
|
self.check_env()
|
||||||
|
|
||||||
|
self.engine = App.BACKENDS[self.backend](self)
|
||||||
|
|
||||||
self.engine = App.BACKENDS[args.backend](**vars(args))
|
def setup_logger(self, verbose=None, debug_level=None, loglevel: str|int = None, logfile:PathLike=None):
|
||||||
if len(args.input) > 1 and not output_dest.is_dir():
|
"""Initialize the package logger from CLI flags and defaults.
|
||||||
self.logger.error(f"Output must be a directory when multiple input files are provided")
|
|
||||||
sys.exit(1)
|
|
||||||
for file in args.input:
|
|
||||||
self.logger.info(file)
|
|
||||||
if not Path(file).exists():
|
|
||||||
self.logger.error(f"Input file %s does not exist", file)
|
|
||||||
sys.exit(1)
|
|
||||||
output_dest = Path(args.output)
|
|
||||||
|
|
||||||
# Log functions
|
Resolve the effective logging level from the class args (or sys.argv).
|
||||||
def log(self, *args,**kwargs):
|
--debug (or debug_level=True) takes priority, then --verbose (or verbose=True)
|
||||||
self.logger.log(self.loglevel, *args, **kwargs)
|
is compared to --loglevel (or loglevel=) and the lower one is proritized.
|
||||||
|
"""
|
||||||
|
# Setup logger
|
||||||
|
self.logger = logger
|
||||||
|
|
||||||
# 10=DEBUG
|
# Find lowest priority loglevel
|
||||||
def debug(self, *args,**kwargs):
|
if debug_level or App.DEBUG or "--debug" in self._args_list:
|
||||||
self.logger.debug(*args, **kwargs)
|
self.debug_level = True
|
||||||
|
self.loglevel = "DEBUG"
|
||||||
|
else: # compare verbose to loglevel
|
||||||
|
if "--verbose" in self._args_list or verbose == True:
|
||||||
|
self.verbose = True
|
||||||
|
for i, a in enumerate(self._args_list):
|
||||||
|
if a == "--loglevel":
|
||||||
|
self.loglevel = self._args_list[i+1]
|
||||||
|
elif a.startswith("--loglevel="):
|
||||||
|
self.loglevel = a.replace("--loglevel=", "")
|
||||||
|
|
||||||
# 20=INFO
|
if "loglevel" in self and self.loglevel is None:
|
||||||
def info(self, *args,**kwargs):
|
if loglevel is not None:
|
||||||
self.logger.info(*args, **kwargs)
|
self.loglevel = loglevel
|
||||||
|
else:
|
||||||
|
self.loglevel = App.LOGLEVEL
|
||||||
|
|
||||||
# 30=WARN/WARNING
|
# lower = more priority
|
||||||
def warning(self, *args,**kwargs):
|
if loglevel_map[self.loglevel] > loglevel_map["INFO"]:
|
||||||
self.logger.warning(*args, **kwargs)
|
self.loglevel = "INFO"
|
||||||
|
|
||||||
# 40=ERROR
|
self.logger.setLevel(loglevel_map[self.loglevel])
|
||||||
def error(self, *args,**kwargs):
|
|
||||||
self.logger.error(*args, **kwargs)
|
|
||||||
|
|
||||||
# 50=CRITICAL/FATAL
|
# Get logfile
|
||||||
def critical(self, *args,**kwargs):
|
for i, a in enumerate(self._args_list):
|
||||||
self.logger.critical(*args, **kwargs)
|
if a == "--logfile":
|
||||||
|
self.logfile = self._args_list[i+1]
|
||||||
|
elif a.startswith("--logfile="):
|
||||||
|
self.logfile = a.replace("--logfile=", "")
|
||||||
|
|
||||||
|
if "logfile" in self and self.logfile:
|
||||||
|
if logfile:
|
||||||
|
self.logger.warning("Overriding --logfile='%s' from setup_logger(logfile='%s')", self.logfile, logfile)
|
||||||
|
self.logfile = logfile
|
||||||
|
fh = logging.FileHandler(logfile)
|
||||||
|
fh.setLevel(self.loglevel)
|
||||||
|
fh.setFormatter(logger.formatter)
|
||||||
|
self.logger.addHandler(fh)
|
||||||
|
|
||||||
|
# if self.debug_level:
|
||||||
|
# logger.info("Loglevel: DEBUG")
|
||||||
|
# if self.loglevel:
|
||||||
|
# logger.warning("Ignoring '--loglevel' flag because DEBUG/'--debug' was also set.")
|
||||||
|
# if "--verbose" in self._args_list:
|
||||||
|
# logger.warning("Ignoring '--verbose' flag because '--debug' was also set.")
|
||||||
|
# self.verbose = False
|
||||||
|
# if self.loglevel and self.verbose:
|
||||||
|
# self.warning("Conflict: trying to --loglevel=%s (%d) and --verbose.", self.loglevel, loglevel_map[self.loglevel])
|
||||||
|
# if loglevel_map[self.loglevel] < logging.INFO:
|
||||||
|
# self.logger.info("Setting loglevel to %s (%d), which is more verbose than INFO.", self.loglevel, loglevel_map[self.loglevel])
|
||||||
|
|
||||||
|
|
||||||
|
return self.logger
|
||||||
|
|
||||||
# Utility methods
|
# Utility methods
|
||||||
def check_env(self, which=None):
|
def check_env(self, which=None):
|
||||||
@@ -238,8 +224,19 @@ class App(DataDict):
|
|||||||
|
|
||||||
# General options
|
# General options
|
||||||
p.add_argument(
|
p.add_argument(
|
||||||
"--debug", action="store_true",
|
"--debug", dest="debug_level", action="store_true",
|
||||||
help="Enable debug logging and verbose diagnostics")
|
help="Enable debug logging and verbose diagnostics")
|
||||||
|
p.add_argument(
|
||||||
|
"--verbose", action="store_true",
|
||||||
|
help="Enable info-level logging")
|
||||||
|
p.add_argument(
|
||||||
|
"--loglevel",
|
||||||
|
type=str.upper, default=logging.INFO,
|
||||||
|
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
|
||||||
|
help="Set logging level, from most verbose to least verbose:")
|
||||||
|
p.add_argument(
|
||||||
|
"--logfile", default=None,
|
||||||
|
help="Write logs to the specified file")
|
||||||
|
|
||||||
# Input options and processing
|
# Input options and processing
|
||||||
p.add_argument(
|
p.add_argument(
|
||||||
|
|||||||
+32
-1
@@ -6,6 +6,7 @@
|
|||||||
# Logging
|
# Logging
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
|
import enum
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
@@ -13,15 +14,45 @@ import sys
|
|||||||
import pprint
|
import pprint
|
||||||
|
|
||||||
# Globals
|
# Globals
|
||||||
|
format_str = "[%(name)s:%(filename)s:%(funcName)s:%(lineno)04d] %(asctime)s::%(levelname).4s: %(message)s"
|
||||||
|
# %(name)s Name of the logger (logging channel)
|
||||||
|
# %(levelno)s Numeric logging level for the message (DEBUG, INFO,
|
||||||
|
# WARNING, ERROR, CRITICAL)
|
||||||
|
# %(levelname)s Text logging level for the message ("DEBUG", "INFO",
|
||||||
|
# "WARNING", "ERROR", "CRITICAL")
|
||||||
|
# %(pathname)s Full pathname of the source file where the logging
|
||||||
|
# call was issued (if available)
|
||||||
|
# %(filename)s Filename portion of pathname
|
||||||
|
# %(module)s Module (name portion of filename)
|
||||||
|
# %(lineno)d Source line number where the logging call was issued
|
||||||
|
# (if available)
|
||||||
|
# %(funcName)s Function name
|
||||||
|
# %(created)f Time when the LogRecord was created (time.time_ns() / 1e9
|
||||||
|
# return value)
|
||||||
|
# %(asctime)s Textual time when the LogRecord was created
|
||||||
|
# %(msecs)d Millisecond portion of the creation time
|
||||||
|
# %(relativeCreated)d Time in milliseconds when the LogRecord was created,
|
||||||
|
# relative to the time the logging module was loaded
|
||||||
|
# (typically at application startup time)
|
||||||
|
# %(thread)d Thread ID (if available)
|
||||||
|
# %(threadName)s Thread name (if available)
|
||||||
|
# %(taskName)s Task name (if available)
|
||||||
|
# %(process)d Process ID (if available)
|
||||||
|
# %(processName)s Process name (if available)
|
||||||
|
# %(message)s The result of record.getMessage(), computed just as
|
||||||
|
# the record is emitted
|
||||||
|
formatter = logging.Formatter(format_str)
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
# 50=CRITICAL/FATAL, 40=ERROR, 30=WARN/WARNING, 20=INFO, 10=DEBUG, 0=NOTSET
|
# 50=CRITICAL/FATAL, 40=ERROR, 30=WARN/WARNING, 20=INFO, 10=DEBUG, 0=NOTSET
|
||||||
# loglevel_map = logging.getLevelNamesMapping()
|
# loglevel_map = logging.getLevelNamesMapping()
|
||||||
level=logging.INFO,
|
level=logging.INFO,
|
||||||
format="%(asctime)s %(levelname)s %(message)s",
|
format=format_str,
|
||||||
)
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
loglevel_map = logging.getLevelNamesMapping()
|
||||||
|
|
||||||
|
|
||||||
# Logging utils
|
# Logging utils
|
||||||
def print(message):
|
def print(message):
|
||||||
|
|||||||
Reference in New Issue
Block a user