diff --git a/.gitignore b/.gitignore index 97e49d4dbb3e05e59ec5d256f4a1599b87f1b9c7..d2a41f322a41f6c51d5daecf291eafacf7fde4ef 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ examples/results tests/temp_data_cache/ notTracked/ *.swp +log/ +*/log/ diff --git a/tests/conversionOfTimestamps.py b/tests/conversionOfTimestamps.py index bb6a18e9448a08866f37fea9a6350e42a75fa9f9..40131a87a80940df56992eda00ce55138c6bb27f 100644 --- a/tests/conversionOfTimestamps.py +++ b/tests/conversionOfTimestamps.py @@ -14,6 +14,7 @@ from toargridding.defaultLogging import toargridding_defaultLogging logger = toargridding_defaultLogging() logger.addShellLogger(logging.DEBUG) logger.logExceptions() +logger.addRotatingLogFile_scriptName(__file__) #logger.addSysLogger(logging.DEBUG) #raise RuntimeError("For testing purposes") diff --git a/toargridding/defaultLogging.py b/toargridding/defaultLogging.py index 70698bc9724b64e32fc8edcca3cb8cbf1814a3e2..36ca102c23de13c4556a12677ffba302ed4524f6 100644 --- a/toargridding/defaultLogging.py +++ b/toargridding/defaultLogging.py @@ -1,10 +1,11 @@ import sys import logging from collections import namedtuple -from logging.handlers import SysLogHandler +from pathlib import Path +from logging.handlers import SysLogHandler, TimedRotatingFileHandler -registeredLogger = namedtuple("registeredLogger", ["handler","formatter"]) +handlerPair = namedtuple("registeredLogger", ["handler","formatter"]) class toargridding_defaultLogging: """! class to setup default loggers for toargridding @@ -33,7 +34,7 @@ class toargridding_defaultLogging: def __init__(self, loggername : str = "toargridding" ): self.logger = logging.getLogger(loggername) self.logger.setLevel(logging.DEBUG) - self.registeredLoggers = {}# name : registeredLogger + self.registeredHandlers = {}# name : registeredLogger def registerHandler(self, name : str, handler, formatter = None): """register a handler. Adds it to the logger and stores references in this class. The given formatter (if not None) is added to the handler. @@ -42,23 +43,23 @@ class toargridding_defaultLogging: Throws an exception if the name of the handler is already known. """ - if name in self.registeredLoggers: + if name in self.registeredHandlers: raise ValueError(f"There is already a registered handler with the name {name}.") if formatter is not None: handler.setFormatter(formatter) self.logger.addHandler(handler) - self.registeredLoggers[name] = registeredLogger(handler, formatter) + self.registeredHandlers[name] = handlerPair(handler, formatter) def getHandler(self, name : str): """get a handler for logging by its name used for the registration """ - if name in self.registeredLoggers: - return self.registeredLoggers[name].handler + if name in self.registeredHandlers: + return self.registeredHandlers[name].handler return None def getFormatter(self, name : str): """get a formatter by its name used for the registration """ - if name in self.registeredLoggers: - return self.registeredLoggers[name].formatter + if name in self.registeredHandlers: + return self.registeredHandlers[name].formatter return None def addShellLogger(self, level=logging.INFO): """!adds a formatted logging to the shell to the "toargridding" logger. @@ -86,6 +87,40 @@ class toargridding_defaultLogging: syslog_formatter = logging.Formatter(fmt="TOARGRIDDING [%(levelname)s] - %(filename)s:%(lineno)d: '%(message)s'") syslog_handler.setLevel(level) self.registerHandler("syslog",syslog_handler, syslog_formatter) + def addRotatingLogFile(self, filename : Path, level=logging.INFO): + """creation of a rotating file handler, that will change the files at midnight. + The last 7 files logfiles are stored. + + Parameters: + ---------- + filename: + basename of the file. The parent path will be created, if required. + level: + output level for this handler + """ + filename.parent.mkdir(parents=True, exist_ok=True) + handler = TimedRotatingFileHandler(filename, when="midnight", backupCount=7) + handler.setLevel(level) + formatter = logging.Formatter(fmt="%(asctime)s [%(levelname)s] - %(filename)s:%(lineno)d: '%(message)s'", datefmt="%Y-%m-%d %H:%M:%S") + self.registerHandler("rotatingFile", handler, formatter) + def addRotatingLogFile_scriptName(self, scriptName : str | Path, level=logging.INFO): + """creation of an rotating log file by using the script name. + In the /path/to/script a subdirectory log will be created. The logfile will be name [script basename].log + + Parameters: + ---------- + scriptName: + name to the script, including its path + level: + verbosity level. + """ + sn = Path(scriptName) + if not sn.is_file: + raise ValueError(f"Expecting name to a script. {sn} is not a file.") + path = sn.parent / "log" + path.mkdir(exist_ok=True) + fn = path / f"{sn.stem}.log" + self.addRotatingLogFile(fn, level) def logExceptions(self): """calling this function will redirect all uncaught exceptions to the logger This is especially useful to write the exceptions to the system log diff --git a/toargridding/toar_rest_client.py b/toargridding/toar_rest_client.py index 89d03f0f1ac926abefe7a80e8bc40c2ef654d2a1..dafb710a20656f19765a12bd2a6452a770f4898e 100644 --- a/toargridding/toar_rest_client.py +++ b/toargridding/toar_rest_client.py @@ -586,7 +586,7 @@ class AnalysisServiceDownload(AnalysisService): with open(filename, "w+b") as downloaded_file: downloaded_file.write(response.content) else: - logger.info(f"Loading already downloaded data from {filename}") + logger.info(f"Loading already downloaded data to file {filename}") with open(filename, "r+b") as data_file: content = data_file.read()